OSDN Git Service

add missing tr() for I18N
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / dialog / OnlineNoteHistory.java
1 /*\r
2  * This file is part of NeverNote \r
3  * Copyright 2009 Randy Baumgarte\r
4  * \r
5  * This file may be licensed under the terms of of the\r
6  * GNU General Public License Version 2 (the ``GPL'').\r
7  *\r
8  * Software distributed under the License is distributed\r
9  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
10  * express or implied. See the GPL for the specific language\r
11  * governing rights and limitations.\r
12  *\r
13  * You should have received a copy of the GPL along with this\r
14  * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
15  * or write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
17  *\r
18 */\r
19 \r
20 package cx.fbn.nevernote.dialog;\r
21 \r
22 import java.io.File;\r
23 import java.text.SimpleDateFormat;\r
24 import java.util.List;\r
25 \r
26 import com.evernote.edam.notestore.NoteVersionId;\r
27 import com.evernote.edam.type.Note;\r
28 import com.evernote.edam.type.Resource;\r
29 import com.trolltech.qt.core.QByteArray;\r
30 import com.trolltech.qt.core.QFile;\r
31 import com.trolltech.qt.core.QIODevice;\r
32 import com.trolltech.qt.core.Qt.ContextMenuPolicy;\r
33 import com.trolltech.qt.gui.QComboBox;\r
34 import com.trolltech.qt.gui.QDialog;\r
35 import com.trolltech.qt.gui.QHBoxLayout;\r
36 import com.trolltech.qt.gui.QLabel;\r
37 import com.trolltech.qt.gui.QPushButton;\r
38 import com.trolltech.qt.gui.QVBoxLayout;\r
39 import com.trolltech.qt.xml.QDomAttr;\r
40 import com.trolltech.qt.xml.QDomDocument;\r
41 import com.trolltech.qt.xml.QDomElement;\r
42 import com.trolltech.qt.xml.QDomNodeList;\r
43 \r
44 import cx.fbn.nevernote.Global;\r
45 import cx.fbn.nevernote.NeverNote;\r
46 import cx.fbn.nevernote.gui.BrowserWindow;\r
47 import cx.fbn.nevernote.sql.DatabaseConnection;\r
48 \r
49 public class OnlineNoteHistory extends QDialog {\r
50         public final QPushButton        restoreAsNew;\r
51         public final QPushButton        restore;\r
52         private DatabaseConnection  conn;\r
53         public final QComboBox          historyCombo;    \r
54         private final BrowserWindow     browser;\r
55         \r
56         // Constructor\r
57         public OnlineNoteHistory(DatabaseConnection c) {\r
58                 setWindowTitle(tr("Online Note History"));\r
59                 QVBoxLayout main = new QVBoxLayout();\r
60                 setLayout(main);\r
61                 historyCombo = new QComboBox(this);\r
62                 \r
63                 QHBoxLayout comboLayout = new QHBoxLayout();\r
64                 comboLayout.addWidget(new QLabel(tr("History Date:")));\r
65                 comboLayout.addWidget(historyCombo);\r
66                 comboLayout.addStretch(100);\r
67                 \r
68                 main.addLayout(comboLayout);\r
69                                 \r
70                 browser = new BrowserWindow(conn);\r
71                 main.addWidget(browser);\r
72                 browser.titleLabel.setVisible(false);\r
73                 browser.notebookBox.setVisible(false);\r
74                 browser.hideButtons();\r
75                 browser.tagEdit.setVisible(false);\r
76                 browser.tagLabel.setVisible(false);\r
77                 \r
78                 QHBoxLayout buttonLayout = new QHBoxLayout();\r
79                 buttonLayout.addStretch(100);\r
80                 restore = new QPushButton(tr("Restore Note"));\r
81                 restore.clicked.connect(this, "restorePushed()");\r
82                 \r
83                 restoreAsNew = new QPushButton(tr("Restore As New Note"));\r
84                 restoreAsNew.clicked.connect(this, "restoreAsNewPushed()");\r
85                 QPushButton cancel = new QPushButton(tr("Cancel"));\r
86                 cancel.clicked.connect(this, "cancelPressed()");\r
87                 \r
88                 buttonLayout.addWidget(restore);\r
89                 buttonLayout.addWidget(restoreAsNew);\r
90                 buttonLayout.addWidget(cancel);\r
91                 main.addLayout(buttonLayout);\r
92                 \r
93                 browser.getBrowser().setContextMenuPolicy(ContextMenuPolicy.NoContextMenu);\r
94 \r
95         }\r
96         \r
97         @SuppressWarnings("unused")\r
98         private void restoreAsNewPushed() {\r
99                 this.close();\r
100         }\r
101         @SuppressWarnings("unused")\r
102         private void restorePushed() {\r
103                 this.close();\r
104         }\r
105         @SuppressWarnings("unused")\r
106         private void cancelPressed() {\r
107                 this.close();\r
108         }\r
109         \r
110         public void setCurrent(boolean isDirty) {\r
111                 if (isDirty) \r
112                         historyCombo.addItem(new String("Current (Non Synchronized)"));\r
113                 else\r
114                         historyCombo.addItem(new String("Current (Synchronized)"));\r
115                                 \r
116         }\r
117         \r
118         public void load(List<NoteVersionId> versions) {\r
119                 String fmt = Global.getDateFormat() + " " + Global.getTimeFormat();\r
120                 String dateTimeFormat = new String(fmt);\r
121                 SimpleDateFormat simple = new SimpleDateFormat(dateTimeFormat);\r
122                 \r
123                 for (int i=0; i<versions.size(); i++) {\r
124                         StringBuilder versionDate = new StringBuilder(simple.format(versions.get(i).getServiceUpdated()));\r
125                         historyCombo.addItem(versionDate.toString());\r
126                 }\r
127         }\r
128         \r
129         public void setContent(Note currentNote) {\r
130                 StringBuffer b = rebuildNoteHTML(currentNote);\r
131                 StringBuffer js = new StringBuffer();\r
132 \r
133                 // We need to prepend the note with <HEAD></HEAD> or encoded characters are ugly \r
134                 js.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");       \r
135                 js.append("<style type=\"text/css\">en-crypt-temp { border-style:solid; border-color:blue; padding:1mm 1mm 1mm 1mm; }</style>");\r
136                 js.append("</head>");\r
137                 js.append(b.toString());\r
138                 js.append("</HTML>");\r
139 //              js.replace("<!DOCTYPE en-note SYSTEM 'http://xml.evernote.com/pub/enml2.dtd'>", "");\r
140 //              js.replace("<?xml version='1.0' encoding='UTF-8'?>", "");\r
141                 \r
142                 browser.setNote(currentNote);\r
143                 browser.getBrowser().page().mainFrame().setHtml(js.toString());\r
144         }\r
145  \r
146         //*************************************************\r
147         //* XML Modifying Methods\r
148         //*************************************************\r
149         private StringBuffer rebuildNoteHTML(Note note) {\r
150                 QDomDocument doc = new QDomDocument();\r
151                 QDomDocument.Result result = doc.setContent(note.getContent());\r
152                 if (!result.success) {\r
153                         return new StringBuffer(note.getContent());\r
154                 }\r
155                 \r
156                 doc = modifyTags(note, doc);\r
157                 QDomElement docElem = doc.documentElement();\r
158                 docElem.setTagName("Body");\r
159                 \r
160                 // Fix the stupid problem where inserting an <img> tag after an <a> tag (which is done\r
161                 // to get the <en-media> application tag to work properly) causes spaces to be inserted\r
162                 // between the <a> & <img>.  This messes things up later.  This is an ugly hack.\r
163                 String docString = doc.toString();\r
164                 StringBuffer html = new StringBuffer(docString.substring(docString.toLowerCase().indexOf("<body>")));\r
165                 \r
166                 for (int i=html.indexOf("<a en-tag=\"en-media\" ", 0); i>-1; i=html.indexOf("<a en-tag=\"en-media\" ", i)) {\r
167                         i=html.indexOf(">\n",i+1);\r
168                         int z = html.indexOf("<img",i);\r
169                         for (int j=z-1; j>i; j--) \r
170                                 html.deleteCharAt(j);\r
171                         i=html.indexOf("/>", z+1);\r
172                         z = html.indexOf("</a>",i);\r
173                         for (int j=z-1; j>i+1; j--) \r
174                                 html.deleteCharAt(j);\r
175                 } \r
176                 return html;\r
177         }       \r
178 \r
179         \r
180         \r
181         private QDomDocument modifyTags(Note note, QDomDocument doc) {\r
182                 QDomElement docElem = doc.documentElement();\r
183                 \r
184                 // Modify en-media tags\r
185                 QDomNodeList anchors = docElem.elementsByTagName("en-media");\r
186                 int enMediaCount = anchors.length();\r
187                 for (int i=enMediaCount-1; i>=0; i--) {\r
188                         QDomElement enmedia = anchors.at(i).toElement();\r
189                         if (enmedia.hasAttribute("type")) {\r
190                                 QDomAttr attr = enmedia.attributeNode("type");\r
191                                 QDomAttr hash = enmedia.attributeNode("hash");\r
192                                 String[] type = attr.nodeValue().split("/");\r
193                                 String appl = type[1];\r
194                                 \r
195                                 if (type[0] != null) {\r
196                                         if (type[0].equals("image")) {\r
197                                                 modifyImageTags(note, docElem, enmedia, hash);\r
198                                         }\r
199                                         if (!type[0].equals("image")) {\r
200                                                 modifyApplicationTags(note, doc, docElem, enmedia, hash, appl);\r
201                                         }\r
202 //                                      if (type[0].equals("audio")) {\r
203 //                                              modifyApplicationTags(doc, docElem, enmedia, hash, appl);\r
204 //                                      }\r
205                                 }\r
206                         }\r
207                 }\r
208                 \r
209                 // Modify todo tags\r
210                 anchors = docElem.elementsByTagName("en-todo");\r
211                 int enTodoCount = anchors.length();\r
212                 for (int i=enTodoCount-1; i>=0; i--) {\r
213                         QDomElement enmedia = anchors.at(i).toElement();\r
214                         modifyTodoTags(enmedia);\r
215                 }\r
216                 \r
217                 // Modify en-crypt tags\r
218                 anchors = docElem.elementsByTagName("en-crypt");\r
219                 int enCryptLen = anchors.length();\r
220                 for (int i=enCryptLen-1; i>=0; i--) {\r
221                         QDomElement enmedia = anchors.at(i).toElement();\r
222                         //enmedia.setAttribute("style","display:none");\r
223                         enmedia.setAttribute("contentEditable","false");\r
224                         enmedia.setAttribute("src", Global.getFileManager().getImageDirPath("encrypt.png"));\r
225                         enmedia.setAttribute("en-tag","en-crypt");\r
226                         enmedia.setAttribute("alt", enmedia.text());\r
227                         Global.cryptCounter++;\r
228                         enmedia.setAttribute("id", "crypt"+Global.cryptCounter.toString());\r
229                         String encryptedText = enmedia.text();\r
230                         \r
231                         // If the encryption string contains crlf at the end, remove them because they mess up the javascript.\r
232                         if (encryptedText.endsWith("\n"))\r
233                                 encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
234                         if (encryptedText.endsWith("\r"))\r
235                                 encryptedText = encryptedText.substring(0,encryptedText.length()-1);\r
236                         \r
237                         // Add the commands\r
238                         enmedia.setAttribute("onClick", "window.jambi.decryptText('crypt"+Global.cryptCounter.toString()+"', '"+encryptedText+"', '"+enmedia.attribute("hint")+"');");\r
239                         enmedia.setAttribute("onMouseOver", "style.cursor='hand'");\r
240                         enmedia.setTagName("img");\r
241                         enmedia.removeChild(enmedia.firstChild());   // Remove the actual encrypted text\r
242                 }\r
243 \r
244                 return doc;\r
245         }\r
246         \r
247         \r
248         \r
249         \r
250            private void modifyApplicationTags(Note n, QDomDocument doc, QDomElement docElem, QDomElement enmedia, QDomAttr hash, String appl) {\r
251                   \r
252                    Resource r = null;\r
253                    for (int i=0; i<n.getResourcesSize(); i++) {\r
254                            String hashValue = hash.value();\r
255                            byte res[] = n.getResources().get(i).getData().getBodyHash();\r
256                            String resourceHashValue = new String(Global.byteArrayToHexString(res));\r
257                            if (resourceHashValue.equalsIgnoreCase(hashValue)) {\r
258                                    r = n.getResources().get(i);\r
259                                    i=n.getResourcesSize();\r
260                            }\r
261                    }\r
262                    \r
263                    if (r!= null) {\r
264                                 if (r.getData()!=null) {\r
265                                         // Did we get a generic applicaiton?  Then look at the file name to \r
266                                         // try and find a good application type for the icon\r
267                                         if (appl.equalsIgnoreCase("octet-stream")) {\r
268                                                 if (r.getAttributes() != null && r.getAttributes().getFileName() != null) {\r
269                                                         String fn = r.getAttributes().getFileName();\r
270                                                         int pos = fn.indexOf(".");\r
271                                                         if (pos > -1) {\r
272                                                                 appl = fn.substring(pos+1);\r
273                                                         }\r
274                                                 }\r
275                                         }\r
276                                         \r
277                                         String fileDetails = null;\r
278                                         if (r.getAttributes() != null && r.getAttributes().getFileName() != null && !r.getAttributes().getFileName().equals(""))\r
279                                                 fileDetails = r.getAttributes().getFileName();\r
280                                         if (fileDetails != null && !fileDetails.equals("")) \r
281                                                 enmedia.setAttribute("href", "nnres://" +r.getGuid()+n.getUpdateSequenceNum() +Global.attachmentNameDelimeter +fileDetails);\r
282                                         else\r
283                                                 enmedia.setAttribute("href", "nnres://" +r.getGuid()+n.getUpdateSequenceNum() +Global.attachmentNameDelimeter +appl);\r
284                                         if (fileDetails == null || fileDetails.equals(""))\r
285                                                 fileDetails = "";\r
286                                         enmedia.setAttribute("en-tag", "en-media");\r
287                                         enmedia.setAttribute("guid", r.getGuid());\r
288                                         enmedia.setTagName("a");\r
289                                         QDomElement newText = doc.createElement("img");\r
290                                         String icon = findIcon(appl);\r
291                                         if (icon.equals("attachment.png"))\r
292                                                 icon = findIcon(fileDetails.substring(fileDetails.indexOf(".")+1));\r
293                                         newText.setAttribute("src", Global.getFileManager().getImageDirPath(icon));\r
294                                         newText.setAttribute("title", fileDetails);\r
295                                         enmedia.removeChild(enmedia.firstChild());\r
296                                         enmedia.appendChild(newText);\r
297                                 }\r
298                         }\r
299             }\r
300            /**\r
301             * find the appropriate icon for an attachment\r
302             *\r
303             * NFC TODO: duplicate of {@link NeverNote#findIcon(String)}\r
304             */\r
305             private String findIcon(String appl) {\r
306                 appl = appl.toLowerCase();\r
307         String relativePath = appl + ".png";\r
308         File f = Global.getFileManager().getImageDirFile(relativePath);\r
309         if (f.exists()) {\r
310             return relativePath;\r
311         }\r
312                 return "attachment.png";\r
313             }\r
314             \r
315         \r
316         \r
317         \r
318         \r
319         \r
320         \r
321     private void modifyTodoTags(QDomElement todo) {\r
322                 todo.setAttribute("type", "checkbox");\r
323                 String checked = todo.attribute("checked");\r
324                 todo.removeAttribute("checked");\r
325                 if (checked.equalsIgnoreCase("true"))\r
326                         todo.setAttribute("checked", "");\r
327                 else\r
328                         todo.setAttribute("unchecked","");\r
329                 todo.setAttribute("value", checked);\r
330                 todo.setAttribute("onClick", "value=checked;window.jambi.contentChanged(); ");\r
331                 todo.setTagName("input");\r
332     }\r
333     \r
334     \r
335     private void modifyImageTags(Note note, QDomElement docElem, QDomElement enmedia, QDomAttr hash) {\r
336         String type = enmedia.attribute("type");\r
337         if (type.startsWith("image/"))\r
338                 type = "."+type.substring(6);\r
339         else\r
340                 type="";\r
341         \r
342         Resource r = null;\r
343                 for (int i=0; i<note.getResourcesSize(); i++) {\r
344                         String hashValue = hash.value();\r
345                         byte res[] = note.getResources().get(i).getData().getBodyHash();\r
346                         String resourceHashValue = new String(Global.byteArrayToHexString(res));\r
347                    if (hashValue.equalsIgnoreCase(resourceHashValue)) {\r
348                            r = note.getResources().get(i);\r
349                            i=note.getResourcesSize();\r
350                    }\r
351                 }\r
352         \r
353                 if (r==null)\r
354                         return;\r
355                 \r
356         QFile tfile = new QFile(Global.getFileManager().getResDirPath(r.getGuid() + note.getUpdateSequenceNum() + type));\r
357         if (!tfile.exists()) {\r
358                         if (r!= null && r.getData() != null && r.getData().getBody().length > 0) {\r
359                                 tfile.open(new QIODevice.OpenMode(QIODevice.OpenModeFlag.WriteOnly));\r
360                                 QByteArray binData = new QByteArray(r.getData().getBody());\r
361                                 tfile.write(binData);\r
362                                 tfile.close();\r
363                                 enmedia.setAttribute("src", tfile.fileName());\r
364                                 enmedia.setAttribute("en-tag", "en-media");\r
365                                 enmedia.setNodeValue("");\r
366                         enmedia.setAttribute("guid", r.getGuid());\r
367                         enmedia.setTagName("img");\r
368                 }\r
369         }\r
370                 enmedia.setAttribute("src", tfile.fileName());\r
371                 enmedia.setAttribute("en-tag", "en-media");\r
372                 enmedia.setNodeValue("");\r
373                 enmedia.setAttribute("guid", r.getGuid());\r
374                 enmedia.setTagName("img");\r
375     }\r
376 }\r