OSDN Git Service

Add the ability to add & remove notebook stacks.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / gui / TagTreeWidget.java
1 /*\r
2  * This file is part of NeverNote \r
3  * Copyright 2009,2010 Randy Baumgarte\r
4  * Copyright 2010 Hiroshi Miura\r
5  * \r
6  * This file may be licensed under the terms of of the\r
7  * GNU General Public License Version 2 (the ``GPL'').\r
8  *\r
9  * Software distributed under the License is distributed\r
10  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
11  * express or implied. See the GPL for the specific language\r
12  * governing rights and limitations.\r
13  *\r
14  * You should have received a copy of the GPL along with this\r
15  * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
16  * or write to the Free Software Foundation, Inc.,\r
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
18  *\r
19 */\r
20 \r
21 package cx.fbn.nevernote.gui;\r
22 \r
23 import java.util.ArrayList;\r
24 import java.util.HashMap;\r
25 import java.util.List;\r
26 \r
27 import com.evernote.edam.type.Tag;\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.MatchFlag;\r
32 import com.trolltech.qt.core.Qt.MatchFlags;\r
33 import com.trolltech.qt.core.Qt.SortOrder;\r
34 import com.trolltech.qt.gui.QAbstractItemView;\r
35 import com.trolltech.qt.gui.QAction;\r
36 import com.trolltech.qt.gui.QBrush;\r
37 import com.trolltech.qt.gui.QColor;\r
38 import com.trolltech.qt.gui.QContextMenuEvent;\r
39 import com.trolltech.qt.gui.QDragEnterEvent;\r
40 import com.trolltech.qt.gui.QDragMoveEvent;\r
41 import com.trolltech.qt.gui.QHeaderView;\r
42 import com.trolltech.qt.gui.QIcon;\r
43 import com.trolltech.qt.gui.QMenu;\r
44 import com.trolltech.qt.gui.QTreeWidget;\r
45 import com.trolltech.qt.gui.QTreeWidgetItem;\r
46 \r
47 import cx.fbn.nevernote.Global;\r
48 import cx.fbn.nevernote.filters.TagCounter;\r
49 import cx.fbn.nevernote.signals.NoteSignal;\r
50 import cx.fbn.nevernote.signals.TagSignal;\r
51 import cx.fbn.nevernote.sql.DatabaseConnection;\r
52 \r
53 public class TagTreeWidget extends QTreeWidget {\r
54         private QAction editAction;\r
55         private QAction deleteAction;\r
56         private QAction addAction;\r
57         private QAction iconAction;\r
58         public TagSignal tagSignal;\r
59         public NoteSignal noteSignal;\r
60         private boolean showAllTags;\r
61         private final DatabaseConnection db;\r
62         private HashMap<String, QIcon>  icons;\r
63         \r
64         \r
65         public TagTreeWidget(DatabaseConnection d) {\r
66                 List<String> headers = new ArrayList<String>();\r
67                 headers.add(tr("Tags"));\r
68                 headers.add("");\r
69                 showAllTags = true;\r
70                 setAcceptDrops(true);\r
71                 setDragEnabled(true);\r
72                 setColumnCount(2);\r
73                 header().setResizeMode(0, QHeaderView.ResizeMode.ResizeToContents);\r
74                 header().setResizeMode(1, QHeaderView.ResizeMode.Stretch);\r
75                 header().setMovable(false);\r
76                 db = d;\r
77                 tagSignal = new TagSignal();\r
78                 noteSignal = new NoteSignal();\r
79                 setDragDropMode(QAbstractItemView.DragDropMode.DragDrop);\r
80         setHeaderLabels(headers);\r
81 //      setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection);\r
82         setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection);\r
83         \r
84                 int width = Global.getColumnWidth("tagTreeName");\r
85                 if (width>0)\r
86                         setColumnWidth(0, width);\r
87 \r
88         }\r
89         \r
90         public void setEditAction(QAction e) {\r
91                 editAction = e;\r
92         }\r
93         public void setDeleteAction(QAction d) {\r
94                 deleteAction = d;\r
95         }\r
96         public void setAddAction(QAction a) {\r
97                 addAction = a;\r
98         }\r
99         public void setIconAction(QAction i) {\r
100                 iconAction = i;\r
101         }\r
102         \r
103         // Insert a new tag into the tree.  This is used when we dynamically add a \r
104         // new tag after the full tag tree has been built.  It only adds to the\r
105         // top level.\r
106         public void insertTag(String name, String guid) {\r
107         String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
108                 QIcon icon = new QIcon(iconPath+"tag.png");\r
109                 QTreeWidgetItem child;\r
110                 Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
111                 \r
112                 // Build new tag & add it\r
113                 child = new QTreeWidgetItem();\r
114                 child.setText(0, name);\r
115                 child.setIcon(0,icon);\r
116                 child.setText(2, guid);\r
117                 child.setTextAlignment(1, ra.value());\r
118                 addTopLevelItem(child);\r
119                 \r
120                 // Resort the list\r
121                 resizeColumnToContents(0);\r
122         resizeColumnToContents(1);\r
123         sortItems(0, SortOrder.AscendingOrder);\r
124         }\r
125         \r
126         public void load(List<Tag> tags) {\r
127         Tag tag;\r
128         List<QTreeWidgetItem> index = new ArrayList<QTreeWidgetItem>();\r
129         QTreeWidgetItem child;\r
130                         \r
131         //Clear out the tree & reload\r
132         clear();\r
133         String iconPath = new String("classpath:cx/fbn/nevernote/icons/");\r
134                 QIcon icon = new QIcon(iconPath+"tag.png");\r
135         \r
136                 Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
137         \r
138                 // Create a copy.  We delete them out as they are found\r
139                 List<Tag> tempList = new ArrayList<Tag>();\r
140                 for (int i=0; i<tags.size(); i++) {\r
141                         tempList.add(tags.get(i));\r
142                 }\r
143                 \r
144         while (tempList.size() > 0) {\r
145                 for (int i=0; i<tempList.size(); i++) {\r
146                         tag = tempList.get(i);\r
147                         if (tag.getParentGuid()==null || tag.getParentGuid().equals("")) {\r
148                                 child = new QTreeWidgetItem();\r
149                                 child.setText(0, tag.getName());\r
150                                 if (icons != null && !icons.containsKey(tag.getGuid())) {\r
151                                         child.setIcon(0, icon);\r
152                                 } else {\r
153                                         child.setIcon(0, icons.get(tag.getGuid()));\r
154                                 }\r
155 \r
156                                 child.setText(2, tag.getGuid());\r
157                                 child.setTextAlignment(1, ra.value());\r
158                                 index.add(child);\r
159                                 addTopLevelItem(child);\r
160                                 tempList.remove(i);\r
161                         } else {\r
162                                 // We need to find the parent\r
163                                 for (int j=0; j<index.size(); j++) {\r
164                                         if (index.get(j).text(2).equals(tag.getParentGuid())) {\r
165                                         child = new QTreeWidgetItem();\r
166                                         child.setText(0, tag.getName());\r
167                                         child.setIcon(0, icon);\r
168                                         child.setText(2, tag.getGuid());\r
169                                         child.setTextAlignment(1, ra.value());\r
170                                         tempList.remove(i);\r
171                                         index.add(child);                                               \r
172                                         index.get(j).addChild(child);\r
173                                         }\r
174                                 }\r
175                         }\r
176                 } \r
177         }\r
178         resizeColumnToContents(0);\r
179         resizeColumnToContents(1);\r
180         sortItems(0, SortOrder.AscendingOrder);\r
181         }\r
182         // Show (unhide) all tags\r
183         public void showAllTags(boolean value) {\r
184                 showAllTags = value;\r
185         }\r
186         public void unhideAllTags() {\r
187                 MatchFlags flags = new MatchFlags();\r
188                 flags.set(MatchFlag.MatchWildcard);\r
189                 flags.set(MatchFlag.MatchRecursive);\r
190                 List <QTreeWidgetItem>  children = findItems("*", flags);\r
191                 for (int i=0; i<children.size(); i++) {\r
192                         children.get(i).setHidden(false);\r
193                 }\r
194         }\r
195         // update the display with the current number of notes\r
196         public void updateCounts(List<TagCounter> counts) {\r
197                                 \r
198                 MatchFlags flags = new MatchFlags();\r
199                 flags.set(MatchFlag.MatchWildcard);\r
200                 flags.set(MatchFlag.MatchRecursive);\r
201 //              List<QTreeWidgetItem> children = new ArrayList<QTreeWidgetItem>();\r
202                 List <QTreeWidgetItem>  children = findItems("*", flags);\r
203                 \r
204                 QBrush black = new QBrush();\r
205                 black.setColor(QColor.black);\r
206                 QBrush blue = new QBrush();\r
207                 blue.setColor(QColor.blue);\r
208                 if (!Global.tagBehavior().equalsIgnoreCase("ColorActive"))\r
209                         blue.setColor(QColor.black);\r
210                 \r
211                 for (int i=0; i<children.size(); i++) {\r
212                         children.get(i).setText(1,"0");\r
213                         children.get(i).setForeground(0, black);                        \r
214                         children.get(i).setForeground(1, black);\r
215                         if (!showAllTags && (Global.tagBehavior().equalsIgnoreCase("HideInactiveCount") || Global.tagBehavior().equalsIgnoreCase("NoHideInactiveCount")))\r
216                                 children.get(i).setHidden(true);\r
217                         else\r
218                                 children.get(i).setHidden(false);\r
219                         if (children.get(i).isSelected())\r
220                                 children.get(i).setHidden(false);\r
221                 }\r
222                 for (int i=0; i<counts.size(); i++) {\r
223                         for (int j=0; j<children.size(); j++) {\r
224                                 String guid = children.get(j).text(2);\r
225                                 if (counts.get(i).getGuid().equals(guid)) {\r
226                                         children.get(j).setText(1, new Integer(counts.get(i).getCount()).toString());\r
227                                         if (counts.get(i).getCount() > 0 || children.get(j).isSelected()) {\r
228                                                 children.get(j).setForeground(0, blue);                 \r
229                                                 children.get(j).setForeground(1, blue);\r
230                                                 QTreeWidgetItem parent = children.get(j);\r
231                                                 while (parent != null) {\r
232                                                         parent.setForeground(0, blue);                  \r
233                                                         parent.setForeground(1, blue);\r
234                                                         parent.setHidden(false);\r
235                                                         parent = parent.parent();\r
236                                                 }\r
237                                         }\r
238                                 }\r
239                         }\r
240                 }\r
241         }\r
242 \r
243         \r
244         public boolean selectGuid(String guid) {\r
245                 MatchFlags flags = new MatchFlags();\r
246                 flags.set(MatchFlag.MatchWildcard);\r
247                 flags.set(MatchFlag.MatchRecursive);\r
248 //              List<QTreeWidgetItem> children = new ArrayList<QTreeWidgetItem>();\r
249                 List <QTreeWidgetItem>  children = findItems("*", flags);\r
250 \r
251                 for (int i=0; i<children.size(); i++) {\r
252                         if (children.get(i).text(2).equals(guid)) {\r
253                                 children.get(i).setSelected(true);\r
254                                 return true;\r
255                         }\r
256                 }\r
257                 return false;\r
258         }\r
259         \r
260          @Override\r
261          protected void dragMoveEvent(QDragMoveEvent event) {\r
262                 if (event.mimeData().hasFormat("application/x-nevernote-note")) {\r
263                         if (event.answerRect().intersects(childrenRect()))\r
264                                 event.acceptProposedAction();\r
265                         return;\r
266                 }\r
267          }\r
268 \r
269         \r
270         @Override\r
271         public void dragEnterEvent(QDragEnterEvent event) {\r
272                 if (event.mimeData().hasFormat("application/x-nevernote-note")) {\r
273                         event.accept();\r
274                         return;\r
275                 }\r
276                 if (event.source() == this) {\r
277                         if (Global.tagBehavior().equals("HideInactiveCount")) {\r
278                                 event.ignore();\r
279                                 return;\r
280                         }\r
281                         event.mimeData().setData("application/x-nevernote-tag", new QByteArray(currentItem().text(2)));\r
282                         event.accept();\r
283                         return;\r
284                 }\r
285                 event.ignore();\r
286         }\r
287 \r
288         @Override\r
289         public boolean dropMimeData(QTreeWidgetItem parent, int index, QMimeData data, Qt.DropAction action) {\r
290                 if (data.hasFormat("application/x-nevernote-tag")) {\r
291                         QByteArray d = data.data("application/x-nevernote-tag");\r
292                         String current = d.toString();\r
293                         \r
294                         // Check we don't do a dumb thing like move a parent to a child of itself\r
295                         if (!checkParent(parent, current))\r
296                                 return false;\r
297                         QTreeWidgetItem newChild;\r
298                         if (parent == null) {\r
299 //                              tagSignal.changeParent.emit(current, "");\r
300                                 db.getTagTable().updateTagParent(current, "");\r
301                                 newChild = new QTreeWidgetItem(this);\r
302                         } else {\r
303 //                              tagSignal.changeParent.emit(current, parent.text(2));\r
304                                 db.getTagTable().updateTagParent(current, parent.text(2));\r
305                                 newChild = new QTreeWidgetItem(parent);\r
306                         }\r
307                         copyTreeItem(currentItem(), newChild);\r
308                         currentItem().setHidden(true);\r
309                         sortItems(0, SortOrder.AscendingOrder);\r
310                         return true;\r
311                 }\r
312                 if (data.hasFormat("application/x-nevernote-note")) {\r
313                         QByteArray d = data.data("application/x-nevernote-note");\r
314                         String s = d.toString();\r
315                         String noteGuidArray[] = s.split(" ");\r
316                         for (String element : noteGuidArray) {\r
317                                 if (!db.getNoteTable().noteTagsTable.checkNoteNoteTags(element.trim(), parent.text(2))) {\r
318                                         db.getNoteTable().noteTagsTable.saveNoteTag(element.trim(), parent.text(2));\r
319                                         noteSignal.tagsAdded.emit(element.trim(), parent.text(2));\r
320                                 }\r
321                         }\r
322                         //tagSignal.listChanged.emit();\r
323                         \r
324                         return true;\r
325                 }\r
326                 return false;\r
327         }\r
328         \r
329         @Override\r
330         public void contextMenuEvent(QContextMenuEvent event) {\r
331                 QMenu menu = new QMenu(this);\r
332                 menu.addAction(addAction);\r
333                 menu.addAction(editAction);\r
334                 menu.addAction(deleteAction);\r
335                 menu.addSeparator();\r
336                 menu.addAction(iconAction);\r
337                 menu.exec(event.globalPos());\r
338         }\r
339         \r
340         public void setIcons(HashMap<String, QIcon> i) {\r
341                 icons = i;\r
342         }\r
343         \r
344         // Copy an individual item within the tree.  I need to do this because\r
345         // Qt doesn't call the dropMimeData on a move, just a copy.\r
346         private void copyTreeItem(QTreeWidgetItem source, QTreeWidgetItem target) {\r
347                 target.setText(0, source.text(0));\r
348                 target.setIcon(0, source.icon(0));\r
349                 target.setText(1, source.text(1));\r
350                 target.setText(2, source.text(2));\r
351                 Qt.Alignment ra = new Qt.Alignment(Qt.AlignmentFlag.AlignRight);\r
352                 target.setTextAlignment(1, ra.value());\r
353                 \r
354                 for (int i=0; i<source.childCount(); i++) {\r
355                         QTreeWidgetItem newChild = new QTreeWidgetItem(target);\r
356                         copyTreeItem(source.child(i), newChild);\r
357                         source.child(i).setHidden(true);\r
358                 }\r
359                 return;\r
360         }\r
361         \r
362         // Check that we don't copy a parent as a child of a current child.\r
363         private boolean checkParent(QTreeWidgetItem parent, String child) {\r
364                 if (parent != null)\r
365                         if (parent.text(2).equals(child))\r
366                                 return false;\r
367                 if (parent == null)\r
368                         return true;\r
369                 return checkParent(parent.parent(), child);\r
370         }\r
371 \r
372 \r
373         public void selectSavedSearch(QTreeWidgetItem item) {\r
374                 MatchFlags flags = new MatchFlags();\r
375                 flags.set(MatchFlag.MatchWildcard);\r
376                 flags.set(MatchFlag.MatchRecursive);\r
377                 List <QTreeWidgetItem>  children = findItems("*", flags);\r
378                 \r
379                 for (int j=0; j<children.size(); j++) {\r
380                         String guid = children.get(j).text(2);\r
381                         if (item.text(2).equals(guid)) {\r
382                                 children.get(j).setSelected(true);\r
383                         }\r
384                 }\r
385         }\r
386 }\r