OSDN Git Service

Check for possible null pointer assignment when preparing resource
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / threads / ThumbnailRunner.java
index f8d9c43..61fbfd2 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- * This file is part of NeverNote \r
+ * This file is part of NixNote \r
  * Copyright 2009 Randy Baumgarte\r
  * \r
  * This file may be licensed under the terms of of the\r
@@ -24,11 +24,13 @@ import java.util.List;
 import java.util.concurrent.LinkedBlockingQueue;\r
 \r
 import com.evernote.edam.type.Note;\r
+import com.trolltech.qt.core.QBuffer;\r
 import com.trolltech.qt.core.QByteArray;\r
-import com.trolltech.qt.core.QFile;\r
-import com.trolltech.qt.core.QIODevice.OpenModeFlag;\r
+import com.trolltech.qt.core.QIODevice;\r
+import com.trolltech.qt.core.QMutex;\r
 import com.trolltech.qt.core.QObject;\r
 import com.trolltech.qt.core.QTemporaryFile;\r
+import com.trolltech.qt.gui.QPixmap;\r
 \r
 import cx.fbn.nevernote.Global;\r
 import cx.fbn.nevernote.signals.NoteSignal;\r
@@ -36,24 +38,55 @@ import cx.fbn.nevernote.sql.DatabaseConnection;
 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
 import cx.fbn.nevernote.xml.NoteFormatter;\r
 \r
+\r
+/*\r
+ * \r
+ * @author Randy Baumgarte\r
+ * \r
+ * Thumbnail Overview:\r
+ * \r
+ * How thumbnails are generated is a bit odd.  The problem is that \r
+ * process of creating the thumbnail involves actually creating an HTML\r
+ * version of the note & all of its resources.  That is very CPU intensive\r
+ * so we try to do it in a separate thread.  Unfortunately, the QWebPage class \r
+ * which actually creates the thumbnail must be in the main GUI thread.\r
+ * This is the odd way I've tried to get around the problem.\r
+ * \r
+ * First, the thumbail thread finds a note which needs a thumbnail.  This\r
+ * can be done by either scanning the database or specifically being told\r
+ * a note needs a new thumbnail.  \r
+ * \r
+ * When a note is found, this thread will read the database and write out\r
+ * the resources and create an HTML version of the note.  It then signals\r
+ * the main GUI thread that a note is ready.  \r
+ * \r
+ * Next, the main GUI thread will process the signal received from the \r
+ * thumbnail thread.  The GUI thread will create a QWebPage (via the\r
+ * Thumbnailer class) and will render the image.  The image is written to \r
+ * the database to be used in the thumbnail view.\r
+ * \r
+ */\r
 public class ThumbnailRunner extends QObject implements Runnable {\r
        \r
        private final ApplicationLogger                         logger;\r
        private String                                                          guid;\r
        public  NoteSignal                                                      noteSignal;\r
        private boolean                                                         keepRunning;\r
+       public boolean                                                          interrupt;\r
        private final DatabaseConnection                        conn;\r
        private volatile LinkedBlockingQueue<String> workQueue;\r
        private static int                                                      MAX_QUEUED_WAITING = 1000;\r
+       public QMutex                                                           mutex;\r
 \r
 \r
 \r
-       public ThumbnailRunner(String logname, String u, String uid, String pswd, String cpswd) {\r
+       public ThumbnailRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) {\r
                logger = new ApplicationLogger(logname);\r
-               conn = new DatabaseConnection(logger, u, uid, pswd, cpswd);\r
+               conn = new DatabaseConnection(logger, u, i, r, uid, pswd, cpswd, 300);\r
                noteSignal = new NoteSignal();\r
                guid = null;\r
                keepRunning = true;\r
+               mutex = new QMutex();\r
                workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);  \r
        }\r
        \r
