2 * This file is part of NeighborNote
3 * Copyright 2013 Yuki Takahashi
5 * This file may be licensed under the terms of of the
6 * GNU General Public License Version 2 (the ``GPL'').
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.
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.
21 package cx.fbn.nevernote.gui;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
29 import com.evernote.edam.type.Note;
30 import com.trolltech.qt.QThread;
31 import com.trolltech.qt.core.QSize;
32 import com.trolltech.qt.core.Qt.MouseButton;
33 import com.trolltech.qt.gui.QAction;
34 import com.trolltech.qt.gui.QApplication;
35 import com.trolltech.qt.gui.QContextMenuEvent;
36 import com.trolltech.qt.gui.QListWidget;
37 import com.trolltech.qt.gui.QListWidgetItem;
38 import com.trolltech.qt.gui.QMenu;
40 import cx.fbn.nevernote.Global;
41 import cx.fbn.nevernote.NeverNote;
42 import cx.fbn.nevernote.sql.DatabaseConnection;
43 import cx.fbn.nevernote.threads.ENRelatedNotesRunner;
44 import cx.fbn.nevernote.threads.SyncRunner;
45 import cx.fbn.nevernote.utilities.ApplicationLogger;
47 public class RensoNoteList extends QListWidget {
48 private final DatabaseConnection conn;
49 private final ApplicationLogger logger;
50 private final HashMap<QListWidgetItem, String> rensoNoteListItems;
51 private final List<RensoNoteListItem> rensoNoteListTrueItems;
52 private String rensoNotePressedItemGuid;
53 private final QAction openNewTabAction;
54 private final QAction starAction;
55 private final QAction unstarAction;
56 private final QAction excludeNoteAction;
57 private final NeverNote parent;
58 private final QMenu menu;
59 private final SyncRunner syncRunner;
60 private final ENRelatedNotesRunner ENRelatedNotesRunner;
61 private final QThread ENRelatedNotesThread;
62 private int allPointSum;
64 public RensoNoteList(DatabaseConnection c, NeverNote p, SyncRunner syncRunner) {
65 logger = new ApplicationLogger("rensoNoteList.log");
66 logger.log(logger.HIGH, "Setting up rensoNoteList");
71 this.syncRunner = syncRunner;
73 this.ENRelatedNotesRunner = new ENRelatedNotesRunner(this.syncRunner);
74 this.ENRelatedNotesRunner.ENRelatedNotesSignal.getENRelatedNotesFinished.connect(this, "ENRelatedNotesComplete()");
75 this.ENRelatedNotesThread = new QThread(ENRelatedNotesRunner, "ENRelatedNotes Thread");
76 this.ENRelatedNotesThread.start();
78 rensoNoteListItems = new HashMap<QListWidgetItem, String>();
79 rensoNoteListTrueItems = new ArrayList<RensoNoteListItem>();
81 this.itemPressed.connect(this, "rensoNoteItemPressed(QListWidgetItem)");
84 menu = new QMenu(this);
86 openNewTabAction = new QAction(tr("Open in New Tab"), this);
87 openNewTabAction.setToolTip(tr("Open this note in new tab"));
88 openNewTabAction.triggered.connect(parent, "openNewTabFromRNL()");
90 starAction = new QAction(tr("Add Star"), this);
91 starAction.setToolTip(tr("Add Star to this item"));
92 starAction.triggered.connect(parent, "starNote()");
94 unstarAction = new QAction(tr("Remove Star"), this);
95 unstarAction.setToolTip(tr("Remove Star from this item"));
96 unstarAction.triggered.connect(parent, "unstarNote()");
98 excludeNoteAction = new QAction(tr("Exclude"), this);
99 excludeNoteAction.setToolTip(tr("Exclude this note from RensoNoteList"));
100 excludeNoteAction.triggered.connect(parent, "excludeNote()");
102 menu.addAction(openNewTabAction);
103 menu.addAction(excludeNoteAction);
104 menu.aboutToHide.connect(this, "contextMenuHidden()");
106 logger.log(logger.HIGH, "rensoNoteList setup complete");
109 public void refreshRensoNoteList(String guid) {
110 logger.log(logger.HIGH, "Entering RensoNoteList.refreshRensoNoteList");
113 rensoNoteListItems.clear();
114 rensoNoteListTrueItems.clear();
116 if (!this.isEnabled()) {
119 if (guid == null || guid.equals("")) {
123 HashMap<String, Integer> mergedHistory = new HashMap<String, Integer>();
125 // Evernoteの関連ノートを別スレッドで取得
126 ENRelatedNotesRunner.addGuid(guid);
127 // ENRelatedNotesRunner.setGuid(guid);
128 // ENRelatedNotesThread.finished.connect(this, "ENRelatedNotesComplete()");
130 // RelatedResult result = getENRelatedNotes(guid);
131 // List<Note> relatedNotes = new ArrayList<Note>();
132 // if (result != null) {
133 // relatedNotes = result.getNotes();
135 // if (relatedNotes != null && !relatedNotes.isEmpty()) {
136 // HashMap<String, Integer> ENRelatedNotes = new HashMap<String, Integer>();
138 // for (Note relatedNote : relatedNotes) {
139 // String relatedGuid = relatedNote.getGuid();
140 // ENRelatedNotes.put(relatedGuid, 1);
142 // addWeight(ENRelatedNotes, 10);
143 // mergedHistory = mergeHistory(ENRelatedNotes, mergedHistory);
146 // browseHistory<guid, 回数(ポイント)>
147 HashMap<String, Integer> browseHistory = conn.getHistoryTable().getBehaviorHistory("browse", guid);
148 addWeight(browseHistory, Global.getBrowseWeight());
149 mergedHistory = mergeHistory(browseHistory, new HashMap<String, Integer>());
151 // copy&pasteHistory<guid, 回数(ポイント)>
152 HashMap<String, Integer> copyAndPasteHistory = conn.getHistoryTable().getBehaviorHistory("copy & paste", guid);
153 addWeight(copyAndPasteHistory, Global.getCopyPasteWeight());
154 mergedHistory = mergeHistory(copyAndPasteHistory, mergedHistory);
156 // addNewNoteHistory<guid, 回数(ポイント)>
157 HashMap<String, Integer> addNewNoteHistory = conn.getHistoryTable().getBehaviorHistory("addNewNote", guid);
158 addWeight(addNewNoteHistory, Global.getAddNewNoteWeight());
159 mergedHistory = mergeHistory(addNewNoteHistory, mergedHistory);
161 // rensoItemClickHistory<guid, 回数(ポイント)>
162 HashMap<String, Integer> rensoItemClickHistory = conn.getHistoryTable().getBehaviorHistory("rensoItemClick", guid);
163 addWeight(rensoItemClickHistory, Global.getRensoItemClickWeight());
164 mergedHistory = mergeHistory(rensoItemClickHistory, mergedHistory);
166 // sameTagHistory<guid, 回数(ポイント)>
167 HashMap<String, Integer> sameTagHistory = conn.getHistoryTable().getBehaviorHistory("sameTag", guid);
168 addWeight(sameTagHistory, Global.getSameTagWeight());
169 mergedHistory = mergeHistory(sameTagHistory, mergedHistory);
171 // sameNotebookNoteHistory<guid, 回数(ポイント)>
172 HashMap<String, Integer> sameNotebookHistory = conn.getHistoryTable().getBehaviorHistory("sameNotebook", guid);
173 addWeight(sameNotebookHistory, Global.getSameNotebookWeight());
174 mergedHistory = mergeHistory(sameNotebookHistory, mergedHistory);
176 // すべての関連ポイントの合計を取得(関連度のパーセント算出に利用)
178 for (int p : mergedHistory.values()) {
182 addRensoNoteList(mergedHistory);
184 logger.log(logger.HIGH, "Leaving RensoNoteList.refreshRensoNoteList");
187 // private RelatedResult getENRelatedNotes(String guid) {
188 // RelatedQuery rquery = new RelatedQuery();
189 // rquery.setNoteGuid(guid);
190 // RelatedResultSpec resultSpec = new RelatedResultSpec();
191 // resultSpec.setMaxNotes(Constants.EDAM_RELATED_MAX_NOTES);
192 // if (syncRunner != null && syncRunner.localNoteStore != null) {
194 // RelatedResult result = syncRunner.localNoteStore.findRelated(syncRunner.authToken, rquery, resultSpec);
196 // } catch (EDAMUserException e) {
197 // // TODO 自動生成された catch ブロック
198 // e.printStackTrace();
199 // } catch (EDAMSystemException e) {
200 // // TODO 自動生成された catch ブロック
201 // e.printStackTrace();
202 // } catch (EDAMNotFoundException e) {
203 // // TODO 自動生成された catch ブロック
204 // e.printStackTrace();
205 // } catch (TException e) {
206 // // TODO 自動生成された catch ブロック
207 // e.printStackTrace();
214 private void addWeight(HashMap<String, Integer> history, int weight){
215 Set<String> keySet = history.keySet();
216 Iterator<String> hist_iterator = keySet.iterator();
217 while(hist_iterator.hasNext()){
218 String key = hist_iterator.next();
219 history.put(key, history.get(key) * weight);
223 // 引数1と引数2をマージしたハッシュマップを返す
224 private HashMap<String, Integer> mergeHistory(HashMap<String, Integer> History1, HashMap<String, Integer> History2){
225 HashMap<String, Integer> mergedHistory = new HashMap<String, Integer>();
227 mergedHistory.putAll(History1);
229 Set<String> keySet = History2.keySet();
230 Iterator<String> hist2_iterator = keySet.iterator();
231 while(hist2_iterator.hasNext()){
232 String key = hist2_iterator.next();
233 if(mergedHistory.containsKey(key)){
234 mergedHistory.put(key, mergedHistory.get(key) + History2.get(key));
236 mergedHistory.put(key, History2.get(key));
240 return mergedHistory;
243 private void addRensoNoteList(HashMap<String, Integer> History){
244 String currentNoteGuid = new String(parent.getCurrentNoteGuid());
246 // スター付きノートとスター無しノートを分ける
247 HashMap<String, Integer> staredNotes = new HashMap<String, Integer>(); // スター付きノートのマップ
248 HashMap<String, Integer> normalNotes = new HashMap<String, Integer>(); // スター無しノートのマップ
249 for (String nextGuid: History.keySet()) {
250 int relationPoint = History.get(nextGuid);
251 boolean isStared = conn.getStaredTable().existNote(currentNoteGuid, nextGuid);
253 staredNotes.put(nextGuid, relationPoint);
255 normalNotes.put(nextGuid, relationPoint);
259 // 連想ノートリストアイテムの最大表示数まで繰り返す
260 for (int i = 0; i < Global.getRensoListItemMaximum(); i++) {
261 // スター付きノートがあれば先に処理する
262 HashMap<String, Integer> tmpMap = new HashMap<String, Integer>();
263 if (!staredNotes.isEmpty()) {
264 tmpMap = staredNotes;
265 }else if (!normalNotes.isEmpty()) {
266 tmpMap = normalNotes;
269 // 操作回数が多い順に取り出して連想ノートリストに追加する
270 if (!tmpMap.isEmpty()) {
272 String maxGuid = new String();
274 for (String nextGuid: tmpMap.keySet()) {
275 int relationPoint = tmpMap.get(nextGuid);
278 if (relationPoint > maxNum) {
279 maxNum = relationPoint;
284 // 次の最大値探索で邪魔なので最大値をHashMapから削除
285 tmpMap.remove(maxGuid);
287 // 関連度最大のノートがアクティブか確認
288 Note maxNote = conn.getNoteTable().getNote(maxGuid, true, false, false, false, true);
289 boolean isNoteActive = false;
290 if(maxNote != null) {
291 isNoteActive = maxNote.isActive();
294 // 存在していて、かつ関連度0でなければノート情報を取得して連想ノートリストに追加
295 if (isNoteActive && maxNum > 0) {
298 isStared = conn.getStaredTable().existNote(currentNoteGuid, maxGuid);
300 QListWidgetItem item = new QListWidgetItem();
301 RensoNoteListItem myItem = new RensoNoteListItem(maxNote, maxNum, isStared, allPointSum, conn, this);
302 item.setSizeHint(new QSize(0, 90));
304 this.setItemWidget(item, myItem);
305 rensoNoteListItems.put(item, maxGuid);
306 rensoNoteListTrueItems.add(myItem);
314 // リストのアイテムから対象ノートのguidを取得
315 public String getNoteGuid(QListWidgetItem item) {
316 return rensoNoteListItems.get(item);
319 // 関連ノートリストの右クリックメニュー
321 public void contextMenuEvent(QContextMenuEvent event){
322 if (rensoNotePressedItemGuid == null || rensoNotePressedItemGuid.equals("")) {
326 // STAR, UNSTARがあれば、一度消す
327 List<QAction> menuActions = new ArrayList<QAction>(menu.actions());
328 if (menuActions.contains(starAction)) {
329 menu.removeAction(starAction);
331 if (menuActions.contains(unstarAction)) {
332 menu.removeAction(unstarAction);
335 // 対象アイテムがスター付きなら「UNSTAR」、スター無しなら「STAR」を追加
336 String currentNoteGuid = parent.getCurrentNoteGuid();
337 boolean isExist = conn.getStaredTable().existNote(currentNoteGuid, rensoNotePressedItemGuid);
339 menu.insertAction(excludeNoteAction, unstarAction);
341 menu.insertAction(excludeNoteAction, starAction);
345 menu.exec(event.globalPos());
347 rensoNotePressedItemGuid = null;
350 // コンテキストメニューが表示されているかどうか
351 public boolean isContextMenuVisible() {
352 return menu.isVisible();
356 @SuppressWarnings("unused")
357 private void contextMenuHidden() {
358 for (int i = 0; i < rensoNoteListTrueItems.size(); i++) {
359 RensoNoteListItem item = rensoNoteListTrueItems.get(i);
360 item.setDefaultBackground();
364 // ユーザが連想ノートリストのアイテムを選択した時の処理
365 @SuppressWarnings("unused")
366 private void rensoNoteItemPressed(QListWidgetItem current) {
367 rensoNotePressedItemGuid = null;
369 if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) {
370 rensoNotePressedItemGuid = getNoteGuid(current);
374 // Evernoteの関連ノートの取得が完了
375 @SuppressWarnings("unused")
376 private void ENRelatedNotesComplete() {
377 // List<String> relatedNoteGuids = ENRelatedNotesRunner.getRelatedGuids();
378 List<String> relatedNoteGuids = ENRelatedNotesRunner.getENRelatedNoteGuids();
379 System.out.println(relatedNoteGuids);
382 // Evernoteの関連ノート取得スレッドを終了させる
383 public void stopThread() {
384 ENRelatedNotesRunner.setKeepRunning(false);
385 // TODO keepRunningをfalseにしても、guidQueueが次のキューが来るまで待機するので終了できない。guidQueueに終了命令を処理できる仕組みを要追加。