OSDN Git Service

e0d9763708a4e5ab246e9ebcc878d7261118c235
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / gui / NotebookTreeWidget.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.gui;\r
21 \r
22 import java.util.ArrayList;\r
23 import java.util.HashMap;\r
24 import java.util.List;\r
25 \r
26 import com.evernote.edam.type.Notebook;\r
27 import com.trolltech.qt.core.QByteArray;\r
28 import com.trolltech.qt.core.QMimeData;\r
29 import com.trolltech.qt.core.Qt;\r
30 import com.trolltech.qt.core.Qt.SortOrder;\r
31 import com.trolltech.qt.gui.QAbstractItemView;\r
32 import com.trolltech.qt.gui.QAction;\r
33 import com.trolltech.qt.gui.QBrush;\r
34 import com.trolltech.qt.gui.QColor;\r
35 import com.trolltech.qt.gui.QContextMenuEvent;\r
36 import com.trolltech.qt.gui.QDragEnterEvent;\r
37 import com.trolltech.qt.gui.QDragMoveEvent;\r
38 import com.trolltech.qt.gui.QHeaderView;\r
39 import com.trolltech.qt.gui.QIcon;\r
40 import com.trolltech.qt.gui.QMenu;\r
41 import com.trolltech.qt.gui.QTreeWidget;\r
42 import com.trolltech.qt.gui.QTreeWidgetItem;\r
43 import com.trolltech.qt.gui.QTreeWidgetItem.ChildIndicatorPolicy;\r
44 \r
45 import cx.fbn.nevernote.Global;\r
46 import cx.fbn.nevernote.filters.NotebookCounter;\r
47 import cx.fbn.nevernote.signals.NoteSignal;\r
48 import cx.fbn.nevernote.sql.DatabaseConnection;\r
49 \r
50 public class NotebookTreeWidget extends QTreeWidget {\r
51         private QAction                                 deleteAction;\r
52         private QAction                                 addAction;\r
53         private QAction                                 editAction;\r
54         private QAction                                 iconAction;\r
55         private QAction                                 stackAction;\r
56         public NoteSignal                               noteSignal;\r
57         private HashMap<String, QIcon>  icons;\r
58         private final DatabaseConnection                db;\r
59         private final HashMap<String, QTreeWidgetItem>  stacks;\r
60 //      private final QTreeWidgetItem                   previousMouseOver;\r
61 //      private boolean                                 previousMouseOverWasSelected;\r
62         \r
63         public void setAddAction(QAction a) {\r
64                 addAction = a;\r
65         }\r
66         \r
67         public void setDeleteAction(QAction d) {\r
68                 deleteAction = d;\r
69         }\r
70         \r
71         public void setEditAction(QAction e) {\r
72                 editAction = e;\r
73         }\r
74         \r
75         public void setStackAction(QAction e) {\r
76                 stackAction = e;\r
77         }\r
78         \r
79         public void setIconAction(QAction e) {\r
80                 iconAction = e;\r
81         }\r
82         \r
83         public NotebookTreeWidget(DatabaseConnection db) {\r
84                 noteSignal = new NoteSignal();\r
85                 this.db = db;\r
86 //              setProperty("hideTree", true);\r
87                 List<String> labels = new ArrayList<String>();\r
88                 labels.add("Notebooks");\r
89                 labels.add("");\r
90                 setAcceptDrops(true);\r
91                 setDragEnabled(true);\r
92                 setColumnCount(2);\r
93                 header().setResizeMode(0, QHeaderView.ResizeMode.ResizeToContents);\r
94                 header().setResizeMode(1, QHeaderView.ResizeMode.Stretch);\r
95                 header().setMovable(false);\r
96                 setHeaderLabels(labels);\r
97                 setDragDropMode(QAbstractItemView.DragDropMode.DragDrop);\r
98                 // If we want to mimic Evernote's notebook selection\r
99                 if (Global.mimicEvernoteInterface) {\r
100                         setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection);\r
101                 } else\r
102                         setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);\r
103 \r
104                 stacks = new HashMap<String, QTreeWidgetItem>();\r
105 //      int width = Global.getColumnWidth("notebookTreeName");\r
106 //              if (width>0)\r
107 //                      setColumnWidth(0, width);\r
108 //              previousMouseOver = new QTreeWidgetItem();\r
109         }\r
110         \r
111         public void selectNotebook(QTreeWidgetItem item) {\r
112                 QTreeWidgetItem root = invisibleRootItem();\r
113                 QTreeWidgetItem child;\r
114                 \r
115                 for (int i=0; i<root.childCount(); i++) {\r
116                         child = root.child(i); \r
117                         if (child.text(2).equals(item.text(2))) {\r
118                                 child.setSelected(true);\r
119                                 return;\r
120                         }\r
121                 }\r
122                 \r
123         }\r
124         \r
125         public boolean selectGuid(String guid) {\r
126                 QTreeWidgetItem root = invisibleRootItem();\r
127                 QTreeWidgetItem child;\r
128 \r
129                 for (int i=0; i<root.childCount(); i++) {\r
130                         child = root.child(i);\r
131                         if (child.text(2).equals(guid)) {\r
132                                 child.setSelected(true);\r
133                                 return true;\r
134                         }\r
135                 }\r
136                 return false;\r
137         }\r
138         \r
139         public void setIcons(HashMap<String, QIcon> i) {\r
140                 icons = i;\r
141         }\r
142         \r
143         public QIcon findDefaultIcon(String guid, String name, List<String> localBooks, boolean isPublished) {\r
144         String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
145         QIcon blueIcon = new QIcon(iconPath+"notebook-blue.png");\r
146         QIcon greenIcon = new QIcon(iconPath+"notebook-green.png");\r
147         QIcon redIcon = new QIcon(iconPath+"notebook-red.png");\r
148         QIcon yellowIcon = new QIcon(iconPath+"notebook-yellow.png");\r
149 \r
150                 if (localBooks.contains(guid)) {\r
151                         return yellowIcon;\r
152                 }\r
153                 \r
154                 if (localBooks.contains(guid) && \r
155                         (name.equalsIgnoreCase("Conflicting Changes") ||\r
156                          name.equalsIgnoreCase("Conflicting Changes (Local)")))\r
157                                 return redIcon;\r
158                 if (isPublished)\r
159                         return blueIcon;\r
160 \r
161                 return greenIcon;\r
162         }\r
163         \r
164         public void load(List<Notebook> books, List<String> localBooks) {\r
165         Notebook book;\r
166         QTreeWidgetItem child;\r
167         clear();\r
168         stacks.clear();\r
169         \r
170         if (books == null)\r
171                 return;\r
172         Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
173         for (int i=0; i<books.size(); i++) {\r
174                         book = books.get(i);\r
175                         child = new QTreeWidgetItem();\r
176                         child.setChildIndicatorPolicy(ChildIndicatorPolicy.DontShowIndicatorWhenChildless);\r
177                         child.setText(0, book.getName());\r
178                 if (icons != null && !icons.containsKey(book.getGuid())) {\r
179                         QIcon icon = findDefaultIcon(book.getGuid(), book.getName(), localBooks, book.isPublished());\r
180                         child.setIcon(0, icon);\r
181                 } else {\r
182                         child.setIcon(0, icons.get(book.getGuid()));\r
183                 }\r
184                 child.setTextAlignment(1, ra.value());\r
185                 child.setText(2, book.getGuid());\r
186                 if (book.getStack() == null || book.getStack().equalsIgnoreCase(""))\r
187                         addTopLevelItem(child); \r
188                 else {\r
189                         String stackName = book.getStack();\r
190                         QTreeWidgetItem parent;\r
191                         if (!stacks.containsKey(stackName)) {\r
192                                 parent = createStackIcon(stackName, ra);\r
193                                 addTopLevelItem(parent);\r
194                                 stacks.put(stackName, parent);\r
195                         } else\r
196                                 parent = stacks.get(stackName);\r
197                         parent.addChild(child);\r
198                         \r
199                 }\r
200         }\r
201 \r
202         sortItems(0, SortOrder.AscendingOrder); \r
203         if (Global.mimicEvernoteInterface) {\r
204                 String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
205                 QIcon allIcon = db.getSystemIconTable().getIcon("All Notebooks", "ALLNOTEBOOK");\r
206                 \r
207                 if (allIcon == null)\r
208                         allIcon = new QIcon(iconPath+"notebook-green.png");\r
209                 \r
210                 child = new QTreeWidgetItem();\r
211                 child.setIcon(0, allIcon);\r
212                 child.setText(0, "All Notebooks");\r
213                 child.setText(2, "");\r
214                 child.setTextAlignment(1, ra.value());\r
215                 insertTopLevelItem(0,child);\r
216         }\r
217         resizeColumnToContents(0);\r
218         resizeColumnToContents(1);\r
219         }\r
220 \r
221         // update the display with the current number of notes\r
222         public void updateCounts(List<Notebook> books, List<NotebookCounter> counts) {\r
223                 QTreeWidgetItem root = invisibleRootItem();\r
224                 QTreeWidgetItem child;\r
225                 \r
226                 QBrush blue = new QBrush();\r
227                 QBrush black = new QBrush();\r
228                 black.setColor(QColor.black);\r
229                 if (Global.tagBehavior().equalsIgnoreCase("ColorActive") && !Global.mimicEvernoteInterface)\r
230                         blue.setColor(QColor.blue);\r
231                 else\r
232                         blue.setColor(QColor.black);\r
233                 int total=0;\r
234                 \r
235                 \r
236                 int size = books.size();\r
237                 if (Global.mimicEvernoteInterface)\r
238                         size++;\r
239                 \r
240                 for (int i=0; i<size; i++) {\r
241                         child = root.child(i);\r
242                         if (child != null && child.childCount() > 0) {\r
243                                 int count = child.childCount();\r
244                                 QTreeWidgetItem parent = child;\r
245                                 int localTotal = 0;\r
246                                 for (int j=0; j<count; j++) {\r
247                                         child = parent.child(j);\r
248                                         int childCount = updateCounts(child, books, counts, blue, black);\r
249                                         total = total+childCount;\r
250                                         localTotal = localTotal+childCount;\r
251                                 }\r
252                                 parent.setText(1, new Integer(localTotal).toString());\r
253                         } else\r
254                                 total = total+updateCounts(child, books, counts, blue, black);\r
255                 }\r
256                 \r
257                 for (int i=0; i<size; i++) {\r
258                         child = root.child(i); \r
259                         if (child != null) {\r
260                                 String guid = child.text(2);\r
261                                 if (guid.equals("") && Global.mimicEvernoteInterface) \r
262                                         child.setText(1, new Integer(total).toString());\r
263                         }\r
264                 }\r
265         }\r
266         \r
267         private int updateCounts(QTreeWidgetItem child, List<Notebook> books, List<NotebookCounter> counts, QBrush blue, QBrush black) {\r
268                 int total=0;\r
269                 if (child != null) {\r
270                         String guid = child.text(2);\r
271                         child.setText(1,"0");\r
272                         child.setForeground(0, black);\r
273                         child.setForeground(1, black);\r
274                         for (int j=0; j<counts.size(); j++) {\r
275                                 if (counts.get(j).getGuid().equals(guid)) {\r
276                                         child.setText(1, new Integer(counts.get(j).getCount()).toString());\r
277                                         total = counts.get(j).getCount();\r
278                                         if (counts.get(j).getCount() > 0) {\r
279                                                 child.setForeground(0, blue);\r
280                                                 child.setForeground(1, blue);\r
281                                         }\r
282                                 }\r
283                         }\r
284                 }\r
285                 return total;\r
286         }\r
287         \r
288         // Return a list of the notebook guids, ordered by the current display order.\r
289         public List<String> getNotebookGuids() {\r
290                 List<String> names = new ArrayList<String>();\r
291                 QTreeWidgetItem root = invisibleRootItem();\r
292                 QTreeWidgetItem child;\r
293                 for (int i=0; i<root.childCount(); i++) {\r
294                         child = root.child(i);\r
295                         String text = child.text(2);\r
296                         names.add(text);\r
297                 }\r
298                 return names;\r
299         }\r
300         \r
301         @Override\r
302         public void contextMenuEvent(QContextMenuEvent event) {\r
303                 QMenu menu = new QMenu(this);\r
304                 menu.addAction(addAction);\r
305                 menu.addAction(editAction);\r
306                 menu.addAction(deleteAction);\r
307                 menu.addAction(stackAction);\r
308                 menu.addSeparator();\r
309                 menu.addAction(iconAction);\r
310                 menu.exec(event.globalPos());\r
311         }\r
312         \r
313         \r
314         @Override\r
315         public void dragEnterEvent(QDragEnterEvent event) {\r
316                 if (event.mimeData().hasFormat("application/x-nevernote-note")) {\r
317                         event.accept();\r
318                         return;\r
319                 }\r
320                 if (event.source() == this) {\r
321                         event.mimeData().setData("application/x-nevernote-notebook", new QByteArray(currentItem().text(2)));\r
322                         List<QTreeWidgetItem> selected = selectedItems();\r
323                         for (int i=0; i<selected.size(); i++) {\r
324                                 if (selected.get(i).text(2).equalsIgnoreCase("STACK") || \r
325                                         selected.get(i).text(2).equals("")) {\r
326                                                 event.ignore();\r
327                                                 return;\r
328                                         }\r
329                         }\r
330                         event.accept();\r
331                         return;\r
332                 }\r
333                 event.ignore();\r
334         }\r
335         \r
336         \r
337          @Override\r
338         protected void dragMoveEvent(QDragMoveEvent event) {\r
339                // if (event.mimeData().hasFormat("text/plain") &&\r
340                      //event.answerRect().intersects(dropFrame.geometry()))\r
341                         QTreeWidgetItem treeItem = itemAt(event.pos().x(), event.pos().y());\r
342                         if (treeItem != null) {\r
343 /*                              if (!previousMouseOver.text(0).equalsIgnoreCase(treeItem.text(0))) {\r
344                                         previousMouseOver.setSelected(previousMouseOverWasSelected);\r
345                                         previousMouseOverWasSelected = treeItem.isSelected();\r
346                                         previousMouseOver = treeItem;\r
347                                         blockSignals(true);\r
348                                         treeItem.setSelected(true);\r
349                                         blockSignals(false);\r
350                                 }\r
351 */                              \r
352                         }\r
353                         if (event.mimeData().hasFormat("application/x-nevernote-note")) {\r
354                                 if (event.answerRect().intersects(childrenRect()))\r
355                                         event.acceptProposedAction();\r
356                                 return;\r
357                         }\r
358             }\r
359 \r
360         \r
361         @Override\r
362         public boolean dropMimeData(QTreeWidgetItem parent, int index, QMimeData data, Qt.DropAction action) {\r
363                 if (data.hasFormat("application/x-nevernote-notebook")) {\r
364                         return false;\r
365                 }\r
366                 \r
367                 if (data.hasFormat("application/x-nevernote-notebook")) {\r
368                         QByteArray d = data.data("application/x-nevernote-notebook");\r
369                         String current = d.toString();\r
370                         \r
371                         // If dropping to the top level, then remove the stack\r
372                         if (parent == null) {\r
373                                 db.getNotebookTable().clearStack(current);\r
374                                 return true;\r
375                         } \r
376                         \r
377                         // If trying to drop under the "All notebooks" then ignore\r
378                         if (parent.text(2).equals(""))\r
379                                 return false;\r
380                         \r
381                         \r
382                         // If we are NOT droping directly onto the stack icon\r
383                         // we need to find the stack widget\r
384                         String stackName;\r
385                         QTreeWidgetItem stackItem;\r
386                         List<QTreeWidgetItem> currentItems = selectedItems();\r
387                         if (!parent.text(2).equalsIgnoreCase("STACK")) {\r
388                                 \r
389                                 // If a parent stack exists, then use it.\r
390                                 if (parent.parent() != null) {\r
391                                         stackName = parent.parent().text(0);\r
392                                         stackItem = parent.parent();\r
393                                 } else {\r
394                                         \r
395                                         currentItems.add(parent);\r
396                                         // If a stack doesn't exist, then we need to create one\r
397                                         stackName = "New Stack";        \r
398                                         // Find a new stack name that isn't in use\r
399                                         for (int i=1; i<101; i++) {\r
400                                                 if (stacks.containsKey(stackName))\r
401                                                         stackName = "New Stack(" +new Integer(i).toString() + ")";\r
402                                                 else\r
403                                                         break;\r
404                                         }\r
405                                         db.getNotebookTable().setStack(parent.text(2), stackName);\r
406                                         Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
407                                         stackItem = createStackIcon(stackName, ra);\r
408                                         addTopLevelItem(stackItem);\r
409                                 }\r
410                         } else {\r
411                                 stackName = parent.text(0);\r
412                                 stackItem = parent;\r
413                         }\r
414                         \r
415                         List<QTreeWidgetItem> newItems = new ArrayList<QTreeWidgetItem>();\r
416                         for (int i=0; i<currentItems.size(); i++) {\r
417                                 newItems.add(copyTreeItem(currentItems.get(i)));\r
418                                 currentItems.get(i).setHidden(true);\r
419                         }\r
420                         db.getNotebookTable().setStack(current, stackName);             \r
421                         stackItem.addChildren(newItems);\r
422                         \r
423                         return true;\r
424                 }\r
425                 \r
426                 \r
427                 // If we are dropping a note onto a notebook\r
428                 if (data.hasFormat("application/x-nevernote-note")) {\r
429                         QByteArray d = data.data("application/x-nevernote-note");\r
430                         String s = d.toString();\r
431                         String noteGuidArray[] = s.split(" ");\r
432                         for (String element : noteGuidArray) {\r
433                                 if (!parent.text(0).equalsIgnoreCase("All Notebooks") && \r
434                                                 !parent.text(2).equalsIgnoreCase("STACK"))\r
435                                         noteSignal.notebookChanged.emit(element.trim(), parent.text(2));\r
436                         }\r
437                         return true;\r
438                 }\r
439                 return false;\r
440         }\r
441         \r
442 \r
443         private QTreeWidgetItem createStackIcon(String stackName, Qt.Alignment ra) {\r
444                 String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
445                 QIcon stackIcon;\r
446                 stackIcon = db.getSystemIconTable().getIcon(stackName, "STACK");\r
447                 \r
448                 if (stackIcon == null)\r
449                         stackIcon = new QIcon(iconPath+"books2.png");\r
450                 QTreeWidgetItem parent = new QTreeWidgetItem();\r
451                 stacks.put(stackName, parent);\r
452                 parent.setText(0, stackName);\r
453                 parent.setIcon(0, stackIcon);\r
454                 parent.setText(2, "STACK");\r
455                 parent.setTextAlignment(1, ra.value());\r
456                 return parent;\r
457         }\r
458 \r
459         \r
460         \r
461         // Copy an individual item within the tree.  I need to do this because\r
462         // Qt doesn't call the dropMimeData on a move, just a copy.\r
463         private QTreeWidgetItem copyTreeItem(QTreeWidgetItem source) {\r
464                 QTreeWidgetItem target = new QTreeWidgetItem(this);\r
465                 target.setText(0, source.text(0));\r
466                 target.setIcon(0, source.icon(0));\r
467                 target.setText(1, source.text(1));\r
468                 target.setText(2, source.text(2));\r
469                 Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
470                 target.setTextAlignment(1, ra.value());\r
471                 source.setHidden(true);\r
472 \r
473                 return target;\r
474         }\r
475 \r
476 }\r