OSDN Git Service

bdb5eeba710b222f7a04a89387eace50573d2d0d
[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 package cx.fbn.nevernote.gui;
21
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import com.evernote.edam.type.Note;
30 import com.trolltech.qt.QThread;
31 import com.trolltech.qt.core.QByteArray;
32 import com.trolltech.qt.core.QFile;
33 import com.trolltech.qt.core.QSize;
34 import com.trolltech.qt.core.Qt.MouseButton;
35 import com.trolltech.qt.gui.QAction;
36 import com.trolltech.qt.gui.QApplication;
37 import com.trolltech.qt.gui.QContextMenuEvent;
38 import com.trolltech.qt.gui.QListWidget;
39 import com.trolltech.qt.gui.QListWidgetItem;
40 import com.trolltech.qt.gui.QMenu;
41
42 import cx.fbn.nevernote.Global;
43 import cx.fbn.nevernote.NeverNote;
44 import cx.fbn.nevernote.sql.DatabaseConnection;
45 import cx.fbn.nevernote.threads.ENRelatedNotesRunner;
46 import cx.fbn.nevernote.threads.ENThumbnailRunner;
47 import cx.fbn.nevernote.threads.SyncRunner;
48 import cx.fbn.nevernote.utilities.ApplicationLogger;
49 import cx.fbn.nevernote.utilities.Pair;
50
51 public class RensoNoteList extends QListWidget {
52         private final DatabaseConnection conn;
53         private final ApplicationLogger logger;
54         private final HashMap<QListWidgetItem, String> rensoNoteListItems;
55         private final HashMap<String, RensoNoteListItem> rensoNoteListTrueItems;
56         private String rensoNotePressedItemGuid;
57         private final QAction openNewTabAction;
58         private final QAction starAction;
59         private final QAction unstarAction;
60         private final QAction excludeNoteAction;
61         private final NeverNote parent;
62         private final QMenu menu;
63         private HashMap<String, Integer> mergedHistory;                         // マージされた操作履歴
64         private final SyncRunner syncRunner;
65         private final ENRelatedNotesRunner enRelatedNotesRunner;
66         private final QThread enRelatedNotesThread;
67         private final HashMap<String, List<String>> enRelatedNotesCache;        // Evernote関連ノートのキャッシュ<guid, 関連ノートリスト>
68         private final ENThumbnailRunner enThumbnailRunner;
69         private final QThread enThumbnailThread;
70         private String guid;
71         private int allPointSum;
72
73         public RensoNoteList(DatabaseConnection c, NeverNote p, SyncRunner syncRunner, ApplicationLogger logger) {
74                 this.logger = logger;
75                 this.logger.log(this.logger.HIGH, "Setting up rensoNoteList");
76                 allPointSum = 0;
77
78                 this.conn = c;
79                 this.parent = p;
80                 this.syncRunner = syncRunner;
81                 
82                 this.guid = new String();
83                 mergedHistory = new HashMap<String, Integer>();
84                 enRelatedNotesCache = new HashMap<String, List<String>>();
85                 this.enRelatedNotesRunner = new ENRelatedNotesRunner(this.syncRunner, this.logger);
86                 this.enRelatedNotesRunner.enRelatedNotesSignal.getENRelatedNotesFinished.connect(this, "enRelatedNotesComplete()");
87                 this.enRelatedNotesRunner.limitSignal.rateLimitReached.connect(parent, "informRateLimit(Integer)");
88                 this.enRelatedNotesThread = new QThread(enRelatedNotesRunner, "ENRelatedNotes Thread");
89                 this.getEnRelatedNotesThread().start();
90                 
91                 this.enThumbnailRunner = new ENThumbnailRunner(this.logger, this.conn);
92                 this.enThumbnailRunner.enThumbnailSignal.getENThumbnailFinished.connect(this, "enThumbnailComplete(String)");
93                 this.enThumbnailRunner.limitSignal.rateLimitReached.connect(parent, "informRateLimit(Integer)");
94                 this.enThumbnailThread = new QThread(enThumbnailRunner, "ENThumbnail Thread");
95                 this.enThumbnailThread.start();
96                 
97                 rensoNoteListItems = new HashMap<QListWidgetItem, String>();
98                 rensoNoteListTrueItems = new HashMap<String, RensoNoteListItem>();
99                 
100                 this.itemPressed.connect(this, "rensoNoteItemPressed(QListWidgetItem)");
101                 
102                 // コンテキストメニュー作成
103                 menu = new QMenu(this);
104                 // 新しいタブで開くアクション生成
105                 openNewTabAction = new QAction(tr("Open in New Tab"), this);
106                 openNewTabAction.setToolTip(tr("Open this note in new tab"));
107                 openNewTabAction.triggered.connect(parent, "openNewTabFromRNL()");
108                 // スターをつけるアクション生成
109                 starAction = new QAction(tr("Add Star"), this);
110                 starAction.setToolTip(tr("Add Star to this item"));
111                 starAction.triggered.connect(parent, "starNote()");
112                 // スターを外すアクション生成
113                 unstarAction = new QAction(tr("Remove Star"), this);
114                 unstarAction.setToolTip(tr("Remove Star from this item"));
115                 unstarAction.triggered.connect(parent, "unstarNote()");
116                 // このノートを除外するアクション生成
117                 excludeNoteAction = new QAction(tr("Exclude"), this);
118                 excludeNoteAction.setToolTip(tr("Exclude this note from RensoNoteList"));
119                 excludeNoteAction.triggered.connect(parent, "excludeNote()");
120                 // コンテキストメニューに登録
121                 menu.addAction(openNewTabAction);
122                 menu.addAction(excludeNoteAction);
123                 menu.aboutToHide.connect(this, "contextMenuHidden()");
124                 
125                 this.logger.log(this.logger.HIGH, "rensoNoteList setup complete");
126         }
127         
128         // オーバーロード
129         // 現在開いているノートの連想ノートリストをリフレッシュ
130         public void refreshRensoNoteList() {
131                 refreshRensoNoteList(guid);
132         }
133
134         // 連想ノートリストをリフレッシュ
135         public void refreshRensoNoteList(String guid) {
136                 logger.log(logger.HIGH, "Entering RensoNoteList.refreshRensoNoteList guid = " + guid);
137
138                 this.clear();
139                 rensoNoteListItems.clear();
140                 rensoNoteListTrueItems.clear();
141                 mergedHistory = new HashMap<String, Integer>();
142
143                 if (!this.isEnabled()) {
144                         return;
145                 }
146                 if (guid == null || guid.equals("")) {
147                         return;
148                 }
149                 
150                 this.guid = guid;
151                 // すでにEvernote関連ノートがキャッシュされているか確認
152                 boolean isCached;
153                 isCached = enRelatedNotesCache.containsKey(guid);
154                 if (!isCached) {        // キャッシュ無し
155                         // Evernoteの関連ノートを別スレッドで取得させる
156                         enRelatedNotesRunner.addGuid(guid);
157                 } else {                        // キャッシュ有り
158                         List<String> relatedNoteGuids = enRelatedNotesCache.get(guid);
159                         addENRelatedNotes(relatedNoteGuids);
160                 }
161                 
162                 calculateHistory(guid);
163                 repaintRensoNoteList(false);
164
165                 logger.log(logger.HIGH, "Leaving RensoNoteList.refreshRensoNoteList");
166         }
167         
168         // 操作履歴をデータベースから取得してノートごとの関連度を算出、その後mergedHistoryに追加
169         private void calculateHistory(String guid) {
170                 logger.log(logger.EXTREME, "Entering RensoNoteList.calculateHistory guid = " + guid);
171                 
172                 // browseHistory<guid, 回数(ポイント)>
173                 HashMap<String, Integer> browseHistory = conn.getHistoryTable().getBehaviorHistory("browse", guid);
174                 addWeight(browseHistory, Global.getBrowseWeight());
175                 mergedHistory = mergeHistory(filterHistory(browseHistory), mergedHistory);
176                 
177                 // copy&pasteHistory<guid, 回数(ポイント)>
178                 HashMap<String, Integer> copyAndPasteHistory = conn.getHistoryTable().getBehaviorHistory("copy & paste", guid);
179                 addWeight(copyAndPasteHistory, Global.getCopyPasteWeight());
180                 mergedHistory = mergeHistory(filterHistory(copyAndPasteHistory), mergedHistory);
181                 
182                 // addNewNoteHistory<guid, 回数(ポイント)>
183                 HashMap<String, Integer> addNewNoteHistory = conn.getHistoryTable().getBehaviorHistory("addNewNote", guid);
184                 addWeight(addNewNoteHistory, Global.getAddNewNoteWeight());
185                 mergedHistory = mergeHistory(filterHistory(addNewNoteHistory), mergedHistory);
186                 
187                 // rensoItemClickHistory<guid, 回数(ポイント)>
188                 HashMap<String, Integer> rensoItemClickHistory = conn.getHistoryTable().getBehaviorHistory("rensoItemClick", guid);
189                 addWeight(rensoItemClickHistory, Global.getRensoItemClickWeight());
190                 mergedHistory = mergeHistory(filterHistory(rensoItemClickHistory), mergedHistory);
191                 
192                 // sameTagHistory<guid, 回数(ポイント)>
193                 HashMap<String, Integer> sameTagHistory = conn.getHistoryTable().getBehaviorHistory("sameTag", guid);
194                 addWeight(sameTagHistory, Global.getSameTagWeight());
195                 mergedHistory = mergeHistory(filterHistory(sameTagHistory), mergedHistory);
196                 
197                 // sameNotebookNoteHistory<guid, 回数(ポイント)>
198                 HashMap<String, Integer> sameNotebookHistory = conn.getHistoryTable().getBehaviorHistory("sameNotebook", guid);
199                 addWeight(sameNotebookHistory, Global.getSameNotebookWeight());
200                 mergedHistory = mergeHistory(filterHistory(sameNotebookHistory), mergedHistory);
201                 logger.log(logger.EXTREME, "Leaving RensoNoteList.calculateHistory");
202         }
203         
204         // 操作回数に重み付けする
205         private void addWeight(HashMap<String, Integer> history, int weight){
206                 logger.log(logger.EXTREME, "Entering RensoNoteList.addWeight");
207                 
208                 Set<String> keySet = history.keySet();
209                 Iterator<String> hist_iterator = keySet.iterator();
210                 while(hist_iterator.hasNext()){
211                         String key = hist_iterator.next();
212                         history.put(key, history.get(key) * weight);
213                 }
214                 
215                 logger.log(logger.EXTREME, "Leaving RensoNoteList.addWeight");
216         }
217         
218         // 連想ノートリストを再描画
219         private void repaintRensoNoteList(boolean needClear) {
220                 logger.log(logger.EXTREME, "Entering RensoNoteList.repaintRensoNoteList");
221                 
222                 if (needClear) {
223                         this.clear();
224                         rensoNoteListItems.clear();
225                         rensoNoteListTrueItems.clear();
226                 }
227                 
228                 if (!this.isEnabled()) {
229                         return;
230                 }
231                 
232                 // すべての関連ポイントの合計を取得(関連度のパーセント算出に利用)
233                 allPointSum = 0;
234                 for (int p : mergedHistory.values()) {
235                         allPointSum += p;
236                 }
237                 
238                 addRensoNoteList(mergedHistory);
239                 
240                 logger.log(logger.EXTREME, "Leaving RensoNoteList.repaintRensoNoteList");
241         }
242         
243         // 引数1と引数2をマージしたハッシュマップを返す
244         private HashMap<String, Integer> mergeHistory(HashMap<String, Integer> History1, HashMap<String, Integer> History2){
245                 logger.log(logger.EXTREME, "Entering RensoNoteList.mergeHistory");
246                 
247                 HashMap<String, Integer> mergedHistory = new HashMap<String, Integer>();
248                 
249                 mergedHistory.putAll(History1);
250                 
251                 Set<String> keySet = History2.keySet();
252                 Iterator<String> hist2_iterator = keySet.iterator();
253                 while(hist2_iterator.hasNext()){
254                         String key = hist2_iterator.next();
255                         if(mergedHistory.containsKey(key)){
256                                 mergedHistory.put(key, mergedHistory.get(key) + History2.get(key));
257                         }else {
258                                 mergedHistory.put(key, History2.get(key));
259                         }
260                 }
261                 
262                 logger.log(logger.EXTREME, "Leaving RensoNoteList.mergeHistory");
263                 return mergedHistory;
264         }
265         
266         // 連想ノートリストにハッシュマップのデータを追加
267         private void addRensoNoteList(HashMap<String, Integer> History){
268                 logger.log(logger.EXTREME, "Entering RensoNoteList.addRensoNoteList");
269                 
270                 enThumbnailRunner.setUser(Global.getUserInformation());
271                 enThumbnailRunner.setServerUrl(Global.getServer());
272                 
273                 String currentNoteGuid = new String(parent.getCurrentNoteGuid());
274                 
275                 // スター付きノートとスター無しノートを分ける
276                 HashMap<String, Integer> staredNotes = new HashMap<String, Integer>();  // スター付きノートのマップ
277                 HashMap<String, Integer> normalNotes = new HashMap<String, Integer>();  // スター無しノートのマップ
278                 for (String nextGuid: History.keySet()) {
279                         int relationPoint = History.get(nextGuid);
280                         boolean isStared = conn.getStaredTable().existNote(currentNoteGuid, nextGuid);
281                         if (isStared) {
282                                 staredNotes.put(nextGuid, relationPoint);
283                         } else {
284                                 normalNotes.put(nextGuid, relationPoint);
285                         }
286                 }
287                 
288                 // 連想ノートリストアイテムの最大表示数まで繰り返す
289                 for (int i = 0; i < Global.getRensoListItemMaximum(); i++) {
290                         // スター付きノートがあれば先に処理する
291                         HashMap<String, Integer> tmpMap = new HashMap<String, Integer>();
292                         if (!staredNotes.isEmpty()) {
293                                 tmpMap = staredNotes;
294                         }else if (!normalNotes.isEmpty()) {
295                                 tmpMap = normalNotes;
296                         }
297                         
298                         // 操作回数が多い順に取り出して連想ノートリストに追加する
299                         if (!tmpMap.isEmpty()) {
300                                 int maxNum = -1;
301                                 String maxGuid = new String();
302                                 
303                                 for (String nextGuid: tmpMap.keySet()) {
304                                         int relationPoint = tmpMap.get(nextGuid);
305                                         
306                                         // 最大ノート探索する
307                                         if (relationPoint > maxNum) {
308                                                 maxNum = relationPoint;
309                                                 maxGuid = nextGuid;
310                                         }
311                                 }
312                                 
313                                 // 次の最大値探索で邪魔なので最大値をHashMapから削除
314                                 tmpMap.remove(maxGuid);
315         
316                                 // 関連度最大のノートがアクティブか確認
317                                 Note maxNote = conn.getNoteTable().getNote(maxGuid, true, false, false, false, true);
318                                 boolean isNoteActive = false;
319                                 if(maxNote != null) {
320                                         isNoteActive = maxNote.isActive();
321                                 }
322                                 
323                                 // 存在していて、かつ関連度0でなければノート情報を取得して連想ノートリストに追加
324                                 if (isNoteActive && maxNum > 0) {
325                                         // Evernoteサムネイルが取得済みか確認。未取得ならサムネイル取得スレッドにキュー
326                                         if (Global.isConnected) {
327                                                 String thumbnailName = Global.getFileManager().getResDirPath("enThumbnail-" + maxGuid + ".png");
328                                                 QFile thumbnail = new QFile(thumbnailName);
329                                                 if (!thumbnail.exists()) {      // Evernoteサムネイルがファイルとして存在しない
330                                                         QByteArray data = conn.getNoteTable().getENThumbnail(maxGuid);
331                                                         if (data == null) {     // Evernoteサムネイル未取得
332                                                                 enThumbnailRunner.addGuid(maxGuid);
333                                                         }
334                                                 }
335                                         }
336                                         
337                                         // スター付きか確認
338                                         boolean isStared;
339                                         isStared = conn.getStaredTable().existNote(currentNoteGuid, maxGuid);
340                                         
341                                         QListWidgetItem item = new QListWidgetItem();
342                                         RensoNoteListItem myItem = new RensoNoteListItem(maxNote, maxNum, isStared, allPointSum, conn, this);
343                                         item.setSizeHint(new QSize(0, 90));
344                                         this.addItem(item);
345                                         this.setItemWidget(item, myItem);
346                                         rensoNoteListItems.put(item, maxGuid);
347                                         rensoNoteListTrueItems.put(maxGuid, myItem);
348                                 } else {
349                                         break;
350                                 }
351                         }
352                 }
353                 logger.log(logger.EXTREME, "Leaving RensoNoteList.addRensoNoteList");
354         }
355
356         // リストのアイテムから対象ノートのguidを取得
357         public String getNoteGuid(QListWidgetItem item) {
358                 return rensoNoteListItems.get(item);
359         }
360         
361         // 関連ノートリストの右クリックメニュー
362         @Override
363         public void contextMenuEvent(QContextMenuEvent event){
364                 logger.log(logger.EXTREME, "Entering RensoNoteList.contextMenuEvent");
365                 
366                 if (rensoNotePressedItemGuid == null || rensoNotePressedItemGuid.equals("")) {
367                         return;
368                 }
369                 
370                 // STAR, UNSTARがあれば、一度消す
371                 List<QAction> menuActions = new ArrayList<QAction>(menu.actions());
372                 if (menuActions.contains(starAction)) {
373                         menu.removeAction(starAction);
374                 }
375                 if (menuActions.contains(unstarAction)) {
376                         menu.removeAction(unstarAction);
377                 }
378                 
379                 // 対象アイテムがスター付きなら「UNSTAR」、スター無しなら「STAR」を追加
380                 String currentNoteGuid = parent.getCurrentNoteGuid();
381                 boolean isExist = conn.getStaredTable().existNote(currentNoteGuid, rensoNotePressedItemGuid);
382                 if (isExist) {
383                         menu.insertAction(excludeNoteAction, unstarAction);
384                 } else {
385                         menu.insertAction(excludeNoteAction, starAction);
386                 }
387                 
388                 // コンテキストメニューを表示
389                 menu.exec(event.globalPos());
390                 
391                 rensoNotePressedItemGuid = null;
392                 
393                 logger.log(logger.EXTREME, "Leaving RensoNoteList.contextMenuEvent");
394         }
395         
396         // コンテキストメニューが表示されているかどうか
397         public boolean isContextMenuVisible() {
398                 return menu.isVisible();
399         }
400         
401         // コンテキストメニューが閉じられた時
402         @SuppressWarnings("unused")
403         private void contextMenuHidden() {
404                 for (RensoNoteListItem item : rensoNoteListTrueItems.values()) {
405                         item.setDefaultBackground();
406                 }
407         }
408         
409         // ユーザが連想ノートリストのアイテムを選択した時の処理
410         @SuppressWarnings("unused")
411         private void rensoNoteItemPressed(QListWidgetItem current) {
412                 logger.log(logger.HIGH, "Entering RensoNoteList.rensoNoteItemPressed");
413                 
414                 rensoNotePressedItemGuid = null;
415                 // 右クリックだったときの処理
416                 if (QApplication.mouseButtons().isSet(MouseButton.RightButton)) {
417                         rensoNotePressedItemGuid = getNoteGuid(current);
418                 }
419                 
420                 logger.log(logger.HIGH, "Leaving RensoNoteList.rensoNoteItemPressed");
421         }
422         
423         // Evernoteの関連ノートの取得が完了
424         @SuppressWarnings("unused")
425         private void enRelatedNotesComplete() {
426                 logger.log(logger.HIGH, "Entering RensoNoteList.enRelatedNotesComplete");
427                 
428                 Pair<String, List<String>> enRelatedNoteGuidPair = enRelatedNotesRunner.getENRelatedNoteGuids();        // <元ノートguid, 関連ノートguidリスト>
429                 
430                 if (enRelatedNoteGuidPair == null) {
431                         return;
432                 }
433                 
434                 String sourceGuid = enRelatedNoteGuidPair.getFirst();
435                 List<String> enRelatedNoteGuids = enRelatedNoteGuidPair.getSecond();
436                 
437                 
438                 if (sourceGuid != null && !sourceGuid.equals("") && enRelatedNoteGuids != null) {       // Evernote関連ノートがnullでなければ
439                         // まずキャッシュに追加
440                         enRelatedNotesCache.put(sourceGuid, enRelatedNoteGuids);
441                         
442                         if (!enRelatedNoteGuids.isEmpty()) {    // Evernote関連ノートが存在していて
443                                 if (sourceGuid.equals(this.guid)) {     // 取得したデータが今開いているノートの関連ノートなら
444                                         // mergedHistoryにEvernote関連ノートを追加してから再描画
445                                         addENRelatedNotes(enRelatedNoteGuids);
446                                         repaintRensoNoteList(true);
447                                 }
448                         }
449                 }
450                 
451                 logger.log(logger.HIGH, "Leaving RensoNoteList.enRelatedNotesComplete");
452         }
453         
454         // Evernote関連ノートの関連度情報をmergedHistoryに追加
455         private void addENRelatedNotes(List<String> relatedNoteGuids) {
456                 logger.log(logger.EXTREME, "Entering RensoNoteList.addENRelatedNotes");
457                 
458                 // Evernote関連ノート<guid, 関連ポイント>
459                 HashMap<String, Integer> enRelatedNotes = new HashMap<String, Integer>();
460                 
461                 for (String relatedGuid : relatedNoteGuids) {
462                         enRelatedNotes.put(relatedGuid, Global.getENRelatedNotesWeight());
463                 }
464                 
465                 mergedHistory = mergeHistory(filterHistory(enRelatedNotes), mergedHistory);
466                 
467                 logger.log(logger.EXTREME, "Leaving RensoNoteList.addENRelatedNotes");
468         }
469         
470         // Evernoteの関連ノート取得スレッドを終了させる
471         public boolean stopThread() {
472                 logger.log(logger.HIGH, "Entering RensoNoteList.stopThread");
473                 
474                 if (!enRelatedNotesRunner.addStop()) {
475                         logger.log(logger.HIGH, "RensoNoteList.stopThread failed(enRelatedNotesRunner)");
476                         return false;
477                 }
478                 if (!enThumbnailRunner.addStop()) {
479                         logger.log(logger.HIGH, "RensoNoteList.stopThread failed(enThumbnailRunner)");
480                         return false;
481                 }
482                 
483                 logger.log(logger.HIGH, "RensoNoteList.stopThread succeeded");
484                 return true;
485         }
486
487         public QThread getEnRelatedNotesThread() {
488                 return enRelatedNotesThread;
489         }
490         
491         public String getGuid() {
492                 return guid;
493         }
494         
495         // ローカルに存在していて、かつアクティブなノートだけを返す
496         private HashMap<String, Integer> filterHistory(HashMap<String, Integer> sourceHistory) {
497                 HashMap<String, Integer> dstHistory = new HashMap<String, Integer>();
498                 
499                 for (String guid : sourceHistory.keySet()) {
500                         if (conn.getNoteTable().exists(guid)) {
501                                 if (conn.getNoteTable().getNote(guid, false, false, false, false, false).isActive()) {
502                                         dstHistory.put(guid, sourceHistory.get(guid));
503                                 }
504                         }
505                 }
506                 
507                 return dstHistory;
508         }
509         
510         /**
511          * Evernoteサムネイルの取得が完了
512          * 
513          * @param guid 現在開いているノートのguid
514          */
515         @SuppressWarnings("unused")
516         private void enThumbnailComplete(String guid) {
517                 logger.log(logger.HIGH, "Entering RensoNoteList.enThumbnailComplete");
518                 
519                 for (Map.Entry<String, RensoNoteListItem> e : rensoNoteListTrueItems.entrySet()) {
520                         // サムネイル取得が完了したノートが現在の連想ノートリストに表示されていたら再描画
521                         if (guid.equals(e.getKey())) {
522                                 e.getValue().repaint();
523                         }
524                 }
525                 
526                 logger.log(logger.HIGH, "Leaving RensoNoteList.enThumbnailComplete");
527         }
528 }