@@ -65,6 +98,7 @@ public class ThumbnailRunner extends QObject implements Runnable {
                logger.log(logger.MEDIUM, "Starting thumbnail thread ");\r
                while (keepRunning) {\r
                        try {\r
+                               interrupt = false;\r
                                String work = workQueue.take();\r
                                if (work.startsWith("GENERATE")) {\r
                                        work = work.replace("GENERATE ", "");\r
@@ -72,7 +106,13 @@ public class ThumbnailRunner extends QObject implements Runnable {
                                        generateThumbnail();\r
                                }\r
                                if (work.startsWith("SCAN")) {\r
-                                       scanDatabase();\r
+                                       if (conn.getNoteTable().getThumbnailNeededCount() > 1)\r
+                                               scanDatabase();\r
+                               }\r
+                               if (work.startsWith("IMAGE")) {\r
+                                       work = work.replace("IMAGE ", "");\r
+                                       guid = work;\r
+                                       processImage();\r
                                }\r
                                if (work.startsWith("STOP")) {\r
                                        logger.log(logger.MEDIUM, "Stopping thumbail thread");\r
@@ -87,6 +127,47 @@ public class ThumbnailRunner extends QObject implements Runnable {
        }\r
        \r
        \r
+       private void processImage() {\r
+               boolean abort = true;\r
+               if (abort)\r
+                       return;\r
+               mutex.lock();\r
+               logger.log(logger.EXTREME, "Image found "+guid);\r
+                       \r
+               logger.log(logger.EXTREME, "Getting image");\r
+               QPixmap image = new QPixmap();\r
+               if (!image.load(Global.getFileManager().getResDirPath()+"thumbnail-"+guid+".png")) {\r
+                       logger.log(logger.EXTREME, "Failure to reload image. Aborting.");\r
+                       mutex.unlock();\r
+                       return;\r
+               }\r
+               \r
+               \r
+               logger.log(logger.EXTREME, "Opening buffer");\r
+        QBuffer buffer = new QBuffer();\r
+        if (!buffer.open(QIODevice.OpenModeFlag.WriteOnly)) {\r
+               logger.log(logger.EXTREME, "Failure to open buffer.  Aborting.");\r
+               mutex.unlock();\r
+               return;\r
+        }\r
+               \r
+               logger.log(logger.EXTREME, "Filling buffer");\r
+        if (!image.save(buffer, "PNG")) {\r
+               logger.log(logger.EXTREME, "Failure to write to buffer.  Aborting.");     \r
+               mutex.unlock();\r
+               return;\r
+        }\r
+        buffer.close();\r
+               \r
+               logger.log(logger.EXTREME, "Updating database");\r
+               QByteArray b = new QBuffer(buffer).buffer();\r
+               conn.getNoteTable().setThumbnail(guid, b);\r
+               conn.getNoteTable().setThumbnailNeeded(guid, false);\r
+               mutex.unlock();\r
+       }\r
+       \r
+       \r
+       \r
        private void scanDatabase() {\r
                // If there is already work in the queue, that takes priority\r
                logger.log(logger.HIGH, "Scanning database for notes needing thumbnail");\r
@@ -96,7 +177,7 @@ public class ThumbnailRunner extends QObject implements Runnable {
                // Find a few records that need thumbnails\r
                List<String> guids = conn.getNoteTable().findThumbnailsNeeded();\r
                logger.log(logger.HIGH, guids.size() +" records returned");\r
-               for (int i=0; i<guids.size() && keepRunning; i++) {\r
+               for (int i=0; i<guids.size() && keepRunning && !interrupt; i++) {\r
                        guid = guids.get(i);\r
                        logger.log(logger.HIGH, "Working on:" +guids.get(i));\r
                        generateThumbnail();\r
@@ -106,6 +187,7 @@ public class ThumbnailRunner extends QObject implements Runnable {
 \r
                \r
        public synchronized boolean addWork(String request) {\r
+\r
                if (workQueue.size() == 0) {\r
                        workQueue.offer(request);\r
                        return true;\r
@@ -137,13 +219,13 @@ public class ThumbnailRunner extends QObject implements Runnable {
                js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");\r
                js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");\r
                js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");\r
-               String fileName = Global.getFileManager().getResDirPath("thumbnail-" + guid + ".html");\r
-               QFile tFile = new QFile(fileName);\r
-               tFile.open(OpenModeFlag.WriteOnly);\r
-               tFile.write(js);\r
-               tFile.close();\r
+               int zoom = 1;\r
+               if (currentNote != null && currentNote.getContent() != null) {\r
+                       String content = currentNote.getContent();\r
+                       zoom = Global.calculateThumbnailZoom(content);\r
+               }\r
                logger.log(logger.HIGH, "Thumbnail file ready");\r
-               noteSignal.thumbnailPageReady.emit(guid, fileName);\r
+               noteSignal.thumbnailPageReady.emit(guid, js, zoom);\r
        }\r
                \r
        \r