vfs: check userland buffers before reading them.
[haiku.git] / src / libs / print / libprint / Preview.cpp
blobd2e3c40c6bba669a17c233cb543ceb52a88f164e
1 /*
2 * Copyright 2002-2008, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Pfeiffer
7 * Hartmut Reh
8 * julun <host.haiku@gmx.de>
9 */
11 #include "Preview.h"
13 #include "GraphicsDriver.h"
14 #include "PrintUtils.h"
17 #include <math.h>
18 #include <stdlib.h>
21 #include <Application.h>
22 #include <Button.h>
23 #include <Debug.h>
24 #include <Region.h>
25 #include <Screen.h>
26 #include <String.h>
27 #include <ScrollView.h>
28 #include <StringView.h>
29 #include <TextControl.h>
32 // #pragma mark - PreviewPage
35 PreviewPage::PreviewPage(int32 page, PrintJobPage* pjp)
36 : fPage(page)
37 , fStatus(B_ERROR)
38 , fNumberOfPictures(0)
39 , fRects(NULL)
40 , fPoints(NULL)
41 , fPictures(NULL)
43 fNumberOfPictures = pjp->NumberOfPictures();
45 fRects = new BRect[fNumberOfPictures];
46 fPoints = new BPoint[fNumberOfPictures];
47 fPictures = new BPicture[fNumberOfPictures];
49 for (int32 i = 0; i < fNumberOfPictures; ++i) {
50 fStatus = pjp->NextPicture(fPictures[i], fPoints[i], fRects[i]);
51 if (fStatus != B_OK)
52 break;
57 PreviewPage::~PreviewPage()
59 delete [] fRects;
60 delete [] fPoints;
61 delete [] fPictures;
65 status_t
66 PreviewPage::InitCheck() const
68 return fStatus;
72 void
73 PreviewPage::Draw(BView* view, const BRect& printRect)
75 ASSERT(fStatus == B_OK);
76 for (int32 i = 0; i < fNumberOfPictures; i++)
77 view->DrawPicture(&fPictures[i], printRect.LeftTop() + fPoints[i]);
81 // #pragma mark - PreviewView
84 namespace {
86 const float kPreviewTopMargin = 10.0;
87 const float kPreviewBottomMargin = 30.0;
88 const float kPreviewLeftMargin = 10.0;
89 const float kPreviewRightMargin = 30.0;
92 // TODO share constant with JobData
93 const char *kJDOrientation = "orientation";
94 const char *kJDNup = "JJJJ_nup";
95 const char *kJDReverse = "JJJJ_reverse";
96 const char* kJDPageSelection = "JJJJ_page_selection";
99 const uint8 ZOOM_IN[] = { 16, 1, 6, 6, 0, 0, 15, 128, 48, 96, 32, 32, 66, 16,
100 66, 16, 79, 144, 66, 16, 66, 16, 32, 32, 48, 112, 15, 184, 0, 28, 0, 14, 0,
101 6, 0, 0, 15, 128, 63, 224, 127, 240, 127, 240, 255, 248, 255, 248, 255, 248,
102 255, 248, 255, 248, 127, 248, 127, 248, 63, 252, 15, 254, 0, 31, 0, 15, 0, 7 };
105 const uint8 ZOOM_OUT[] = { 16, 1, 6, 6, 0, 0, 15, 128, 48, 96, 32, 32, 64, 16,
106 64, 16, 79, 144, 64, 16, 64, 16, 32, 32, 48, 112, 15, 184, 0, 28, 0, 14, 0,
107 6, 0, 0, 15, 128, 63, 224, 127, 240, 127, 240, 255, 248, 255, 248, 255, 248,
108 255, 248, 255, 248, 127, 248, 127, 248, 63, 252, 15, 254, 0, 31, 0, 15, 0, 7 };
111 BRect
112 RotateRect(const BRect& rect)
114 return BRect(rect.top, rect.left, rect.bottom, rect.right);
118 BRect
119 ScaleDown(BRect rect, float factor)
121 rect.left /= factor;
122 rect.top /= factor;
123 rect.right /= factor;
124 rect.bottom /= factor;
125 return rect;
129 BPoint
130 CalulateOffset(int32 numberOfPagesPerPage, int32 index,
131 JobData::Orientation orientation, BRect printableRect)
133 BPoint offset(0.0, 0.0);
134 if (numberOfPagesPerPage == 1)
135 return offset;
137 float width = printableRect.Width();
138 float height = printableRect.Height();
140 switch (numberOfPagesPerPage) {
141 case 2: {
142 if (index == 1) {
143 if (JobData::kPortrait == orientation)
144 offset.x = width;
145 else
146 offset.y = height;
148 } break;
150 case 8: {
151 if (JobData::kPortrait == orientation) {
152 offset.x = width * (index / 2);
153 offset.y = height * (index % 2);
154 } else {
155 offset.x = width * (index % 2);
156 offset.y = height * (index / 2);
158 } break;
160 case 32: {
161 if (JobData::kPortrait == orientation) {
162 offset.x = width * (index / 4);
163 offset.y = height * (index % 4);
164 } else {
165 offset.x = width * (index % 4);
166 offset.y = height * (index / 4);
168 } break;
170 case 4: {
171 case 9:
172 case 16:
173 case 25:
174 case 36:
175 case 49:
176 case 64:
177 case 81:
178 case 100:
179 case 121:
180 int32 value = int32(sqrt(double(numberOfPagesPerPage)));
181 offset.x = width * (index % value);
182 offset.y = height * (index / value);
183 } break;
185 return offset;
191 PreviewView::PreviewView(BFile* jobFile, BRect rect)
192 : BView(rect, "PreviewView", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS)
193 , fPage(0)
194 , fZoom(0)
195 , fReader(jobFile)
196 , fReverse(false)
197 , fPaperRect(BRect())
198 , fPrintableRect(BRect())
199 , fTracking(false)
200 , fInsideView(true)
201 , fScrollStart(0.0, 0.0)
202 , fNumberOfPages(1)
203 , fNumberOfPagesPerPage(1)
204 , fCachedPage(NULL)
205 , fOrientation(JobData::kPortrait)
206 , fPageSelection(JobData::kAllPages)
208 int32 value32;
209 if (fReader.JobSettings()->FindInt32(kJDOrientation, &value32) == B_OK)
210 fOrientation = (JobData::Orientation)value32;
212 if (fReader.JobSettings()->FindInt32(kJDPageSelection, &value32) == B_OK)
213 fPageSelection = (JobData::PageSelection)value32;
215 bool value;
216 if (fReader.JobSettings()->FindBool(kJDReverse, &value) == B_OK)
217 fReverse = value;
219 if (fReader.JobSettings()->FindInt32(kJDNup, &value32) == B_OK)
220 fNumberOfPagesPerPage = value32;
222 fNumberOfPages = (fReader.NumberOfPages() + fNumberOfPagesPerPage - 1)
223 / fNumberOfPagesPerPage;
225 if (fPageSelection == JobData::kOddNumberedPages)
226 fNumberOfPages = (fNumberOfPages + 1) / 2;
227 else if (fPageSelection == JobData::kEvenNumberedPages)
228 fNumberOfPages /= 2;
230 fPaperRect = fReader.PaperRect();
231 fPrintableRect = fReader.PrintableRect();
232 switch (fNumberOfPagesPerPage) {
233 case 2:
234 case 8:
235 case 32:
236 case 128: {
237 fPaperRect = RotateRect(fPaperRect);
238 fPrintableRect = RotateRect(fPrintableRect);
239 } break;
244 PreviewView::~PreviewView()
246 delete fCachedPage;
250 void
251 PreviewView::Show()
253 BView::Show();
254 be_app->SetCursor(ZOOM_IN);
258 void
259 PreviewView::Hide()
261 be_app->SetCursor(B_HAND_CURSOR);
262 BView::Hide();
266 void
267 PreviewView::Draw(BRect rect)
269 if (fReader.InitCheck() == B_OK) {
270 _DrawPageFrame(rect);
271 _DrawPage(rect);
272 _DrawMarginFrame(rect);
277 void
278 PreviewView::FrameResized(float width, float height)
280 Invalidate();
281 FixScrollbars();
285 void
286 PreviewView::MouseDown(BPoint point)
288 MakeFocus(true);
289 BMessage *message = Window()->CurrentMessage();
291 int32 button;
292 if (message && message->FindInt32("buttons", &button) == B_OK) {
293 if (button == B_PRIMARY_MOUSE_BUTTON) {
294 int32 modifier;
295 if (message->FindInt32("modifiers", &modifier) == B_OK) {
296 if (modifier & B_SHIFT_KEY)
297 ZoomOut();
298 else
299 ZoomIn();
303 if (button == B_SECONDARY_MOUSE_BUTTON) {
304 fTracking = true;
305 be_app->SetCursor(B_HAND_CURSOR);
306 SetMouseEventMask(B_POINTER_EVENTS,
307 B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
308 fScrollStart = Bounds().LeftTop() + ConvertToScreen(point);
314 void
315 PreviewView::MouseMoved(BPoint point, uint32 transit, const BMessage* message)
317 if (fTracking) {
318 uint32 button;
319 GetMouse(&point, &button, false);
320 point = fScrollStart - ConvertToScreen(point);
322 float hMin, hMax;
323 BScrollBar *hBar = ScrollBar(B_HORIZONTAL);
324 hBar->GetRange(&hMin, &hMax);
326 float vMin, vMax;
327 BScrollBar *vBar = ScrollBar(B_VERTICAL);
328 vBar->GetRange(&vMin, &vMax);
330 if (point.x < 0.0) point.x = 0.0;
331 if (point.y < 0.0) point.y = 0.0;
332 if (point.x > hMax) point.x = hMax;
333 if (point.y > vMax) point.y = vMax;
335 ScrollTo(point);
336 } else {
337 switch (transit) {
338 case B_ENTERED_VIEW: {
339 fInsideView = true;
340 be_app->SetCursor(ZOOM_IN);
341 } break;
343 case B_EXITED_VIEW: {
344 fInsideView = false;
345 be_app->SetCursor(B_HAND_CURSOR);
346 } break;
348 default: {
349 if (modifiers() & B_SHIFT_KEY)
350 be_app->SetCursor(ZOOM_OUT);
351 else
352 be_app->SetCursor(ZOOM_IN);
353 } break;
359 void
360 PreviewView::MouseUp(BPoint point)
362 (void)point;
363 fTracking = false;
364 fScrollStart.Set(0.0, 0.0);
365 if (fInsideView && ((modifiers() & B_SHIFT_KEY) == 0))
366 be_app->SetCursor(ZOOM_IN);
370 void
371 PreviewView::KeyDown(const char* bytes, int32 numBytes)
373 MakeFocus(true);
374 switch (bytes[0]) {
375 case '-': {
376 if (modifiers() & B_CONTROL_KEY)
377 ZoomOut();
378 } break;
380 case '+' : {
381 if (modifiers() & B_CONTROL_KEY)
382 ZoomIn();
383 } break;
385 default: {
386 BView::KeyDown(bytes, numBytes);
387 } break;
392 void
393 PreviewView::ShowFirstPage()
395 if (!ShowsFirstPage()) {
396 fPage = 0;
397 Invalidate();
402 void
403 PreviewView::ShowPrevPage()
405 if (!ShowsFirstPage()) {
406 fPage--;
407 Invalidate();
412 void
413 PreviewView::ShowNextPage()
415 if (!ShowsLastPage()) {
416 fPage++;
417 Invalidate();
422 void
423 PreviewView::ShowLastPage()
425 if (!ShowsLastPage()) {
426 fPage = NumberOfPages()-1;
427 Invalidate();
432 bool
433 PreviewView::ShowsFirstPage() const
435 return fPage == 0;
439 bool
440 PreviewView::ShowsLastPage() const
442 return fPage == NumberOfPages() - 1;
446 void
447 PreviewView::ShowFindPage(int32 page)
449 page--;
451 if (page < 0) {
452 page = 0;
453 } else if (page > (NumberOfPages()-1)) {
454 page = NumberOfPages()-1;
457 fPage = page;
458 Invalidate();
462 void
463 PreviewView::ZoomIn()
465 if (CanZoomIn()) {
466 fZoom++;
467 FixScrollbars();
468 Invalidate();
473 bool
474 PreviewView::CanZoomIn() const
476 return fZoom < 4;
480 void
481 PreviewView::ZoomOut()
483 if (CanZoomOut()) {
484 fZoom--;
485 FixScrollbars();
486 Invalidate();
491 bool
492 PreviewView::CanZoomOut() const
494 return fZoom > -2;
498 void
499 PreviewView::FixScrollbars()
501 float width = _PaperRect().Width() + kPreviewLeftMargin + kPreviewRightMargin;
502 float height = _PaperRect().Height() + kPreviewTopMargin + kPreviewBottomMargin;
504 BRect frame(Bounds());
505 float x = width - frame.Width();
506 if (x < 0.0)
507 x = 0.0;
509 float y = height - frame.Height();
510 if (y < 0.0)
511 y = 0.0;
513 BScrollBar * scroll = ScrollBar(B_HORIZONTAL);
514 scroll->SetRange(0.0, x);
515 scroll->SetProportion((width - x) / width);
516 float bigStep = frame.Width() - 2;
517 float smallStep = bigStep / 10.;
518 scroll->SetSteps(smallStep, bigStep);
520 scroll = ScrollBar(B_VERTICAL);
521 scroll->SetRange(0.0, y);
522 scroll->SetProportion((height - y) / height);
523 bigStep = frame.Height() - 2;
524 smallStep = bigStep / 10.;
525 scroll->SetSteps(smallStep, bigStep);
529 BRect
530 PreviewView::ViewRect() const
532 BRect r(_PaperRect());
533 r.right += kPreviewLeftMargin + kPreviewRightMargin;
534 r.bottom += kPreviewTopMargin + kPreviewBottomMargin;
535 return r;
539 status_t
540 PreviewView::InitCheck() const
542 return fReader.InitCheck();
546 int32
547 PreviewView::NumberOfPages() const
549 return fNumberOfPages;
553 BRect
554 PreviewView::_PaperRect() const
556 return ScaleRect(fPaperRect, _ZoomFactor());
560 float
561 PreviewView::_ZoomFactor() const
563 const int32 b = 4;
564 int32 zoom;
565 if (fZoom > 0) {
566 zoom = (1 << b) << fZoom;
567 } else {
568 zoom = (1 << b) >> -fZoom;
570 float factor = zoom / (float)(1 << b);
571 return factor * fReader.GetScale() / 100.0;
575 BRect
576 PreviewView::_PrintableRect() const
578 return ScaleRect(fPrintableRect, _ZoomFactor());
582 bool
583 PreviewView::_IsPageValid() const
585 return fCachedPage && fCachedPage->InitCheck() == B_OK;
589 void
590 PreviewView::_LoadPage(int32 page)
592 delete fCachedPage;
593 fCachedPage = NULL;
595 PrintJobPage pjp;
596 if (fReader.GetPage(page, pjp) == B_OK)
597 fCachedPage = new PreviewPage(page, &pjp);
601 bool
602 PreviewView::_IsPageLoaded(int32 page) const
604 return fCachedPage != NULL && fCachedPage->Page() == page;
608 BRect
609 PreviewView::_ContentRect() const
611 float offsetX = kPreviewLeftMargin;
612 float offsetY = kPreviewTopMargin;
614 BRect rect = Bounds();
615 BRect paperRect = _PaperRect();
617 float min, max;
618 ScrollBar(B_HORIZONTAL)->GetRange(&min, &max);
619 if (min == max) {
620 if ((paperRect.right + 2 * offsetX) < rect.right)
621 offsetX = (rect.right - (paperRect.right + 2 * offsetX)) / 2;
624 ScrollBar(B_VERTICAL)->GetRange(&min, &max);
625 if (min == max) {
626 if ((paperRect.bottom + 2 * offsetY) < rect.bottom)
627 offsetY = (rect.bottom - (paperRect.bottom + 2 * offsetY)) / 2;
630 paperRect.OffsetTo(offsetX, offsetY);
631 return paperRect;
635 void
636 PreviewView::_DrawPageFrame(BRect rect)
638 const float kShadowIndent = 3;
639 const float kShadowWidth = 3;
641 const rgb_color frameColor = { 0, 0, 0, 0 };
642 const rgb_color shadowColor = { 90, 90, 90, 0 };
644 PushState();
646 // draw page border around page
647 BRect r(_ContentRect().InsetByCopy(-1, -1));
649 SetHighColor(frameColor);
650 StrokeRect(r);
652 // draw page shadow
653 SetHighColor(shadowColor);
655 float x = r.right + 1;
656 float right = x + kShadowWidth;
657 float bottom = r.bottom + 1 + kShadowWidth;
658 float y = r.top + kShadowIndent;
659 FillRect(BRect(x, y, right, bottom));
661 x = r.left + kShadowIndent;
662 y = r.bottom + 1;
663 FillRect(BRect(x, y, r.right, bottom));
665 PopState();
670 void PreviewView::_DrawPage(BRect rect)
672 BRect printRect(_PrintableRect());
673 switch (fNumberOfPagesPerPage) {
674 case 2:
675 case 8:
676 case 32:
677 case 128: {
678 printRect = RotateRect(printRect);
679 } break;
681 printRect.OffsetBy(_ContentRect().LeftTop());
683 BPoint scalingXY = GraphicsDriver::GetScale(fNumberOfPagesPerPage, printRect, 100.0);
684 float scaling = min_c(scalingXY.x, scalingXY.y);
686 printRect = ScaleDown(printRect, _ZoomFactor() * scaling);
687 BRect clipRect(ScaleRect(printRect, scaling));
689 for (int32 index = 0; index < fNumberOfPagesPerPage; ++index) {
690 int32 pageNumber = _GetPageNumber(index);
691 if (pageNumber < 0)
692 continue;
694 if (!_IsPageLoaded(pageNumber))
695 _LoadPage(pageNumber);
697 if (!_IsPageValid())
698 continue;
700 BPoint offset(CalulateOffset(fNumberOfPagesPerPage, index, fOrientation,
701 clipRect));
703 clipRect.OffsetTo(printRect.LeftTop());
704 clipRect.OffsetBy(offset);
706 BRegion clip(clipRect);
707 ConstrainClippingRegion(&clip);
709 SetScale(_ZoomFactor() * scaling);
711 fCachedPage->Draw(this, printRect.OffsetByCopy(offset));
713 if (fNumberOfPagesPerPage > 1)
714 StrokeRect(clipRect.InsetByCopy(1.0, 1.0), B_MIXED_COLORS);
716 SetScale(1.0);
718 ConstrainClippingRegion(NULL);
723 void
724 PreviewView::_DrawMarginFrame(BRect rect)
726 BRect paperRect(_ContentRect());
727 BRect printRect(_PrintableRect());
728 printRect.OffsetBy(paperRect.LeftTop());
730 const rgb_color highColor = HighColor();
731 const rgb_color white = { 255, 255, 255, 255 };
733 SetHighColor(white);
735 FillRect(BRect(paperRect.left, paperRect.top, printRect.left
736 , paperRect.bottom));
737 FillRect(BRect(paperRect.left, paperRect.top, paperRect.right
738 , printRect.top));
739 FillRect(BRect(printRect.right, paperRect.top, paperRect.right
740 , paperRect.bottom));
741 FillRect(BRect(paperRect.left, printRect.bottom, paperRect.right
742 , paperRect.bottom));
744 SetHighColor(highColor);
746 BeginLineArray(4);
748 SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
749 StrokeLine(BPoint(printRect.left, paperRect.top),
750 BPoint(printRect.left, paperRect.bottom), B_MIXED_COLORS);
751 StrokeLine(BPoint(printRect.right, paperRect.top),
752 BPoint(printRect.right, paperRect.bottom), B_MIXED_COLORS);
753 StrokeLine(BPoint(paperRect.left, printRect.top),
754 BPoint(paperRect.right, printRect.top), B_MIXED_COLORS);
755 StrokeLine(BPoint(paperRect.left, printRect.bottom),
756 BPoint(paperRect.right, printRect.bottom), B_MIXED_COLORS);
758 EndLineArray();
763 int32 PreviewView::_GetPageNumber(int32 index) const
765 int32 page = fPage;
766 if (fReverse)
767 page = fNumberOfPages - fPage - 1;
769 if (fPageSelection == JobData::kOddNumberedPages)
770 page *= 2; // 0, 2, 4, ...
771 else if (fPageSelection == JobData::kEvenNumberedPages)
772 page = 2 * page + 1; // 1, 3, 5, ...
774 return page * fNumberOfPagesPerPage + index;
778 // #pragma mark - PreviewWindow
781 PreviewWindow::PreviewWindow(BFile* jobFile, bool showOkAndCancelButtons)
782 : BlockingWindow(BRect(20, 24, 400, 600), "Preview", B_TITLED_WINDOW,
783 B_ASYNCHRONOUS_CONTROLS)
784 , fButtonBarHeight(0.0)
786 BRect bounds(Bounds());
788 BView* panel = new BBox(Bounds(), "top_panel", B_FOLLOW_ALL,
789 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP,
790 B_PLAIN_BORDER);
791 AddChild(panel);
793 bounds.OffsetBy(10.0, 10.0);
795 fFirst = new BButton(bounds, "first", "First page", new BMessage(MSG_FIRST_PAGE));
796 panel->AddChild(fFirst);
797 fFirst->ResizeToPreferred();
799 bounds.OffsetBy(fFirst->Bounds().Width() + 10.0, 0.0);
800 fPrev = new BButton(bounds, "previous", "Previous page", new BMessage(MSG_PREV_PAGE));
801 panel->AddChild(fPrev);
802 fPrev->ResizeToPreferred();
804 bounds.OffsetBy(fPrev->Bounds().Width() + 10.0, 0.0);
805 fNext = new BButton(bounds, "next", "Next page", new BMessage(MSG_NEXT_PAGE));
806 panel->AddChild(fNext);
807 fNext->ResizeToPreferred();
809 bounds.OffsetBy(fNext->Bounds().Width() + 10.0, 0.0);
810 fLast = new BButton(bounds, "last", "Last page", new BMessage(MSG_LAST_PAGE));
811 panel->AddChild(fLast);
812 fLast->ResizeToPreferred();
814 bounds = fLast->Frame();
815 bounds.OffsetBy(fLast->Bounds().Width() + 10.0, 0.0);
816 fPageNumber = new BTextControl(bounds, "numOfPage", "99", "",
817 new BMessage(MSG_FIND_PAGE));
818 panel->AddChild(fPageNumber);
819 fPageNumber->ResizeToPreferred();
820 fPageNumber->SetDivider(0.0);
821 fPageNumber->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_RIGHT);
822 fPageNumber->MoveBy(0.0, bounds.Height() - fPageNumber->Bounds().Height());
824 uint32 num;
825 for (num = 0; num <= 255; num++)
826 fPageNumber->TextView()->DisallowChar(num);
828 for (num = 0; num <= 9; num++)
829 fPageNumber->TextView()->AllowChar('0' + num);
830 fPageNumber->TextView()-> SetMaxBytes(5);
832 bounds.OffsetBy(fPageNumber->Bounds().Width() + 5.0, 0.0);
833 fPageText = new BStringView(bounds, "pageText", "");
834 panel->AddChild(fPageText);
835 fPageText->ResizeTo(fPageText->StringWidth("of 99999 pages"),
836 fFirst->Bounds().Height());
838 bounds.OffsetBy(fPageText->Bounds().Width() + 10.0, 0.0);
839 fZoomIn = new BButton(bounds, "zoomIn", "Zoom in", new BMessage(MSG_ZOOM_IN));
840 panel->AddChild(fZoomIn);
841 fZoomIn->ResizeToPreferred();
843 bounds.OffsetBy(fZoomIn->Bounds().Width() + 10.0, 0.0);
844 fZoomOut = new BButton(bounds, "ZoomOut", "Zoom out", new BMessage(MSG_ZOOM_OUT));
845 panel->AddChild(fZoomOut);
846 fZoomOut->ResizeToPreferred();
848 fButtonBarHeight = fZoomOut->Frame().bottom + 10.0;
850 bounds = Bounds();
851 bounds.top = fButtonBarHeight;
853 if (showOkAndCancelButtons) {
854 // adjust preview height
855 bounds.bottom -= fButtonBarHeight;
856 // update the total height of both bars
857 fButtonBarHeight *= 2;
859 // cancel printing if user closes the preview window
860 SetUserQuitResult(B_ERROR);
862 BButton *printJob = new BButton(BRect(), "printJob", "Print",
863 new BMessage(MSG_PRINT_JOB), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
864 panel->AddChild(printJob);
865 printJob->ResizeToPreferred();
866 printJob->MoveTo(bounds.right - (printJob->Bounds().Width() + 10.0),
867 bounds.bottom + 10.0);
869 BButton *cancelJob = new BButton(BRect(), "cancelJob", "Cancel",
870 new BMessage(MSG_CANCEL_JOB), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
871 panel->AddChild(cancelJob);
872 cancelJob->ResizeToPreferred();
873 cancelJob->MoveTo(printJob->Frame().left - (10.0 + cancelJob->Bounds().Width()),
874 bounds.bottom + 10.0);
876 printJob->MakeDefault(true);
879 bounds.right -= B_V_SCROLL_BAR_WIDTH;
880 bounds.bottom -= B_H_SCROLL_BAR_HEIGHT;
882 fPreview = new PreviewView(jobFile, bounds);
883 fPreviewScroller = new BScrollView("PreviewScroller", fPreview, B_FOLLOW_ALL,
884 B_FRAME_EVENTS, true, true, B_FANCY_BORDER);
885 fPreviewScroller->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
886 panel->AddChild(fPreviewScroller);
888 if (fPreview->InitCheck() == B_OK) {
889 _ResizeToPage();
890 fPreview->FixScrollbars();
891 _UpdateControls();
892 fPreview->MakeFocus(true);
897 void
898 PreviewWindow::MessageReceived(BMessage* m)
900 switch (m->what) {
901 case MSG_FIRST_PAGE:
902 fPreview->ShowFirstPage();
903 break;
905 case MSG_NEXT_PAGE:
906 fPreview->ShowNextPage();
907 break;
909 case MSG_PREV_PAGE:
910 fPreview->ShowPrevPage();
911 break;
913 case MSG_LAST_PAGE:
914 fPreview->ShowLastPage();
915 break;
917 case MSG_FIND_PAGE:
918 fPreview->ShowFindPage(atoi(fPageNumber->Text())) ;
919 break;
921 case MSG_ZOOM_IN:
922 fPreview->ZoomIn();
923 break;
925 case MSG_ZOOM_OUT:
926 fPreview->ZoomOut();
927 break;
929 case B_MODIFIERS_CHANGED:
930 fPreview->MouseMoved(BPoint(), B_INSIDE_VIEW, m);
931 break;
933 case MSG_CANCEL_JOB:
934 Quit(B_ERROR);
935 break;
937 case MSG_PRINT_JOB:
938 Quit(B_OK);
939 break;
941 default:
942 BlockingWindow::MessageReceived(m);
943 return;
945 _UpdateControls();
949 status_t
950 PreviewWindow::Go()
952 status_t st = InitCheck();
953 if (st == B_OK)
954 return BlockingWindow::Go();
956 be_app->SetCursor(B_HAND_CURSOR);
957 Quit();
958 return st;
962 void
963 PreviewWindow::_ResizeToPage()
965 BScreen screen;
966 if (screen.Frame().right == 0.0)
967 return;
969 const float windowBorderWidth = 5;
970 const float windowBorderHeight = 5;
972 BRect rect(fPreview->ViewRect());
973 float width = rect.Width() + 1 + B_V_SCROLL_BAR_WIDTH;
974 float height = rect.Height() + 1 + fButtonBarHeight + B_H_SCROLL_BAR_HEIGHT;
976 rect = screen.Frame();
977 // dimensions so that window does not reach outside of screen
978 float maxWidth = rect.Width() + 1 - windowBorderWidth - Frame().left;
979 float maxHeight = rect.Height() + 1 - windowBorderHeight - Frame().top;
981 // width so that all buttons are visible
982 float minWidth = fZoomOut->Frame().right + 10;
984 if (width < minWidth) width = minWidth;
985 if (width > maxWidth) width = maxWidth;
986 if (height > maxHeight) height = maxHeight;
988 ResizeTo(width, height);
992 void
993 PreviewWindow::_UpdateControls()
995 fFirst->SetEnabled(!fPreview->ShowsFirstPage());
996 fPrev->SetEnabled(!fPreview->ShowsFirstPage());
997 fNext->SetEnabled(!fPreview->ShowsLastPage());
998 fLast->SetEnabled(!fPreview->ShowsLastPage());
999 fZoomIn->SetEnabled(fPreview->CanZoomIn());
1000 fZoomOut->SetEnabled(fPreview->CanZoomOut());
1002 BString text;
1003 text << fPreview->CurrentPage();
1004 fPageNumber->SetText(text.String());
1006 text.SetTo("of ");
1007 text << fPreview->NumberOfPages() << " Page";
1008 if (fPreview->NumberOfPages() > 1)
1009 text.Append("s");
1010 fPageText->SetText(text.String());