Part of a refactoring/rewrite I was once working on,
work in progress, don't remember how far I got. Supposed to extract the image file and document page navigation from ShowImageView. Not included in build. Untested. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39101 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
43eea4c2c4
commit
707466cad1
443
src/apps/showimage/ImageFileNavigator.cpp
Normal file
443
src/apps/showimage/ImageFileNavigator.cpp
Normal file
@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright 2003-2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2004-2005 yellowTAB GmbH. All Rights Reserverd.
|
||||
* Copyright 2006 Bernd Korz. All Rights Reserved
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Fernando Francisco de Oliveira
|
||||
* Michael Wilber
|
||||
* Michael Pfeiffer
|
||||
* Ryan Leavengood
|
||||
* yellowTAB GmbH
|
||||
* Bernd Korz
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
|
||||
#include "ImageFileNavigator.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Application.h>
|
||||
#include <Bitmap.h>
|
||||
#include <BitmapStream.h>
|
||||
#include <Catalog.h>
|
||||
#include <Clipboard.h>
|
||||
#include <Debug.h>
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <Locale.h>
|
||||
#include <MenuBar.h>
|
||||
#include <MenuItem.h>
|
||||
#include <Message.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <Path.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <Rect.h>
|
||||
#include <Region.h>
|
||||
#include <Roster.h>
|
||||
#include <Screen.h>
|
||||
#include <ScrollBar.h>
|
||||
#include <StopWatch.h>
|
||||
#include <SupportDefs.h>
|
||||
#include <TranslatorRoster.h>
|
||||
|
||||
#include <tracker_private.h>
|
||||
|
||||
#include "ProgressWindow.h"
|
||||
#include "ShowImageApp.h"
|
||||
#include "ShowImageConstants.h"
|
||||
#include "ShowImageWindow.h"
|
||||
|
||||
|
||||
// TODO: Remove this and use Tracker's Command.h once it is moved into the
|
||||
// private headers!
|
||||
namespace BPrivate {
|
||||
const uint32 kMoveToTrash = 'Ttrs';
|
||||
}
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
|
||||
#define SHOW_IMAGE_ORIENTATION_ATTRIBUTE "ShowImage:orientation"
|
||||
|
||||
enum ImageFileNavigator::image_orientation
|
||||
ImageFileNavigator::fTransformation[ImageProcessor::kNumberOfAffineTransformations][kNumberOfOrientations] = {
|
||||
// rotate 90°
|
||||
{k90, k180, k270, k0, k270V, k0V, k90V, k0H},
|
||||
// rotate -90°
|
||||
{k270, k0, k90, k180, k90V, k0H, k270V, k0V},
|
||||
// mirror vertical
|
||||
{k0H, k270V, k0V, k90V, k180, k270, k0, k90},
|
||||
// mirror horizontal
|
||||
{k0V, k90V, k0H, k270V, k0, k90, k180, k270}
|
||||
};
|
||||
|
||||
static bool
|
||||
entry_ref_is_file(const entry_ref *ref)
|
||||
{
|
||||
BEntry entry(ref, true);
|
||||
if (entry.InitCheck() != B_OK)
|
||||
return false;
|
||||
|
||||
return entry.IsFile();
|
||||
}
|
||||
|
||||
|
||||
ImageFileNavigator::ImageFileNavigator(BRect rect, const char *name, uint32 resizingMode,
|
||||
uint32 flags)
|
||||
:
|
||||
fDocumentIndex(1),
|
||||
fDocumentCount(1),
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ImageFileNavigator::~ImageFileNavigator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageFileNavigator::SetTrackerMessenger(const BMessenger& trackerMessenger)
|
||||
{
|
||||
fTrackerMessenger = trackerMessenger;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::LoadImage(const entry_ref* ref, BBitmap** bitmap)
|
||||
{
|
||||
if (bitmap == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// If no ref was specified, load the specified page of the current file.
|
||||
if (ref == NULL)
|
||||
ref = &fCurrentRef;
|
||||
|
||||
BTranslatorRoster *roster = BTranslatorRoster::Default();
|
||||
if (roster == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
if (!entry_ref_is_file(ref))
|
||||
return B_ERROR;
|
||||
|
||||
BFile file(ref, B_READ_ONLY);
|
||||
translator_info info;
|
||||
memset(&info, 0, sizeof(translator_info));
|
||||
BMessage ioExtension;
|
||||
if (ref != &fCurrentRef) {
|
||||
// if new image, reset to first document
|
||||
fDocumentIndex = 1;
|
||||
}
|
||||
|
||||
if (ioExtension.AddInt32("/documentIndex", fDocumentIndex) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
BMessage progress(kMsgProgressStatusUpdate);
|
||||
if (ioExtension.AddMessenger("/progressMonitor", fProgressWindow) == B_OK
|
||||
&& ioExtension.AddMessage("/progressMessage", &progress) == B_OK)
|
||||
fProgressWindow->Start();
|
||||
|
||||
// Translate image data and create a new ShowImage window
|
||||
|
||||
BBitmapStream outstream;
|
||||
|
||||
status_t status = roster->Identify(&file, &ioExtension, &info, 0, NULL,
|
||||
B_TRANSLATOR_BITMAP);
|
||||
if (status == B_OK) {
|
||||
status = roster->Translate(&file, &info, &ioExtension, &outstream,
|
||||
B_TRANSLATOR_BITMAP);
|
||||
}
|
||||
|
||||
fProgressWindow->Stop();
|
||||
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (outstream.DetachBitmap(bitmap) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
fCurrentRef = *ref;
|
||||
|
||||
// restore orientation
|
||||
int32 orientation;
|
||||
fImageOrientation = k0;
|
||||
fInverted = false;
|
||||
if (file.ReadAttr(SHOW_IMAGE_ORIENTATION_ATTRIBUTE, B_INT32_TYPE, 0,
|
||||
&orientation, sizeof(orientation)) == sizeof(orientation)) {
|
||||
fInverted = (orientation & 256) != 0;
|
||||
fImageOrientation = (orientation & 255) != 0;
|
||||
}
|
||||
|
||||
// get the number of documents (pages) if it has been supplied
|
||||
int32 documentCount = 0;
|
||||
if (ioExtension.FindInt32("/documentCount", &documentCount) == B_OK
|
||||
&& documentCount > 0)
|
||||
fDocumentCount = documentCount;
|
||||
else
|
||||
fDocumentCount = 1;
|
||||
|
||||
fImageType = info.name;
|
||||
fImageMime = info.MIME;
|
||||
|
||||
be_roster->AddToRecentDocuments(&fCurrentRef, kApplicationSignature);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageFileNavigator::GetName(BString* outName)
|
||||
{
|
||||
BEntry entry(&fCurrentRef);
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
if (entry.InitCheck() < B_OK || entry.GetName(name) < B_OK)
|
||||
outName->SetTo("");
|
||||
else
|
||||
outName->SetTo(name);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageFileNavigator::GetPath(BString* outPath)
|
||||
{
|
||||
BEntry entry(&fCurrentRef);
|
||||
BPath path;
|
||||
if (entry.InitCheck() < B_OK || entry.GetPath(&path) < B_OK)
|
||||
outPath->SetTo("");
|
||||
else
|
||||
outPath->SetTo(path.Path());
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
ImageFileNavigator::CurrentPage()
|
||||
{
|
||||
return fDocumentIndex;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
ImageFileNavigator::PageCount()
|
||||
{
|
||||
return fDocumentCount;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::FirstPage(BBitmap** bitmap)
|
||||
{
|
||||
if (fDocumentIndex != 1) {
|
||||
fDocumentIndex = 1;
|
||||
return LoadImage(NULL, bitmap);
|
||||
}
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::LastPage(BBitmap** bitmap)
|
||||
{
|
||||
if (fDocumentIndex != fDocumentCount) {
|
||||
fDocumentIndex = fDocumentCount;
|
||||
return LoadImage(NULL, bitmap);
|
||||
}
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::NextPage(BBitmap** bitmap)
|
||||
{
|
||||
if (fDocumentIndex < fDocumentCount) {
|
||||
fDocumentIndex++;
|
||||
return LoadImage(NULL, bitmap);
|
||||
}
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::PrevPage(BBitmap** bitmap)
|
||||
{
|
||||
if (fDocumentIndex > 1) {
|
||||
fDocumentIndex--;
|
||||
return LoadImage(NULL, bitmap);
|
||||
}
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::GoToPage(int32 page, BBitmap** bitmap)
|
||||
{
|
||||
if (page > 0 && page <= fDocumentCount && page != fDocumentIndex) {
|
||||
fDocumentIndex = page;
|
||||
return LoadImage(NULL, bitmap);
|
||||
}
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::FirstFile(BBitmap** bitmap)
|
||||
{
|
||||
return _LoadNextImage(true, true, bitmap);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::NextFile(BBitmap** bitmap)
|
||||
{
|
||||
return _LoadNextImage(true, false, bitmap);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::PrevFile(BBitmap** bitmap)
|
||||
{
|
||||
return _LoadNextImage(false, false, bitmap);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ImageFileNavigator::HasNextFile()
|
||||
{
|
||||
entry_ref ref;
|
||||
return _FindNextImage(&fCurrentRef, &ref, true, false);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ImageFileNavigator::HasPrevFile()
|
||||
{
|
||||
entry_ref ref;
|
||||
return _FindNextImage(&fCurrentRef, &ref, false, false);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
bool
|
||||
ImageFileNavigator::_IsImage(const entry_ref *ref)
|
||||
{
|
||||
if (ref == NULL || !entry_ref_is_file(ref))
|
||||
return false;
|
||||
|
||||
BFile file(ref, B_READ_ONLY);
|
||||
if (file.InitCheck() != B_OK)
|
||||
return false;
|
||||
|
||||
BTranslatorRoster *roster = BTranslatorRoster::Default();
|
||||
if (!roster)
|
||||
return false;
|
||||
|
||||
BMessage ioExtension;
|
||||
if (ioExtension.AddInt32("/documentIndex", fDocumentIndex) != B_OK)
|
||||
return false;
|
||||
|
||||
translator_info info;
|
||||
memset(&info, 0, sizeof(translator_info));
|
||||
if (roster->Identify(&file, &ioExtension, &info, 0, NULL,
|
||||
B_TRANSLATOR_BITMAP) != B_OK)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ImageFileNavigator::_FindNextImage(entry_ref* currentRef, entry_ref* ref,
|
||||
bool next, bool rewind)
|
||||
{
|
||||
// Based on GetTrackerWindowFile function from BeMail
|
||||
if (!fTrackerMessenger.IsValid())
|
||||
return false;
|
||||
|
||||
//
|
||||
// Ask the Tracker what the next/prev file in the window is.
|
||||
// Continue asking for the next reference until a valid
|
||||
// image is found.
|
||||
//
|
||||
entry_ref nextRef = *currentRef;
|
||||
bool foundRef = false;
|
||||
while (!foundRef) {
|
||||
BMessage request(B_GET_PROPERTY);
|
||||
BMessage spc;
|
||||
if (rewind)
|
||||
spc.what = B_DIRECT_SPECIFIER;
|
||||
else if (next)
|
||||
spc.what = 'snxt';
|
||||
else
|
||||
spc.what = 'sprv';
|
||||
spc.AddString("property", "Entry");
|
||||
if (rewind)
|
||||
// if rewinding, ask for the ref to the
|
||||
// first item in the directory
|
||||
spc.AddInt32("data", 0);
|
||||
else
|
||||
spc.AddRef("data", &nextRef);
|
||||
request.AddSpecifier(&spc);
|
||||
|
||||
BMessage reply;
|
||||
if (fTrackerMessenger.SendMessage(&request, &reply) != B_OK)
|
||||
return false;
|
||||
if (reply.FindRef("result", &nextRef) != B_OK)
|
||||
return false;
|
||||
|
||||
if (_IsImage(&nextRef))
|
||||
foundRef = true;
|
||||
|
||||
rewind = false;
|
||||
// stop asking for the first ref in the directory
|
||||
}
|
||||
|
||||
*ref = nextRef;
|
||||
return foundRef;
|
||||
}
|
||||
|
||||
status_t
|
||||
ImageFileNavigator::_LoadNextImage(bool next, bool rewind, BBitmap** bitmap)
|
||||
{
|
||||
if (bitmap == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
entry_ref curRef = fCurrentRef;
|
||||
entry_ref imgRef;
|
||||
bool found = _FindNextImage(&curRef, &imgRef, next, rewind);
|
||||
if (found) {
|
||||
// Keep trying to load images until:
|
||||
// 1. The image loads successfully
|
||||
// 2. The last file in the directory is found (for find next or find first)
|
||||
// 3. The first file in the directory is found (for find prev)
|
||||
// 4. The call to _FindNextImage fails for any other reason
|
||||
while (LoadImage(&imgRef, bitmap) != B_OK) {
|
||||
curRef = imgRef;
|
||||
found = _FindNextImage(&curRef, &imgRef, next, false);
|
||||
if (!found)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
_SetTrackerSelectionToCurrent();
|
||||
return B_OK;
|
||||
}
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageFileNavigator::_SetTrackerSelectionToCurrent()
|
||||
{
|
||||
BMessage setsel(B_SET_PROPERTY);
|
||||
setsel.AddSpecifier("Selection");
|
||||
setsel.AddRef("data", &fCurrentRef);
|
||||
fTrackerMessenger.SendMessage(&setsel);
|
||||
}
|
||||
|
||||
|
109
src/apps/showimage/ImageFileNavigator.h
Normal file
109
src/apps/showimage/ImageFileNavigator.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2003-2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2004-2005 yellowTAB GmbH. All Rights Reserverd.
|
||||
* Copyright 2006 Bernd Korz. All Rights Reserved
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Fernando Francisco de Oliveira
|
||||
* Michael Wilber
|
||||
* Michael Pfeiffer
|
||||
* yellowTAB GmbH
|
||||
* Bernd Korz
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
#ifndef IMAGE_FILE_NAVIGATOR_H
|
||||
#define IMAGE_FILE_NAVIGATOR_H
|
||||
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Entry.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <String.h>
|
||||
#include <TranslatorRoster.h>
|
||||
|
||||
|
||||
class ProgressWindow;
|
||||
|
||||
class ImageFileNavigator {
|
||||
public:
|
||||
ImageFileNavigator(
|
||||
ProgressWindow* progressWindow);
|
||||
virtual ~ImageFileNavigator();
|
||||
|
||||
void SetTrackerMessenger(
|
||||
const BMessenger& trackerMessenger);
|
||||
|
||||
status_t LoadImage(const entry_ref* ref, BBitmap** bitmap);
|
||||
const entry_ref* ImageRef() const { return &fCurrentRef; }
|
||||
|
||||
void GetName(BString* name);
|
||||
void GetPath(BString* name);
|
||||
|
||||
// The same image file may have multiple pages, TIFF images for
|
||||
// example. The page count is determined at image loading time.
|
||||
int32 CurrentPage();
|
||||
int32 PageCount();
|
||||
|
||||
status_t FirstPage(BBitmap** bitmap);
|
||||
status_t LastPage(BBitmap** bitmap);
|
||||
status_t NextPage(BBitmap** bitmap);
|
||||
status_t PrevPage(BBitmap** bitmap);
|
||||
status_t GoToPage(int32 page, BBitmap** bitmap);
|
||||
|
||||
// Navigation to the next/previous image file is based on
|
||||
// communication with Tracker, the folder containing the current
|
||||
// image needs to be open for this to work. The routine first tries
|
||||
// to find the next candidate file, then tries to load it as image.
|
||||
// As long as loading fails, the operation is repeated for the next
|
||||
// candidate file.
|
||||
status_t FirstFile(BBitmap** bitmap);
|
||||
status_t NextFile(BBitmap** bitmap);
|
||||
status_t PrevFile(BBitmap** bitmap);
|
||||
bool HasNextFile();
|
||||
bool HasPrevFile();
|
||||
|
||||
private:
|
||||
enum image_orientation {
|
||||
k0, // 0
|
||||
k90, // 1
|
||||
k180, // 2
|
||||
k270, // 3
|
||||
k0V, // 4
|
||||
k90V, // 5
|
||||
k0H, // 6
|
||||
k270V, // 7
|
||||
kNumberOfOrientations,
|
||||
};
|
||||
|
||||
bool _IsImage(const entry_ref* pref);
|
||||
bool _FindNextImage(entry_ref* inCurrent,
|
||||
entry_ref* outImage, bool next,
|
||||
bool rewind);
|
||||
status_t _LoadNextImage(bool next, bool rewind);
|
||||
void _SetTrackerSelectionToCurrent();
|
||||
|
||||
private:
|
||||
BMessenger fTrackerMessenger;
|
||||
// of the window that this was launched from
|
||||
entry_ref fCurrentRef;
|
||||
|
||||
int32 fDocumentIndex;
|
||||
// of the image in the file
|
||||
int32 fDocumentCount;
|
||||
// number of images in the file
|
||||
|
||||
BString fImageType;
|
||||
// Type of image, for use in status bar and caption
|
||||
BString fImageMime;
|
||||
|
||||
ProgressWindow* fProgressWindow;
|
||||
|
||||
image_orientation fImageOrientation;
|
||||
static image_orientation fTransformation[
|
||||
ImageProcessor
|
||||
::kNumberOfAffineTransformations]
|
||||
[kNumberOfOrientations];
|
||||
};
|
||||
|
||||
#endif // IMAGE_FILE_NAVIGATOR_H
|
Loading…
Reference in New Issue
Block a user