-/*\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
- * GNU General Public License Version 2 (the ``GPL'').\r
- *\r
- * Software distributed under the License is distributed\r
- * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
- * express or implied. See the GPL for the specific language\r
- * governing rights and limitations.\r
- *\r
- * You should have received a copy of the GPL along with this\r
- * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
- * or write to the Free Software Foundation, Inc.,\r
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
- *\r
-*/\r
-\r
-package cx.fbn.nevernote.threads;\r
-\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-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.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
-import cx.fbn.nevernote.sql.DatabaseConnection;\r
-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 i, String r, String uid, String pswd, String cpswd) {\r
- logger = new ApplicationLogger(logname);\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
- \r
- @Override\r
- public void run() {\r
- thread().setPriority(Thread.MIN_PRIORITY);\r
- \r
- 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
- guid = work;\r
- generateThumbnail();\r
- }\r
- if (work.startsWith("SCAN")) {\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
- keepRunning = false;\r
- }\r
- } catch (InterruptedException e) {\r
- // TODO Auto-generated catch block\r
- e.printStackTrace();\r
- }\r
- }\r
- conn.dbShutdown();\r
- }\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
- if (workQueue.size() > 0)\r
- return;\r
- \r
- // 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 && !interrupt; i++) {\r
- guid = guids.get(i);\r
- logger.log(logger.HIGH, "Working on:" +guids.get(i));\r
- generateThumbnail();\r
- }\r
- logger.log(logger.HIGH, "Scan completed");\r
- }\r
-\r
- \r
- public synchronized boolean addWork(String request) {\r
-\r
- if (workQueue.size() == 0) {\r
- workQueue.offer(request);\r
- return true;\r
- }\r
- return false;\r
- }\r
- \r
- public synchronized int getWorkQueueSize() {\r
- return workQueue.size();\r
- }\r
- \r
- private void generateThumbnail() {\r
- QByteArray js = new QByteArray();\r
- logger.log(logger.HIGH, "Starting thumbnail for " +guid);\r
- ArrayList<QTemporaryFile> tempFiles = new ArrayList<QTemporaryFile>();\r
- Note currentNote = conn.getNoteTable().getNote(guid,true,true,false,true,false);\r
- NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);\r
- currentNote = conn.getNoteTable().getNote(guid, true, true, false, true, false);\r
- formatter.setNote(currentNote, true);\r
- formatter.setHighlight(null);\r
- js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">"); \r
- js.append("<style type=\"text/css\">.en-crypt-temp { border-collapse:collapse; border-style:solid; border-color:blue; padding:0.0mm 0.0mm 0.0mm 0.0mm; }</style>");\r
- js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");\r
- js.append("<style> img { max-width:100%; }</style>");\r
- js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");\r
- js.append("</head>");\r
- js.append(formatter.rebuildNoteHTML());\r
- js.append("</HTML>");\r
- 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
- 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, js, zoom);\r
- }\r
- \r
- \r
-\r
-\r
-}\r
+/*
+ * This file is part of NixNote
+ * Copyright 2009 Randy Baumgarte
+ *
+ * This file may be licensed under the terms of of the
+ * GNU General Public License Version 2 (the ``GPL'').
+ *
+ * Software distributed under the License is distributed
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
+ * express or implied. See the GPL for the specific language
+ * governing rights and limitations.
+ *
+ * You should have received a copy of the GPL along with this
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html
+ * or write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+*/
+
+package cx.fbn.nevernote.threads;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import com.evernote.edam.type.Note;
+import com.trolltech.qt.core.QBuffer;
+import com.trolltech.qt.core.QByteArray;
+import com.trolltech.qt.core.QIODevice;
+import com.trolltech.qt.core.QMutex;
+import com.trolltech.qt.core.QObject;
+import com.trolltech.qt.core.QTemporaryFile;
+import com.trolltech.qt.gui.QPixmap;
+
+import cx.fbn.nevernote.Global;
+import cx.fbn.nevernote.signals.NoteSignal;
+import cx.fbn.nevernote.sql.DatabaseConnection;
+import cx.fbn.nevernote.utilities.ApplicationLogger;
+import cx.fbn.nevernote.xml.NoteFormatter;
+
+
+/*
+ *
+ * @author Randy Baumgarte
+ *
+ * Thumbnail Overview:
+ *
+ * How thumbnails are generated is a bit odd. The problem is that
+ * process of creating the thumbnail involves actually creating an HTML
+ * version of the note & all of its resources. That is very CPU intensive
+ * so we try to do it in a separate thread. Unfortunately, the QWebPage class
+ * which actually creates the thumbnail must be in the main GUI thread.
+ * This is the odd way I've tried to get around the problem.
+ *
+ * First, the thumbail thread finds a note which needs a thumbnail. This
+ * can be done by either scanning the database or specifically being told
+ * a note needs a new thumbnail.
+ *
+ * When a note is found, this thread will read the database and write out
+ * the resources and create an HTML version of the note. It then signals
+ * the main GUI thread that a note is ready.
+ *
+ * Next, the main GUI thread will process the signal received from the
+ * thumbnail thread. The GUI thread will create a QWebPage (via the
+ * Thumbnailer class) and will render the image. The image is written to
+ * the database to be used in the thumbnail view.
+ *
+ */
+public class ThumbnailRunner extends QObject implements Runnable {
+
+ private final ApplicationLogger logger;
+ private String guid;
+ public NoteSignal noteSignal;
+ private boolean keepRunning;
+ public boolean interrupt;
+ private final DatabaseConnection conn;
+ private volatile LinkedBlockingQueue<String> workQueue;
+ private static int MAX_QUEUED_WAITING = 1000;
+ public QMutex mutex;
+
+
+ // ICHANGED String bを追加
+ public ThumbnailRunner(String logname, String u, String i, String r, String b, String uid, String pswd, String cpswd) {
+ logger = new ApplicationLogger(logname);
+ // ICHANGED bを追加
+ conn = new DatabaseConnection(logger, u, i, r, b, uid, pswd, cpswd, 300);
+ noteSignal = new NoteSignal();
+ guid = null;
+ keepRunning = true;
+ mutex = new QMutex();
+ workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);
+ }
+
+
+ @Override
+ public void run() {
+ thread().setPriority(Thread.MIN_PRIORITY);
+
+ logger.log(logger.MEDIUM, "Starting thumbnail thread ");
+ while (keepRunning) {
+ try {
+ interrupt = false;
+ String work = workQueue.take();
+ if (work.startsWith("GENERATE")) {
+ work = work.replace("GENERATE ", "");
+ guid = work;
+ generateThumbnail();
+ }
+ if (work.startsWith("SCAN")) {
+ if (conn.getNoteTable().getThumbnailNeededCount() > 1)
+ scanDatabase();
+ }
+ if (work.startsWith("IMAGE")) {
+ work = work.replace("IMAGE ", "");
+ guid = work;
+ processImage();
+ }
+ if (work.startsWith("STOP")) {
+ logger.log(logger.MEDIUM, "Stopping thumbail thread");
+ keepRunning = false;
+ }
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ conn.dbShutdown();
+ }
+
+
+ private void processImage() {
+ boolean abort = true;
+ if (abort)
+ return;
+ mutex.lock();
+ logger.log(logger.EXTREME, "Image found "+guid);
+
+ logger.log(logger.EXTREME, "Getting image");
+ QPixmap image = new QPixmap();
+ if (!image.load(Global.getFileManager().getResDirPath()+"thumbnail-"+guid+".png")) {
+ logger.log(logger.EXTREME, "Failure to reload image. Aborting.");
+ mutex.unlock();
+ return;
+ }
+
+
+ logger.log(logger.EXTREME, "Opening buffer");
+ QBuffer buffer = new QBuffer();
+ if (!buffer.open(QIODevice.OpenModeFlag.WriteOnly)) {
+ logger.log(logger.EXTREME, "Failure to open buffer. Aborting.");
+ mutex.unlock();
+ return;
+ }
+
+ logger.log(logger.EXTREME, "Filling buffer");
+ if (!image.save(buffer, "PNG")) {
+ logger.log(logger.EXTREME, "Failure to write to buffer. Aborting.");
+ mutex.unlock();
+ return;
+ }
+ buffer.close();
+
+ logger.log(logger.EXTREME, "Updating database");
+ QByteArray b = new QBuffer(buffer).buffer();
+ conn.getNoteTable().setThumbnail(guid, b);
+ conn.getNoteTable().setThumbnailNeeded(guid, false);
+ mutex.unlock();
+ }
+
+
+
+ private void scanDatabase() {
+ // If there is already work in the queue, that takes priority
+ logger.log(logger.HIGH, "Scanning database for notes needing thumbnail");
+ if (workQueue.size() > 0)
+ return;
+
+ // Find a few records that need thumbnails
+ List<String> guids = conn.getNoteTable().findThumbnailsNeeded();
+ logger.log(logger.HIGH, guids.size() +" records returned");
+ for (int i=0; i<guids.size() && keepRunning && !interrupt; i++) {
+ guid = guids.get(i);
+ logger.log(logger.HIGH, "Working on:" +guids.get(i));
+ generateThumbnail();
+ }
+ logger.log(logger.HIGH, "Scan completed");
+ }
+
+
+ public synchronized boolean addWork(String request) {
+
+ if (workQueue.size() == 0) {
+ workQueue.offer(request);
+ return true;
+ }
+ return false;
+ }
+
+ public synchronized int getWorkQueueSize() {
+ return workQueue.size();
+ }
+
+ private void generateThumbnail() {
+ QByteArray js = new QByteArray();
+ logger.log(logger.HIGH, "Starting thumbnail for " +guid);
+ ArrayList<QTemporaryFile> tempFiles = new ArrayList<QTemporaryFile>();
+ Note currentNote = conn.getNoteTable().getNote(guid,true,true,false,true,false);
+ NoteFormatter formatter = new NoteFormatter(logger, conn, tempFiles);
+ currentNote = conn.getNoteTable().getNote(guid, true, true, false, true, false);
+ formatter.setNote(currentNote, true);
+ formatter.setHighlight(null);
+ js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
+ js.append("<style type=\"text/css\">.en-crypt-temp { border-collapse:collapse; border-style:solid; border-color:blue; padding:0.0mm 0.0mm 0.0mm 0.0mm; }</style>");
+ js.append("<style type=\"text/css\">en-hilight { background-color: rgb(255,255,0) }</style>");
+ js.append("<style> img { max-width:100%; }</style>");
+ js.append("<style type=\"text/css\">en-spell { text-decoration: none; border-bottom: dotted 1px #cc0000; }</style>");
+ js.append("</head>");
+ js.append(formatter.rebuildNoteHTML());
+ js.append("</HTML>");
+ js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml.dtd'>", "");
+ js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");
+ js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");
+ int zoom = 1;
+ if (currentNote != null && currentNote.getContent() != null) {
+ String content = currentNote.getContent();
+ zoom = Global.calculateThumbnailZoom(content);
+ }
+ logger.log(logger.HIGH, "Thumbnail file ready");
+ noteSignal.thumbnailPageReady.emit(guid, js, zoom);
+ }
+
+
+
+
+}