xref: /haiku/src/tools/translation/inspector/ImageView.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
1 /*****************************************************************************/
2 // ImageView
3 // Written by Michael Wilber, Haiku Translation Kit Team
4 //
5 // ImageView.cpp
6 //
7 // BView class for showing images.  Images can be dropped on this view
8 // from the tracker and images viewed in this view can be dragged
9 // to the tracker to be saved.
10 //
11 //
12 // Copyright (c) 2003 Haiku Project
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 /*****************************************************************************/
32 
33 
34 #include "ImageView.h"
35 #include "Constants.h"
36 #include "StatusCheck.h"
37 #include "InspectorApp.h"
38 #include "TranslatorItem.h"
39 #include <Application.h>
40 #include <Catalog.h>
41 #include <Message.h>
42 #include <Locale.h>
43 #include <List.h>
44 #include <String.h>
45 #include <TranslationUtils.h>
46 #include <TranslatorRoster.h>
47 #include <BitmapStream.h>
48 #include <Entry.h>
49 #include <Path.h>
50 #include <Directory.h>
51 #include <File.h>
52 #include <MenuBar.h>
53 #include <Screen.h>
54 #include <ScrollBar.h>
55 #include <Alert.h>
56 #include <stdlib.h>
57 #include <stdio.h>
58 #include <string.h>
59 
60 #define BORDER_WIDTH 16
61 #define BORDER_HEIGHT 16
62 #define PEN_SIZE 1.0f
63 
64 #undef B_TRANSLATION_CONTEXT
65 #define B_TRANSLATION_CONTEXT "ImageView"
66 
67 
ImageView(BRect rect,const char * name)68 ImageView::ImageView(BRect rect, const char *name)
69 	: BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS)
70 {
71 	fpbitmap = NULL;
72 	fdocumentIndex = 1;
73 	fdocumentCount = 1;
74 
75 	SetViewColor(192, 192, 192);
76 	SetHighColor(0, 0, 0);
77 	SetPenSize(PEN_SIZE);
78 }
79 
80 
~ImageView()81 ImageView::~ImageView()
82 {
83 	delete fpbitmap;
84 	fpbitmap = NULL;
85 }
86 
87 
88 void
AttachedToWindow()89 ImageView::AttachedToWindow()
90 {
91 	AdjustScrollBars();
92 }
93 
94 
95 void
Draw(BRect rect)96 ImageView::Draw(BRect rect)
97 {
98 	if (HasImage()) {
99 		// Draw black rectangle around image
100 		StrokeRect(
101 			BRect(BORDER_WIDTH - PEN_SIZE,
102 				BORDER_HEIGHT - PEN_SIZE,
103 				fpbitmap->Bounds().Width() + BORDER_WIDTH + PEN_SIZE,
104 				fpbitmap->Bounds().Height() + BORDER_HEIGHT + PEN_SIZE));
105 
106 		DrawBitmap(fpbitmap, BPoint(BORDER_WIDTH, BORDER_HEIGHT));
107 	}
108 }
109 
110 
111 void
ReDraw()112 ImageView::ReDraw()
113 {
114 	Draw(Bounds());
115 }
116 
117 
118 void
FrameResized(float width,float height)119 ImageView::FrameResized(float width, float height)
120 {
121 	AdjustScrollBars();
122 
123 	if (!HasImage())
124 		Invalidate();
125 }
126 
127 
128 void
MouseDown(BPoint point)129 ImageView::MouseDown(BPoint point)
130 {
131 	if (!HasImage())
132 		return;
133 
134 	// Only accept left button clicks
135 	BMessage *pmsg = Window()->CurrentMessage();
136 	int32 button = pmsg->FindInt32("buttons");
137 	if (button != B_PRIMARY_MOUSE_BUTTON)
138 		return;
139 
140 	// Tell BeOS to setup a Drag/Drop operation
141 	//
142 	// (When the image is dropped, BeOS sends
143 	// the following message to ImageWindow,
144 	// which causes it to call ImageView::SetImage())
145 	BMessage msg(B_SIMPLE_DATA);
146 	msg.AddInt32("be:actions", B_COPY_TARGET);
147 	msg.AddString("be:filetypes", "application/octet-stream");
148 	msg.AddString("be:types", "application/octet-stream");
149 	msg.AddString("be:clip_name", "Bitmap");
150 
151 	DragMessage(&msg, Bounds());
152 }
153 
154 
155 void
MouseMoved(BPoint point,uint32 state,const BMessage * pmsg)156 ImageView::MouseMoved(BPoint point, uint32 state, const BMessage *pmsg)
157 {
158 }
159 
160 
161 void
MouseUp(BPoint point)162 ImageView::MouseUp(BPoint point)
163 {
164 }
165 
166 
167 void
MessageReceived(BMessage * pmsg)168 ImageView::MessageReceived(BMessage *pmsg)
169 {
170 	switch (pmsg->what) {
171 		case B_COPY_TARGET:
172 			SaveImageAtDropLocation(pmsg);
173 			break;
174 
175 		default:
176 			BView::MessageReceived(pmsg);
177 			break;
178 	}
179 }
180 
181 
182 void
SaveImageAtDropLocation(BMessage * pmsg)183 ImageView::SaveImageAtDropLocation(BMessage *pmsg)
184 {
185 	// Find the location and name of the drop and
186 	// write the image file there
187 	BBitmapStream stream(fpbitmap);
188 
189 	StatusCheck chk;
190 		// throw an exception if this is assigned
191 		// anything other than B_OK
192 
193 	try {
194 		entry_ref dirref;
195 		chk = pmsg->FindRef("directory", &dirref);
196 		const char *filename;
197 		chk = pmsg->FindString("name", &filename);
198 
199 		BDirectory dir(&dirref);
200 		BFile file(&dir, filename, B_WRITE_ONLY | B_CREATE_FILE);
201 		chk = file.InitCheck();
202 
203 		BTranslatorRoster *proster = BTranslatorRoster::Default();
204 		chk = proster->Translate(&stream, NULL, NULL, &file, B_TGA_FORMAT);
205 
206 	} catch (StatusNotOKException) {
207 		BAlert *palert = new BAlert(NULL,
208 			B_TRANSLATE("Sorry, unable to write the image file."),
209 			B_TRANSLATE("OK"));
210 		palert->Go();
211 	}
212 
213 	stream.DetachBitmap(&fpbitmap);
214 }
215 
216 
217 void
AdjustScrollBars()218 ImageView::AdjustScrollBars()
219 {
220 	BRect rctview = Bounds(), rctbitmap(0, 0, 0, 0);
221 	if (HasImage())
222 		rctbitmap = fpbitmap->Bounds();
223 
224 	float prop, range;
225 	BScrollBar *psb = ScrollBar(B_HORIZONTAL);
226 	if (psb) {
227 		range = rctbitmap.Width() + (BORDER_WIDTH * 2) - rctview.Width();
228 		if (range < 0) range = 0;
229 		prop = rctview.Width() / (rctbitmap.Width() + (BORDER_WIDTH * 2));
230 		if (prop > 1.0f) prop = 1.0f;
231 		psb->SetRange(0, range);
232 		psb->SetProportion(prop);
233 		psb->SetSteps(10, 100);
234 	}
235 
236 	psb = ScrollBar(B_VERTICAL);
237 	if (psb) {
238 		range = rctbitmap.Height() + (BORDER_HEIGHT * 2) - rctview.Height();
239 		if (range < 0) range = 0;
240 		prop = rctview.Height() / (rctbitmap.Height() + (BORDER_HEIGHT * 2));
241 		if (prop > 1.0f) prop = 1.0f;
242 		psb->SetRange(0, range);
243 		psb->SetProportion(prop);
244 		psb->SetSteps(10, 100);
245 	}
246 }
247 
248 
249 struct ColorSpaceName {
250 	color_space id;
251 	const char *name;
252 };
253 #define COLORSPACENAME(id) {id, #id}
254 
255 
256 // convert colorspace numerical value to
257 // a string value
258 const char *
get_color_space_name(color_space colors)259 get_color_space_name(color_space colors)
260 {
261 	// print out colorspace if it matches an item in the list
262 	const ColorSpaceName kcolorspaces[] = {
263 		COLORSPACENAME(B_NO_COLOR_SPACE),
264 		COLORSPACENAME(B_RGB32),
265 		COLORSPACENAME(B_RGBA32),
266 		COLORSPACENAME(B_RGB24),
267 		COLORSPACENAME(B_RGB16),
268 		COLORSPACENAME(B_RGB15),
269 		COLORSPACENAME(B_RGBA15),
270 		COLORSPACENAME(B_CMAP8),
271 		COLORSPACENAME(B_GRAY8),
272 		COLORSPACENAME(B_GRAY1),
273 		COLORSPACENAME(B_RGB32_BIG),
274 		COLORSPACENAME(B_RGBA32_BIG),
275 		COLORSPACENAME(B_RGB24_BIG),
276 		COLORSPACENAME(B_RGB16_BIG),
277 		COLORSPACENAME(B_RGB15_BIG),
278 		COLORSPACENAME(B_RGBA15_BIG),
279 		COLORSPACENAME(B_YCbCr422),
280 		COLORSPACENAME(B_YCbCr411),
281 		COLORSPACENAME(B_YCbCr444),
282 		COLORSPACENAME(B_YCbCr420),
283 		COLORSPACENAME(B_YUV422),
284 		COLORSPACENAME(B_YUV411),
285 		COLORSPACENAME(B_YUV444),
286 		COLORSPACENAME(B_YUV420),
287 		COLORSPACENAME(B_YUV9),
288 		COLORSPACENAME(B_YUV12),
289 		COLORSPACENAME(B_UVL24),
290 		COLORSPACENAME(B_UVL32),
291 		COLORSPACENAME(B_UVLA32),
292 		COLORSPACENAME(B_LAB24),
293 		COLORSPACENAME(B_LAB32),
294 		COLORSPACENAME(B_LABA32),
295 		COLORSPACENAME(B_HSI24),
296 		COLORSPACENAME(B_HSI32),
297 		COLORSPACENAME(B_HSIA32),
298 		COLORSPACENAME(B_HSV24),
299 		COLORSPACENAME(B_HSV32),
300 		COLORSPACENAME(B_HSVA32),
301 		COLORSPACENAME(B_HLS24),
302 		COLORSPACENAME(B_HLS32),
303 		COLORSPACENAME(B_HLSA32),
304 		COLORSPACENAME(B_CMY24),
305 		COLORSPACENAME(B_CMY32),
306 		COLORSPACENAME(B_CMYA32),
307 		COLORSPACENAME(B_CMYK32)
308 	};
309 	const int32 kncolorspaces =  sizeof(kcolorspaces) /
310 		sizeof(ColorSpaceName);
311 	for (int32 i = 0; i < kncolorspaces; i++) {
312 		if (colors == kcolorspaces[i].id)
313 			return kcolorspaces[i].name;
314 	}
315 
316 	return B_TRANSLATE("Unknown");
317 }
318 
319 
320 // return a string of the passed number formated
321 // as a hexadecimal number in lowercase with a leading "0x"
322 const char *
hex_format(uint32 num)323 hex_format(uint32 num)
324 {
325 	static char str[11] = { 0 };
326 	sprintf(str, "0x%.8lx", num);
327 
328 	return str;
329 }
330 
331 
332 // convert passed number to a string of 4 characters
333 // and return that string
334 const char *
char_format(uint32 num)335 char_format(uint32 num)
336 {
337 	static char str[5] = { 0 };
338 	uint32 bnum = B_HOST_TO_BENDIAN_INT32(num);
339 	memcpy(str, &bnum, 4);
340 
341 	return str;
342 }
343 
344 
345 void
dump_translation_formats(BString & bstr,const translation_format * pfmts,int32 nfmts)346 dump_translation_formats(BString &bstr, const translation_format *pfmts,
347 	int32 nfmts)
348 {
349 	BString *str1 = NULL;
350 	for (int i = 0; i < nfmts; i++) {
351 		BString string = B_TRANSLATE("\nType: '%1' (%2)\n"
352 			"Group: '%3' (%4)\n"
353 			"Quality: %5\n"
354 			"Capability: %6\n"
355 			"MIME Type: %7\n"
356 			"Name: %8\n");
357 		string.ReplaceFirst("%1", char_format(pfmts[i].type));
358 		string.ReplaceFirst("%2", hex_format(pfmts[i].type));
359 		string.ReplaceFirst("%3", char_format(pfmts[i].group));
360 		string.ReplaceFirst("%4", hex_format(pfmts[i].group));
361 		char str2[127] = { 0 };
362 		sprintf(str2, "%f", pfmts[i].quality);
363 		string.ReplaceFirst("%5", str2 );
364 		str2[0] = '\0';
365 		sprintf(str2, "%f", pfmts[i].capability);
366 		string.ReplaceFirst("%6",  str2 );
367 		string.ReplaceFirst("%7", pfmts[i].MIME);
368 		string.ReplaceFirst("%8", pfmts[i].name);
369 		if (i == 0)
370 			str1 = new BString(string);
371 		else
372 			str1->Append(string);
373 	}
374 	bstr = str1->String();
375 }
376 
377 
378 // Send information about the currently open image to the
379 // BApplication object so it can send it to the InfoWindow
380 void
UpdateInfoWindow(const BPath & path,BMessage & ioExtension,const translator_info & tinfo,BTranslatorRoster * proster)381 ImageView::UpdateInfoWindow(const BPath &path, BMessage &ioExtension,
382 	const translator_info &tinfo, BTranslatorRoster *proster)
383 {
384 	BMessage msg(M_INFO_WINDOW_TEXT);
385 	BString bstr;
386 
387 	bstr = B_TRANSLATE("Image: %1\n"
388 		"Color Space: %2 (%3)\n"
389 		"Dimensions: %4 x %5\n"
390 		"Bytes per Row: %6\n"
391 		"Total Bytes: %7\n"
392 		"\nIdentify Info:\n"
393 		"ID String: %8\n"
394 		"MIME Type: %9\n"
395 		"Type: '%10' (%11)\n"
396 		"Translator ID: %12\n"
397 		"Group: '%13' (%14)\n"
398 		"Quality: %15\n"
399 		"Capability: %16\n"
400 		"\nExtension Info:\n");
401 	bstr.ReplaceFirst("%1", path.Path());
402 	color_space cs = fpbitmap->ColorSpace();
403 	bstr.ReplaceFirst("%2", get_color_space_name(cs));
404 	bstr.ReplaceFirst("%3", hex_format(static_cast<uint32>(cs)));
405 	char str2[127] = { 0 };
406 	sprintf(str2, "%ld", fpbitmap->Bounds().IntegerWidth() + 1);
407 	bstr.ReplaceFirst("%4", str2);
408 	str2[0] = '\0';
409 	sprintf(str2, "%ld", fpbitmap->Bounds().IntegerHeight() + 1);
410 	bstr.ReplaceFirst("%5", str2);
411 	str2[0] = '\0';
412 	sprintf(str2, "%ld", fpbitmap->BytesPerRow());
413 	bstr.ReplaceFirst("%6", str2);
414 	str2[0] = '\0';
415 	sprintf(str2, "%ld", fpbitmap->BitsLength());
416 	bstr.ReplaceFirst("%7", str2);
417 	bstr.ReplaceFirst("%8", tinfo.name);
418 	bstr.ReplaceFirst("%9", tinfo.MIME);
419 	bstr.ReplaceFirst("%10", char_format(tinfo.type));
420 	bstr.ReplaceFirst("%11", hex_format(tinfo.type));
421 	str2[0] = '\0';
422 	sprintf(str2, "%ld", tinfo.translator);
423 	bstr.ReplaceFirst("%12", str2);
424 	bstr.ReplaceFirst("%13", char_format(tinfo.group));
425 	bstr.ReplaceFirst("%14", hex_format(tinfo.group));
426 	str2[0] = '\0';
427 	sprintf(str2, "%f", tinfo.quality);
428 	bstr.ReplaceFirst("%15", str2);
429 	str2[0] = '\0';
430 	sprintf(str2, "%f", tinfo.capability);
431 	bstr.ReplaceFirst("%16", str2);
432 
433 	int32 document_count = 0, document_index = 0;
434 	// Translator Info
435 	const char *tranname = NULL, *traninfo = NULL;
436 	int32 tranversion = 0;
437 
438 	if (ioExtension.FindInt32("/documentCount", &document_count) == B_OK) {
439 		BString str = B_TRANSLATE("Number of Documents: %1\n"
440 			"\nTranslator Used:\n"
441 			"Name: %2\n"
442 			"Info: %3\n"
443 			"Version: %4\n");
444 		char str2[127] = { 0 };
445 		sprintf(str2, "%ld", document_count);
446 		str.ReplaceFirst("%1", str2);
447 		str.ReplaceFirst("%2", tranname);
448 		str.ReplaceFirst("%3", traninfo);
449 		str2[0] = '\0';
450 		sprintf(str2, "%d", (int)tranversion);
451 		str.ReplaceFirst("%4", str2);
452 		bstr.Append(str.String());
453 	}
454 	else
455 		if (ioExtension.FindInt32("/documentIndex", &document_index) == B_OK) {
456 			BString str = B_TRANSLATE("Selected Document: %1\n"
457 				"\nTranslator Used:\n"
458 				"Name: %2\n"
459 				"Info: %3\n"
460 				"Version: %4\n");
461 			char str2[127] = { 0 };
462 			sprintf(str2, "%ld", document_index);
463 			str.ReplaceFirst("%1", str2);
464 			str.ReplaceFirst("%2", tranname);
465 			str.ReplaceFirst("%3", traninfo);
466 			str2[0] = '\0';
467 			sprintf(str2, "%d", (int)tranversion);
468 			str.ReplaceFirst("%4", str2);
469 			bstr.Append(str.String());
470 		}
471 		else
472 			if (proster->GetTranslatorInfo(tinfo.translator, &tranname,
473 				&traninfo, &tranversion) == B_OK) {
474 					BString str = B_TRANSLATE("\nTranslator Used:\n"
475 						"Name: %1\n"
476 						"Info: %2\n"
477 						"Version: %3\n");
478 					str.ReplaceFirst("%1", tranname);
479 					str.ReplaceFirst("%2", traninfo);
480 					char str2[127] = { 0 };
481 					sprintf(str2, "%d", (int)tranversion);
482 					str.ReplaceFirst("%3", str2);
483 					bstr.Append(str.String());
484 			}
485 
486 	// Translator Input / Output Formats
487 	int32 nins = 0, nouts = 0;
488 	const translation_format *pins = NULL, *pouts = NULL;
489 	if (proster->GetInputFormats(tinfo.translator, &pins, &nins) == B_OK) {
490 		bstr << B_TRANSLATE("\nInput Formats:");
491 		dump_translation_formats(bstr, pins, nins);
492 		pins = NULL;
493 	}
494 	if (proster->GetOutputFormats(tinfo.translator, &pouts, &nouts) == B_OK) {
495 		bstr << B_TRANSLATE("\nOutput Formats:");
496 		dump_translation_formats(bstr, pouts, nouts);
497 		pouts = NULL;
498 	}
499 	msg.AddString("text", bstr);
500 	be_app->PostMessage(&msg);
501 }
502 
503 
504 BTranslatorRoster *
SelectTranslatorRoster(BTranslatorRoster & roster)505 ImageView::SelectTranslatorRoster(BTranslatorRoster &roster)
506 {
507 	bool bNoneSelected = true;
508 
509 	InspectorApp *papp;
510 	papp = static_cast<InspectorApp *>(be_app);
511 	if (papp) {
512 		BList *plist = papp->GetTranslatorsList();
513 		if (plist) {
514 			for (int32 i = 0; i < plist->CountItems(); i++) {
515 				BTranslatorItem *pitem =
516 					static_cast<BTranslatorItem *>(plist->ItemAt(i));
517 				if (pitem->IsSelected()) {
518 					bNoneSelected = false;
519 					roster.AddTranslators(pitem->Path());
520 				}
521 			}
522 		}
523 	}
524 
525 	if (bNoneSelected)
526 		return BTranslatorRoster::Default();
527 	else
528 		return &roster;
529 }
530 
531 
532 void
SetImage(BMessage * pmsg)533 ImageView::SetImage(BMessage *pmsg)
534 {
535 	// Replace current image with the image
536 	// specified in the given BMessage
537 
538 	entry_ref ref;
539 	if (!pmsg)
540 		ref = fcurrentRef;
541 	else if (pmsg->FindRef("refs", &ref) != B_OK)
542 		// If refs not found, just ignore the message
543 		return;
544 
545 	StatusCheck chk;
546 
547 	try {
548 		BFile file(&ref, B_READ_ONLY);
549 		chk = file.InitCheck();
550 
551 		BTranslatorRoster roster, *proster;
552 		proster = SelectTranslatorRoster(roster);
553 		if (!proster)
554 			// throw exception
555 			chk = B_ERROR;
556 		// determine what type the image is
557 		translator_info tinfo;
558 		BMessage ioExtension;
559 		if (ref != fcurrentRef)
560 			// if new image, reset to first document
561 			fdocumentIndex = 1;
562 		chk = ioExtension.AddInt32("/documentIndex", fdocumentIndex);
563 		chk = proster->Identify(&file, &ioExtension, &tinfo, 0, NULL,
564 			B_TRANSLATOR_BITMAP);
565 
566 		// perform the actual translation
567 		BBitmapStream outstream;
568 		chk = proster->Translate(&file, &tinfo, &ioExtension, &outstream,
569 			B_TRANSLATOR_BITMAP);
570 		BBitmap *pbitmap = NULL;
571 		chk = outstream.DetachBitmap(&pbitmap);
572 		delete fpbitmap;
573 		fpbitmap = pbitmap;
574 		pbitmap = NULL;
575 		fcurrentRef = ref;
576 			// need to keep the ref around if user wants to switch pages
577 		int32 documentCount = 0;
578 		if (ioExtension.FindInt32("/documentCount", &documentCount) == B_OK &&
579 			documentCount > 0)
580 			fdocumentCount = documentCount;
581 		else
582 			fdocumentCount = 1;
583 
584 		// Set the name of the Window to reflect the file name
585 		BWindow *pwin = Window();
586 		BEntry entry(&ref);
587 		BPath path;
588 		if (entry.InitCheck() == B_OK) {
589 			if (path.SetTo(&entry) == B_OK)
590 				pwin->SetTitle(path.Leaf());
591 			else
592 				pwin->SetTitle(IMAGEWINDOW_TITLE);
593 		} else
594 			pwin->SetTitle(IMAGEWINDOW_TITLE);
595 		UpdateInfoWindow(path, ioExtension, tinfo, proster);
596 
597 		// Resize parent window and set size limits to
598 		// reflect the size of the new bitmap
599 		float width, height;
600 		BMenuBar *pbar = pwin->KeyMenuBar();
601 		width = fpbitmap->Bounds().Width() + B_V_SCROLL_BAR_WIDTH + (BORDER_WIDTH * 2);
602 		height = fpbitmap->Bounds().Height() +
603 			pbar->Bounds().Height() + B_H_SCROLL_BAR_HEIGHT + (BORDER_HEIGHT * 2) + 1;
604 		BScreen *pscreen = new BScreen(pwin);
605 		BRect rctscreen = pscreen->Frame();
606 		if (width > rctscreen.Width())
607 			width = rctscreen.Width();
608 		if (height > rctscreen.Height())
609 			height = rctscreen.Height();
610 		pwin->SetSizeLimits(B_V_SCROLL_BAR_WIDTH * 4, width,
611 			pbar->Bounds().Height() + (B_H_SCROLL_BAR_HEIGHT * 4) + 1, height);
612 		pwin->SetZoomLimits(width, height);
613 		AdjustScrollBars();
614 
615 		//pwin->Zoom();
616 			// Perform all of the hard work of resizing the
617 			// window while taking into account the size of
618 			// the screen, the tab and borders of the window
619 			//
620 			// HACK: Need to fix case where window un-zooms
621 			// when the window is already the correct size
622 			// for the current image
623 
624 		// repaint view
625 		Invalidate();
626 
627 	} catch (StatusNotOKException) {
628 		BAlert *palert = new BAlert(NULL,
629 			B_TRANSLATE("Sorry, unable to load the image."),
630 			B_TRANSLATE("OK"));
631 		palert->Go();
632 	}
633 }
634 
635 
636 void
FirstPage()637 ImageView::FirstPage()
638 {
639 	if (fdocumentIndex != 1) {
640 		fdocumentIndex = 1;
641 		SetImage(NULL);
642 	}
643 }
644 
645 
646 void
LastPage()647 ImageView::LastPage()
648 {
649 	if (fdocumentIndex != fdocumentCount) {
650 		fdocumentIndex = fdocumentCount;
651 		SetImage(NULL);
652 	}
653 }
654 
655 
656 void
NextPage()657 ImageView::NextPage()
658 {
659 	if (fdocumentIndex < fdocumentCount) {
660 		fdocumentIndex++;
661 		SetImage(NULL);
662 	}
663 }
664 
665 
666 void
PrevPage()667 ImageView::PrevPage()
668 {
669 	if (fdocumentIndex > 1) {
670 		fdocumentIndex--;
671 		SetImage(NULL);
672 	}
673 }
674 
675