comparison demos/browser/history.d @ 77:0654fc9bac95

more porting
author mandel
date Sun, 24 May 2009 13:46:32 +0000
parents 37caa90ce503
children 85c59c4e5f19
comparison
equal deleted inserted replaced
76:454e4b4beb59 77:0654fc9bac95
80 { 80 {
81 public: 81 public:
82 82
83 this() {} 83 this() {}
84 84
85 this(QString u, QDateTime d = QDateTime(), QString t = QString()) 85 this(string u, QDateTime d = QDateTime(), string t = null)
86 { 86 {
87 title = t; 87 title = t;
88 url = u; 88 url = u;
89 dateTime = d; 89 dateTime = d;
90 } 90 }
100 int opCmp(HistoryItem other) 100 int opCmp(HistoryItem other)
101 { 101 {
102 return cast(int) (dateTime > other.dateTime); 102 return cast(int) (dateTime > other.dateTime);
103 } 103 }
104 104
105 QString title; 105 string title;
106 QString url; 106 string url;
107 QDateTime dateTime; 107 QDateTime dateTime;
108 } 108 }
109 109
110 110
111 class HistoryManager : public QWebHistoryInterface 111 class HistoryManager : public QWebHistoryInterface
145 ~this() 145 ~this()
146 { 146 {
147 m_saveTimer.saveIfNeccessary(); 147 m_saveTimer.saveIfNeccessary();
148 } 148 }
149 149
150 bool historyContains(QString url) 150 bool historyContains(string url)
151 { 151 {
152 return m_historyFilterModel.historyContains(url); 152 return m_historyFilterModel.historyContains(url);
153 } 153 }
154 154
155 void addHistoryEntry(QString url) 155 void addHistoryEntry(string url)
156 { 156 {
157 QUrl cleanUrl(url); 157 QUrl cleanUrl(url);
158 cleanUrl.setPassword(QString()); 158 cleanUrl.setPassword(null);
159 cleanUrl.setHost(cleanUrl.host().toLower()); 159 cleanUrl.setHost(toLower(cleanUrl.host()));
160 auto item = new HistoryItem(cleanUrl.toString(), QDateTime.currentDateTime()); 160 auto item = new HistoryItem(cleanUrl.toString(), QDateTime.currentDateTime());
161 addHistoryItem(item); 161 addHistoryItem(item);
162 } 162 }
163 163
164 void updateHistoryItem(QUrl url, QString title) 164 void updateHistoryItem(QUrl url, string title)
165 { 165 {
166 for (int i = 0; i < m_history.count(); ++i) { 166 for (int i = 0; i < m_history.length; ++i) {
167 if (url == m_history.at(i).url) { 167 if (url == m_history[i].url) {
168 m_history[i].title = title; 168 m_history[i].title = title;
169 m_saveTimer.changeOccurred(); 169 m_saveTimer.changeOccurred();
170 if (m_lastSavedUrl.isEmpty()) 170 if (m_lastSavedUrl.isEmpty())
171 m_lastSavedUrl = m_history.at(i).url; 171 m_lastSavedUrl = m_history[i].url;
172 emit entryUpdated(i); 172 entryUpdated.emit(i);
173 break; 173 break;
174 } 174 }
175 } 175 }
176 } 176 }
177 177
205 checkForExpired(); 205 checkForExpired();
206 206
207 if (loadedAndSorted) { 207 if (loadedAndSorted) {
208 m_lastSavedUrl = m_history.value(0).url; 208 m_lastSavedUrl = m_history.value(0).url;
209 } else { 209 } else {
210 m_lastSavedUrl = QString(); 210 m_lastSavedUrl = null;
211 m_saveTimer.changeOccurred(); 211 m_saveTimer.changeOccurred();
212 } 212 }
213 emit historyReset(); 213 historyReset.emit();
214 } 214 }
215 215
216 // History manager keeps around these models for use by the completer and other classes 216 // History manager keeps around these models for use by the completer and other classes
217 HistoryModel historyModel() 217 HistoryModel historyModel()
218 { 218 {
231 231
232 public: 232 public:
233 233
234 void clear() 234 void clear()
235 { 235 {
236 m_history.clear(); 236 m_history = null;
237 m_lastSavedUrl = QString(); 237 m_lastSavedUrl = null;
238 m_saveTimer.changeOccurred(); 238 m_saveTimer.changeOccurred();
239 m_saveTimer.saveIfNeccessary(); 239 m_saveTimer.saveIfNeccessary();
240 historyReset(); 240 historyReset();
241 } 241 }
242 242
255 QSettings settings; 255 QSettings settings;
256 settings.beginGroup(QLatin1String("history")); 256 settings.beginGroup(QLatin1String("history"));
257 settings.setValue(QLatin1String("historyLimit"), m_historyLimit); 257 settings.setValue(QLatin1String("historyLimit"), m_historyLimit);
258 258
259 bool saveAll = m_lastSavedUrl.isEmpty(); 259 bool saveAll = m_lastSavedUrl.isEmpty();
260 int first = m_history.count() - 1; 260 int first = m_history.length - 1;
261 if (!saveAll) { 261 if (!saveAll) {
262 // find the first one to save 262 // find the first one to save
263 for (int i = 0; i < m_history.count(); ++i) { 263 for (int i = 0; i < m_history.length; ++i) {
264 if (m_history.at(i).url == m_lastSavedUrl) { 264 if (m_history[i].url == m_lastSavedUrl) {
265 first = i - 1; 265 first = i - 1;
266 break; 266 break;
267 } 267 }
268 } 268 }
269 } 269 }
270 270
271 if (first == m_history.count() - 1) 271 if (first == m_history.length - 1)
272 saveAll = true; 272 saveAll = true;
273 273
274 QString directory = QDesktopServices.storageLocation(QDesktopServices.DataLocation); 274 string directory = QDesktopServices.storageLocation(QDesktopServices.DataLocation);
275 if (directory.isEmpty()) 275 if (directory.isEmpty())
276 directory = QDir.homePath() + QLatin1String("/.") + QCoreApplication.applicationName(); 276 directory = QDir.homePath() + QLatin1String("/.") + QCoreApplication.applicationName();
277 if (!QFile.exists(directory)) { 277 if (!QFile.exists(directory)) {
278 QDir dir; 278 QDir dir;
279 dir.mkpath(directory); 279 dir.mkpath(directory);
298 298
299 QDataStream out_ = (saveAll ? tempFile : historyFile); 299 QDataStream out_ = (saveAll ? tempFile : historyFile);
300 for (int i = first; i >= 0; --i) { 300 for (int i = first; i >= 0; --i) {
301 QByteArray data; 301 QByteArray data;
302 auto stream = new QDataStream(data, QIODevice.WriteOnly); 302 auto stream = new QDataStream(data, QIODevice.WriteOnly);
303 HistoryItem item = m_history.at(i); 303 HistoryItem item = m_history[i];
304 stream << HISTORY_VERSION << item.url << item.dateTime << item.title; 304 stream << HISTORY_VERSION << item.url << item.dateTime << item.title;
305 out_ << data; 305 out_ << data;
306 } 306 }
307 tempFile.close(); 307 tempFile.close();
308 308
315 m_lastSavedUrl = m_history.value(0).url; 315 m_lastSavedUrl = m_history.value(0).url;
316 } 316 }
317 317
318 void checkForExpired() 318 void checkForExpired()
319 { 319 {
320 if (m_historyLimit < 0 || m_history.isEmpty()) 320 if (m_historyLimit < 0 || m_history.length == 0)
321 return; 321 return;
322 322
323 QDateTime now = QDateTime.currentDateTime(); 323 QDateTime now = QDateTime.currentDateTime();
324 int nextTimeout = 0; 324 int nextTimeout = 0;
325 325
326 while (!m_history.isEmpty()) { 326 while (m_history.length) {
327 QDateTime checkForExpired = m_history.last().dateTime; 327 QDateTime checkForExpired = m_history.last().dateTime;
328 checkForExpired.setDate(checkForExpired.date().addDays(m_historyLimit)); 328 checkForExpired.setDate(checkForExpired.date().addDays(m_historyLimit));
329 if (now.daysTo(checkForExpired) > 7) { 329 if (now.daysTo(checkForExpired) > 7) {
330 // check at most in a week to prevent int overflows on the timer 330 // check at most in a week to prevent int overflows on the timer
331 nextTimeout = 7 * 86400; 331 nextTimeout = 7 * 86400;
334 } 334 }
335 if (nextTimeout > 0) 335 if (nextTimeout > 0)
336 break; 336 break;
337 HistoryItem item = m_history.takeLast(); 337 HistoryItem item = m_history.takeLast();
338 // remove from saved file also 338 // remove from saved file also
339 m_lastSavedUrl = QString(); 339 m_lastSavedUrl = null;
340 emit entryRemoved(item); 340 entryRemoved.emit(item);
341 } 341 }
342 342
343 if (nextTimeout > 0) 343 if (nextTimeout > 0)
344 m_expiredTimer.start(nextTimeout * 1000); 344 m_expiredTimer.start(nextTimeout * 1000);
345 } 345 }
350 { 350 {
351 QWebSettings globalSettings = QWebSettings.globalSettings(); 351 QWebSettings globalSettings = QWebSettings.globalSettings();
352 if (globalSettings.testAttribute(QWebSettings.PrivateBrowsingEnabled)) 352 if (globalSettings.testAttribute(QWebSettings.PrivateBrowsingEnabled))
353 return; 353 return;
354 354
355 m_history.prepend(item); 355 m_history = [item] ~ m_history;
356 emit entryAdded(item); 356 entryAdded.emit(item);
357 if (m_history.count() == 1) 357 if (m_history.length == 1)
358 checkForExpired(); 358 checkForExpired();
359 } 359 }
360 360
361 private: 361 private:
362 362
363 void load() 363 void load()
364 { 364 {
365 loadSettings(); 365 loadSettings();
366 366
367 historyFile = new QFile(QDesktopServices.storageLocation(QDesktopServices.DataLocation) + QLatin1String("/history")); 367 historyFile = new QFile(QDesktopServices.storageLocation(QDesktopServices.DataLocation) ~ QLatin1String("/history"));
368 if (!historyFile.exists()) 368 if (!historyFile.exists())
369 return; 369 return;
370 if (!historyFile.open(QFile.ReadOnly)) { 370 if (!historyFile.open(QFile.ReadOnly)) {
371 qWarning() << "Unable to open history file" << historyFile.fileName(); 371 qWarning() << "Unable to open history file" << historyFile.fileName();
372 return; 372 return;
374 374
375 HistoryItem[] list; 375 HistoryItem[] list;
376 auto in_ = new QDataStream(&historyFile); 376 auto in_ = new QDataStream(&historyFile);
377 // Double check that the history file is sorted as it is read in 377 // Double check that the history file is sorted as it is read in
378 bool needToSort = false; 378 bool needToSort = false;
379 HistoryItem lastInsertedItem; 379 auto lastInsertedItem = new HistoryItem;
380 QByteArray data; 380 auto data = new QByteArray;
381 QDataStream stream; 381 auto stream = new QDataStream;
382 QBuffer buffer; 382 auto buffer = new QBuffer;
383 stream.setDevice(buffer); 383 stream.setDevice(buffer);
384 while (!historyFile.atEnd()) { 384 while (!historyFile.atEnd()) {
385 in_ >> data; 385 in_ >> data;
386 buffer.close(); 386 buffer.close();
387 buffer.setBuffer(data); 387 buffer.setBuffer(data);
388 buffer.open(QIODevice.ReadOnly); 388 buffer.open(QIODevice.ReadOnly);
389 quint32 ver; 389 uint ver;
390 stream >> ver; 390 stream >> ver;
391 if (ver != HISTORY_VERSION) 391 if (ver != HISTORY_VERSION)
392 continue; 392 continue;
393 HistoryItem item; 393 auto item = new HistoryItem;
394 stream >> item.url; 394 stream >> item.url;
395 stream >> item.dateTime; 395 stream >> item.dateTime;
396 stream >> item.title; 396 stream >> item.title;
397 397
398 if (!item.dateTime.isValid()) 398 if (!item.dateTime.isValid())
416 416
417 setHistory(list, true); 417 setHistory(list, true);
418 418
419 // If we had to sort re-write the whole history sorted 419 // If we had to sort re-write the whole history sorted
420 if (needToSort) { 420 if (needToSort) {
421 m_lastSavedUrl = QString(); 421 m_lastSavedUrl = null;
422 m_saveTimer.changeOccurred(); 422 m_saveTimer.changeOccurred();
423 } 423 }
424 } 424 }
425 425
426 AutoSaver m_saveTimer; 426 AutoSaver m_saveTimer;
427 int m_historyLimit; 427 int m_historyLimit;
428 QTimer m_expiredTimer; 428 QTimer m_expiredTimer;
429 HistoryItem[] m_history; 429 HistoryItem[] m_history;
430 QString m_lastSavedUrl; 430 string m_lastSavedUrl;
431 431
432 HistoryModel m_historyModel; 432 HistoryModel m_historyModel;
433 HistoryFilterModel m_historyFilterModel; 433 HistoryFilterModel m_historyFilterModel;
434 HistoryTreeModel m_historyTreeModel; 434 HistoryTreeModel m_historyTreeModel;
435 } 435 }
451 } 451 }
452 452
453 void entryUpdated(int offset) 453 void entryUpdated(int offset)
454 { 454 {
455 QModelIndex idx = index(offset, 0); 455 QModelIndex idx = index(offset, 0);
456 emit dataChanged(idx, idx); 456 dataChanged.emit(idx, idx);
457 } 457 }
458 458
459 public: 459 public:
460 460
461 enum Roles { 461 enum Roles {
489 } 489 }
490 490
491 QVariant data(QModelIndex index, int role = Qt.DisplayRole) 491 QVariant data(QModelIndex index, int role = Qt.DisplayRole)
492 { 492 {
493 HistoryItem[] lst = m_history.history(); 493 HistoryItem[] lst = m_history.history();
494 if (index.row() < 0 || index.row() >= lst.size()) 494 if (index.row() < 0 || index.row() >= lst.length)
495 return QVariant(); 495 return QVariant();
496 496
497 HistoryItem item = lst.at(index.row()); 497 HistoryItem item = lst[index.row()];
498 switch (role) { 498 switch (role) {
499 case DateTimeRole: 499 case DateTimeRole:
500 return item.dateTime; 500 return item.dateTime;
501 case DateRole: 501 case DateRole:
502 return item.dateTime.date(); 502 return item.dateTime.date();
508 case Qt.EditRole: { 508 case Qt.EditRole: {
509 switch (index.column()) { 509 switch (index.column()) {
510 case 0: 510 case 0:
511 // when there is no title try to generate one from the url 511 // when there is no title try to generate one from the url
512 if (item.title.isEmpty()) { 512 if (item.title.isEmpty()) {
513 QString page = QFileInfo(QUrl(item.url).path()).fileName(); 513 string page = QFileInfo(QUrl(item.url).path()).fileName();
514 if (!page.isEmpty()) 514 if (!page.isEmpty())
515 return page; 515 return page;
516 return item.url; 516 return item.url;
517 } 517 }
518 return item.title; 518 return item.title;
552 m_history.historyReset.connect(&this.historyReset); 552 m_history.historyReset.connect(&this.historyReset);
553 endRemoveRows(); 553 endRemoveRows();
554 return true; 554 return true;
555 } 555 }
556 556
557
558 private: 557 private:
558
559 HistoryManager m_history; 559 HistoryManager m_history;
560 } 560 }
561 561
562 562
563 const uint MOVEDROWS = 15; 563 const uint MOVEDROWS = 15;
577 super(parent); 577 super(parent);
578 m_loaded = false; 578 m_loaded = false;
579 setSourceModel(sourceModel); 579 setSourceModel(sourceModel);
580 } 580 }
581 581
582 bool historyContains(QString url) 582 bool historyContains(string url)
583 { 583 {
584 load(); 584 load();
585 return m_historyHash.contains(url); 585 return ((url in m_historyHash) != null);
586 } 586 }
587 587
588 int historyLocation(QString url) 588 int historyLocation(string url)
589 { 589 {
590 load(); 590 load();
591 if (!m_historyHash.contains(url)) 591 if (!(url in m_historyHash))
592 return 0; 592 return 0;
593 return sourceModel().rowCount() - m_historyHash.value(url); 593 return sourceModel().rowCount() - m_historyHash.value(url);
594 } 594 }
595 595
596 QModelIndex mapFromSource(QModelIndex sourceIndex) 596 QModelIndex mapFromSource(QModelIndex sourceIndex)
597 { 597 {
598 load(); 598 load();
599 QString url = sourceIndex.data(HistoryModel.UrlStringRole).toString(); 599 string url = sourceIndex.data(HistoryModel.UrlStringRole).toString();
600 if (!m_historyHash.contains(url)) 600 if (!(url in m_historyHash))
601 return QModelIndex(); 601 return QModelIndex();
602 602
603 // This can be done in a binary search, but we can't use qBinary find 603 // This can be done in a binary search, but we can't use qBinary find
604 // because it can't take: qBinaryFind(m_sourceRow.end(), m_sourceRow.begin(), v); 604 // because it can't take: qBinaryFind(m_sourceRow.end(), m_sourceRow.begin(), v);
605 // so if this is a performance bottlneck then convert to binary search, until then 605 // so if this is a performance bottlneck then convert to binary search, until then
606 // the cleaner/easier to read code wins the day. 606 // the cleaner/easier to read code wins the day.
607 int realRow = -1; 607 int realRow = -1;
608 int sourceModelRow = sourceModel().rowCount() - sourceIndex.row(); 608 int sourceModelRow = sourceModel().rowCount() - sourceIndex.row();
609 609
610 for (int i = 0; i < m_sourceRow.count(); ++i) { 610 for (int i = 0; i < m_sourceRow.count(); ++i) {
611 if (m_sourceRow.at(i) == sourceModelRow) { 611 if (m_sourceRow[i] == sourceModelRow) {
612 realRow = i; 612 realRow = i;
613 break; 613 break;
614 } 614 }
615 } 615 }
616 if (realRow == -1) 616 if (realRow == -1)
654 int rowCount(QModelIndex parent = QModelIndex()) 654 int rowCount(QModelIndex parent = QModelIndex())
655 { 655 {
656 load(); 656 load();
657 if (parent.isValid()) 657 if (parent.isValid())
658 return 0; 658 return 0;
659 return m_historyHash.count(); 659 return m_historyHash.length;
660 } 660 }
661 661
662 int columnCount(QModelIndex parent = QModelIndex()) 662 int columnCount(QModelIndex parent = QModelIndex())
663 { 663 {
664 return (parent.isValid()) ? 0 : 2; 664 return (parent.isValid()) ? 0 : 2;
699 if (oldCount - count != rowCount()) 699 if (oldCount - count != rowCount())
700 reset(); 700 reset();
701 return true; 701 return true;
702 } 702 }
703 703
704
705 QVariant data(QModelIndex index, int role = Qt.DisplayRole) 704 QVariant data(QModelIndex index, int role = Qt.DisplayRole)
706 { 705 {
707 return QAbstractProxyModel.data(index, role); 706 return QAbstractProxyModel.data(index, role);
708 } 707 }
709 708
720 dataChanged.emit(mapFromSource(topLeft), mapFromSource(bottomRight)); 719 dataChanged.emit(mapFromSource(topLeft), mapFromSource(bottomRight));
721 } 720 }
722 721
723 void sourceRowsRemoved(QModelIndex , int start, int end) 722 void sourceRowsRemoved(QModelIndex , int start, int end)
724 { 723 {
725 //Q_UNUSED(start);
726 //Q_UNUSED(end);
727 sourceReset(); 724 sourceReset();
728 } 725 }
729 726
730 void sourceRowsInserted(QModelIndex parent, int start, int end) 727 void sourceRowsInserted(QModelIndex parent, int start, int end)
731 { 728 {
732 assert(start == end && start == 0); 729 assert(start == end && start == 0);
733 //Q_UNUSED(end); 730
734 if (!m_loaded) 731 if (!m_loaded)
735 return; 732 return;
736 QModelIndex idx = sourceModel().index(start, 0, parent); 733 QModelIndex idx = sourceModel().index(start, 0, parent);
737 QString url = idx.data(HistoryModel.UrlStringRole).toString(); 734 string url = idx.data(HistoryModel.UrlStringRole).toString();
738 if (m_historyHash.contains(url)) { 735 if (url in m_historyHash) {
739 int sourceRow = sourceModel().rowCount() - m_historyHash[url]; 736 int sourceRow = sourceModel().rowCount() - m_historyHash[url];
740 int realRow = mapFromSource(sourceModel().index(sourceRow, 0)).row(); 737 int realRow = mapFromSource(sourceModel().index(sourceRow, 0)).row();
741 beginRemoveRows(QModelIndex(), realRow, realRow); 738 beginRemoveRows(QModelIndex(), realRow, realRow);
742 m_sourceRow.removeAt(realRow); 739 m_sourceRow.removeAt(realRow);
743 m_historyHash.remove(url); 740 m_historyHash.remove(url);
744 endRemoveRows(); 741 endRemoveRows();
745 } 742 }
746 beginInsertRows(QModelIndex(), 0, 0); 743 beginInsertRows(QModelIndex(), 0, 0);
747 m_historyHash.insert(url, sourceModel().rowCount() - start); 744 m_historyHash[url] = (sourceModel().rowCount() - start);
748 m_sourceRow.insert(0, sourceModel().rowCount()); 745 m_sourceRow.insert(0, sourceModel().rowCount());
749 endInsertRows(); 746 endInsertRows();
750 } 747 }
751 748
752 private: 749 private:
753 void load() 750 void load()
754 { 751 {
755 if (m_loaded) 752 if (m_loaded)
756 return; 753 return;
757 m_sourceRow.clear(); 754 m_sourceRow.clear();
758 m_historyHash.clear(); 755 m_historyHash = null;
759 m_historyHash.reserve(sourceModel().rowCount()); 756 m_historyHash.length = sourceModel().rowCount();
757 m_historyHash.length = 0;
760 for (int i = 0; i < sourceModel().rowCount(); ++i) { 758 for (int i = 0; i < sourceModel().rowCount(); ++i) {
761 QModelIndex idx = sourceModel().index(i, 0); 759 QModelIndex idx = sourceModel().index(i, 0);
762 QString url = idx.data(HistoryModel.UrlStringRole).toString(); 760 string url = idx.data(HistoryModel.UrlStringRole).toString();
763 if (!m_historyHash.contains(url)) { 761 if (!(url in m_historyHash)) {
764 m_sourceRow.append(sourceModel().rowCount() - i); 762 m_sourceRow.append(sourceModel().rowCount() - i);
765 m_historyHash[url] = sourceModel().rowCount() - i; 763 m_historyHash[url] = sourceModel().rowCount() - i;
766 } 764 }
767 } 765 }
768 m_loaded = true; 766 m_loaded = true;
769 } 767 }
770 768
771 int[] m_sourceRow; 769 int[] m_sourceRow;
772 int[QString] m_historyHash; 770 int[string] m_historyHash;
773 bool m_loaded; 771 bool m_loaded;
774 } 772 }
775 773
776 774
777 /* 775 /*
921 } 919 }
922 920
923 void setInitialActions(QAction[] actions) 921 void setInitialActions(QAction[] actions)
924 { 922 {
925 m_initialActions = actions; 923 m_initialActions = actions;
926 for (int i = 0; i < m_initialActions.count(); ++i) 924 for (int i = 0; i < m_initialActions.length; ++i)
927 addAction(m_initialActions.at(i)); 925 addAction(m_initialActions[i]);
928 } 926 }
929 927
930 protected: 928 protected:
931 929
932 bool prePopulated() 930 bool prePopulated()
935 m_history = BrowserApplication.historyManager(); 933 m_history = BrowserApplication.historyManager();
936 m_historyMenuModel = new HistoryMenuModel(m_history.historyTreeModel(), this); 934 m_historyMenuModel = new HistoryMenuModel(m_history.historyTreeModel(), this);
937 setModel(m_historyMenuModel); 935 setModel(m_historyMenuModel);
938 } 936 }
939 // initial actions 937 // initial actions
940 for (int i = 0; i < m_initialActions.count(); ++i) 938 for (int i = 0; i < m_initialActions.length; ++i)
941 addAction(m_initialActions.at(i)); 939 addAction(m_initialActions[i]);
942 if (!m_initialActions.isEmpty()) 940 if (m_initialActions.length)
943 addSeparator(); 941 addSeparator();
944 setFirstSeparator(m_historyMenuModel.bumpedRows()); 942 setFirstSeparator(m_historyMenuModel.bumpedRows());
945 943
946 return false; 944 return false;
947 } 945 }
996 QVariant data(QModelIndex index, int role) 994 QVariant data(QModelIndex index, int role)
997 { 995 {
998 if (sourceModel() && (role == Qt.EditRole || role == Qt.DisplayRole) && index.isValid()) { 996 if (sourceModel() && (role == Qt.EditRole || role == Qt.DisplayRole) && index.isValid()) {
999 QModelIndex idx = mapToSource(index); 997 QModelIndex idx = mapToSource(index);
1000 idx = idx.sibling(idx.row(), 1); 998 idx = idx.sibling(idx.row(), 1);
1001 QString urlString = idx.data(HistoryModel.UrlStringRole).toString(); 999 string urlString = idx.data(HistoryModel.UrlStringRole).toString();
1002 if (index.row() % 2) { 1000 if (index.row() % 2) {
1003 QUrl url = urlString; 1001 QUrl url = urlString;
1004 QString s = url.toString(QUrl.RemoveScheme | QUrl.RemoveUserInfo | QUrl.StripTrailingSlash); 1002 string s = url.toString(QUrl.RemoveScheme | QUrl.RemoveUserInfo | QUrl.StripTrailingSlash);
1005 return s.mid(2); // strip // from the front 1003 return s.mid(2); // strip // from the front
1006 } 1004 }
1007 return urlString; 1005 return urlString;
1008 } 1006 }
1009 return QAbstractProxyModel.data(index, role); 1007 return QAbstractProxyModel.data(index, role);
1098 if (date == QDate.currentDate()) 1096 if (date == QDate.currentDate())
1099 return tr("Earlier Today"); 1097 return tr("Earlier Today");
1100 return date.toString(QLatin1String("dddd, MMMM d, yyyy")); 1098 return date.toString(QLatin1String("dddd, MMMM d, yyyy"));
1101 } 1099 }
1102 if (index.column() == 1) { 1100 if (index.column() == 1) {
1103 return tr("%1 items").arg(rowCount(index.sibling(index.row(), 0))); 1101 return Format(tr("{} items"), rowCount(index.sibling(index.row(), 0)));
1104 } 1102 }
1105 } 1103 }
1106 } 1104 }
1107 if (role == Qt.DecorationRole && index.column() == 0 && !index.parent().isValid()) 1105 if (role == Qt.DecorationRole && index.column() == 0 && !index.parent().isValid())
1108 return QIcon(QLatin1String(":history.png")); 1106 return QIcon(QLatin1String(":history.png"));
1125 if ( parent.internalId() != 0 || parent.column() > 0 || !sourceModel()) 1123 if ( parent.internalId() != 0 || parent.column() > 0 || !sourceModel())
1126 return 0; 1124 return 0;
1127 1125
1128 // row count OF dates 1126 // row count OF dates
1129 if (!parent.isValid()) { 1127 if (!parent.isValid()) {
1130 if (!m_sourceRowCache.isEmpty()) 1128 if (m_sourceRowCache.length)
1131 return m_sourceRowCache.count(); 1129 return m_sourceRowCache.length;
1132 QDate currentDate; 1130 QDate currentDate;
1133 int rows = 0; 1131 int rows = 0;
1134 int totalRows = sourceModel().rowCount(); 1132 int totalRows = sourceModel().rowCount();
1135 1133
1136 for (int i = 0; i < totalRows; ++i) { 1134 for (int i = 0; i < totalRows; ++i) {
1137 QDate rowDate = sourceModel().index(i, 0).data(HistoryModel.DateRole).toDate(); 1135 QDate rowDate = sourceModel().index(i, 0).data(HistoryModel.DateRole).toDate();
1138 if (rowDate != currentDate) { 1136 if (rowDate != currentDate) {
1139 m_sourceRowCache.append(i); 1137 m_sourceRowCache ~= i;
1140 currentDate = rowDate; 1138 currentDate = rowDate;
1141 ++rows; 1139 ++rows;
1142 } 1140 }
1143 } 1141 }
1144 assert(m_sourceRowCache.count() == rows); 1142 assert(m_sourceRowCache.length == rows);
1145 return rows; 1143 return rows;
1146 } 1144 }
1147 1145
1148 // row count FOR a date 1146 // row count FOR a date
1149 int start = sourceDateRow(parent.row()); 1147 int start = sourceDateRow(parent.row());
1154 QModelIndex mapFromSource(QModelIndex sourceIndex) 1152 QModelIndex mapFromSource(QModelIndex sourceIndex)
1155 { 1153 {
1156 if (!sourceIndex.isValid()) 1154 if (!sourceIndex.isValid())
1157 return QModelIndex(); 1155 return QModelIndex();
1158 1156
1159 if (m_sourceRowCache.isEmpty()) 1157 if (m_sourceRowCache.length == 0)
1160 rowCount(QModelIndex()); 1158 rowCount(QModelIndex());
1161 1159
1162 int[].iterator it; 1160 int[].iterator it;
1163 it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), sourceIndex.row()); 1161 it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), sourceIndex.row());
1164 if (*it != sourceIndex.row()) 1162 if (*it != sourceIndex.row())
1165 --it; 1163 --it;
1166 int dateRow = qMax(0, it - m_sourceRowCache.begin()); 1164 int dateRow = qMax(0, it - m_sourceRowCache.begin());
1167 int row = sourceIndex.row() - m_sourceRowCache.at(dateRow); 1165 int row = sourceIndex.row() - m_sourceRowCache[dateRow];
1168 return createIndex(row, sourceIndex.column(), dateRow + 1); 1166 return createIndex(row, sourceIndex.column(), dateRow + 1);
1169 } 1167 }
1170 1168
1171 QModelIndex mapToSource(QModelIndex proxyIndex) 1169 QModelIndex mapToSource(QModelIndex proxyIndex)
1172 { 1170 {
1259 1257
1260 private: 1258 private:
1261 1259
1262 void sourceReset() 1260 void sourceReset()
1263 { 1261 {
1264 m_sourceRowCache.clear(); 1262 m_sourceRowCache.length = 0;
1265 reset(); 1263 reset();
1266 } 1264 }
1267 1265
1268 void sourceRowsInserted(QModelIndex parent, int start, int end) 1266 void sourceRowsInserted(QModelIndex parent, int start, int end)
1269 { 1267 {
1270 //Q_UNUSED(parent); // Avoid warnings when compiling release
1271 assert(!parent.isValid()); 1268 assert(!parent.isValid());
1272 if (start != 0 || start != end) { 1269 if (start != 0 || start != end) {
1273 m_sourceRowCache.clear(); 1270 m_sourceRowCache.length = 0;
1274 reset(); 1271 reset();
1275 return; 1272 return;
1276 } 1273 }
1277 1274
1278 m_sourceRowCache.clear(); 1275 m_sourceRowCache.length = 0;
1279 QModelIndex treeIndex = mapFromSource(sourceModel().index(start, 0)); 1276 QModelIndex treeIndex = mapFromSource(sourceModel().index(start, 0));
1280 QModelIndex treeParent = treeIndex.parent(); 1277 QModelIndex treeParent = treeIndex.parent();
1281 if (rowCount(treeParent) == 1) { 1278 if (rowCount(treeParent) == 1) {
1282 beginInsertRows(QModelIndex(), 0, 0); 1279 beginInsertRows(QModelIndex(), 0, 0);
1283 endInsertRows(); 1280 endInsertRows();
1285 beginInsertRows(treeParent, treeIndex.row(), treeIndex.row()); 1282 beginInsertRows(treeParent, treeIndex.row(), treeIndex.row());
1286 endInsertRows(); 1283 endInsertRows();
1287 } 1284 }
1288 } 1285 }
1289 1286
1290 void sourceRowsRemoved(QModelIndex parent, int start, int end); 1287 void sourceRowsRemoved(QModelIndex parent, int start, int end)
1291 { 1288 {
1292 //Q_UNUSED(parent); // Avoid warnings when compiling release
1293 assert(!parent.isValid()); 1289 assert(!parent.isValid());
1294 if (m_sourceRowCache.isEmpty()) 1290 if (m_sourceRowCache.length == 0)
1295 return; 1291 return;
1296 for (int i = end; i >= start;) { 1292 for (int i = end; i >= start;) {
1297 int[]::iterator it; 1293 int[]::iterator it;
1298 it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), i); 1294 it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), i);
1299 // playing it safe 1295 // playing it safe
1300 if (it == m_sourceRowCache.end()) { 1296 if (it == m_sourceRowCache.end()) {
1301 m_sourceRowCache.clear(); 1297 m_sourceRowCache = null;
1302 reset(); 1298 reset();
1303 return; 1299 return;
1304 } 1300 }
1305 1301
1306 if (*it != i) 1302 if (*it != i)
1317 } else { 1313 } else {
1318 beginRemoveRows(dateParent, i - offset, i - offset); 1314 beginRemoveRows(dateParent, i - offset, i - offset);
1319 ++row; 1315 ++row;
1320 --i; 1316 --i;
1321 } 1317 }
1322 for (int j = row; j < m_sourceRowCache.count(); ++j) 1318 for (int j = row; j < m_sourceRowCache.length; ++j)
1323 --m_sourceRowCache[j]; 1319 --m_sourceRowCache[j];
1324 endRemoveRows(); 1320 endRemoveRows();
1325 } 1321 }
1326 } 1322 }
1327 1323
1331 int sourceDateRow(int row) 1327 int sourceDateRow(int row)
1332 { 1328 {
1333 if (row <= 0) 1329 if (row <= 0)
1334 return 0; 1330 return 0;
1335 1331
1336 if (m_sourceRowCache.isEmpty()) 1332 if (m_sourceRowCache.length == 0)
1337 rowCount(QModelIndex()); 1333 rowCount(QModelIndex());
1338 1334
1339 if (row >= m_sourceRowCache.count()) { 1335 if (row >= m_sourceRowCache.length) {
1340 if (!sourceModel()) 1336 if (!sourceModel())
1341 return 0; 1337 return 0;
1342 return sourceModel().rowCount(); 1338 return sourceModel().rowCount();
1343 } 1339 }
1344 return m_sourceRowCache.at(row); 1340 return m_sourceRowCache[row];
1345 } 1341 }
1346 1342
1347 int[] m_sourceRowCache; 1343 int[] m_sourceRowCache;
1348 } 1344 }
1349 1345
1360 super(parent); 1356 super(parent);
1361 setSortRole(HistoryModel.DateTimeRole); 1357 setSortRole(HistoryModel.DateTimeRole);
1362 setFilterCaseSensitivity(Qt.CaseInsensitive); 1358 setFilterCaseSensitivity(Qt.CaseInsensitive);
1363 } 1359 }
1364 1360
1365 protected: 1361 protected:
1362
1366 bool filterAcceptsRow(int source_row, QModelIndex source_parent) 1363 bool filterAcceptsRow(int source_row, QModelIndex source_parent)
1367 { 1364 {
1368 if (!source_parent.isValid()) 1365 if (!source_parent.isValid())
1369 return true; 1366 return true;
1370 return QSortFilterProxyModel.filterAcceptsRow(source_row, source_parent); 1367 return QSortFilterProxyModel.filterAcceptsRow(source_row, source_parent);
1390 tree.setUniformRowHeights(true); 1387 tree.setUniformRowHeights(true);
1391 tree.setSelectionBehavior(QAbstractItemView.SelectRows); 1388 tree.setSelectionBehavior(QAbstractItemView.SelectRows);
1392 tree.setTextElideMode(Qt.ElideMiddle); 1389 tree.setTextElideMode(Qt.ElideMiddle);
1393 auto model = history.historyTreeModel(); 1390 auto model = history.historyTreeModel();
1394 auto proxyModel = new TreeProxyModel(this); 1391 auto proxyModel = new TreeProxyModel(this);
1395 search.textChanged(QString).connect(&proxyModel.setFilterFixedString(QString)); 1392 search.textChanged.connect(&proxyModel.setFilterFixedString);
1396 removeButton.clicked.connect(&tree.removeOne); 1393 removeButton.clicked.connect(&tree.removeOne);
1397 removeAllButton.clicked.connect(&history.clear); 1394 removeAllButton.clicked.connect(&history.clear);
1398 proxyModel.setSourceModel(model); 1395 proxyModel.setSourceModel(model);
1399 tree.setModel(proxyModel); 1396 tree.setModel(proxyModel);
1400 tree.setExpanded(proxyModel.index(0, 0), true); 1397 tree.setExpanded(proxyModel.index(0, 0), true);
1410 1407
1411 private: 1408 private:
1412 1409
1413 void customContextMenuRequested(QPoint pos) 1410 void customContextMenuRequested(QPoint pos)
1414 { 1411 {
1415 QMenu menu; 1412 auto menu = new QMenu;
1416 QModelIndex index = tree.indexAt(pos); 1413 QModelIndex index = tree.indexAt(pos);
1417 index = index.sibling(index.row(), 0); 1414 index = index.sibling(index.row(), 0);
1418 if (index.isValid() && !tree.model().hasChildren(index)) { 1415 if (index.isValid() && !tree.model().hasChildren(index)) {
1419 menu.addAction(tr("Open"), this, SLOT(open())); 1416 menu.addAction(tr("Open"), this, SLOT(open()));
1420 menu.addSeparator(); 1417 menu.addSeparator();
1427 void open() 1424 void open()
1428 { 1425 {
1429 QModelIndex index = tree.currentIndex(); 1426 QModelIndex index = tree.currentIndex();
1430 if (!index.parent().isValid()) 1427 if (!index.parent().isValid())
1431 return; 1428 return;
1432 emit openUrl(index.data(HistoryModel.UrlRole).toUrl()); 1429 openUrl.emit(index.data(HistoryModel.UrlRole).toUrl());
1433 } 1430 }
1434 1431
1435 void copy() 1432 void copy()
1436 { 1433 {
1437 QModelIndex index = tree.currentIndex(); 1434 QModelIndex index = tree.currentIndex();
1438 if (!index.parent().isValid()) 1435 if (!index.parent().isValid())
1439 return; 1436 return;
1440 QString url = index.data(HistoryModel.UrlStringRole).toString(); 1437 string url = index.data(HistoryModel.UrlStringRole).toString();
1441 1438
1442 QClipboard clipboard = QApplication.clipboard(); 1439 QClipboard clipboard = QApplication.clipboard();
1443 clipboard.setText(url); 1440 clipboard.setText(url);
1444 } 1441 }
1445 } 1442 }