OSDN Git Service

747a4f675d5fd2192acf9efddc571ca5a5d392e4
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / gui / RensoNoteList.java
1 /*
2  * This file is part of NeighborNote
3  * Copyright 2013 Yuki Takahashi
4  * 
5  * This file may be licensed under the terms of of the
6  * GNU General Public License Version 2 (the ``GPL'').
7  *
8  * Software distributed under the License is distributed
9  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
10  * express or implied. See the GPL for the specific language
11  * governing rights and limitations.
12  *
13  * You should have received a copy of the GPL along with this
14  * program. If not, go to http://www.gnu.org/licenses/gpl.html
15  * or write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18 */
19
20 // ICHANGED
21 package cx.fbn.nevernote.gui;
22
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Set;
28
29 import com.evernote.edam.error.EDAMNotFoundException;
30 import com.evernote.edam.error.EDAMSystemException;
31 import com.evernote.edam.error.EDAMUserException;
32 import com.evernote.edam.limits.Constants;
33 import com.evernote.edam.notestore.RelatedQuery;
34 import com.evernote.edam.notestore.RelatedResult;
35 import com.evernote.edam.notestore.RelatedResultSpec;
36 import com.evernote.edam.type.Note;
37 import com.evernote.thrift.TException;
38 import com.trolltech.qt.core.QSize;
39 import com.trolltech.qt.core.Qt.MouseButton;
40 import com.trolltech.qt.gui.QAction;
41 import com.trolltech.qt.gui.QApplication;
42 import com.trolltech.qt.gui.QContextMenuEvent;
43 import com.trolltech.qt.gui.QListWidget;
44 import com.trolltech.qt.gui.QListWidgetItem;
45 import com.trolltech.qt.gui.QMenu;
46
47 import cx.fbn.nevernote.Global;
48 import cx.fbn.nevernote.NeverNote;
49 import cx.fbn.nevernote.sql.DatabaseConnection;
50 import cx.fbn.nevernote.threads.SyncRunner;
51 import cx.fbn.nevernote.utilities.ApplicationLogger;
52
53 public class RensoNoteList extends QListWidget {
54         private final DatabaseConnection conn;
55         private final ApplicationLogger logger;
56         private final HashMap<QListWidgetItem, String> rensoNoteListItems;
57         private final List<RensoNoteListItem> rensoNoteListTrueItems;
58         private String rensoNotePressedItemGuid;
59         
60         private final QAction openNewTabAction;
61         private final QAction starAction;
62         private final QAction unstarAction;
63         private final QAction excludeNoteAction;
64         private final NeverNote parent;
65         private final QMenu menu;
66         private final SyncRunner syncRunner;
67         private int allPointSum;
68
69         public RensoNoteList(DatabaseConnection c, NeverNote p, SyncRunner syncRunner) {
70                 logger = new ApplicationLogger("rensoNoteList.log");
71                 logger.log(logger.HIGH, "Setting up rensoNoteList");
72                 allPointSum = 0;
73
74                 this.conn = c;
75                 this.parent = p;
76                 this.syncRunner = syncRunner;
77                 rensoNoteListItems = new HashMap<QListWidgetItem, String>();
78                 rensoNoteListTrueItems = new ArrayList<RensoNoteListItem>();
79                 
80                 this.itemPressed.connect(this, "rensoNoteItemPressed(QListWidgetItem)");
81                 
82                 // コンテキストメニュー作成
83                 menu = new QMenu(this);
84                 // 新しいタブで開くアクション生成
85                 openNewTabAction = new QAction(tr("Open in New Tab"), this);
86                 openNewTabAction.setToolTip(tr("Open this note in new tab"));
87                 openNewTabAction.triggered.connect(parent, "openNewTabFromRNL()");
88                 // スターをつけるアクション生成
89                 starAction = new QAction(tr("Add Star"), this);
90                 starAction.setToolTip(tr("Add Star to this item"));
91                 starAction.triggered.connect(parent, "starNote()");
92                 // スターを外すアクション生成
93                 unstarAction = new QAction(tr("Remove Star"), this);
94                 unstarAction.setToolTip(tr("Remove Star from this item"));
95                 unstarAction.triggered.connect(parent, "unstarNote()");
96                 // このノートを除外するアクション生成
97                 excludeNoteAction = new QAction(tr("Exclude"), this);
98                 excludeNoteAction.setToolTip(tr("Exclude this note from RensoNoteList"));
99                 excludeNoteAction.triggered.connect(parent, "excludeNote()");
100                 // コンテキストメニューに登録
101                 menu.addAction(openNewTabAction);
102                 menu.addAction(excludeNoteAction);
103                 menu.aboutToHide.connect(this, "contextMenuHidden()");
104                 
105                 logger.log(logger.HIGH, "rensoNoteList setup complete");
106         }
107
108         public void refreshRensoNoteList(String guid) {
109                 logger.log(logger.HIGH, "Entering RensoNoteList.refreshRensoNoteList");
110
111                 this.clear();
112                 rensoNoteListItems.clear();
113                 rensoNoteListTrueItems.clear();
114
115                 if (!this.isEnabled()) {
116                         return;
117                 }
118                 if (guid == null || guid.equals("")) {
119                         return;
120                 }
121
122                 HashMap<String, Integer> mergedHistory = new HashMap<String, Integer>();
123                 
124                 // browseHistory<guid, 回数(ポイント)>
125                 HashMap<String, Integer> browseHistory = conn.getHistoryTable().getBehaviorHistory("browse", guid);
126                 addWeight(browseHistory, Global.getBrowseWeight());
127                 mergedHistory = mergeHistory(browseHistory, new HashMap<String, Integer>());
128                 
129                 // copy&pasteHistory<guid, 回数(ポイント)>
130                 HashMap<String, Integer> copyAndPasteHistory = conn.getHistoryTable().getBehaviorHistory("copy & paste", guid);
131                 addWeight(copyAndPasteHistory, Global.getCopyPasteWeight());
132                 mergedHistory = mergeHistory(copyAndPasteHistory, mergedHistory);
133                 
134                 // addNewNoteHistory<guid, 回数(ポイント)>
135                 HashMap<String, Integer> addNewNoteHistory = conn.getHistoryTable().getBehaviorHistory("addNewNote", guid);
136                 addWeight(addNewNoteHistory, Global.getAddNewNoteWeight());
137                 mergedHistory = mergeHistory(addNewNoteHistory, mergedHistory);
138                 
139                 // rensoItemClickHistory<guid, 回数(ポイント)>
140                 HashMap<String, Integer> rensoItemClickHistory = conn.getHistoryTable().getBehaviorHistory("rensoItemClick", guid);
141                 addWeight(rensoItemClickHistory, Global.getRensoItemClickWeight());
142                 mergedHistory = mergeHistory(rensoItemClickHistory, mergedHistory);
143                 
144                 // sameTagHistory<guid, 回数(ポイント)>
145                 HashMap<String, Integer> sameTagHistory = conn.getHistoryTable().getBehaviorHistory("sameTag", guid);
146                 addWeight(sameTagHistory, Global.getSameTagWeight());
147                 mergedHistory = mergeHistory(sameTagHistory, mergedHistory);
148                 
149                 // sameNotebookNoteHistory<guid, 回数(ポイント)>
150                 HashMap<String, Integer> sameNotebookHistory = conn.getHistoryTable().getBehaviorHistory("sameNotebook", guid);
151                 addWeight(sameNotebookHistory, Global.getSameNotebookWeight());
152                 mergedHistory = mergeHistory(sameNotebookHistory, mergedHistory);
153                 
154                 // Evernoteの関連ノートを取得
155                 RelatedResult result = getENRelatedNotes(guid);
156                 List<Note> relatedNotes = new ArrayList<Note>();
157                 if (result != null) {
158                         relatedNotes = result.getNotes();
159                 }
160                 if (relatedNotes != null && !relatedNotes.isEmpty()) {
161                         HashMap<String, Integer> ENRelatedNotes = new HashMap<String, Integer>();
162                         
163                         for (Note relatedNote : relatedNotes) {
164                                 String relatedGuid = relatedNote.getGuid();
165                                 ENRelatedNotes.put(relatedGuid, 1);
166                         }
167                         addWeight(ENRelatedNotes, 10);
168                         mergedHistory = mergeHistory(ENRelatedNotes, mergedHistory);
169                 }
170                 
171                 // すべての関連ポイントの合計を取得(関連度のパーセント算出に利用)
172                 allPointSum = 0;
173                 for (int p : mergedHistory.values()) {
174                         allPointSum += p;
175                 }
176                 
177                 addRensoNoteList(mergedHistory);
178
179                 logger.log(logger.HIGH, "Leaving RensoNoteList.refreshRensoNoteList");
180         }
181         
182         private RelatedResult getENRelatedNotes(String guid) {
183                 RelatedQuery rquery = new RelatedQuery();
184                 rquery.setNoteGuid(guid);
185                 RelatedResultSpec resultSpec = new RelatedResultSpec();
186                 resultSpec.setMaxNotes(Constants.EDAM_RELATED_MAX_NOTES);
187                 if (syncRunner != null && syncRunner.localNoteStore != null) {
188                         try {
189                                 RelatedResult result = syncRunner.localNoteStore.findRelated(syncRunner.authToken, rquery, resultSpec);
190                                 return result;
191                         } catch (EDAMUserException e) {
192                                 // TODO 自動生成された catch ブロック
193                                 e.printStackTrace();
194                         } catch (EDAMSystemException e) {
195                                 // TODO 自動生成された catch ブロック
196                                 e.printStackTrace();
197                         } catch (EDAMNotFoundException e) {
198                                 // TODO 自動生成された catch ブロック
199                                 e.printStackTrace();
200                         } catch (TException e) {
201                                 // TODO 自動生成された catch ブロック
202                                 e.printStackTrace();
203                         }
204                 }
205                 return null;
206         }
207
208         // 操作回数に重み付けする
209         private void addWeight(HashMap<String, Integer> history, int weight){
210                 Set<String> keySet = history.keySet();
211                 Iterator<String> hist_iterator = keySet.iterator();
212                 while(hist_iterator.hasNext()){
213                         String key = hist_iterator.next();
214                         history.put(key, history.get(key) * weight);
215                 }
216         }
217         
218         // 引数1と引数2をマージしたハッシュマップを返す
219         private HashMap<String, Integer> mergeHistory(HashMap<String, Integer> History1, HashMap<String, Integer> History2){
220                 HashMap<String, Integer> mergedHistory = new HashMap<String, Integer>();
221                 
222                 mergedHistory.putAll(History1);
223                 
224                 Set<String> keySet = History2.keySet();
225                 Iterator<String> hist2_iterator = keySet.iterator();
226                 while(hist2_iterator.hasNext()){
227                         String key = hist2_iterator.next();
228                         if(mergedHistory.containsKey(key)){
229                                 mergedHistory.put(key, mergedHistory.get(key) + History2.get(key));
230                         }else {
231                                 mergedHistory.put(key, History2.get(key));
232                         }
233                 }
234
235                 return mergedHistory;
236         }
237         
238         private void addRensoNoteList(HashMap<String, Integer> History){
239                 String currentNoteGuid = new String(parent.getCurrentNoteGuid());
240                 
241                 // スター付きノートとスター無しノートを分ける
242                 HashMap<String, Integer> staredNotes = new HashMap<String, Integer>();  // スター付きノートのマップ
243                 HashMap<String, Integer> normalNotes = new HashMap<String, Integer>();  // スター無しノートのマップ
244                 for (String nextGuid: History.keySet()) {
245                         int relationPoint = History.get(nextGuid);
246                         boolean isStared = conn.getStaredTable().existNote(currentNoteGuid, nextGuid);
247                         if (isStared) {
248                                 staredNotes.put(nextGuid, relationPoint);
249                         } else {
250                                 normalNotes.put(nextGuid, relationPoint);
251                         }
252                 }
253                 
254                 // 連想ノートリストアイテムの最大表示数まで繰り返す
255                 for (int i = 0; i < Global.getRensoListItemMaximum(); i++) {
256                         // スター付きノートがあれば先に処理する
257                         HashMap<String, Integer> tmpMap = new HashMap<String, Integer>();
258                         if (!staredNotes.isEmpty()) {
259                                 tmpMap = staredNotes;
260                         }else if (!normalNotes.isEmpty()) {
261                                 tmpMap = normalNotes;
262                         }
263                         
264                         // 操作回数が多い順に取り出して連想ノートリストに追加する
265                         if (!tmpMap.isEmpty()) {
266                                 int maxNum = -1;
267                                 String maxGuid = new String();
268                                 
269                                 for (String nextGuid: tmpMap.keySet()) {
270                                         int relationPoint = tmpMap.get(nextGuid);
271                                         
272                                         // 最大ノート探索する
273                                         if (relationPoint > maxNum) {
274                                                 maxNum = relationPoint;
275                                                 maxGuid = nextGuid;
276                                         }
277                                 }
278                                 
279                                 // 次の最大値探索で邪魔なので最大値をHashMapから削除
280                                 tmpMap.remove(maxGuid);
281         
282                                 // 関連度最大のノートがアクティブか確認
283                                 Note maxNote = conn.getNoteTable().getNote(maxGuid, true, false, false, false, true);
284                                 boolean isNoteActive = false;
285                                 if(maxNote != null) {
286                                         isNoteActive = maxNote.isActive();
287                                 }
288                                 
289                                 // 存在していて、かつ関連度0でなければノート情報を取得して連想ノートリストに追加
290                                 if (isNoteActive && maxNum > 0) {
291                                         // スター付きか確認
292                                         boolean isStared;
293                                         isStared = conn.getStaredTable().existNote(currentNoteGuid, maxGuid);
294                                         
295                                         QListWidgetItem item = new QListWidgetItem();
296                                         RensoNoteListItem myItem = new RensoNoteListItem(maxNote, maxNum, isStared, allPointSum, conn, this);
297                                         item.setSizeHint(new QSize(0, 90));
298                                         this.addItem(item);
299                                         this.setItemWidget(item, myItem);
300                                         rensoNoteListItems.put(item, maxGuid);
301                                         rensoNoteListTrueItems.add(myItem);
302                                 } else {
303                                         break;
304                                 }
305                         }
306                 }
307         }
308
309         // リストのアイテムから対象ノートのguidを取得
310         public String getNoteGuid(QListWidgetItem item) {
311                 return rensoNoteListItems.get(item);
312         }
313         
314         // 関連ノートリストの右クリックメニュー
315         @Override
316         public void contextMenuEvent(QContextMenuEvent event){
317                 if (rensoNotePressedItemGuid == null || rensoNotePressedItemGuid.equals("")) {
318                         return;
319                 }
320                 
321                 // STAR, UNSTARがあれば、一度消す
322                 List<QAction> menuActions = new ArrayList<QAction>(menu.actions());
323                 if (menuActions.contains(starAction)) {
324                         menu.removeAction(starAction);
325                 }
326                 if (menuActions.contains(unstarAction)) {
327                         menu.removeAction(unstarAction);
328                 }
329                 
330                 // 対象アイテムがスター付きなら「UNSTAR」、スター無しなら「STAR」を追加
331                 String currentNoteGuid = parent.getCurrentNoteGuid();
332                 boolean isExist = conn.getStaredTable().existNote(currentNoteGuid, rensoNotePressedItemGuid);
333                 if (isExist) {
334                         menu.insertAction(excludeNoteAction, unstarAction);
335                 } else {
336                         menu.insertAction(excludeNoteAction, starAction);
337                 }
338                 
339                 // コンテキストメニューを表示
340                 menu.exec(event.globalPos());
341                 
342                 rensoNotePressedItemGuid = null;
343         }
344         
345         // コンテキストメニューが表示されているかどうか
346         public boolean isContextMenuVisible() {
347                 return menu.isVisible();
348         }
349         
350         // コンテキストメニューが閉じられた時
351         @SuppressWarnings("unused")
352         private void contextMenuHidden() {
353                 for (int i = 0; i < rensoNoteListTrueItems.size(); i++) {
354                         RensoNoteListItem item = rensoNoteListTrueItems.get(i);
355                         item.setDefaultBackground();
356                 }
357         }
358         
359         // ユーザが連想ノートリストのアイテムを選択した時の処理
360         @SuppressWarnings("unused")
361         private void rensoNoteItemPressed(QListWidgetItem current) {
362                 rensoNotePressedItemGuid = null;
363                 // 右クリックだったときの処理
364                 if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) {
365                         rensoNotePressedItemGuid = getNoteGuid(current);
366                 }
367         }
368 }