[haiku-commits] r39322 - haiku/trunk/src/apps/showimage

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 6 Nov 2010 13:17:50 +0100 (CET)

Author: axeld
Date: 2010-11-06 13:17:49 +0100 (Sat, 06 Nov 2010)
New Revision: 39322
Changeset: http://dev.haiku-os.org/changeset/39322

Modified:
   haiku/trunk/src/apps/showimage/ImageFileNavigator.cpp
   haiku/trunk/src/apps/showimage/ImageFileNavigator.h
   haiku/trunk/src/apps/showimage/ShowImageConstants.h
   haiku/trunk/src/apps/showimage/ShowImageView.cpp
   haiku/trunk/src/apps/showimage/ShowImageWindow.cpp
Log:
* Work in progress on implementing asynchronous image retrieval with a
  read-ahead cache. Not yet done or used.
* Added deleting images via delete key again. The only difference to before is
  that it will open the previous image if the last image in a folder was
  removed, and only close ShowImage if there is no image left.


Modified: haiku/trunk/src/apps/showimage/ImageFileNavigator.cpp
===================================================================
--- haiku/trunk/src/apps/showimage/ImageFileNavigator.cpp       2010-11-06 
11:33:59 UTC (rev 39321)
+++ haiku/trunk/src/apps/showimage/ImageFileNavigator.cpp       2010-11-06 
12:17:49 UTC (rev 39322)
@@ -18,7 +18,11 @@
 
 #include "ImageFileNavigator.h"
 
+#include <deque>
+#include <map>
 #include <new>
+#include <set>
+
 #include <stdio.h>
 
 #include <Bitmap.h>
@@ -26,11 +30,14 @@
 #include <Directory.h>
 #include <Entry.h>
 #include <File.h>
+#include <Locker.h>
 #include <ObjectList.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"
@@ -183,11 +190,11 @@
                else
                        specifier.what = 'sprv';
                specifier.AddString("property", "Entry");
-               if (rewind)
+               if (rewind) {
                        // if rewinding, ask for the ref to the
                        // first item in the directory
                        specifier.AddInt32("data", 0);
-               else
+               } else
                        specifier.AddRef("data", &nextRef);
                request.AddSpecifier(&specifier);
 
@@ -313,6 +320,249 @@
 // #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()
+       :
+       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)
        :
@@ -534,24 +784,33 @@
 }
 
 
-void
-ImageFileNavigator::DeleteFile()
+/*!    Moves the current file into the trash.
+       Returns true if a new file is being loaded, false if not.
+*/
+bool
+ImageFileNavigator::MoveFileToTrash()
 {
+       entry_ref nextRef;
+       if (!fNavigator->FindNextImage(fCurrentRef, nextRef, true, false)
+               && !fNavigator->FindNextImage(fCurrentRef, nextRef, false, 
false))
+               nextRef.device = -1;
+
        // Move image to Trash
        BMessage trash(BPrivate::kMoveToTrash);
        trash.AddRef("refs", &fCurrentRef);
 
-// TODO!
-#if 0
        // We create our own messenger because the member fTrackerMessenger
        // could be invalid
        BMessenger tracker(kTrackerSignature);
-       if (tracker.SendMessage(&trash) == B_OK && !NextFile()) {
-               // This is the last (or only file) in this directory,
-               // close the window
-               _SendMessageToWindow(B_QUIT_REQUESTED);
+       if (tracker.SendMessage(&trash) != B_OK)
+               return true;
+
+       if (nextRef.device != -1 && LoadImage(nextRef) == B_OK) {
+               fNavigator->UpdateSelection(nextRef);
+               return true;
        }
-#endif
+
+       return false;
 }
 
 

Modified: haiku/trunk/src/apps/showimage/ImageFileNavigator.h
===================================================================
--- haiku/trunk/src/apps/showimage/ImageFileNavigator.h 2010-11-06 11:33:59 UTC 
(rev 39321)
+++ haiku/trunk/src/apps/showimage/ImageFileNavigator.h 2010-11-06 12:17:49 UTC 
(rev 39322)
@@ -61,7 +61,7 @@
                        bool                            HasNextFile();
                        bool                            HasPreviousFile();
 
-                       void                            DeleteFile();
+                       bool                            MoveFileToTrash();
 
 private:
                        status_t                        _LoadNextImage(bool 
next, bool rewind);

Modified: haiku/trunk/src/apps/showimage/ShowImageConstants.h
===================================================================
--- haiku/trunk/src/apps/showimage/ShowImageConstants.h 2010-11-06 11:33:59 UTC 
(rev 39321)
+++ haiku/trunk/src/apps/showimage/ShowImageConstants.h 2010-11-06 12:17:49 UTC 
(rev 39322)
@@ -38,6 +38,7 @@
        MSG_GOTO_PAGE                           = 'mGTP',
        MSG_FILE_NEXT                           = 'mFLN',
        MSG_FILE_PREV                           = 'mFLP',
+       kMsgDeleteCurrentFile           = 'mDcF',
        MSG_SHRINK_TO_WINDOW            = 'mSTW',
        MSG_STRETCH_TO_WINDOW           = 'mZTW',
        MSG_ROTATE_90                           = 'mR90',

Modified: haiku/trunk/src/apps/showimage/ShowImageView.cpp
===================================================================
--- haiku/trunk/src/apps/showimage/ShowImageView.cpp    2010-11-06 11:33:59 UTC 
(rev 39321)
+++ haiku/trunk/src/apps/showimage/ShowImageView.cpp    2010-11-06 12:17:49 UTC 
(rev 39322)
@@ -1331,11 +1331,8 @@
                        ClearSelection();
                        break;
                case B_DELETE:
-               {
-                       // TODO!
-                       //fNavigator.DeleteFile();
+                       _SendMessageToWindow(kMsgDeleteCurrentFile);
                        break;
-               }
                case '+':
                case '=':
                        ZoomIn();

Modified: haiku/trunk/src/apps/showimage/ShowImageWindow.cpp
===================================================================
--- haiku/trunk/src/apps/showimage/ShowImageWindow.cpp  2010-11-06 11:33:59 UTC 
(rev 39321)
+++ haiku/trunk/src/apps/showimage/ShowImageWindow.cpp  2010-11-06 12:17:49 UTC 
(rev 39322)
@@ -709,6 +709,11 @@
                                fNavigator.NextFile();
                        break;
 
+               case kMsgDeleteCurrentFile:
+                       if (!fNavigator.MoveFileToTrash())
+                               PostMessage(B_QUIT_REQUESTED);
+                       break;
+
                case MSG_ROTATE_90:
                        fImageView->Rotate(90);
                        break;


Other related posts:

  • » [haiku-commits] r39322 - haiku/trunk/src/apps/showimage - axeld