Package cx.fbn.nevernote.threads

Source Code of cx.fbn.nevernote.threads.ThumbnailRunner

/*
* 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;



  public ThumbnailRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) {
    logger = new ApplicationLogger(logname);
    conn = new DatabaseConnection(logger, u, i, r, 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);
  }
   
 


}
TOP

Related Classes of cx.fbn.nevernote.threads.ThumbnailRunner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.