diff --git a/src/apps/showimage/ImageFileNavigator.cpp b/src/apps/showimage/ImageFileNavigator.cpp index 933bdbfbe0..ef63142a4f 100644 --- a/src/apps/showimage/ImageFileNavigator.cpp +++ b/src/apps/showimage/ImageFileNavigator.cpp @@ -12,47 +12,85 @@ * yellowTAB GmbH * Bernd Korz * Stephan Aßmus + * Axel Dörfler, axeld@pinc-software.de */ #include "ImageFileNavigator.h" -#include #include #include -#include -#include #include #include -#include -#include -#include #include #include #include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include "ProgressWindow.h" -#include "ShowImageApp.h" #include "ShowImageConstants.h" -#include "ShowImageWindow.h" + + +class Navigator { +public: + Navigator(); + virtual ~Navigator(); + + virtual bool FindNextImage(const entry_ref& currentRef, + entry_ref& ref, bool next, bool rewind) = 0; + virtual void UpdateSelection(const entry_ref& ref) = 0; + +protected: + bool IsImage(const entry_ref& ref); +}; + + +// 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. + +class TrackerNavigator : public Navigator { +public: + TrackerNavigator( + const BMessenger& trackerMessenger); + virtual ~TrackerNavigator(); + + virtual bool FindNextImage(const entry_ref& currentRef, + entry_ref& ref, bool next, bool rewind); + virtual void UpdateSelection(const entry_ref& ref); + +private: + BMessenger fTrackerMessenger; + // of the window that this was launched from +}; + + +class FolderNavigator : public Navigator { +public: + FolderNavigator(const entry_ref& ref); + virtual ~FolderNavigator(); + + virtual bool FindNextImage(const entry_ref& currentRef, + entry_ref& ref, bool next, bool rewind); + virtual void UpdateSelection(const entry_ref& ref); + +private: + void _BuildEntryList(); + static int _CompareRefs(const entry_ref* refA, + const entry_ref* refB); + +private: + BDirectory fFolder; + BObjectList fEntries; +}; // TODO: Remove this and use Tracker's Command.h once it is moved into the @@ -76,25 +114,223 @@ entry_ref_is_file(const entry_ref& ref) // #pragma mark - -ImageFileNavigator::ImageFileNavigator(const BMessenger& target) +Navigator::Navigator() +{ +} + + +Navigator::~Navigator() +{ +} + + +bool +Navigator::IsImage(const entry_ref& ref) +{ + if (!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 == NULL) + return false; + + translator_info info; + memset(&info, 0, sizeof(translator_info)); + return roster->Identify(&file, NULL, &info, 0, NULL, + B_TRANSLATOR_BITMAP) == B_OK; +} + + +// #pragma mark - + + +TrackerNavigator::TrackerNavigator(const BMessenger& trackerMessenger) + : + fTrackerMessenger(trackerMessenger) +{ +} + + +TrackerNavigator::~TrackerNavigator() +{ +} + + +bool +TrackerNavigator::FindNextImage(const 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 specifier; + if (rewind) + specifier.what = B_DIRECT_SPECIFIER; + else if (next) + specifier.what = 'snxt'; + else + specifier.what = 'sprv'; + specifier.AddString("property", "Entry"); + if (rewind) + // if rewinding, ask for the ref to the + // first item in the directory + specifier.AddInt32("data", 0); + else + specifier.AddRef("data", &nextRef); + request.AddSpecifier(&specifier); + + 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; +} + + +void +TrackerNavigator::UpdateSelection(const entry_ref& ref) +{ + BMessage setSelection(B_SET_PROPERTY); + setSelection.AddSpecifier("Selection"); + setSelection.AddRef("data", &ref); + fTrackerMessenger.SendMessage(&setSelection); +} + + +// #pragma mark - + + +FolderNavigator::FolderNavigator(const entry_ref& ref) + : + fEntries(true) +{ + node_ref nodeRef; + nodeRef.device = ref.device; + nodeRef.node = ref.directory; + + fFolder.SetTo(&nodeRef); + _BuildEntryList(); + + // TODO: monitor the directory for changes, sort it naturally +} + + +FolderNavigator::~FolderNavigator() +{ +} + + +bool +FolderNavigator::FindNextImage(const entry_ref& currentRef, entry_ref& nextRef, + bool next, bool rewind) +{ + int32 index; + if (rewind) { + index = next ? fEntries.CountItems() : 0; + next = !next; + } else { + index = fEntries.BinarySearchIndex(currentRef, + &FolderNavigator::_CompareRefs); + if (next) + index++; + else + index--; + } + + while (index < fEntries.CountItems() && index >= 0) { + const entry_ref& ref = *fEntries.ItemAt(index); + if (IsImage(ref)) { + nextRef = ref; + return true; + } else { + // remove non-image entries + delete fEntries.RemoveItemAt(index); + if (!next) + index--; + } + } + + return false; +} + + +void +FolderNavigator::UpdateSelection(const entry_ref& ref) +{ + // nothing to do for us here +} + + +void +FolderNavigator::_BuildEntryList() +{ + fEntries.MakeEmpty(); + fFolder.Rewind(); + + while (true) { + entry_ref* ref = new entry_ref(); + status_t status = fFolder.GetNextRef(ref); + if (status != B_OK) + break; + + fEntries.AddItem(ref); + } + + fEntries.SortItems(&FolderNavigator::_CompareRefs); +} + + +/*static*/ int +FolderNavigator::_CompareRefs(const entry_ref* refA, const entry_ref* refB) +{ + // TODO: natural sorting? Collating via current locale? + return strcasecmp(refA->name, refB->name); +} + + +// #pragma mark - + + +ImageFileNavigator::ImageFileNavigator(const BMessenger& target, + const entry_ref& ref, const BMessenger& trackerMessenger) : fTarget(target), fProgressWindow(NULL), fDocumentIndex(1), fDocumentCount(1) { + if (trackerMessenger.IsValid()) + fNavigator = new TrackerNavigator(trackerMessenger); + else + fNavigator = new FolderNavigator(ref); } ImageFileNavigator::~ImageFileNavigator() { -} - - -void -ImageFileNavigator::SetTrackerMessenger(const BMessenger& trackerMessenger) -{ - fTrackerMessenger = trackerMessenger; + delete fNavigator; } @@ -175,23 +411,10 @@ ImageFileNavigator::LoadImage(const entry_ref& ref, int32 page) return status; } - 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) { @@ -299,7 +522,7 @@ bool ImageFileNavigator::HasNextFile() { entry_ref ref; - return _FindNextImage(fCurrentRef, ref, true, false); + return fNavigator->FindNextImage(fCurrentRef, ref, true, false); } @@ -307,7 +530,7 @@ bool ImageFileNavigator::HasPreviousFile() { entry_ref ref; - return _FindNextImage(fCurrentRef, ref, false, false); + return fNavigator->FindNextImage(fCurrentRef, ref, false, false); } @@ -335,90 +558,12 @@ ImageFileNavigator::DeleteFile() // #pragma mark - -bool -ImageFileNavigator::_IsImage(const entry_ref& ref) -{ - if (!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(const 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) { entry_ref currentRef = fCurrentRef; entry_ref ref; - bool found = _FindNextImage(currentRef, ref, next, rewind); - if (found) { + if (fNavigator->FindNextImage(currentRef, ref, next, rewind)) { // 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 @@ -427,24 +572,13 @@ ImageFileNavigator::_LoadNextImage(bool next, bool rewind) // 4. The call to _FindNextImage fails for any other reason while (LoadImage(ref) != B_OK) { currentRef = ref; - found = _FindNextImage(currentRef, ref, next, false); - if (!found) + if (!fNavigator->FindNextImage(currentRef, ref, next, false)) return B_ENTRY_NOT_FOUND; } - _SetTrackerSelectionToCurrent(); + fNavigator->UpdateSelection(fCurrentRef); return B_OK; } return B_ENTRY_NOT_FOUND; } -void -ImageFileNavigator::_SetTrackerSelectionToCurrent() -{ - BMessage setSelection(B_SET_PROPERTY); - setSelection.AddSpecifier("Selection"); - setSelection.AddRef("data", &fCurrentRef); - fTrackerMessenger.SendMessage(&setSelection); -} - - diff --git a/src/apps/showimage/ImageFileNavigator.h b/src/apps/showimage/ImageFileNavigator.h index f5c92338e1..5ec0f8bef4 100644 --- a/src/apps/showimage/ImageFileNavigator.h +++ b/src/apps/showimage/ImageFileNavigator.h @@ -21,6 +21,7 @@ #include +class Navigator; class ProgressWindow; enum { @@ -30,18 +31,17 @@ enum { class ImageFileNavigator { public: - ImageFileNavigator(const BMessenger& target); + ImageFileNavigator(const BMessenger& target, + const entry_ref& ref, + const BMessenger& trackerMessenger); virtual ~ImageFileNavigator(); - void SetTrackerMessenger( - const BMessenger& trackerMessenger); void SetProgressWindow( ProgressWindow* progressWindow); status_t LoadImage(const entry_ref& ref, int32 page = 1); 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 @@ -55,12 +55,6 @@ public: bool PreviousPage(); bool GoToPage(int32 page); - // 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. void FirstFile(); void NextFile(); void PreviousFile(); @@ -70,18 +64,12 @@ public: void DeleteFile(); private: - bool _IsImage(const entry_ref& ref); - bool _FindNextImage(const entry_ref& current, - entry_ref& ref, bool next, - bool rewind); status_t _LoadNextImage(bool next, bool rewind); - void _SetTrackerSelectionToCurrent(); private: BMessenger fTarget; - BMessenger fTrackerMessenger; - // of the window that this was launched from ProgressWindow* fProgressWindow; + Navigator* fNavigator; entry_ref fCurrentRef; int32 fDocumentIndex; diff --git a/src/apps/showimage/ShowImageApp.cpp b/src/apps/showimage/ShowImageApp.cpp index c331782211..b1c18348fa 100644 --- a/src/apps/showimage/ShowImageApp.cpp +++ b/src/apps/showimage/ShowImageApp.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2003-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -168,7 +168,7 @@ ShowImageApp::RefsReceived(BMessage* message) entry_ref ref; for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { - _Open(&ref, trackerMessenger); + _Open(ref, trackerMessenger); } } @@ -200,7 +200,7 @@ ShowImageApp::_StartPulse() void -ShowImageApp::_Open(const entry_ref* ref, BMessenger& trackerMessenger) +ShowImageApp::_Open(const entry_ref& ref, BMessenger& trackerMessenger) { new ShowImageWindow(ref, trackerMessenger); } diff --git a/src/apps/showimage/ShowImageApp.h b/src/apps/showimage/ShowImageApp.h index 033ac00265..27c610b0fb 100644 --- a/src/apps/showimage/ShowImageApp.h +++ b/src/apps/showimage/ShowImageApp.h @@ -35,7 +35,7 @@ public: private: void _StartPulse(); - void _Open(const entry_ref* ref, + void _Open(const entry_ref& ref, BMessenger& trackerMessenger); void _BroadcastToWindows(BMessage* message); void _CheckClipboard(); diff --git a/src/apps/showimage/ShowImageView.cpp b/src/apps/showimage/ShowImageView.cpp index bbe9059dad..ed2eb4dd05 100644 --- a/src/apps/showimage/ShowImageView.cpp +++ b/src/apps/showimage/ShowImageView.cpp @@ -256,13 +256,6 @@ ShowImageView::Pulse() } -void -ShowImageView::SetTrackerMessenger(const BMessenger& trackerMessenger) -{ - fTrackerMessenger = trackerMessenger; -} - - void ShowImageView::_SendMessageToWindow(BMessage *message) { @@ -422,6 +415,8 @@ ShowImageView::SetImage(const entry_ref* ref, BBitmap* bitmap) fFormatDescription = "Bitmap"; fMimeType = "image/x-be-bitmap"; + be_roster->AddToRecentDocuments(ref, kApplicationSignature); + fFitToBoundsZoom = _FitToBoundsZoom(); ResetZoom(); Invalidate(); diff --git a/src/apps/showimage/ShowImageView.h b/src/apps/showimage/ShowImageView.h index 684fcb011d..3ad38b2939 100644 --- a/src/apps/showimage/ShowImageView.h +++ b/src/apps/showimage/ShowImageView.h @@ -191,8 +191,6 @@ private: private: ShowImageUndo fUndo; - BMessenger fTrackerMessenger; - // of the window that this was launched from entry_ref fCurrentRef; BBitmap* fBitmap; diff --git a/src/apps/showimage/ShowImageWindow.cpp b/src/apps/showimage/ShowImageWindow.cpp index 2bc3d5245b..9ea77c070a 100644 --- a/src/apps/showimage/ShowImageWindow.cpp +++ b/src/apps/showimage/ShowImageWindow.cpp @@ -75,11 +75,11 @@ bs_printf(BString* string, const char* format, ...) // #pragma mark -- ShowImageWindow -ShowImageWindow::ShowImageWindow(const entry_ref* ref, +ShowImageWindow::ShowImageWindow(const entry_ref& ref, const BMessenger& trackerMessenger) : BWindow(BRect(5, 24, 250, 100), "", B_DOCUMENT_WINDOW, 0), - fNavigator(this), + fNavigator(this, ref, trackerMessenger), fSavePanel(NULL), fBar(NULL), fBrowseMenu(NULL), @@ -142,9 +142,8 @@ ShowImageWindow::ShowImageWindow(const entry_ref* ref, SetSizeLimits(250, 100000, 100, 100000); // finish creating the window - fNavigator.SetTrackerMessenger(trackerMessenger); - if (fNavigator.LoadImage(*ref) != B_OK) { - _LoadError(*ref); + if (fNavigator.LoadImage(ref) != B_OK) { + _LoadError(ref); Quit(); return; } diff --git a/src/apps/showimage/ShowImageWindow.h b/src/apps/showimage/ShowImageWindow.h index e6057e0aa0..d957a1b6aa 100644 --- a/src/apps/showimage/ShowImageWindow.h +++ b/src/apps/showimage/ShowImageWindow.h @@ -27,7 +27,7 @@ class ShowImageStatusView; class ShowImageWindow : public BWindow { public: - ShowImageWindow(const entry_ref* ref, + ShowImageWindow(const entry_ref& ref, const BMessenger& trackerMessenger); virtual ~ShowImageWindow();