OSDN Git Service

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