OSDN Git Service

uni-gramで日本語全文検索できるように変更。ノートコンテンツとタイトルが対象。日本語全文検索時に日本語がハイライトされない問題を修正。
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / xml / NoteFormatter.java
1 package cx.fbn.nevernote.xml;\r
2 \r
3 import java.io.ByteArrayInputStream;\r
4 import java.io.ByteArrayOutputStream;\r
5 import java.io.File;\r
6 import java.util.ArrayList;\r
7 import java.util.List;\r
8 \r
9 import org.w3c.tidy.Tidy;\r
10 import org.w3c.tidy.TidyMessage;\r
11 \r
12 import com.evernote.edam.type.Note;\r
13 import com.evernote.edam.type.Resource;\r
14 import com.trolltech.qt.core.QByteArray;\r
15 import com.trolltech.qt.core.QDataStream;\r
16 import com.trolltech.qt.core.QFile;\r
17 import com.trolltech.qt.core.QIODevice;\r
18 import com.trolltech.qt.core.QIODevice.OpenModeFlag;\r
19 import com.trolltech.qt.core.QTemporaryFile;\r
20 import com.trolltech.qt.core.QTextCodec;\r
21 import com.trolltech.qt.core.QUrl;\r
22 import com.trolltech.qt.core.Qt.BGMode;\r
23 import com.trolltech.qt.gui.QColor;\r
24 import com.trolltech.qt.gui.QPainter;\r
25 import com.trolltech.qt.gui.QPainter.RenderHint;\r
26 import com.trolltech.qt.gui.QPixmap;\r
27 import com.trolltech.qt.xml.QDomAttr;\r
28 import com.trolltech.qt.xml.QDomDocument;\r
29 import com.trolltech.qt.xml.QDomElement;\r
30 import com.trolltech.qt.xml.QDomNodeList;\r
31 \r
32 import cx.fbn.nevernote.Global;\r
33 import cx.fbn.nevernote.config.FileManager;\r
34 import cx.fbn.nevernote.filters.EnSearch;\r
35 import cx.fbn.nevernote.gui.PDFPreview;\r
36 import cx.fbn.nevernote.sql.DatabaseConnection;\r
37 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
38 \r
39 public class NoteFormatter {\r
40 \r
41         private final ApplicationLogger logger;\r
42         private final DatabaseConnection conn;\r
43         public boolean resourceError = false;\r
44         public boolean readOnly = false; \r
45         public boolean inkNote = false;\r
46         public boolean addHighlight = true;\r
47         private Note currentNote;\r
48         private String currentNoteGuid;\r
49         private boolean pdfPreview;\r
50         ArrayList<QTemporaryFile> tempFiles;\r
51         private EnSearch enSearch;\r
52         private boolean noteHistory;\r
53         public boolean formatError;\r
54         \r
55         public NoteFormatter(ApplicationLogger logger, DatabaseConnection conn, List<QTemporaryFile> tempFiles2) {\r
56                 this.logger = logger;\r
57                 this.conn = conn;\r
58                 noteHistory = false;\r
59         }\r
60         \r
61         \r
62         private class TidyListener implements org.w3c.tidy.TidyMessageListener {\r
63                 \r
64                 ApplicationLogger logger;\r
65                 public boolean errorFound; \r
66                 \r
67                 public TidyListener(ApplicationLogger logger) {\r
68                         this.logger = logger;\r
69                         errorFound = false;\r
70                 }\r
71                 @Override\r
72                 public void messageReceived(TidyMessage msg) {\r
73                         if (msg.getLevel() == TidyMessage.Level.ERROR) {\r
74                                 logger.log(logger.LOW, "******* JTIDY ERORR *******");\r
75                                 logger.log(logger.LOW, "Error Code: " +msg.getErrorCode());\r
76                                 logger.log(logger.LOW, "Column: " +msg.getColumn());\r
77                                 logger.log(logger.LOW, "Column: " +msg.getColumn());\r
78                                 logger.log(logger.LOW, "Line: " +msg.getLine());\r
79                                 logger.log(logger.LOW, "Message: " +msg.getMessage());\r
80                                 logger.log(logger.LOW, "***************************");\r
81                                 errorFound = true;\r
82                         } else \r
83                                 logger.log(logger.EXTREME, "JTidy Results: "+msg.getMessage());\r
84                 }\r
85                 \r
86         }\r
87 \r
88         \r
89         \r
90         public void setNote(Note note, boolean pdfPreview) {\r
91                 currentNote = note;\r
92                 this.pdfPreview = pdfPreview;\r
93                 readOnly = false;\r
94                 currentNoteGuid = null;\r
95                 if (note != null) {\r
96                         currentNoteGuid = note.getGuid();\r
97                         readOnly = conn.getNotebookTable().isReadOnly(note.getNotebookGuid());\r
98                 } \r
99                 resourceError = false;\r
100         }\r
101         \r
102         public void setHighlight(EnSearch search) {\r
103                 if (search==null || search.hilightWords == null ||search.hilightWords.size() == 0) {\r
104                         enSearch = null;\r
105                         addHighlight = false;\r
106                 } else {\r
107                         enSearch = search;\r
108                         addHighlight = true;\r
109                 }\r
110         }\r
111         \r
112         // Set if we are coming here through note histary.  It triggers longer file names to avoid conflicts\r
113         public void setNoteHistory(boolean value) {\r
114                 noteHistory = value;\r
115         }\r
116         \r
117         // Rebuild the note HTML to something usable\r
118         public String rebuildNoteHTML() {\r
119                 formatError = false;\r
120                 if (currentNote == null)\r
121                         return null;\r
122                 logger.log(logger.HIGH, "Entering NeverNote.rebuildNoteHTML");\r
123                 logger.log(logger.EXTREME, "Note guid: " +currentNoteGuid);\r
124                 logger.log(logger.EXTREME, "Note Text:" +currentNote);\r
125                 QDomDocument doc = new QDomDocument();\r
126 //              QDomDocument.Result result = doc.setContent(currentNote.getContent());\r
127                 QDomDocument.Result result = doc.setContent(conn.getNoteTable().getNoteContentNoUTFConversion(currentNote.getGuid()));\r
128                 \r
129                 // Handle any errors\r
130                 if (!result.success) {\r
131                         logger.log(logger.LOW, "Error parsing document.  Attempting to restructure");\r
132                         Tidy tidy = new Tidy();\r
133                         TidyListener tidyListener = new TidyListener(logger);\r
134                         tidy.setMessageListener(tidyListener);\r
135                         tidy.getStderr().close();  // the listener will capture messages\r
136                         tidy.setXmlTags(true);\r
137                         \r
138                         QTextCodec codec;\r
139                         codec = QTextCodec.codecForName("UTF-8");\r
140                 QByteArray unicode =  codec.fromUnicode(currentNote.getContent());\r
141                 \r
142                 logger.log(logger.MEDIUM, "Starting JTidy check");\r
143                 logger.log(logger.MEDIUM, "Start of JTidy Input");\r
144                 logger.log(logger.MEDIUM, currentNote.getContent());\r
145                 logger.log(logger.MEDIUM, "End Of JTidy Input");\r
146                         ByteArrayInputStream is = new ByteArrayInputStream(unicode.toByteArray());\r
147                 ByteArrayOutputStream os = new ByteArrayOutputStream();\r
148                 tidy.setInputEncoding("UTF-8");\r
149                         tidy.parse(is, os);\r
150                         String tidyContent = os.toString();\r
151                         if (tidyListener.errorFound) {\r
152                                 logger.log(logger.LOW, "Restructure failed!!!");\r
153                         } else {\r
154                                 doc = null;\r
155                                 doc = new QDomDocument();\r
156                                 result = doc.setContent(tidyContent);\r
157                         }\r
158                 }\r
159                 if (!result.success) {\r
160                         logger.log(logger.MEDIUM, "Parse error when rebuilding XML to HTML");\r
161                         logger.log(logger.MEDIUM, "Note guid: " +currentNoteGuid);\r
162                         logger.log(logger.MEDIUM, "Error: "+result.errorMessage);\r
163                         logger.log(logger.MEDIUM, "Line: " +result.errorLine + " Column: " +result.errorColumn);\r
164                         System.out.println("Error: "+result.errorMessage);\r
165                         System.out.println("Line: " +result.errorLine + " Column: " +result.errorColumn);\r
166                         logger.log(logger.EXTREME, "**** Start of unmodified note HTML");\r
167                         logger.log(logger.EXTREME, currentNote.getContent());\r
168                         logger.log(logger.EXTREME, "**** End of unmodified note HTML");\r
169                         formatError = true;\r
170                         readOnly = true;\r
171                         return currentNote.getContent();\r
172                 }\r
173 \r
174                 if (tempFiles == null)\r
175                         tempFiles = new ArrayList<QTemporaryFile>();\r
176                 tempFiles.clear();\r
177                 \r
178                 doc = modifyTags(doc);\r
179                 if (addHighlight)\r
180                         doc = addHilight(doc);\r
181                 QDomElement docElem = doc.documentElement();\r
182                 docElem.setTagName("Body");\r
183 //              docElem.setAttribute("bgcolor", "green");\r
184                 logger.log(logger.EXTREME, "Rebuilt HTML:");\r
185                 logger.log(logger.EXTREME, doc.toString());     \r
186                 logger.log(logger.HIGH, "Leaving NeverNote.rebuildNoteHTML");\r
187                 // Fix the stupid problem where inserting an <img> tag after an <a> tag (which is done\r
188                 // to get the <en-media> application tag to work properly) causes spaces to be inserted\r
189                 // between the <a> & <img>.  This messes things up later.  This is an ugly hack.\r
190                 StringBuffer html = new StringBuffer(doc.toString());\r
191                 for (int i=html.indexOf("<a en-tag=\"en-media\" ", 0); i>-1; i=html.indexOf("<a en-tag=\"en-media\" ", i)) {\r
192                         i=html.indexOf(">\n",i+1);\r
193                         int z = html.indexOf("<img",i);\r
194                         for (int j=z-1; j>i; j--) \r
195                                 html.deleteCharAt(j);\r
196                         i=html.indexOf("/>", z+1);\r
197                         z = html.indexOf("</a>",i);\r
198                         for (int j=z-1; j>i+1; j--) \r
199                                 html.deleteCharAt(j);\r
200                 } \r
201                 \r
202                 QTextCodec codec;\r
203                 codec = QTextCodec.codecForName("UTF-8");\r
204                 String value = codec.fromUnicode(html.toString()).toString();\r
205                 return value;\r
206 \r
207 //              return html.toString(); //.replace("<Body", "<Body dir=\"rtl\"");\r
208         }       \r
209 \r
210         private void addImageHilight(String resGuid, QFile f) {\r
211                 if (enSearch == null || enSearch.hilightWords == null || enSearch.hilightWords.size() == 0)\r
212                         return;\r
213                 \r
214                 // Get the recognition XML that tells where to hilight on the image\r
215                 Resource recoResource = conn.getNoteTable().noteResourceTable.getNoteResourceRecognition(resGuid);\r
216                 if (recoResource.getRecognition().getBody() == null || recoResource.getRecognition().getBody().length == 0)\r
217                         return;\r
218                 QByteArray recoData = new QByteArray(recoResource.getRecognition().getBody());\r
219                 String xml = recoData.toString();\r
220                 \r
221                 // Get a painter for the image.  This is the background (the initial image).\r
222         QPixmap pix = new QPixmap(f.fileName());\r
223         QPixmap hilightedPix = new QPixmap(pix.size());\r
224         QPainter p = new QPainter(hilightedPix);\r
225         p.drawPixmap(0,0, pix);\r
226 \r
227         // Create a transparent pixmap.  The only non-transparent\r
228         // piece is the hilight that will be overlayed to hilight text no the background\r
229         QPixmap overlayPix = new QPixmap(pix.size());\r
230         overlayPix.fill(QColor.transparent);\r
231         QPainter p2 = new QPainter(overlayPix);\r
232         p2.setBackgroundMode(BGMode.TransparentMode);\r
233         p2.setRenderHint(RenderHint.Antialiasing, true);\r
234                 QColor yellow = QColor.yellow;\r
235 //              yellow.setAlphaF(0.4);\r
236         p2.setBrush(yellow);\r
237         \r
238                 // Get the recognition data from the note\r
239         QDomDocument doc = new QDomDocument();\r
240         doc.setContent(xml);\r
241         \r
242         // Go through all "item" nodes\r
243                 QDomNodeList anchors = doc.elementsByTagName("item");\r
244                 for (int i=0; i<anchors.length(); i++) {\r
245                         QDomElement element = anchors.at(i).toElement();\r
246                         int x = new Integer(element.attribute("x"));   // x coordinate\r
247                         int y = new Integer(element.attribute("y"));   // y coordinate\r
248                         int w = new Integer(element.attribute("w"));   // width\r
249                         int h = new Integer(element.attribute("h"));   // height\r
250                         QDomNodeList children = element.childNodes();  // all children ("t" nodes).\r
251                         \r
252                         // Go through the children ("t" nodes)\r
253                         for (int j=0; j<children.length(); j++) {\r
254                         QDomElement child = children.at(j).toElement();\r
255                         if (child.nodeName().equalsIgnoreCase("t")) {\r
256                                 String text = child.text();   // recognition text\r
257                                 int weight = new Integer(child.attribute("w"));  // recognition weight\r
258                                 if (weight >= Global.getRecognitionWeight()) {   // Are we above the maximum?\r
259                                         \r
260                                         // Check to see if this word matches something we were searching for.\r
261                                         for (int k=0; k<enSearch.hilightWords.size(); k++) {\r
262                                                 String searchWord = enSearch.hilightWords.get(k).toLowerCase();\r
263                                                 if (searchWord.startsWith("*"))\r
264                                                         searchWord = searchWord.substring(1);\r
265                                                 if (searchWord.endsWith("*"))\r
266                                                         searchWord = searchWord.substring(0,searchWord.length()-1);\r
267                                                 if (text.toLowerCase().contains(searchWord)) {\r
268                                                         p2.drawRect(x,y,w,h);                   \r
269                                                 }\r
270                                         }\r
271                                 }\r
272                         }\r
273                         }\r
274                 }\r
275         p2.end();\r
276         \r
277         // Paint the hilight onto the background.\r
278         p.setOpacity(0.4);\r
279         p.drawPixmap(0,0, overlayPix);\r
280         p.end();\r
281         \r
282         // Save over the initial pixmap.\r
283         hilightedPix.save(f.fileName());\r
284         }\r
285         \r
286     // Modify the en-media tag into an image tag so it can be displayed.\r
287     private void modifyImageTags(QDomDocument doc, QDomElement docElem, QDomElement enmedia, QDomAttr hash) {\r
288         logger.log(logger.HIGH, "Entering NeverNote.modifyImageTags");\r
289         String type = enmedia.attribute("type");\r
290         if (type.startsWith("image/"))\r
291                 type = "."+type.substring(6);\r
292         else\r
293                 type="";\r
294         \r
295         String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNoteGuid, hash.value());\r
296         QFile tfile = new QFile(Global.getFileManager().getResDirPath(resGuid + type));\r
297 //      if (!tfile.exists()) {\r
298                 Resource r = null;\r
299                 if (resGuid != null)\r
300                                 r = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid,true);\r
301                         if (r==null || r.getData() == null || r.getData().getBody().length == 0) {\r
302                                 resourceError = true;\r
303                                 readOnly = true;\r
304                         }\r
305                         if (r!= null && r.getData() != null && r.getData().getBody().length > 0) {\r
306                                 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
307                                 QByteArray binData = new QByteArray(r.getData().getBody());\r
308                                 tfile.write(binData);\r
309                                 tfile.close();\r
310                                 \r
311                                 // If we have recognition text, outline it\r
312                                 addImageHilight(r.getGuid(), tfile);\r
313                                 \r
314                                 enmedia.setAttribute("src", QUrl.fromLocalFile(tfile.fileName()).toString());\r
315                                 enmedia.setAttribute("en-tag", "en-media");\r
316                                 enmedia.setNodeValue("");\r
317                         enmedia.setAttribute("guid", r.getGuid());\r
318                         enmedia.setTagName("img");\r
319                 }\r
320 //      }\r
321         // Technically, we should do a file:// to have a proper url, but for some reason QWebPage hates\r
322         // them and won't generate a thumbnail image properly if we use them.\r
323 //              enmedia.setAttribute("src", QUrl.fromLocalFile(tfile.fileName()).toString());\r
324                 enmedia.setAttribute("src", tfile.fileName().toString());\r
325                 enmedia.setAttribute("en-tag", "en-media");\r
326                 enmedia.setTagName("img");\r
327                 if (r != null && r.getAttributes() != null && \r
328                                 (r.getAttributes().getSourceURL() == null || !r.getAttributes().getSourceURL().toLowerCase().startsWith("http://latex.codecogs.com/gif.latex?")))\r
329                         enmedia.setAttribute("onContextMenu", "window.jambi.imageContextMenu('" +tfile.fileName()  +"');");\r
330                 else {\r
331                         QDomElement newText = doc.createElement("a");\r
332                         enmedia.setAttribute("src", tfile.fileName().toString());\r
333                         enmedia.setAttribute("en-tag", "en-latex");\r
334                         newText.setAttribute("onMouseOver", "style.cursor='hand'");\r
335                         if (r!= null && r.getAttributes() != null && r.getAttributes().getSourceURL() != null)\r
336                                 newText.setAttribute("title", r.getAttributes().getSourceURL());\r
337                         newText.setAttribute("href", "latex://"+tfile.fileName().toString());\r
338                         enmedia.parentNode().replaceChild(newText, enmedia);\r
339                         newText.appendChild(enmedia);\r
340 \r
341                 }\r
342                 enmedia.setNodeValue("");\r
343                 enmedia.setAttribute("guid", resGuid);\r
344 \r
345 \r
346                 logger.log(logger.HIGH, "Leaving NeverNote.modifyImageTags");\r
347     }\r
348     \r
349     \r
350         // Modify tags from Evernote specific things to XHTML tags.\r
351         private QDomDocument modifyTags(QDomDocument doc) {\r
352                 logger.log(logger.HIGH, "Entering NeverNote.modifyTags");\r
353                 if (tempFiles == null)\r
354                         tempFiles = new ArrayList<QTemporaryFile>();\r
355                 tempFiles.clear();\r
356                 QDomElement docElem = doc.documentElement();\r
357                 \r
358                 // Modify en-media tags\r
359                 QDomNodeList anchors = docElem.elementsByTagName("en-media");\r
360                 int enMediaCount = anchors.length();\r
361                 for (int i=enMediaCount-1; i>=0; --i) {\r
362                         QDomElement enmedia = anchors.at(i).toElement();\r
363                         if (enmedia.hasAttribute("type")) {\r
364                                 QDomAttr attr = enmedia.attributeNode("type");\r
365                                 QDomAttr hash = enmedia.attributeNode("hash");\r
366                                 String[] type = attr.nodeValue().split("/");\r
367                                 String appl = type[1];\r
368                                 \r
369                                 if (type[0] != null) {\r
370                                         if (type[0].equals("image")) {\r
371                                                 modifyImageTags(doc, docElem, enmedia, hash);\r
372                                         }\r
373                                         if (!type[0].equals("image")) {\r
374                                                 modifyApplicationTags(doc, docElem, enmedia, hash, appl);\r
375                                         }\r
376                                 }\r
377                         }\r
378                 }\r
379                 \r
380                 // Modify todo tags\r
381                 anchors = docElem.elementsByTagName("en-todo");\r
382                 int enTodoCount = anchors.length();\r
383                 for (int i=enTodoCount-1; i>=0; i--) {\r
384                         QDomElement enmedia = anchors.at(i).toElement();\r
385                         modifyTodoTags(enmedia);\r
386                 }\r
387                 \r
388                 // Modify en-crypt tags\r
389                 anchors = docElem.elementsByTagName("en-crypt");\r
390                 int enCryptLen = anchors.length();\r
391                 for (int i=enCryptLen-1; i>=0; i--) {\r
392                         QDomElement enmedia = anchors.at(i).toElement();\r
393                         enmedia.setAttribute("contentEditable","false");\r
394                         enmedia.setAttribute("src", Global.getFileManager().getImageDirPath("encrypt.png"));\r
395                         enmedia.setAttribute("en-tag","en-crypt");\r
396                         enmedia.setAttribute("alt", enmedia.text());\r
397                         Global.cryptCounter++;\r
398                         enmedia.setAttribute("id", "crypt"+Global.cryptCounter.toString());\r
399                         String encryptedText = enmedia.text();\r
400                         \r
401                         // If the encryption string contains crlf at the end, remove them because they mess up the javascript.\r
402                         if (encryptedText.endsWith("\n"))\r
403                                 encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
404                         if (encryptedText.endsWith("\r"))\r
405                                 encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
406                         \r
407                         // Add the commands\r
408                         String hint = enmedia.attribute("hint");\r
409                         hint = hint.replace("'","&apos;");\r
410                         enmedia.setAttribute("onClick", "window.jambi.decryptText('crypt"+Global.cryptCounter.toString()+"', '"+encryptedText+"', '"+hint+"');");\r
411                         enmedia.setAttribute("onMouseOver", "style.cursor='hand'");\r
412                         enmedia.setTagName("img");\r
413                         enmedia.removeChild(enmedia.firstChild());   // Remove the actual encrypted text\r
414                 }\r
415 \r
416                 \r
417                 // Modify link tags\r
418                 anchors = docElem.elementsByTagName("a");\r
419                 enCryptLen = anchors.length();\r
420                 for (int i=0; i<anchors.length(); i++) {\r
421                         QDomElement element = anchors.at(i).toElement();\r
422                         if (!element.attribute("href").toLowerCase().startsWith("latex://"))\r
423                                 element.setAttribute("title", element.attribute("href"));\r
424                         else {\r
425                                 element.setAttribute("title", element.attribute("title").toLowerCase().replace("http://latex.codecogs.com/gif.latex?",""));\r
426                         }\r
427                 }\r
428 \r
429                 logger.log(logger.HIGH, "Leaving NeverNote.modifyTags");\r
430                 return doc;\r
431         }\r
432         \r
433 \r
434         // Get an ink note image.  If an image doesn't exist then we fall back \r
435         // to the old ugly icon\r
436     private boolean buildInkNote(QDomDocument doc, QDomElement docElem, QDomElement enmedia, QDomAttr hash, String appl) {\r
437         String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNote.getGuid(), hash.value());\r
438         Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, false);\r
439  \r
440         // If we can't find the resource, then fall back to the old method.  We'll return & show\r
441         // an error later\r
442         if (r == null || r.getData() == null) \r
443                 return false;\r
444         \r
445         // If there isn't some type of error, continue on.\r
446                 if (!resourceError) {\r
447                         \r
448                         // Get a list of images in the database.  We'll use these to bulid the page.\r
449                         List<QByteArray> data = conn.getInkImagesTable().getImage(r.getGuid());\r
450                         \r
451                         // If no pictures are found, go back to & just show the icon\r
452                         if (data.size() == 0)\r
453                                 return false;\r
454                         \r
455                         // We have pictures, so append them to the page.  This really isn't proper since\r
456                         // we leave the en-media tag in place, but since we can't edit the page it doesn't\r
457                         // hurt anything.\r
458                         for (int i=0; i<data.size(); i++) {\r
459                         QFile f = new QFile(Global.getFileManager().getResDirPath(resGuid + new Integer(i).toString()+".png"));\r
460                                 f.open(OpenModeFlag.WriteOnly);\r
461                                 f.write(data.get(i));\r
462                                 f.close();\r
463                                 QDomElement newImage = doc.createElement("img");\r
464                                 newImage.setAttribute("src", QUrl.fromLocalFile(f.fileName()).toString());\r
465                                 enmedia.appendChild(newImage);\r
466                         }\r
467                         return true;\r
468                 }\r
469         return false;\r
470     }\r
471         \r
472         \r
473     // Modify the en-media tag into an attachment\r
474     private void modifyApplicationTags(QDomDocument doc, QDomElement docElem, QDomElement enmedia, QDomAttr hash, String appl) {\r
475         logger.log(logger.HIGH, "Entering NeverNote.modifyApplicationTags");\r
476         if (appl.equalsIgnoreCase("vnd.evernote.ink")) {\r
477                 inkNote = true;\r
478             if (buildInkNote(doc, docElem, enmedia, hash, appl))\r
479                 return;\r
480         }\r
481         String resGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(currentNote.getGuid(), hash.value());\r
482         Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(resGuid, false);\r
483         if (r == null || r.getData() == null) \r
484                 resourceError = true;\r
485                 if (r!= null) {\r
486                         if (r.getData()!=null) {\r
487                                 // Did we get a generic applicaiton?  Then look at the file name to \r
488                                 // try and find a good application type for the icon\r
489                                 if (appl.equalsIgnoreCase("octet-stream")) {\r
490                                         if (r.getAttributes() != null && r.getAttributes().getFileName() != null) {\r
491                                                 String fn = r.getAttributes().getFileName();\r
492                                                 int pos = fn.lastIndexOf(".");\r
493                                                 if (pos > -1) {\r
494                                                         appl = fn.substring(pos+1);\r
495                                                 }\r
496                                         }\r
497                                 }\r
498                                 \r
499                                 String fileDetails = null;\r
500                                 if (r.getAttributes() != null && r.getAttributes().getFileName() != null && !r.getAttributes().getFileName().equals(""))\r
501                                         fileDetails = r.getAttributes().getFileName();\r
502                                 String contextFileName;\r
503                                 FileManager fileManager = Global.getFileManager();\r
504                 if (fileDetails != null && !fileDetails.equals("")) {\r
505                         if (!noteHistory) {\r
506                                 enmedia.setAttribute("href", "nnres://" +r.getGuid() \r
507                                                 +Global.attachmentNameDelimeter +fileDetails);\r
508                                 contextFileName = fileManager.getResDirPath(r.getGuid() \r
509                                                 +Global.attachmentNameDelimeter + fileDetails);\r
510                         } else {\r
511                                 enmedia.setAttribute("href", "nnres://" +r.getGuid() + currentNote.getUpdateSequenceNum() \r
512                                                 +Global.attachmentNameDelimeter +fileDetails);\r
513                                 contextFileName = fileManager.getResDirPath(r.getGuid() + currentNote.getUpdateSequenceNum() \r
514                                                 +Global.attachmentNameDelimeter + fileDetails);\r
515                         }\r
516                                 } else { \r
517                                         if (!noteHistory) {\r
518                                                 enmedia.setAttribute("href", "nnres://" +r.getGuid() +currentNote.getUpdateSequenceNum()\r
519                                                                 +Global.attachmentNameDelimeter +appl);\r
520                                                 contextFileName = fileManager.getResDirPath(r.getGuid() +currentNote.getUpdateSequenceNum() \r
521                                                                 +Global.attachmentNameDelimeter + appl);\r
522                                         } else {\r
523                                                 enmedia.setAttribute("href", "nnres://" +r.getGuid() \r
524                                                                 +Global.attachmentNameDelimeter +appl);\r
525                                                 contextFileName = fileManager.getResDirPath(r.getGuid() \r
526                                                                 +Global.attachmentNameDelimeter + appl);\r
527                                         }\r
528                                 }\r
529                                 contextFileName = contextFileName.replace("\\", "/");\r
530                                 enmedia.setAttribute("onContextMenu", "window.jambi.resourceContextMenu('" +contextFileName +"');");\r
531                                 if (fileDetails == null || fileDetails.equals(""))\r
532                                         fileDetails = "";\r
533                                 enmedia.setAttribute("en-tag", "en-media");\r
534                                 enmedia.setAttribute("guid", r.getGuid());\r
535                                 enmedia.setTagName("a");\r
536                                 QDomElement newText = doc.createElement("img");\r
537                                 boolean goodPreview = false;\r
538                                 String filePath = "";\r
539                                 if (appl.equalsIgnoreCase("pdf") && pdfPreview) {\r
540                                         String fileName;\r
541                                         Resource res = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), true);\r
542                                         if (res.getAttributes() != null && \r
543                                                         res.getAttributes().getFileName() != null && \r
544                                                         !res.getAttributes().getFileName().trim().equals(""))\r
545                                                 fileName = res.getGuid()+Global.attachmentNameDelimeter+res.getAttributes().getFileName();\r
546                                         else\r
547                                                 fileName = res.getGuid()+".pdf";\r
548                                         QFile file = new QFile(fileManager.getResDirPath(fileName));\r
549                                 QFile.OpenMode mode = new QFile.OpenMode();\r
550                                 mode.set(QFile.OpenModeFlag.WriteOnly);\r
551                                 file.open(mode);\r
552                                 QDataStream out = new QDataStream(file);\r
553                                 Resource resBinary = conn.getNoteTable().noteResourceTable.getNoteResource(res.getGuid(), true);\r
554                                         QByteArray binData = new QByteArray(resBinary.getData().getBody());\r
555                                         resBinary = null;\r
556                                 out.writeBytes(binData.toByteArray());\r
557                                 file.close();\r
558                                 PDFPreview pdfPreview = new PDFPreview();\r
559                                         goodPreview = pdfPreview.setupPreview(file.fileName(), appl,0);\r
560                                         if (goodPreview) {\r
561                                                 QDomElement span = doc.createElement("span");\r
562                                                 QDomElement table = doc.createElement("table");\r
563                                                 span.setAttribute("pdfNavigationTable", "true");\r
564                                                 QDomElement tr = doc.createElement("tr");\r
565                                                 QDomElement td = doc.createElement("td");\r
566                                                 QDomElement left = doc.createElement("img");\r
567                                                 left.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");\r
568                                                 left.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");\r
569                                                 left.setAttribute("onMouseOver", "style.cursor='hand'");\r
570                                                 QDomElement right = doc.createElement("img");\r
571                                                 right.setAttribute("onMouseDown", "window.jambi.nextPage('" +file.fileName() +"')");\r
572                                                 left.setAttribute("onMouseDown", "window.jambi.previousPage('" +file.fileName() +"')");\r
573                                                 // NFC TODO: should these be file:// URLs?\r
574                                                 left.setAttribute("src", Global.getFileManager().getImageDirPath("small_left.png"));\r
575                                                 right.setAttribute("src", Global.getFileManager().getImageDirPath("small_right.png"));\r
576                                                 right.setAttribute("onMouseOver", "style.cursor='hand'");\r
577                                                 \r
578                                                 table.appendChild(tr);\r
579                                                 tr.appendChild(td);\r
580                                                 td.appendChild(left);\r
581                                                 td.appendChild(right);\r
582                                                 span.appendChild(table);\r
583                                                 enmedia.parentNode().insertBefore(span, enmedia);\r
584                                         } \r
585                                         filePath = fileName+".png";\r
586                                 }\r
587                                 String icon = findIcon(appl);\r
588                                 if (icon.equals("attachment.png"))\r
589                                         icon = findIcon(fileDetails.substring(fileDetails.indexOf(".")+1));\r
590                                 // NFC TODO: should this be a 'file://' URL?\r
591                                 newText.setAttribute("src", Global.getFileManager().getImageDirPath(icon));\r
592                                 if (goodPreview) {\r
593                                 // NFC TODO: should this be a 'file://' URL?\r
594                                         newText.setAttribute("src", fileManager.getResDirPathSpecialChar(filePath));\r
595                                         newText.setAttribute("style", "border-style:solid; border-color:green; padding:0.5mm 0.5mm 0.5mm 0.5mm;");\r
596                                 }\r
597                                 newText.setAttribute("title", fileDetails);\r
598                                 enmedia.removeChild(enmedia.firstChild());\r
599                                 \r
600                                 enmedia.appendChild(newText);\r
601                         }\r
602                 }\r
603                 logger.log(logger.HIGH, "Leaving NeverNote.modifyApplicationTags");\r
604     }\r
605     // Modify the en-to tag into an input field\r
606     private void modifyTodoTags(QDomElement todo) {\r
607         logger.log(logger.HIGH, "Entering NeverNote.modifyTodoTags");\r
608                 todo.setAttribute("type", "checkbox");\r
609                 String checked = todo.attribute("checked");\r
610                 todo.removeAttribute("checked");\r
611                 if (checked.equalsIgnoreCase("true"))\r
612                         todo.setAttribute("checked", "");\r
613                 else\r
614                         todo.setAttribute("unchecked","");\r
615                 todo.setAttribute("value", checked);\r
616                 todo.setAttribute("onClick", "value=checked;window.jambi.contentChanged(); ");\r
617                 todo.setAttribute("onMouseOver", "style.cursor='hand'");\r
618                 todo.setTagName("input");\r
619                 logger.log(logger.HIGH, "Leaving NeverNote.modifyTodoTags");\r
620     }\r
621     \r
622     \r
623     \r
624     // Modify any cached todo tags that may have changed\r
625     public String modifyCachedTodoTags(String note) {\r
626         logger.log(logger.HIGH, "Entering NeverNote.modifyCachedTodoTags");\r
627         StringBuffer html = new StringBuffer(note);\r
628                 for (int i=html.indexOf("<input", 0); i>-1; i=html.indexOf("<input", i)) {\r
629                         int endPos =html.indexOf(">",i+1);\r
630                         String input = html.substring(i,endPos);\r
631                         if (input.indexOf("value=\"true\"") > 0) \r
632                                 input = input.replace(" unchecked=\"\"", " checked=\"\"");\r
633                         else\r
634                                 input = input.replace(" checked=\"\"", " unchecked=\"\"");\r
635                         html.replace(i, endPos, input);\r
636                         i++;\r
637                 }\r
638                 logger.log(logger.HIGH, "Leaving NeverNote.modifyCachedTodoTags");\r
639                 return html.toString();\r
640     }\r
641     \r
642     \r
643 \r
644 \r
645         // Scan and do hilighting of words\r
646         public QDomDocument addHilight(QDomDocument doc) {\r
647 //              EnSearch e = listManager.getEnSearch();\r
648                 if (enSearch.hilightWords == null || enSearch.hilightWords.size() == 0)\r
649                         return doc;\r
650                 XMLInsertHilight hilight = new XMLInsertHilight(doc, enSearch.hilightWords);\r
651                 return hilight.getDoc();\r
652         }\r
653         \r
654         \r
655     // find the appropriate icon for an attachment\r
656     private String findIcon(String appl) {\r
657         logger.log(logger.HIGH, "Entering NeverNote.findIcon");\r
658         appl = appl.toLowerCase();\r
659         String relativePath = appl + ".png";\r
660         File f = Global.getFileManager().getImageDirFile(relativePath);\r
661         if (f.exists()) {\r
662             return relativePath;\r
663         }\r
664         if (f.exists())\r
665                 return appl+".png";\r
666         logger.log(logger.HIGH, "Leaving NeverNote.findIcon");\r
667         return "attachment.png";\r
668     }\r
669 \r
670 }\r