* 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:
@@ -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(¬ification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ImageCache::_NotifyTarget(CacheEntry* entry, const BMessenger* target)
|
||||||
|
{
|
||||||
|
if (target == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BMessage notification(kMsgImageLoaded);
|
||||||
|
_BuildNotification(entry, notification);
|
||||||
|
|
||||||
|
target->SendMessage(¬ification);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -18,26 +18,20 @@
|
|||||||
|
|
||||||
#include "ImageFileNavigator.h"
|
#include "ImageFileNavigator.h"
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <map>
|
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <Bitmap.h>
|
|
||||||
#include <BitmapStream.h>
|
#include <BitmapStream.h>
|
||||||
#include <Directory.h>
|
#include <Directory.h>
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
#include <File.h>
|
#include <File.h>
|
||||||
#include <Locker.h>
|
//#include <Locker.h>
|
||||||
#include <ObjectList.h>
|
#include <ObjectList.h>
|
||||||
#include <Path.h>
|
//#include <Path.h>
|
||||||
#include <TranslatorRoster.h>
|
#include <TranslatorRoster.h>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
|
||||||
#include <tracker_private.h>
|
#include <tracker_private.h>
|
||||||
#include <kernel/util/DoublyLinkedList.h>
|
|
||||||
|
|
||||||
#include "ProgressWindow.h"
|
#include "ProgressWindow.h"
|
||||||
#include "ShowImageConstants.h"
|
#include "ShowImageConstants.h"
|
||||||
@@ -320,254 +314,10 @@ FolderNavigator::_CompareRefs(const entry_ref* refA, const entry_ref* refB)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
struct CacheEntry : DoublyLinkedListLinkImpl<CacheEntry> {
|
ImageFileNavigator::ImageFileNavigator(const entry_ref& ref,
|
||||||
entry_ref ref;
|
const BMessenger& trackerMessenger)
|
||||||
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()
|
|
||||||
:
|
:
|
||||||
fCacheLocker("image cache"),
|
fCurrentRef(ref),
|
||||||
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),
|
|
||||||
fDocumentIndex(1),
|
fDocumentIndex(1),
|
||||||
fDocumentCount(1)
|
fDocumentCount(1)
|
||||||
{
|
{
|
||||||
@@ -585,95 +335,11 @@ ImageFileNavigator::~ImageFileNavigator()
|
|||||||
|
|
||||||
|
|
||||||
void
|
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;
|
fCurrentRef = ref;
|
||||||
fDocumentIndex = page;
|
fDocumentIndex = page;
|
||||||
|
fDocumentCount = pageCount;
|
||||||
// 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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -695,7 +361,7 @@ bool
|
|||||||
ImageFileNavigator::FirstPage()
|
ImageFileNavigator::FirstPage()
|
||||||
{
|
{
|
||||||
if (fDocumentIndex != 1) {
|
if (fDocumentIndex != 1) {
|
||||||
LoadImage(fCurrentRef, 1);
|
fDocumentIndex = 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -706,7 +372,7 @@ bool
|
|||||||
ImageFileNavigator::LastPage()
|
ImageFileNavigator::LastPage()
|
||||||
{
|
{
|
||||||
if (fDocumentIndex != fDocumentCount) {
|
if (fDocumentIndex != fDocumentCount) {
|
||||||
LoadImage(fCurrentRef, fDocumentCount);
|
fDocumentIndex = fDocumentCount;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -717,7 +383,7 @@ bool
|
|||||||
ImageFileNavigator::NextPage()
|
ImageFileNavigator::NextPage()
|
||||||
{
|
{
|
||||||
if (fDocumentIndex < fDocumentCount) {
|
if (fDocumentIndex < fDocumentCount) {
|
||||||
LoadImage(fCurrentRef, ++fDocumentIndex);
|
fDocumentIndex++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -728,7 +394,7 @@ bool
|
|||||||
ImageFileNavigator::PreviousPage()
|
ImageFileNavigator::PreviousPage()
|
||||||
{
|
{
|
||||||
if (fDocumentIndex > 1) {
|
if (fDocumentIndex > 1) {
|
||||||
LoadImage(fCurrentRef, --fDocumentIndex);
|
fDocumentIndex--;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -740,31 +406,51 @@ ImageFileNavigator::GoToPage(int32 page)
|
|||||||
{
|
{
|
||||||
if (page > 0 && page <= fDocumentCount && page != fDocumentIndex) {
|
if (page > 0 && page <= fDocumentCount && page != fDocumentIndex) {
|
||||||
fDocumentIndex = page;
|
fDocumentIndex = page;
|
||||||
LoadImage(fCurrentRef, fDocumentIndex);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
bool
|
||||||
ImageFileNavigator::FirstFile()
|
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()
|
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()
|
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.
|
/*! 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
|
bool
|
||||||
ImageFileNavigator::MoveFileToTrash()
|
ImageFileNavigator::MoveFileToTrash()
|
||||||
@@ -803,41 +489,12 @@ ImageFileNavigator::MoveFileToTrash()
|
|||||||
// could be invalid
|
// could be invalid
|
||||||
BMessenger tracker(kTrackerSignature);
|
BMessenger tracker(kTrackerSignature);
|
||||||
if (tracker.SendMessage(&trash) != B_OK)
|
if (tracker.SendMessage(&trash) != B_OK)
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
if (nextRef.device != -1 && LoadImage(nextRef) == B_OK) {
|
if (nextRef.device != -1) {
|
||||||
fNavigator->UpdateSelection(nextRef);
|
SetTo(nextRef, 1, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,27 +22,17 @@
|
|||||||
|
|
||||||
|
|
||||||
class Navigator;
|
class Navigator;
|
||||||
class ProgressWindow;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
kMsgImageLoaded = 'ifnL'
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ImageFileNavigator {
|
class ImageFileNavigator {
|
||||||
public:
|
public:
|
||||||
ImageFileNavigator(const BMessenger& target,
|
ImageFileNavigator(const entry_ref& ref,
|
||||||
const entry_ref& ref,
|
|
||||||
const BMessenger& trackerMessenger);
|
const BMessenger& trackerMessenger);
|
||||||
virtual ~ImageFileNavigator();
|
virtual ~ImageFileNavigator();
|
||||||
|
|
||||||
void SetProgressWindow(
|
void SetTo(const entry_ref& ref, int32 page = 1,
|
||||||
ProgressWindow* progressWindow);
|
int32 pageCount = 1);
|
||||||
|
const entry_ref& CurrentRef() const { return fCurrentRef; }
|
||||||
status_t LoadImage(const entry_ref& ref, int32 page = 1);
|
|
||||||
const entry_ref& ImageRef() const { return fCurrentRef; }
|
|
||||||
|
|
||||||
void GetPath(BString* name);
|
|
||||||
|
|
||||||
// The same image file may have multiple pages, TIFF images for
|
// The same image file may have multiple pages, TIFF images for
|
||||||
// example. The page count is determined at image loading time.
|
// example. The page count is determined at image loading time.
|
||||||
@@ -55,20 +45,15 @@ public:
|
|||||||
bool PreviousPage();
|
bool PreviousPage();
|
||||||
bool GoToPage(int32 page);
|
bool GoToPage(int32 page);
|
||||||
|
|
||||||
void FirstFile();
|
bool FirstFile();
|
||||||
void NextFile();
|
bool NextFile();
|
||||||
void PreviousFile();
|
bool PreviousFile();
|
||||||
bool HasNextFile();
|
bool HasNextFile();
|
||||||
bool HasPreviousFile();
|
bool HasPreviousFile();
|
||||||
|
|
||||||
bool MoveFileToTrash();
|
bool MoveFileToTrash();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _LoadNextImage(bool next, bool rewind);
|
|
||||||
|
|
||||||
private:
|
|
||||||
BMessenger fTarget;
|
|
||||||
ProgressWindow* fProgressWindow;
|
|
||||||
Navigator* fNavigator;
|
Navigator* fNavigator;
|
||||||
|
|
||||||
entry_ref fCurrentRef;
|
entry_ref fCurrentRef;
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ SubDir HAIKU_TOP src apps showimage ;
|
|||||||
UsePrivateSystemHeaders ;
|
UsePrivateSystemHeaders ;
|
||||||
UsePrivateHeaders tracker shared ;
|
UsePrivateHeaders tracker shared ;
|
||||||
UsePublicHeaders [ FDirName be_apps Tracker ] ;
|
UsePublicHeaders [ FDirName be_apps Tracker ] ;
|
||||||
|
SubDirHdrs $(HAIKU_TOP) src kits tracker ;
|
||||||
|
|
||||||
Application ShowImage :
|
Application ShowImage :
|
||||||
EntryMenuItem.cpp
|
EntryMenuItem.cpp
|
||||||
Filter.cpp
|
Filter.cpp
|
||||||
|
ImageCache.cpp
|
||||||
ImageFileNavigator.cpp
|
ImageFileNavigator.cpp
|
||||||
PrintOptionsWindow.cpp
|
PrintOptionsWindow.cpp
|
||||||
ProgressWindow.cpp
|
ProgressWindow.cpp
|
||||||
|
|||||||
@@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Fernando Francisco de Oliveira
|
* Fernando Francisco de Oliveira
|
||||||
* Michael Wilber
|
* Michael Wilber
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "ShowImageStatusView.h"
|
#include "ShowImageStatusView.h"
|
||||||
|
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
@@ -14,6 +16,9 @@
|
|||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
#include <PopUpMenu.h>
|
#include <PopUpMenu.h>
|
||||||
|
|
||||||
|
#include <tracker_private.h>
|
||||||
|
#include "DirMenu.h"
|
||||||
|
|
||||||
#include "ShowImageView.h"
|
#include "ShowImageView.h"
|
||||||
#include "ShowImageWindow.h"
|
#include "ShowImageWindow.h"
|
||||||
|
|
||||||
@@ -77,47 +82,30 @@ ShowImageStatusView::Draw(BRect updateRect)
|
|||||||
void
|
void
|
||||||
ShowImageStatusView::MouseDown(BPoint where)
|
ShowImageStatusView::MouseDown(BPoint where)
|
||||||
{
|
{
|
||||||
ShowImageWindow *window = dynamic_cast<ShowImageWindow *>(Window());
|
BPrivate::BDirMenu* menu = new BDirMenu(NULL, B_REFS_RECEIVED);
|
||||||
if (!window || window->GetShowImageView() == NULL)
|
BEntry entry;
|
||||||
return;
|
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;
|
menu->SetTargetForItems(BMessenger(kTrackerSignature));
|
||||||
path.SetTo(window->GetShowImageView()->Image());
|
BPoint point = Bounds().LeftBottom();
|
||||||
|
point.y += 3;
|
||||||
BPopUpMenu popup("no title");
|
ConvertToScreen(&point);
|
||||||
popup.SetFont(be_plain_font);
|
BRect clickToOpenRect(Bounds());
|
||||||
|
ConvertToScreen(&clickToOpenRect);
|
||||||
while (path.GetParent(&path) == B_OK && path != "/") {
|
menu->Go(point, true, true, clickToOpenRect);
|
||||||
popup.AddItem(new BMenuItem(path.Leaf(), NULL));
|
delete menu;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ShowImageStatusView::SetText(BString &text)
|
ShowImageStatusView::Update(const entry_ref& ref, const BString& text)
|
||||||
{
|
{
|
||||||
fText = text;
|
fText = text;
|
||||||
|
fRef = ref;
|
||||||
|
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -10,21 +10,26 @@
|
|||||||
#define SHOW_IMAGE_STATUS_VIEW_H
|
#define SHOW_IMAGE_STATUS_VIEW_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Entry.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
|
|
||||||
|
|
||||||
class ShowImageStatusView : public BView {
|
class ShowImageStatusView : public BView {
|
||||||
public:
|
public:
|
||||||
ShowImageStatusView(BRect rect, const char *name,
|
ShowImageStatusView(BRect rect,
|
||||||
uint32 resizingMode, uint32 flags);
|
const char* name, uint32 resizingMode,
|
||||||
|
uint32 flags);
|
||||||
|
|
||||||
virtual void Draw(BRect updateRect);
|
virtual void Draw(BRect updateRect);
|
||||||
virtual void MouseDown(BPoint where);
|
virtual void MouseDown(BPoint where);
|
||||||
void SetText(BString &text);
|
|
||||||
|
void Update(const entry_ref& ref,
|
||||||
|
const BString& text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BString fText;
|
BString fText;
|
||||||
|
entry_ref fRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ ShowImageView::_DeleteBitmap()
|
|||||||
delete fDisplayBitmap;
|
delete fDisplayBitmap;
|
||||||
fDisplayBitmap = NULL;
|
fDisplayBitmap = NULL;
|
||||||
|
|
||||||
delete fBitmap;
|
// TODO: the bitmap is currently only owned by the cache!!!
|
||||||
fBitmap = NULL;
|
fBitmap = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,6 +751,9 @@ ShowImageView::Draw(BRect updateRect)
|
|||||||
void
|
void
|
||||||
ShowImageView::FrameResized(float /*width*/, float /*height*/)
|
ShowImageView::FrameResized(float /*width*/, float /*height*/)
|
||||||
{
|
{
|
||||||
|
if (fBitmap == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
fFitToBoundsZoom = _FitToBoundsZoom();
|
fFitToBoundsZoom = _FitToBoundsZoom();
|
||||||
SetZoom(_ShouldStretch() ? fFitToBoundsZoom : fZoom);
|
SetZoom(_ShouldStretch() ? fFitToBoundsZoom : fZoom);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
#include <TranslationUtils.h>
|
#include <TranslationUtils.h>
|
||||||
#include <TranslatorRoster.h>
|
#include <TranslatorRoster.h>
|
||||||
|
|
||||||
#include "EntryMenuItem.h"
|
#include "ImageCache.h"
|
||||||
#include "ShowImageApp.h"
|
#include "ShowImageApp.h"
|
||||||
#include "ShowImageConstants.h"
|
#include "ShowImageConstants.h"
|
||||||
#include "ShowImageStatusView.h"
|
#include "ShowImageStatusView.h"
|
||||||
@@ -79,7 +79,7 @@ ShowImageWindow::ShowImageWindow(const entry_ref& ref,
|
|||||||
const BMessenger& trackerMessenger)
|
const BMessenger& trackerMessenger)
|
||||||
:
|
:
|
||||||
BWindow(BRect(5, 24, 250, 100), "", B_DOCUMENT_WINDOW, 0),
|
BWindow(BRect(5, 24, 250, 100), "", B_DOCUMENT_WINDOW, 0),
|
||||||
fNavigator(this, ref, trackerMessenger),
|
fNavigator(ref, trackerMessenger),
|
||||||
fSavePanel(NULL),
|
fSavePanel(NULL),
|
||||||
fBar(NULL),
|
fBar(NULL),
|
||||||
fBrowseMenu(NULL),
|
fBrowseMenu(NULL),
|
||||||
@@ -96,7 +96,7 @@ ShowImageWindow::ShowImageWindow(const entry_ref& ref,
|
|||||||
|
|
||||||
// create menu bar
|
// create menu bar
|
||||||
fBar = new BMenuBar(BRect(0, 0, Bounds().right, 1), "menu_bar");
|
fBar = new BMenuBar(BRect(0, 0, Bounds().right, 1), "menu_bar");
|
||||||
AddMenus(fBar);
|
_AddMenus(fBar);
|
||||||
AddChild(fBar);
|
AddChild(fBar);
|
||||||
|
|
||||||
BRect viewFrame = Bounds();
|
BRect viewFrame = Bounds();
|
||||||
@@ -142,7 +142,7 @@ ShowImageWindow::ShowImageWindow(const entry_ref& ref,
|
|||||||
SetSizeLimits(250, 100000, 100, 100000);
|
SetSizeLimits(250, 100000, 100, 100000);
|
||||||
|
|
||||||
// finish creating the window
|
// finish creating the window
|
||||||
if (fNavigator.LoadImage(ref) != B_OK) {
|
if (_LoadImage() != B_OK) {
|
||||||
_LoadError(ref);
|
_LoadError(ref);
|
||||||
Quit();
|
Quit();
|
||||||
return;
|
return;
|
||||||
@@ -173,14 +173,6 @@ ShowImageWindow::~ShowImageWindow()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ShowImageWindow::UpdateTitle()
|
|
||||||
{
|
|
||||||
BPath path(fImageView->Image());
|
|
||||||
SetTitle(path.Path());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ShowImageWindow::BuildContextMenu(BMenu* menu)
|
ShowImageWindow::BuildContextMenu(BMenu* menu)
|
||||||
{
|
{
|
||||||
@@ -261,7 +253,7 @@ ShowImageWindow::_BuildViewMenu(BMenu* menu, bool popupMenu)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ShowImageWindow::AddMenus(BMenuBar* bar)
|
ShowImageWindow::_AddMenus(BMenuBar* bar)
|
||||||
{
|
{
|
||||||
BMenu* menu = new BMenu(B_TRANSLATE("File"));
|
BMenu* menu = new BMenu(B_TRANSLATE("File"));
|
||||||
|
|
||||||
@@ -377,7 +369,7 @@ ShowImageWindow::_AddDelayItem(BMenu* menu, const char* label, float value)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ShowImageWindow::WindowRedimension(BBitmap* bitmap)
|
ShowImageWindow::_WindowRedimension(BBitmap* bitmap)
|
||||||
{
|
{
|
||||||
BScreen screen;
|
BScreen screen;
|
||||||
if (!screen.IsValid())
|
if (!screen.IsValid())
|
||||||
@@ -492,12 +484,15 @@ ShowImageWindow::MessageReceived(BMessage* message)
|
|||||||
case kMsgImageLoaded:
|
case kMsgImageLoaded:
|
||||||
{
|
{
|
||||||
bool first = fImageView->Bitmap() == NULL;
|
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);
|
status_t status = fImageView->SetImage(message);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
entry_ref ref;
|
|
||||||
message->FindRef("ref", &ref);
|
|
||||||
|
|
||||||
_LoadError(ref);
|
_LoadError(ref);
|
||||||
|
|
||||||
// quit if file could not be opened
|
// quit if file could not be opened
|
||||||
@@ -507,9 +502,11 @@ ShowImageWindow::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fImageType = message->FindString("type");
|
fImageType = message->FindString("type");
|
||||||
|
fNavigator.SetTo(ref, message->FindInt32("page"),
|
||||||
|
message->FindInt32("pageCount"));
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
WindowRedimension(fImageView->Bitmap());
|
_WindowRedimension(fImageView->Bitmap());
|
||||||
fImageView->ResetZoom();
|
fImageView->ResetZoom();
|
||||||
fImageView->MakeFocus(true);
|
fImageView->MakeFocus(true);
|
||||||
// to receive key messages
|
// to receive key messages
|
||||||
@@ -519,7 +516,7 @@ ShowImageWindow::MessageReceived(BMessage* message)
|
|||||||
if (!fImageView->StretchesToBounds()
|
if (!fImageView->StretchesToBounds()
|
||||||
&& !fImageView->ShrinksToBounds()
|
&& !fImageView->ShrinksToBounds()
|
||||||
&& !fFullScreen)
|
&& !fFullScreen)
|
||||||
WindowRedimension(fImageView->Bitmap());
|
_WindowRedimension(fImageView->Bitmap());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -596,7 +593,9 @@ ShowImageWindow::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_UpdateStatusText(message);
|
_UpdateStatusText(message);
|
||||||
UpdateTitle();
|
|
||||||
|
BPath path(fImageView->Image());
|
||||||
|
SetTitle(path.Path());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,23 +647,23 @@ ShowImageWindow::MessageReceived(BMessage* message)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_PAGE_FIRST:
|
case MSG_PAGE_FIRST:
|
||||||
if (_ClosePrompt())
|
if (_ClosePrompt() && fNavigator.FirstPage())
|
||||||
fNavigator.FirstPage();
|
_LoadImage();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_PAGE_LAST:
|
case MSG_PAGE_LAST:
|
||||||
if (_ClosePrompt())
|
if (_ClosePrompt() && fNavigator.LastPage())
|
||||||
fNavigator.LastPage();
|
_LoadImage();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_PAGE_NEXT:
|
case MSG_PAGE_NEXT:
|
||||||
if (_ClosePrompt())
|
if (_ClosePrompt() && fNavigator.NextPage())
|
||||||
fNavigator.NextPage();
|
_LoadImage();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_PAGE_PREV:
|
case MSG_PAGE_PREV:
|
||||||
if (_ClosePrompt())
|
if (_ClosePrompt() && fNavigator.PreviousPage())
|
||||||
fNavigator.PreviousPage();
|
_LoadImage();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_GOTO_PAGE:
|
case MSG_GOTO_PAGE:
|
||||||
@@ -679,13 +678,15 @@ ShowImageWindow::MessageReceived(BMessage* message)
|
|||||||
int32 currentPage = fNavigator.CurrentPage();
|
int32 currentPage = fNavigator.CurrentPage();
|
||||||
int32 pages = fNavigator.PageCount();
|
int32 pages = fNavigator.PageCount();
|
||||||
|
|
||||||
|
// TODO: use radio mode instead!
|
||||||
if (newPage > 0 && newPage <= pages) {
|
if (newPage > 0 && newPage <= pages) {
|
||||||
BMenuItem* currentItem = fGoToPageMenu->ItemAt(currentPage - 1);
|
BMenuItem* currentItem = fGoToPageMenu->ItemAt(currentPage - 1);
|
||||||
BMenuItem* newItem = fGoToPageMenu->ItemAt(newPage - 1);
|
BMenuItem* newItem = fGoToPageMenu->ItemAt(newPage - 1);
|
||||||
if (currentItem != NULL && newItem != NULL) {
|
if (currentItem != NULL && newItem != NULL) {
|
||||||
currentItem->SetMarked(false);
|
currentItem->SetMarked(false);
|
||||||
newItem->SetMarked(true);
|
newItem->SetMarked(true);
|
||||||
fNavigator.GoToPage(newPage);
|
if (fNavigator.GoToPage(newPage))
|
||||||
|
_LoadImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -700,19 +701,23 @@ ShowImageWindow::MessageReceived(BMessage* message)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_FILE_PREV:
|
case MSG_FILE_PREV:
|
||||||
if (_ClosePrompt())
|
if (_ClosePrompt() && fNavigator.PreviousFile())
|
||||||
fNavigator.PreviousFile();
|
_LoadImage();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_FILE_NEXT:
|
case MSG_FILE_NEXT:
|
||||||
if (_ClosePrompt())
|
if (_ClosePrompt() && fNavigator.NextFile())
|
||||||
fNavigator.NextFile();
|
_LoadImage();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kMsgDeleteCurrentFile:
|
case kMsgDeleteCurrentFile:
|
||||||
if (!fNavigator.MoveFileToTrash())
|
{
|
||||||
|
if (fNavigator.MoveFileToTrash())
|
||||||
|
_LoadImage();
|
||||||
|
else
|
||||||
PostMessage(B_QUIT_REQUESTED);
|
PostMessage(B_QUIT_REQUESTED);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MSG_ROTATE_90:
|
case MSG_ROTATE_90:
|
||||||
fImageView->Rotate(90);
|
fImageView->Rotate(90);
|
||||||
@@ -838,7 +843,7 @@ ShowImageWindow::_UpdateStatusText(const BMessage* message)
|
|||||||
status << ", " << text;
|
status << ", " << text;
|
||||||
}
|
}
|
||||||
|
|
||||||
fStatusView->SetText(status);
|
fStatusView->Update(fNavigator.CurrentRef(), status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -934,6 +939,7 @@ ShowImageWindow::_SaveToFile(BMessage* message)
|
|||||||
#undef B_TRANSLATE_CONTEXT
|
#undef B_TRANSLATE_CONTEXT
|
||||||
#define B_TRANSLATE_CONTEXT "ClosePrompt"
|
#define B_TRANSLATE_CONTEXT "ClosePrompt"
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ShowImageWindow::_ClosePrompt()
|
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
|
void
|
||||||
ShowImageWindow::_ToggleFullScreen()
|
ShowImageWindow::_ToggleFullScreen()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,18 +31,16 @@ public:
|
|||||||
const BMessenger& trackerMessenger);
|
const BMessenger& trackerMessenger);
|
||||||
virtual ~ShowImageWindow();
|
virtual ~ShowImageWindow();
|
||||||
|
|
||||||
|
void BuildContextMenu(BMenu* menu);
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual void FrameResized(float width, float height);
|
virtual void FrameResized(float width, float height);
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
virtual bool QuitRequested();
|
virtual bool QuitRequested();
|
||||||
|
|
||||||
ShowImageView* GetShowImageView() const { return fImageView; }
|
|
||||||
|
|
||||||
void UpdateTitle();
|
|
||||||
void AddMenus(BMenuBar* bar);
|
|
||||||
void BuildContextMenu(BMenu* menu);
|
|
||||||
void WindowRedimension(BBitmap* bitmap);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void _AddMenus(BMenuBar* bar);
|
||||||
|
void _WindowRedimension(BBitmap* bitmap);
|
||||||
void _BuildViewMenu(BMenu* menu, bool popupMenu);
|
void _BuildViewMenu(BMenu* menu, bool popupMenu);
|
||||||
BMenuItem* _AddItemMenu(BMenu* menu, const char* label,
|
BMenuItem* _AddItemMenu(BMenu* menu, const char* label,
|
||||||
uint32 what, char shortcut, uint32 modifier,
|
uint32 what, char shortcut, uint32 modifier,
|
||||||
@@ -66,6 +64,7 @@ private:
|
|||||||
void _SaveToFile(BMessage* message);
|
void _SaveToFile(BMessage* message);
|
||||||
// Handle save file panel message
|
// Handle save file panel message
|
||||||
bool _ClosePrompt();
|
bool _ClosePrompt();
|
||||||
|
status_t _LoadImage();
|
||||||
void _ToggleFullScreen();
|
void _ToggleFullScreen();
|
||||||
void _ApplySettings();
|
void _ApplySettings();
|
||||||
void _SavePrintOptions();
|
void _SavePrintOptions();
|
||||||
@@ -88,6 +87,7 @@ private:
|
|||||||
BRect fWindowFrame;
|
BRect fWindowFrame;
|
||||||
BMessage* fPrintSettings;
|
BMessage* fPrintSettings;
|
||||||
PrintOptions fPrintOptions;
|
PrintOptions fPrintOptions;
|
||||||
|
|
||||||
BString fImageType;
|
BString fImageType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user