OSDN Git Service

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