* The ImageFileNavigator is now only for navigation, it doesn't load any images

anymore.
* Moved the new ImageCache into its own source file.
* The cache is now used within ShowImage. There is no read-ahead caching being
  done yet, though, but you can quickly return to previous images, and you can
  also skip images faster than before.
* Improved separation between the ShowImageStatusView and the rest;
  ShowImageWindow no longer has a getter for the image view.
* The status view is now using the private BDirMenu which implements enhancement
  ticket #6778.
* Made a few more methods private/protected in ShowImageWindow.
* Fixed bug #6797.
* The bitmap is currently only owned by the ImageCache, but we need to have a
  separate referenceable object owning it. Added a TODO comment for this.
* The ProgressWindow is currently not being used anymore, added a TODO comment
  for this as well.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39364 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2010-11-08 23:06:36 +00:00
parent 824f5533d7
commit b9767a83ed
10 changed files with 535 additions and 495 deletions
+300
View File
@@ -0,0 +1,300 @@
/*
* Copyright 2010, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "ImageCache.h"
#include <new>
#include <Autolock.h>
#include <Bitmap.h>
#include <BitmapStream.h>
#include <Debug.h>
#include <File.h>
#include <Messenger.h>
#include <TranslatorRoster.h>
#include <AutoDeleter.h>
#include "ShowImageConstants.h"
struct QueueEntry {
entry_ref ref;
int32 page;
status_t status;
std::set<BMessenger> listeners;
};
/*static*/ ImageCache ImageCache::sCache;
// #pragma mark -
ImageCache::ImageCache()
:
fLocker("image cache"),
fThreadCount(0),
fBytes(0)
{
system_info info;
get_system_info(&info);
fMaxThreadCount = (info.cpu_count + 1) / 2;
fMaxBytes = info.max_pages * B_PAGE_SIZE / 8;
fMaxEntries = 10;
}
ImageCache::~ImageCache()
{
// TODO: delete CacheEntries, and QueueEntries
}
status_t
ImageCache::RetrieveImage(const entry_ref& ref, int32 page,
const BMessenger* target)
{
BAutolock locker(fLocker);
CacheMap::iterator find = fCacheMap.find(std::make_pair(ref, page));
if (find != fCacheMap.end()) {
CacheEntry* entry = find->second;
// Requeue cache entry to the end of the by-age list
fCacheEntriesByAge.Remove(entry);
fCacheEntriesByAge.Add(entry);
// Notify target, if any
_NotifyTarget(entry, target);
return B_OK;
}
QueueMap::iterator findQueue = fQueueMap.find(std::make_pair(ref, page));
QueueEntry* entry;
if (findQueue == fQueueMap.end()) {
// Push new entry to the queue
entry = new(std::nothrow) QueueEntry();
if (entry == NULL)
return B_NO_MEMORY;
entry->ref = ref;
entry->page = page;
if (fThreadCount < fMaxThreadCount) {
// start a new worker thread to load the image
thread_id thread = spawn_thread(&ImageCache::_QueueWorkerThread,
"image loader", B_LOW_PRIORITY, this);
if (thread >= B_OK) {
atomic_add(&fThreadCount, 1);
resume_thread(thread);
} else if (fThreadCount == 0) {
delete entry;
return thread;
}
}
fQueueMap.insert(std::make_pair(
std::make_pair(entry->ref, entry->page), entry));
fQueue.push_front(entry);
} else
entry = findQueue->second;
if (target != NULL) {
// Attach target as listener
entry->listeners.insert(*target);
}
return B_OK;
}
/*static*/ status_t
ImageCache::_QueueWorkerThread(void* _self)
{
ImageCache* self = (ImageCache*)_self;
// get next queue entry
while (true) {
self->fLocker.Lock();
if (self->fQueue.empty()) {
self->fLocker.Unlock();
break;
}
QueueEntry* entry = *self->fQueue.begin();
self->fQueue.pop_front();
self->fLocker.Unlock();
if (entry == NULL)
break;
CacheEntry* cacheEntry = NULL;
entry->status = self->_RetrieveImage(entry, &cacheEntry);
self->fLocker.Lock();
self->fQueueMap.erase(std::make_pair(entry->ref, entry->page));
self->fLocker.Unlock();
self->_NotifyListeners(cacheEntry, entry);
delete entry;
}
atomic_add(&self->fThreadCount, -1);
return B_OK;
}
status_t
ImageCache::_RetrieveImage(QueueEntry* queueEntry, CacheEntry** _entry)
{
CacheEntry* entry = new(std::nothrow) CacheEntry();
if (entry == NULL)
return B_NO_MEMORY;
ObjectDeleter<CacheEntry> deleter(entry);
BTranslatorRoster* roster = BTranslatorRoster::Default();
if (roster == NULL)
return B_ERROR;
BFile file;
status_t status = file.SetTo(&queueEntry->ref, B_READ_ONLY);
if (status != B_OK)
return status;
translator_info info;
memset(&info, 0, sizeof(translator_info));
BMessage ioExtension;
if (queueEntry->page != 0
&& ioExtension.AddInt32("/documentIndex", queueEntry->page) != B_OK)
return B_NO_MEMORY;
// TODO: rethink this!
#if 0
if (fProgressWindow != NULL) {
BMessage progress(kMsgProgressStatusUpdate);
if (ioExtension.AddMessenger("/progressMonitor",
fProgressWindow) == B_OK
&& ioExtension.AddMessage("/progressMessage", &progress) == B_OK)
fProgressWindow->Start();
}
#endif
// Translate image data and create a new ShowImage window
BBitmapStream outstream;
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);
}
#if 0
if (fProgressWindow != NULL)
fProgressWindow->Stop();
#endif
if (status != B_OK)
return status;
BBitmap* bitmap;
if (outstream.DetachBitmap(&bitmap) != B_OK)
return B_ERROR;
entry->ref = queueEntry->ref;
entry->page = queueEntry->page;
entry->bitmap = bitmap;
entry->type = info.name;
entry->mimeType = info.MIME;
// get the number of documents (pages) if it has been supplied
int32 documentCount = 0;
if (ioExtension.FindInt32("/documentCount", &documentCount) == B_OK
&& documentCount > 0)
entry->pageCount = documentCount;
else
entry->pageCount = 1;
deleter.Detach();
*_entry = entry;
BAutolock locker(fLocker);
fCacheMap.insert(std::make_pair(
std::make_pair(entry->ref, entry->page), entry));
fCacheEntriesByAge.Add(entry);
fBytes += bitmap->BitsLength();
while (fBytes > fMaxBytes || fCacheMap.size() > fMaxEntries) {
if (fCacheMap.size() <= 2)
break;
// Remove the oldest entry
entry = fCacheEntriesByAge.RemoveHead();
fBytes -= entry->bitmap->BitsLength();
fCacheMap.erase(std::make_pair(entry->ref, entry->page));
delete entry;
}
return B_OK;
}
void
ImageCache::_NotifyListeners(CacheEntry* entry, QueueEntry* queueEntry)
{
ASSERT(fLocker.IsLocked());
if (queueEntry->listeners.empty())
return;
BMessage notification(kMsgImageLoaded);
_BuildNotification(entry, notification);
if (queueEntry->status != B_OK)
notification.AddInt32("error", queueEntry->status);
std::set<BMessenger>::iterator iterator = queueEntry->listeners.begin();
for (; iterator != queueEntry->listeners.end(); iterator++) {
iterator->SendMessage(&notification);
}
}
void
ImageCache::_NotifyTarget(CacheEntry* entry, const BMessenger* target)
{
if (target == NULL)
return;
BMessage notification(kMsgImageLoaded);
_BuildNotification(entry, notification);
target->SendMessage(&notification);
}
void
ImageCache::_BuildNotification(CacheEntry* entry, BMessage& message)
{
if (entry == NULL)
return;
message.AddString("type", entry->type);
message.AddString("mime", entry->mimeType);
message.AddRef("ref", &entry->ref);
message.AddInt32("page", entry->page);
message.AddInt32("pageCount", entry->pageCount);
message.AddPointer("bitmap", (void*)entry->bitmap);
}
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright 2010, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef IMAGE_CACHE_H
#define IMAGE_CACHE_H
#include <deque>
#include <map>
#include <set>
#include <Entry.h>
#include <Locker.h>
#include <String.h>
#include <kernel/util/DoublyLinkedList.h>
class BBitmap;
class BMessage;
class BMessenger;
struct QueueEntry;
enum {
kMsgImageLoaded = 'ifnL'
};
struct CacheEntry : DoublyLinkedListLinkImpl<CacheEntry> {
entry_ref ref;
int32 page;
int32 pageCount;
BBitmap* bitmap;
BString type;
BString mimeType;
};
class ImageCache {
public:
static ImageCache& Default() { return sCache; }
status_t RetrieveImage(const entry_ref& ref, int32 page,
const BMessenger* target);
private:
ImageCache();
virtual ~ImageCache();
static status_t _QueueWorkerThread(void* self);
status_t _RetrieveImage(QueueEntry* entry,
CacheEntry** _entry);
void _NotifyListeners(CacheEntry* entry,
QueueEntry* queueEntry);
void _NotifyTarget(CacheEntry* entry,
const BMessenger* target);
void _BuildNotification(CacheEntry* entry,
BMessage& message);
private:
typedef std::pair<entry_ref, int32> ImageSelector;
typedef std::map<ImageSelector, CacheEntry*> CacheMap;
typedef std::map<ImageSelector, QueueEntry*> QueueMap;
typedef std::deque<QueueEntry*> QueueDeque;
typedef DoublyLinkedList<CacheEntry> CacheList;
BLocker fLocker;
CacheMap fCacheMap;
CacheList fCacheEntriesByAge;
QueueMap fQueueMap;
QueueDeque fQueue;
vint32 fThreadCount;
int32 fMaxThreadCount;
uint64 fBytes;
uint64 fMaxBytes;
size_t fMaxEntries;
static ImageCache sCache;
};
#endif // IMAGE_CACHE_H
+42 -385
View File
@@ -18,26 +18,20 @@
#include "ImageFileNavigator.h"
#include <deque>
#include <map>
#include <new>
#include <set>
#include <stdio.h>
#include <Bitmap.h>
#include <BitmapStream.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <Locker.h>
//#include <Locker.h>
#include <ObjectList.h>
#include <Path.h>
//#include <Path.h>
#include <TranslatorRoster.h>
#include <AutoDeleter.h>
#include <tracker_private.h>
#include <kernel/util/DoublyLinkedList.h>
#include "ProgressWindow.h"
#include "ShowImageConstants.h"
@@ -320,254 +314,10 @@ FolderNavigator::_CompareRefs(const entry_ref* refA, const entry_ref* refB)
// #pragma mark -
struct CacheEntry : DoublyLinkedListLinkImpl<CacheEntry> {
entry_ref ref;
int32 page;
int32 pageCount;
BBitmap* bitmap;
BString type;
BString mimeType;
};
struct QueueEntry {
entry_ref ref;
int32 page;
std::set<BMessenger> listeners;
};
class ImageCache {
public:
ImageCache();
virtual ~ImageCache();
void RetrieveImage(const entry_ref& ref,
const BMessenger* target);
private:
static status_t _QueueWorkerThread(void* self);
status_t _RetrieveImage(QueueEntry* entry,
BMessage& message);
void _NotifyListeners(QueueEntry* entry,
BMessage& message);
private:
typedef std::pair<entry_ref, int32> ImageSelector;
typedef std::map<ImageSelector, CacheEntry*> CacheMap;
typedef std::map<ImageSelector, QueueEntry*> QueueMap;
typedef std::deque<QueueEntry*> QueueDeque;
typedef DoublyLinkedList<CacheEntry> CacheList;
BLocker fCacheLocker;
CacheMap fCacheMap;
CacheList fCacheEntriesByAge;
BLocker fQueueLocker;
QueueMap fQueueMap;
QueueDeque fQueue;
vint32 fThreadCount;
int32 fMaxThreadCount;
uint64 fBytes;
uint64 fMaxBytes;
size_t fMaxEntries;
};
ImageCache::ImageCache()
ImageFileNavigator::ImageFileNavigator(const entry_ref& ref,
const BMessenger& trackerMessenger)
:
fCacheLocker("image cache"),
fQueueLocker("image queue"),
fThreadCount(0),
fBytes(0)
{
system_info info;
get_system_info(&info);
fMaxThreadCount = (info.cpu_count + 1) / 2;
fMaxBytes = info.max_pages * B_PAGE_SIZE / 8;
fMaxEntries = 10;
}
ImageCache::~ImageCache()
{
// TODO: delete CacheEntries, and QueueEntries
}
void
ImageCache::RetrieveImage(const entry_ref& ref, const BMessenger* target)
{
// TODO!
}
/*static*/ status_t
ImageCache::_QueueWorkerThread(void* _self)
{
ImageCache* self = (ImageCache*)_self;
// get next queue entry
while (true) {
self->fQueueLocker.Lock();
if (self->fQueue.empty()) {
self->fQueueLocker.Unlock();
break;
}
QueueEntry* entry = *self->fQueue.begin();
self->fQueue.pop_front();
self->fQueueLocker.Unlock();
if (entry == NULL)
break;
BMessage notification(kMsgImageLoaded);
status_t status = self->_RetrieveImage(entry, notification);
if (status != B_OK)
notification.AddInt32("error", status);
self->fQueueLocker.Lock();
self->fQueueMap.erase(std::make_pair(entry->ref, entry->page));
self->fQueueLocker.Unlock();
self->_NotifyListeners(entry, notification);
delete entry;
}
atomic_add(&self->fThreadCount, -1);
return B_OK;
}
status_t
ImageCache::_RetrieveImage(QueueEntry* queueEntry, BMessage& message)
{
CacheEntry* entry = new(std::nothrow) CacheEntry();
if (entry == NULL)
return B_NO_MEMORY;
ObjectDeleter<CacheEntry> deleter(entry);
BTranslatorRoster* roster = BTranslatorRoster::Default();
if (roster == NULL)
return B_ERROR;
if (!entry_ref_is_file(queueEntry->ref))
return B_IS_A_DIRECTORY;
BFile file;
status_t status = file.SetTo(&queueEntry->ref, B_READ_ONLY);
if (status != B_OK)
return status;
translator_info info;
memset(&info, 0, sizeof(translator_info));
BMessage ioExtension;
if (queueEntry->page != 0
&& ioExtension.AddInt32("/documentIndex", queueEntry->page) != B_OK)
return B_NO_MEMORY;
// TODO: rethink this!
#if 0
if (fProgressWindow != NULL) {
BMessage progress(kMsgProgressStatusUpdate);
if (ioExtension.AddMessenger("/progressMonitor",
fProgressWindow) == B_OK
&& ioExtension.AddMessage("/progressMessage", &progress) == B_OK)
fProgressWindow->Start();
}
#endif
// Translate image data and create a new ShowImage window
BBitmapStream outstream;
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);
}
#if 0
if (fProgressWindow != NULL)
fProgressWindow->Stop();
#endif
if (status != B_OK)
return status;
BBitmap* bitmap;
if (outstream.DetachBitmap(&bitmap) != B_OK)
return B_ERROR;
entry->ref = queueEntry->ref;
entry->page = queueEntry->page;
entry->bitmap = bitmap;
entry->type = info.name;
entry->mimeType = info.MIME;
// get the number of documents (pages) if it has been supplied
int32 documentCount = 0;
if (ioExtension.FindInt32("/documentCount", &documentCount) == B_OK
&& documentCount > 0)
entry->pageCount = documentCount;
else
entry->pageCount = 1;
message.AddString("type", info.name);
message.AddString("mime", info.MIME);
message.AddRef("ref", &entry->ref);
message.AddInt32("page", entry->page);
message.AddPointer("bitmap", (void*)bitmap);
deleter.Detach();
fCacheLocker.Lock();
fCacheMap.insert(std::make_pair(
std::make_pair(entry->ref, entry->page), entry));
fCacheEntriesByAge.Add(entry);
fBytes += bitmap->BitsLength();
while (fBytes > fMaxBytes || fCacheMap.size() > fMaxEntries) {
if (fCacheMap.size() <= 2)
break;
// Remove the oldest entry
entry = fCacheEntriesByAge.RemoveHead();
fBytes -= entry->bitmap->BitsLength();
fCacheMap.erase(std::make_pair(entry->ref, entry->page));
delete entry;
}
fCacheLocker.Unlock();
return B_OK;
}
void
ImageCache::_NotifyListeners(QueueEntry* entry, BMessage& message)
{
std::set<BMessenger>::iterator iterator = entry->listeners.begin();
for (; iterator != entry->listeners.end(); iterator++) {
iterator->SendMessage(&message);
}
}
// #pragma mark -
ImageFileNavigator::ImageFileNavigator(const BMessenger& target,
const entry_ref& ref, const BMessenger& trackerMessenger)
:
fTarget(target),
fProgressWindow(NULL),
fCurrentRef(ref),
fDocumentIndex(1),
fDocumentCount(1)
{
@@ -585,95 +335,11 @@ ImageFileNavigator::~ImageFileNavigator()
void
ImageFileNavigator::SetProgressWindow(ProgressWindow* progressWindow)
ImageFileNavigator::SetTo(const entry_ref& ref, int32 page, int32 pageCount)
{
fProgressWindow = progressWindow;
}
status_t
ImageFileNavigator::LoadImage(const entry_ref& ref, int32 page)
{
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 (page != 0 && ioExtension.AddInt32("/documentIndex", page) != B_OK)
return B_ERROR;
if (fProgressWindow != NULL) {
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);
}
if (fProgressWindow != NULL)
fProgressWindow->Stop();
if (status != B_OK)
return status;
BBitmap* bitmap;
if (outstream.DetachBitmap(&bitmap) != B_OK)
return B_ERROR;
fCurrentRef = ref;
fDocumentIndex = page;
// 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;
BMessage message(kMsgImageLoaded);
message.AddString("type", info.name);
message.AddString("mime", info.MIME);
message.AddRef("ref", &ref);
message.AddInt32("page", page);
message.AddPointer("bitmap", (void*)bitmap);
status = fTarget.SendMessage(&message);
if (status != B_OK) {
delete bitmap;
return status;
}
return B_OK;
}
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());
fDocumentCount = pageCount;
}
@@ -695,7 +361,7 @@ bool
ImageFileNavigator::FirstPage()
{
if (fDocumentIndex != 1) {
LoadImage(fCurrentRef, 1);
fDocumentIndex = 1;
return true;
}
return false;
@@ -706,7 +372,7 @@ bool
ImageFileNavigator::LastPage()
{
if (fDocumentIndex != fDocumentCount) {
LoadImage(fCurrentRef, fDocumentCount);
fDocumentIndex = fDocumentCount;
return true;
}
return false;
@@ -717,7 +383,7 @@ bool
ImageFileNavigator::NextPage()
{
if (fDocumentIndex < fDocumentCount) {
LoadImage(fCurrentRef, ++fDocumentIndex);
fDocumentIndex++;
return true;
}
return false;
@@ -728,7 +394,7 @@ bool
ImageFileNavigator::PreviousPage()
{
if (fDocumentIndex > 1) {
LoadImage(fCurrentRef, --fDocumentIndex);
fDocumentIndex--;
return true;
}
return false;
@@ -740,31 +406,51 @@ ImageFileNavigator::GoToPage(int32 page)
{
if (page > 0 && page <= fDocumentCount && page != fDocumentIndex) {
fDocumentIndex = page;
LoadImage(fCurrentRef, fDocumentIndex);
return true;
}
return false;
}
void
bool
ImageFileNavigator::FirstFile()
{
_LoadNextImage(true, true);
entry_ref ref;
if (fNavigator->FindNextImage(fCurrentRef, ref, false, true)) {
SetTo(ref, 1, 1);
fNavigator->UpdateSelection(fCurrentRef);
return true;
}
return false;
}
void
bool
ImageFileNavigator::NextFile()
{
_LoadNextImage(true, false);
entry_ref ref;
if (fNavigator->FindNextImage(fCurrentRef, ref, true, false)) {
SetTo(ref, 1, 1);
fNavigator->UpdateSelection(fCurrentRef);
return true;
}
return false;
}
void
bool
ImageFileNavigator::PreviousFile()
{
_LoadNextImage(false, false);
entry_ref ref;
if (fNavigator->FindNextImage(fCurrentRef, ref, false, false)) {
SetTo(ref, 1, 1);
fNavigator->UpdateSelection(fCurrentRef);
return true;
}
return false;
}
@@ -785,7 +471,7 @@ ImageFileNavigator::HasPreviousFile()
/*! Moves the current file into the trash.
Returns true if a new file is being loaded, false if not.
Returns true if a new file should be loaded, false if not.
*/
bool
ImageFileNavigator::MoveFileToTrash()
@@ -803,41 +489,12 @@ ImageFileNavigator::MoveFileToTrash()
// could be invalid
BMessenger tracker(kTrackerSignature);
if (tracker.SendMessage(&trash) != B_OK)
return true;
return false;
if (nextRef.device != -1 && LoadImage(nextRef) == B_OK) {
fNavigator->UpdateSelection(nextRef);
if (nextRef.device != -1) {
SetTo(nextRef, 1, 1);
return true;
}
return false;
}
// #pragma mark -
status_t
ImageFileNavigator::_LoadNextImage(bool next, bool rewind)
{
entry_ref currentRef = fCurrentRef;
entry_ref ref;
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
// 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(ref) != B_OK) {
currentRef = ref;
if (!fNavigator->FindNextImage(currentRef, ref, next, false))
return B_ENTRY_NOT_FOUND;
}
fNavigator->UpdateSelection(fCurrentRef);
return B_OK;
}
return B_ENTRY_NOT_FOUND;
}
+7 -22
View File
@@ -22,27 +22,17 @@
class Navigator;
class ProgressWindow;
enum {
kMsgImageLoaded = 'ifnL'
};
class ImageFileNavigator {
public:
ImageFileNavigator(const BMessenger& target,
const entry_ref& ref,
ImageFileNavigator(const entry_ref& ref,
const BMessenger& trackerMessenger);
virtual ~ImageFileNavigator();
void SetProgressWindow(
ProgressWindow* progressWindow);
status_t LoadImage(const entry_ref& ref, int32 page = 1);
const entry_ref& ImageRef() const { return fCurrentRef; }
void GetPath(BString* name);
void SetTo(const entry_ref& ref, int32 page = 1,
int32 pageCount = 1);
const entry_ref& CurrentRef() const { return fCurrentRef; }
// The same image file may have multiple pages, TIFF images for
// example. The page count is determined at image loading time.
@@ -55,20 +45,15 @@ public:
bool PreviousPage();
bool GoToPage(int32 page);
void FirstFile();
void NextFile();
void PreviousFile();
bool FirstFile();
bool NextFile();
bool PreviousFile();
bool HasNextFile();
bool HasPreviousFile();
bool MoveFileToTrash();
private:
status_t _LoadNextImage(bool next, bool rewind);
private:
BMessenger fTarget;
ProgressWindow* fProgressWindow;
Navigator* fNavigator;
entry_ref fCurrentRef;
+3 -1
View File
@@ -3,10 +3,12 @@ SubDir HAIKU_TOP src apps showimage ;
UsePrivateSystemHeaders ;
UsePrivateHeaders tracker shared ;
UsePublicHeaders [ FDirName be_apps Tracker ] ;
SubDirHdrs $(HAIKU_TOP) src kits tracker ;
Application ShowImage :
EntryMenuItem.cpp
Filter.cpp
ImageCache.cpp
ImageFileNavigator.cpp
PrintOptionsWindow.cpp
ProgressWindow.cpp
@@ -18,7 +20,7 @@ Application ShowImage :
ShowImageView.cpp
ShowImageWindow.cpp
: libshared.a
be tracker translation $(HAIKU_LOCALE_LIBS) $(TARGET_LIBSTDC++)
be tracker translation $(HAIKU_LOCALE_LIBS) $(TARGET_LIBSTDC++)
$(TARGET_LIBSUPC++)
: ShowImage.rdef
;
+23 -35
View File
@@ -1,12 +1,14 @@
/*
* 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:
* Fernando Francisco de Oliveira
* Michael Wilber
* Axel Dörfler, [email protected]
*/
#include "ShowImageStatusView.h"
#include <Entry.h>
@@ -14,6 +16,9 @@
#include <Path.h>
#include <PopUpMenu.h>
#include <tracker_private.h>
#include "DirMenu.h"
#include "ShowImageView.h"
#include "ShowImageWindow.h"
@@ -77,47 +82,30 @@ ShowImageStatusView::Draw(BRect updateRect)
void
ShowImageStatusView::MouseDown(BPoint where)
{
ShowImageWindow *window = dynamic_cast<ShowImageWindow *>(Window());
if (!window || window->GetShowImageView() == NULL)
return;
BPrivate::BDirMenu* menu = new BDirMenu(NULL, B_REFS_RECEIVED);
BEntry entry;
if (entry.SetTo(&fRef) == B_OK)
menu->Populate(&entry, Window(), false, false, true, false, true);
else
menu->Populate(NULL, Window(), false, false, true, false, true);
BPath path;
path.SetTo(window->GetShowImageView()->Image());
BPopUpMenu popup("no title");
popup.SetFont(be_plain_font);
while (path.GetParent(&path) == B_OK && path != "/") {
popup.AddItem(new BMenuItem(path.Leaf(), NULL));
}
BRect bounds(Bounds());
ConvertToScreen(&bounds);
where = bounds.LeftBottom();
BMenuItem *item;
item = popup.Go(where, true, false, ConvertToScreen(Bounds()));
if (item) {
path.SetTo(window->GetShowImageView()->Image());
path.GetParent(&path);
int index = popup.IndexOf(item);
while (index--)
path.GetParent(&path);
BMessenger tracker("application/x-vnd.Be-TRAK");
BMessage msg(B_REFS_RECEIVED);
entry_ref ref;
get_ref_for_path(path.Path(), &ref);
msg.AddRef("refs", &ref);
tracker.SendMessage(&msg);
}
menu->SetTargetForItems(BMessenger(kTrackerSignature));
BPoint point = Bounds().LeftBottom();
point.y += 3;
ConvertToScreen(&point);
BRect clickToOpenRect(Bounds());
ConvertToScreen(&clickToOpenRect);
menu->Go(point, true, true, clickToOpenRect);
delete menu;
}
void
ShowImageStatusView::SetText(BString &text)
ShowImageStatusView::Update(const entry_ref& ref, const BString& text)
{
fText = text;
fRef = ref;
Invalidate();
}
+14 -9
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:
@@ -10,21 +10,26 @@
#define SHOW_IMAGE_STATUS_VIEW_H
#include <Entry.h>
#include <String.h>
#include <View.h>
class ShowImageStatusView : public BView {
public:
ShowImageStatusView(BRect rect, const char *name,
uint32 resizingMode, uint32 flags);
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
void SetText(BString &text);
ShowImageStatusView(BRect rect,
const char* name, uint32 resizingMode,
uint32 flags);
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
void Update(const entry_ref& ref,
const BString& text);
private:
BString fText;
BString fText;
entry_ref fRef;
};
+4 -1
View File
@@ -316,7 +316,7 @@ ShowImageView::_DeleteBitmap()
delete fDisplayBitmap;
fDisplayBitmap = NULL;
delete fBitmap;
// TODO: the bitmap is currently only owned by the cache!!!
fBitmap = NULL;
}
@@ -751,6 +751,9 @@ ShowImageView::Draw(BRect updateRect)
void
ShowImageView::FrameResized(float /*width*/, float /*height*/)
{
if (fBitmap == NULL)
return;
fFitToBoundsZoom = _FitToBoundsZoom();
SetZoom(_ShouldStretch() ? fFitToBoundsZoom : fZoom);
}
+50 -35
View File
@@ -44,7 +44,7 @@
#include <TranslationUtils.h>
#include <TranslatorRoster.h>
#include "EntryMenuItem.h"
#include "ImageCache.h"
#include "ShowImageApp.h"
#include "ShowImageConstants.h"
#include "ShowImageStatusView.h"
@@ -79,7 +79,7 @@ ShowImageWindow::ShowImageWindow(const entry_ref& ref,
const BMessenger& trackerMessenger)
:
BWindow(BRect(5, 24, 250, 100), "", B_DOCUMENT_WINDOW, 0),
fNavigator(this, ref, trackerMessenger),
fNavigator(ref, trackerMessenger),
fSavePanel(NULL),
fBar(NULL),
fBrowseMenu(NULL),
@@ -96,7 +96,7 @@ ShowImageWindow::ShowImageWindow(const entry_ref& ref,
// create menu bar
fBar = new BMenuBar(BRect(0, 0, Bounds().right, 1), "menu_bar");
AddMenus(fBar);
_AddMenus(fBar);
AddChild(fBar);
BRect viewFrame = Bounds();
@@ -142,7 +142,7 @@ ShowImageWindow::ShowImageWindow(const entry_ref& ref,
SetSizeLimits(250, 100000, 100, 100000);
// finish creating the window
if (fNavigator.LoadImage(ref) != B_OK) {
if (_LoadImage() != B_OK) {
_LoadError(ref);
Quit();
return;
@@ -173,14 +173,6 @@ ShowImageWindow::~ShowImageWindow()
}
void
ShowImageWindow::UpdateTitle()
{
BPath path(fImageView->Image());
SetTitle(path.Path());
}
void
ShowImageWindow::BuildContextMenu(BMenu* menu)
{
@@ -261,7 +253,7 @@ ShowImageWindow::_BuildViewMenu(BMenu* menu, bool popupMenu)
void
ShowImageWindow::AddMenus(BMenuBar* bar)
ShowImageWindow::_AddMenus(BMenuBar* bar)
{
BMenu* menu = new BMenu(B_TRANSLATE("File"));
@@ -377,7 +369,7 @@ ShowImageWindow::_AddDelayItem(BMenu* menu, const char* label, float value)
void
ShowImageWindow::WindowRedimension(BBitmap* bitmap)
ShowImageWindow::_WindowRedimension(BBitmap* bitmap)
{
BScreen screen;
if (!screen.IsValid())
@@ -492,12 +484,15 @@ ShowImageWindow::MessageReceived(BMessage* message)
case kMsgImageLoaded:
{
bool first = fImageView->Bitmap() == NULL;
entry_ref ref;
message->FindRef("ref", &ref);
if (!first && ref != fNavigator.CurrentRef()) {
// ignore older images
break;
}
status_t status = fImageView->SetImage(message);
if (status != B_OK) {
entry_ref ref;
message->FindRef("ref", &ref);
_LoadError(ref);
// quit if file could not be opened
@@ -507,9 +502,11 @@ ShowImageWindow::MessageReceived(BMessage* message)
}
fImageType = message->FindString("type");
fNavigator.SetTo(ref, message->FindInt32("page"),
message->FindInt32("pageCount"));
if (first) {
WindowRedimension(fImageView->Bitmap());
_WindowRedimension(fImageView->Bitmap());
fImageView->ResetZoom();
fImageView->MakeFocus(true);
// to receive key messages
@@ -519,7 +516,7 @@ ShowImageWindow::MessageReceived(BMessage* message)
if (!fImageView->StretchesToBounds()
&& !fImageView->ShrinksToBounds()
&& !fFullScreen)
WindowRedimension(fImageView->Bitmap());
_WindowRedimension(fImageView->Bitmap());
}
break;
}
@@ -596,7 +593,9 @@ ShowImageWindow::MessageReceived(BMessage* message)
}
_UpdateStatusText(message);
UpdateTitle();
BPath path(fImageView->Image());
SetTitle(path.Path());
break;
}
@@ -648,23 +647,23 @@ ShowImageWindow::MessageReceived(BMessage* message)
break;
case MSG_PAGE_FIRST:
if (_ClosePrompt())
fNavigator.FirstPage();
if (_ClosePrompt() && fNavigator.FirstPage())
_LoadImage();
break;
case MSG_PAGE_LAST:
if (_ClosePrompt())
fNavigator.LastPage();
if (_ClosePrompt() && fNavigator.LastPage())
_LoadImage();
break;
case MSG_PAGE_NEXT:
if (_ClosePrompt())
fNavigator.NextPage();
if (_ClosePrompt() && fNavigator.NextPage())
_LoadImage();
break;
case MSG_PAGE_PREV:
if (_ClosePrompt())
fNavigator.PreviousPage();
if (_ClosePrompt() && fNavigator.PreviousPage())
_LoadImage();
break;
case MSG_GOTO_PAGE:
@@ -679,13 +678,15 @@ ShowImageWindow::MessageReceived(BMessage* message)
int32 currentPage = fNavigator.CurrentPage();
int32 pages = fNavigator.PageCount();
// TODO: use radio mode instead!
if (newPage > 0 && newPage <= pages) {
BMenuItem* currentItem = fGoToPageMenu->ItemAt(currentPage - 1);
BMenuItem* newItem = fGoToPageMenu->ItemAt(newPage - 1);
if (currentItem != NULL && newItem != NULL) {
currentItem->SetMarked(false);
newItem->SetMarked(true);
fNavigator.GoToPage(newPage);
if (fNavigator.GoToPage(newPage))
_LoadImage();
}
}
break;
@@ -700,19 +701,23 @@ ShowImageWindow::MessageReceived(BMessage* message)
break;
case MSG_FILE_PREV:
if (_ClosePrompt())
fNavigator.PreviousFile();
if (_ClosePrompt() && fNavigator.PreviousFile())
_LoadImage();
break;
case MSG_FILE_NEXT:
if (_ClosePrompt())
fNavigator.NextFile();
if (_ClosePrompt() && fNavigator.NextFile())
_LoadImage();
break;
case kMsgDeleteCurrentFile:
if (!fNavigator.MoveFileToTrash())
{
if (fNavigator.MoveFileToTrash())
_LoadImage();
else
PostMessage(B_QUIT_REQUESTED);
break;
}
case MSG_ROTATE_90:
fImageView->Rotate(90);
@@ -838,7 +843,7 @@ ShowImageWindow::_UpdateStatusText(const BMessage* message)
status << ", " << text;
}
fStatusView->SetText(status);
fStatusView->Update(fNavigator.CurrentRef(), status);
}
@@ -934,6 +939,7 @@ ShowImageWindow::_SaveToFile(BMessage* message)
#undef B_TRANSLATE_CONTEXT
#define B_TRANSLATE_CONTEXT "ClosePrompt"
bool
ShowImageWindow::_ClosePrompt()
{
@@ -969,6 +975,15 @@ ShowImageWindow::_ClosePrompt()
}
status_t
ShowImageWindow::_LoadImage()
{
BMessenger us(this);
return ImageCache::Default().RetrieveImage(fNavigator.CurrentRef(),
fNavigator.CurrentPage(), &us);
}
void
ShowImageWindow::_ToggleFullScreen()
{
+7 -7
View File
@@ -31,18 +31,16 @@ public:
const BMessenger& trackerMessenger);
virtual ~ShowImageWindow();
void BuildContextMenu(BMenu* menu);
protected:
virtual void FrameResized(float width, float height);
virtual void MessageReceived(BMessage* message);
virtual bool QuitRequested();
ShowImageView* GetShowImageView() const { return fImageView; }
void UpdateTitle();
void AddMenus(BMenuBar* bar);
void BuildContextMenu(BMenu* menu);
void WindowRedimension(BBitmap* bitmap);
private:
void _AddMenus(BMenuBar* bar);
void _WindowRedimension(BBitmap* bitmap);
void _BuildViewMenu(BMenu* menu, bool popupMenu);
BMenuItem* _AddItemMenu(BMenu* menu, const char* label,
uint32 what, char shortcut, uint32 modifier,
@@ -66,6 +64,7 @@ private:
void _SaveToFile(BMessage* message);
// Handle save file panel message
bool _ClosePrompt();
status_t _LoadImage();
void _ToggleFullScreen();
void _ApplySettings();
void _SavePrintOptions();
@@ -88,6 +87,7 @@ private:
BRect fWindowFrame;
BMessage* fPrintSettings;
PrintOptions fPrintOptions;
BString fImageType;
};