* Moved the Tracker navigation logic into its own class, TrackerNavigation.

* Added a new class FolderNavigation that implements the same for folders
  without a Tracker window.
* ImageFileNavigator is now using either one depending on whether it got a
  valid tracker messenger.
* Removed some unused/unneeded methods.
* Made entry_ref a reference at some more methods, as it's not really optional.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39292 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2010-11-03 23:29:54 +00:00
parent 9aed025e4a
commit ba3217eee8
8 changed files with 286 additions and 172 deletions
+270 -136
View File
@@ -12,47 +12,85 @@
* yellowTAB GmbH
* Bernd Korz
* Stephan Aßmus <[email protected]>
* Axel Dörfler, [email protected]
*/
#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 <ObjectList.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"
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<entry_ref> 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);
}
+5 -17
View File
@@ -21,6 +21,7 @@
#include <String.h>
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;
+3 -3
View File
@@ -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);
}
+1 -1
View File
@@ -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();
+2 -7
View File
@@ -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();
-2
View File
@@ -191,8 +191,6 @@ private:
private:
ShowImageUndo fUndo;
BMessenger fTrackerMessenger;
// of the window that this was launched from
entry_ref fCurrentRef;
BBitmap* fBitmap;
+4 -5
View File
@@ -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;
}
+1 -1
View File
@@ -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();