vfs: check userland buffers before reading them.
[haiku.git] / src / libs / print / libprint / PageSetupDlg.cpp
blob9023cf32166378120cea6ad9aa09c94c12a523d8
1 /*
2 * PageSetupDlg.cpp
3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved.
4 */
6 #include <string>
7 #include <cstring>
8 #include <cstdlib>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <sys/stat.h>
13 #include <Alert.h>
14 #include <Bitmap.h>
15 #include <Box.h>
16 #include <Button.h>
17 #include <Debug.h>
18 #include <Font.h>
19 #include <GridView.h>
20 #include <GroupLayout.h>
21 #include <GroupLayoutBuilder.h>
22 #include <Looper.h>
23 #include <MessageFilter.h>
24 #include <MenuField.h>
25 #include <MenuItem.h>
26 #include <Message.h>
27 #include <Point.h>
28 #include <PopUpMenu.h>
29 #include <PrintJob.h>
30 #include <RadioButton.h>
31 #include <Rect.h>
32 #include <String.h>
33 #include <SupportDefs.h>
34 #include <TextControl.h>
35 #include <View.h>
38 #include "DbgMsg.h"
39 #include "JobData.h"
40 #include "MarginView.h"
41 #include "PageSetupDlg.h"
42 #include "PrinterData.h"
43 #include "PrinterCap.h"
44 #include "PrintUtils.h"
47 using namespace std;
50 enum MSGS {
51 kMsgCancel = 1,
52 kMsgOK,
53 kMsgOrientationChanged,
54 kMsgPaperChanged,
57 PageSetupView::PageSetupView(JobData *job_data, PrinterData *printer_data,
58 const PrinterCap *printer_cap)
59 : BView("pageSetupView", B_WILL_DRAW)
60 , fJobData(job_data)
61 , fPrinterData(printer_data)
62 , fPrinterCap(printer_cap)
64 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
67 PageSetupView::~PageSetupView()
71 void
72 PageSetupView::AddOrientationItem(const char* name, JobData::Orientation orientation)
74 BMessage *msg = new BMessage(kMsgOrientationChanged);
75 msg->AddInt32("orientation", orientation);
76 BMenuItem *item = new BMenuItem(name, msg);
78 fOrientation->AddItem(item);
79 item->SetTarget(this);
80 if (fJobData->GetOrientation() == orientation) {
81 item->SetMarked(true);
82 } else if (fOrientation->CountItems() == 1) {
83 item->SetMarked(true);
87 void
88 PageSetupView::AttachedToWindow()
90 BMenuItem *item = NULL;
91 bool marked;
92 int count;
94 // margin
95 MarginUnit units = fJobData->GetMarginUnit();
96 BRect paper = fJobData->GetPaperRect();
97 BRect margin = fJobData->GetPrintableRect();
99 // re-calculate the margin from the printable rect in points
100 margin.top -= paper.top;
101 margin.left -= paper.left;
102 margin.right = paper.right - margin.right;
103 margin.bottom = paper.bottom - margin.bottom;
105 fMarginView = new MarginView(
106 paper.IntegerWidth(),
107 paper.IntegerHeight(),
108 margin, units);
110 // paper selection
111 marked = false;
112 fPaper = new BPopUpMenu("paperSize");
113 fPaper->SetRadioMode(true);
114 count = fPrinterCap->CountCap(PrinterCap::kPaper);
115 PaperCap **paper_cap = (PaperCap **)fPrinterCap->GetCaps(PrinterCap::kPaper);
116 while (count--) {
117 BMessage *msg = new BMessage(kMsgPaperChanged);
118 msg->AddPointer("paperCap", *paper_cap);
119 item = new BMenuItem((*paper_cap)->fLabel.c_str(), msg);
120 fPaper->AddItem(item);
121 item->SetTarget(this);
122 if ((*paper_cap)->fPaper == fJobData->GetPaper()) {
123 item->SetMarked(true);
124 marked = true;
126 paper_cap++;
128 if (!marked)
129 item->SetMarked(true);
130 BMenuField* paperSize = new BMenuField("paperSize", "Paper size:", fPaper);
132 // orientation
133 fOrientation = new BPopUpMenu("orientation");
134 fOrientation->SetRadioMode(true);
136 BMenuField* orientation = new BMenuField("orientation", "Orientation:", fOrientation);
138 count = fPrinterCap->CountCap(PrinterCap::kOrientation);
139 if (count == 0) {
140 AddOrientationItem("Portrait", JobData::kPortrait);
141 AddOrientationItem("Landscape", JobData::kLandscape);
142 } else {
143 OrientationCap **orientation_cap = (OrientationCap **)fPrinterCap->GetCaps(PrinterCap::kOrientation);
144 while (count--) {
145 AddOrientationItem((*orientation_cap)->fLabel.c_str(),
146 (*orientation_cap)->fOrientation);
147 orientation_cap++;
151 // resolution
152 marked = false;
153 fResolution = new BPopUpMenu("resolution");
154 fResolution->SetRadioMode(true);
155 count = fPrinterCap->CountCap(PrinterCap::kResolution);
156 ResolutionCap **resolution_cap = (ResolutionCap **)fPrinterCap->GetCaps(PrinterCap::kResolution);
157 while (count--) {
158 item = new BMenuItem((*resolution_cap)->fLabel.c_str(), NULL);
159 fResolution->AddItem(item);
160 item->SetTarget(this);
161 if (((*resolution_cap)->fXResolution == fJobData->GetXres()) &&
162 ((*resolution_cap)->fYResolution == fJobData->GetYres())) {
163 item->SetMarked(true);
164 marked = true;
166 resolution_cap++;
168 if (!marked)
169 item->SetMarked(true);
170 BMenuField* resolution = new BMenuField("resolution", "Resolution:", fResolution);
172 // scale
173 BString scale;
174 scale << (int)fJobData->GetScaling();
175 fScaling = new BTextControl("scale", "Scale [%]:",
176 scale.String(),
177 NULL);
178 int num;
179 for (num = 0; num <= 255; num++) {
180 fScaling->TextView()->DisallowChar(num);
182 for (num = 0; num <= 9; num++) {
183 fScaling->TextView()->AllowChar('0' + num);
185 fScaling->TextView()->SetMaxBytes(3);
187 // cancel and ok
188 BButton* cancel = new BButton("cancel", "Cancel", new BMessage(kMsgCancel));
189 BButton* ok = new BButton("ok", "OK", new BMessage(kMsgOK));
191 ok->MakeDefault(true);
193 BGridView* settings = new BGridView();
194 BGridLayout* settingsLayout = settings->GridLayout();
195 settingsLayout->AddItem(paperSize->CreateLabelLayoutItem(), 0, 0);
196 settingsLayout->AddItem(paperSize->CreateMenuBarLayoutItem(), 1, 0);
197 settingsLayout->AddItem(orientation->CreateLabelLayoutItem(), 0, 1);
198 settingsLayout->AddItem(orientation->CreateMenuBarLayoutItem(), 1, 1);
199 settingsLayout->AddItem(resolution->CreateLabelLayoutItem(), 0, 2);
200 settingsLayout->AddItem(resolution->CreateMenuBarLayoutItem(), 1, 2);
201 settingsLayout->AddItem(fScaling->CreateLabelLayoutItem(), 0, 3);
202 settingsLayout->AddItem(fScaling->CreateTextViewLayoutItem(), 1, 3);
203 settingsLayout->SetSpacing(0, 0);
205 SetLayout(new BGroupLayout(B_VERTICAL));
206 AddChild(BGroupLayoutBuilder(B_VERTICAL, 0)
207 .AddGroup(B_HORIZONTAL, 5, 1.0f)
208 .AddGroup(B_VERTICAL, 0, 1.0f)
209 .Add(fMarginView)
210 .AddGlue()
211 .End()
212 .AddGroup(B_VERTICAL, 0, 1.0f)
213 .Add(settings)
214 .AddGlue()
215 .End()
216 .End()
217 .AddGroup(B_HORIZONTAL, 10, 1.0f)
218 .AddGlue()
219 .Add(cancel)
220 .Add(ok)
221 .End()
222 .SetInsets(10, 10, 10, 10)
226 inline void
227 swap(float *e1, float *e2)
229 float e = *e1;
230 *e1 = *e2;
231 *e2 = e;
234 JobData::Orientation
235 PageSetupView::GetOrientation()
237 BMenuItem *item = fOrientation->FindMarked();
238 int32 orientation;
239 if (item != NULL &&
240 item->Message()->FindInt32("orientation", &orientation) == B_OK) {
241 return (JobData::Orientation)orientation;
242 } else {
243 return JobData::kPortrait;
247 PaperCap *
248 PageSetupView::GetPaperCap()
250 BMenuItem *item = fPaper->FindMarked();
251 void *pointer;
252 if (item != NULL &&
253 item->Message()->FindPointer("paperCap", &pointer) == B_OK) {
254 return (PaperCap*)pointer;
255 } else {
256 return (PaperCap*)fPrinterCap->GetDefaultCap(PrinterCap::kPaper);
260 bool
261 PageSetupView::UpdateJobData()
263 fJobData->SetOrientation(GetOrientation());
265 PaperCap *paperCap = GetPaperCap();
266 BRect paper_rect = paperCap->fPaperRect;
267 BRect physical_rect = paperCap->fPhysicalRect;
268 fJobData->SetPaper(paperCap->fPaper);
270 const char *resolutionLabel = fResolution->FindMarked()->Label();
271 const ResolutionCap* resolution = static_cast<const ResolutionCap*>(
272 fPrinterCap->FindCap(PrinterCap::kResolution, resolutionLabel));
273 ASSERT(resolution != NULL);
274 if (resolution != NULL) {
275 fJobData->SetXres(resolution->fXResolution);
276 fJobData->SetYres(resolution->fYResolution);
277 fJobData->SetResolutionID(resolution->ID());
280 // rotate paper and physical rectangle if landscape orientation
281 if (JobData::kLandscape == fJobData->GetOrientation()) {
282 swap(&paper_rect.left, &paper_rect.top);
283 swap(&paper_rect.right, &paper_rect.bottom);
284 swap(&physical_rect.left, &physical_rect.top);
285 swap(&physical_rect.right, &physical_rect.bottom);
288 // adjust printable rect by margin
289 fJobData->SetMarginUnit(fMarginView->Unit());
290 BRect margin = fMarginView->Margin();
291 BRect printable_rect;
292 printable_rect.left = paper_rect.left + margin.left;
293 printable_rect.top = paper_rect.top + margin.top;
294 printable_rect.right = paper_rect.right - margin.right;
295 printable_rect.bottom = paper_rect.bottom - margin.bottom;
297 printable_rect.left = max_c(printable_rect.left, physical_rect.left);
298 printable_rect.top = max_c(printable_rect.top, physical_rect.top);
299 printable_rect.right = min_c(printable_rect.right, physical_rect.right);
300 printable_rect.bottom = min_c(printable_rect.bottom, physical_rect.bottom);
302 float scaling = atoi(fScaling->Text());
303 if (scaling <= 0.0) { // sanity check
304 scaling = 100.0;
306 if (scaling > 1000.0) {
307 scaling = 1000.0;
310 float scalingR = 100.0 / scaling;
312 fJobData->SetScaling(scaling);
313 fJobData->SetPaperRect(paper_rect);
314 fJobData->SetScaledPaperRect(ScaleRect(paper_rect, scalingR));
315 fJobData->SetPrintableRect(printable_rect);
316 fJobData->SetScaledPrintableRect(ScaleRect(printable_rect, scalingR));
317 fJobData->SetPhysicalRect(physical_rect);
318 fJobData->SetScaledPhysicalRect(ScaleRect(physical_rect, scalingR));
320 fJobData->Save();
321 return true;
324 void
325 PageSetupView::MessageReceived(BMessage *msg)
327 switch (msg->what) {
328 case kMsgPaperChanged:
329 case kMsgOrientationChanged:
331 JobData::Orientation orientation = GetOrientation();
332 PaperCap *paperCap = GetPaperCap();
333 float width = paperCap->fPaperRect.Width();
334 float height = paperCap->fPaperRect.Height();
335 if (orientation != JobData::kPortrait) {
336 swap(&width, &height);
338 fMarginView->SetPageSize(width, height);
339 fMarginView->UpdateView(MARGIN_CHANGED);
342 break;
346 //====================================================================
348 // TODO center window on screen
349 PageSetupDlg::PageSetupDlg(JobData *job_data, PrinterData *printer_data, const PrinterCap *printer_cap)
350 : DialogWindow(BRect(100, 100, 160, 160),
351 "Paper setup", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
352 B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE
353 | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE)
355 AddShortcut('W',B_COMMAND_KEY,new BMessage(B_QUIT_REQUESTED));
357 fPageSetupView = new PageSetupView(job_data, printer_data,
358 printer_cap);
360 SetLayout(new BGroupLayout(B_HORIZONTAL));
361 AddChild(BGroupLayoutBuilder(B_HORIZONTAL, 0)
362 .Add(fPageSetupView)
365 SetResult(B_ERROR);
368 void
369 PageSetupDlg::MessageReceived(BMessage *msg)
371 switch (msg->what) {
372 case kMsgOK:
373 Lock();
374 fPageSetupView->UpdateJobData();
375 Unlock();
376 SetResult(B_NO_ERROR);
377 PostMessage(B_QUIT_REQUESTED);
378 break;
380 case kMsgCancel:
381 PostMessage(B_QUIT_REQUESTED);
382 break;
384 default:
385 DialogWindow::MessageReceived(msg);