Commits

Ivan Andrianov committed a5fe7bf

Added history support:
- History disk storage
- History dialog:
- - List of history items
- - "Clear" button
- - Double-click on item opens new tab with page associated with this item
- Adress Bar completion

committer: PayableOnDeath <>

Comments (0)

Files changed (32)

Added
New image
         <file>closeTab.png</file>
         <file>restore.png</file>
         <file>clear.png</file>
+        <file>history.png</file>
     </qresource>
 </RCC>

src/adressbar.cpp

 #include "adressbar.h"
-#include "lineedit.h"
+#include "historylistmodel.h"
 
 AdressBar::AdressBar(const QUrl & url, QWidget * parent)
-        : QComboBox(parent)
+        : QLineEdit(parent)
 {
-    setEditable(true);
-    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+    m_model = new HistoryListModel(this);
 
-    m_lineEdit = new LineEdit(this);
-    setLineEdit(m_lineEdit);
+    m_completer = new QCompleter(m_model, this);
+    setCompleter(m_completer);
 
     setUrl(url);
 
     load();
 
-    connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(load()));
+    connect(this, SIGNAL(returnPressed()), this, SLOT(load()));
 }
 
-QUrl AdressBar::url()
+QUrl AdressBar::url() const
 {
-    return QUrl(m_lineEdit->text());
+    return QUrl(text());
 }
 
 void AdressBar::setUrl(const QUrl & url)
 {
-    m_lineEdit->setText(url.toString());
+    setText(url.toString());
 }
 
 void AdressBar::load()
 {
-    emit loadRequsted(QUrl(m_lineEdit->text()));
+    QUrl url(text());
+    if(url.scheme().isEmpty())
+    {
+        url = QUrl("http://" + url.toString());
+        setUrl(url);
+    }
+    else if(url.scheme() != "http" &&
+            url.scheme() != "https" &&
+            url.toString() != "about:blank")
+    {
+        QDesktopServices::openUrl(url);
+    }
+    emit loadRequsted(url);
 }
 #include <QtGui>
 #include <QtWebKit>
 
-class LineEdit;
+class HistoryListModel;
 
 class AdressBar
-        : public QComboBox
+        : public QLineEdit
 {
     Q_OBJECT
 
 public:
     AdressBar(const QUrl & url, QWidget * parent = 0);
-    QUrl url();
+    QUrl url() const;
 
 private:
-    LineEdit * m_lineEdit;
+    HistoryListModel * m_model;
+    QCompleter * m_completer;
 
 public slots:
     void setUrl(const QUrl & url);

src/historydialog.cpp

+#include "historydialog.h"
+#include "historyview.h"
+#include "mainwindow.h"
+#include "historymanager.h"
+
+HistoryDialog::HistoryDialog(QWidget * parent)
+        : QDialog(parent)
+{
+    setWindowIcon(QIcon(":/surfer.png"));
+    setWindowTitle(trUtf8("History"));
+    resize(500, 300);
+
+    m_view = new HistoryView(this);
+    m_clearButton = new QPushButton(this);
+    m_clearButton->setText(trUtf8("Clear history"));
+    QHBoxLayout * hlayout = new QHBoxLayout();
+    hlayout->addWidget(m_clearButton, 0);
+    QVBoxLayout * vlayout = new QVBoxLayout(this);
+    vlayout->addWidget(m_view, 1);
+    vlayout->addLayout(hlayout, 0);
+
+    connect(m_clearButton, SIGNAL(clicked()),
+            MainWindow::historyManager(), SLOT(clear()));
+}

src/historydialog.h

+#ifndef HISTORYDIALOG_H
+#define HISTORYDIALOG_H
+
+#include <QtCore>
+#include <QtGui>
+#include <QtWebKit>
+
+class HistoryView;
+class MainWindow;
+class HistoryManager;
+
+class HistoryDialog
+        : public QDialog
+{
+    Q_OBJECT
+
+public:
+    HistoryDialog(QWidget * parent = 0);
+
+private:
+    HistoryView * m_view;
+    QPushButton * m_clearButton;
+};
+
+#endif // HISTORYDIALOG_H

src/historyitem.cpp

+#include "historyitem.h"
+
+HistoryItem::HistoryItem(QUrl url,
+                         QString title,
+                         QIcon icon,
+                         QDateTime visitTime,
+                         QObject * parent)
+        : QObject(parent)
+        , m_url(url)
+        , m_title(title)
+        , m_icon(icon)
+        , m_visitTime(visitTime)
+{
+}
+
+QUrl HistoryItem::url() const
+{
+    return m_url;
+}
+
+QString HistoryItem::title() const
+{
+    return m_title;
+}
+
+QIcon HistoryItem::icon() const
+{
+    return m_icon;
+}
+
+QDateTime HistoryItem::visitTime() const
+{
+    return m_visitTime;
+}

src/historyitem.h

+#ifndef HISTORYITEM_H
+#define HISTORYITEM_H
+
+#include <QtCore>
+#include <QtGui>
+#include <QtWebKit>
+
+class HistoryItem
+        : QObject
+{
+    Q_OBJECT
+
+public:
+    HistoryItem(QUrl url,
+                QString title,
+                QIcon icon,
+                QDateTime visitTime,
+                QObject * parent = 0);
+    QUrl url() const;
+    QString title() const;
+    QIcon icon() const;
+    QDateTime visitTime() const;
+
+private:
+    QUrl m_url;
+    QString m_title;
+    QIcon m_icon;
+    QDateTime m_visitTime;
+};
+
+#endif // HISTORYITEM_H

src/historylistmodel.cpp

+#include "historylistmodel.h"
+#include "mainwindow.h"
+#include "historymanager.h"
+#include "historyitem.h"
+
+HistoryListModel::HistoryListModel(QObject * parent)
+        : QAbstractListModel(parent)
+{
+}
+
+int HistoryListModel::rowCount(const QModelIndex & /*parent*/) const
+{
+    return MainWindow::historyManager()->count();
+}
+
+QVariant HistoryListModel::data(const QModelIndex & index, int role) const
+{
+    HistoryManager * manager = MainWindow::historyManager();
+    int number = manager->count() - index.row() - 1;
+    if(!index.isValid() || index.column() >= 1 || index.row() >= manager->count())
+    {
+        return QVariant();
+    }
+    else if(role == Qt::DecorationRole)
+    {
+        return manager->item(number)->icon();
+    }
+    else if(role == Qt::EditRole)
+    {
+        return manager->item(number)->url().toString();
+    }
+    else if(role == Qt::DisplayRole)
+    {
+        QString text = manager->item(number)->title();
+        text += "\n";
+        text += manager->item(number)->url().toString();
+        return text;
+    }
+    else
+    {
+        return QVariant();
+    }
+}

src/historylistmodel.h

+#ifndef HISTORYLISTMODEL_H
+#define HISTORYLISTMODEL_H
+
+#include <QtCore>
+#include <QtGui>
+#include <QtWebKit>
+
+class MainWindow;
+class HistoryManager;
+class HistoryItem;
+
+class HistoryListModel
+        : public QAbstractListModel
+{
+    Q_OBJECT
+
+public:
+    HistoryListModel(QObject * parent = 0);
+    int rowCount(const QModelIndex & parent = QModelIndex()) const;
+    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+};
+
+#endif // HISTORYLISTMODEL_H

src/historymanager.cpp

+#include "historymanager.h"
+#include "historyitem.h"
+
+HistoryManager::HistoryManager(QObject * parent)
+        : QObject(parent)
+{
+}
+
+void HistoryManager::addItem(HistoryItem * item)
+{
+    m_items += item;
+}
+
+HistoryItem * HistoryManager::item(int index) const
+{
+    return m_items.at(index);
+}
+
+void HistoryManager::clear()
+{
+    m_items.clear();
+}
+
+int HistoryManager::count() const
+{
+    return m_items.count();
+}
+
+void HistoryManager::load()
+{
+    QString path =
+            QDesktopServices::storageLocation(QDesktopServices::DataLocation) + "Surfer/";
+    QDir dir;
+    if(!dir.mkpath(path))
+    {
+        return;
+    }
+    QFile file(path + "history");
+    if(!file.open(QIODevice::ReadOnly))
+    {
+        return;
+    }
+    QByteArray array;
+    while(!(array = file.readLine()).isEmpty())
+    {
+        QString title = QString::fromUtf8(array.data()).trimmed();
+        array = file.readLine();
+        QString urlString = QString::fromUtf8(array.data()).trimmed();
+        array = file.readLine();
+        QString dateString = QString::fromUtf8(array.data()).trimmed();
+        QDateTime date = QDateTime::fromString(dateString, "dd.MM.yyyy hh:mm");
+        HistoryItem * item =
+                new HistoryItem(QUrl(urlString), title, QIcon(), date, this);
+        addItem(item);
+    }
+    file.close();
+}
+
+void HistoryManager::save()
+{
+    QString path =
+            QDesktopServices::storageLocation(QDesktopServices::DataLocation) + "Surfer/";
+    QDir dir;
+    if(!dir.mkpath(path))
+    {
+        return;
+    }
+    QFile file(path + "history");
+    if(!file.open(QIODevice::WriteOnly))
+    {
+        return;
+    }
+    QByteArray array;
+    foreach(HistoryItem * item, m_items)
+    {
+        array += item->title().toUtf8();
+        array += "\n";
+        array += item->url().toString().toUtf8();
+        array += "\n";
+        array += item->visitTime().toString("dd.MM.yyyy hh:mm").toUtf8();
+        array += "\n";
+    }
+    file.write(array);
+    file.close();
+}

src/historymanager.h

+#ifndef HISTORYMANAGER_H
+#define HISTORYMANAGER_H
+
+#include <QtCore>
+#include <QtGui>
+#include <QtWebKit>
+
+class HistoryItem;
+
+class HistoryManager
+        : public QObject
+{
+    Q_OBJECT
+
+public:
+    HistoryManager(QObject * parent = 0);
+    void addItem(HistoryItem * item);
+    HistoryItem * item(int index) const;
+    int count() const;
+
+private:
+    QList<HistoryItem *> m_items;
+
+public slots:
+    void clear();
+    void load();
+    void save();
+};
+
+#endif // HISTORYMANAGER_H

src/historytreemodel.cpp

+#include "historytreemodel.h"
+#include "mainwindow.h"
+#include "historymanager.h"
+#include "historyitem.h"
+
+HistoryTreeModel::HistoryTreeModel(QObject * parent)
+        : QAbstractListModel(parent)
+{
+}
+
+int HistoryTreeModel::columnCount(const QModelIndex & /*parent*/) const
+{
+    return 2;
+}
+
+int HistoryTreeModel::rowCount(const QModelIndex & /*parent*/) const
+{
+    return MainWindow::historyManager()->count();
+}
+
+QVariant HistoryTreeModel::data(const QModelIndex & index, int role) const
+{
+    HistoryManager * manager = MainWindow::historyManager();
+    int number = manager->count() - index.row() - 1;
+    if(!index.isValid() || index.column() >= 2 || index.row() >= manager->count())
+    {
+        return QVariant();
+    }
+    else if(role == Qt::DecorationRole && index.column() == 0)
+    {
+        return manager->item(number)->icon();
+    }
+    else if(role == Qt::DisplayRole && index.column() == 0)
+    {
+        return manager->item(number)->title();
+    }
+    else if(role == Qt::DisplayRole && index.column() == 1)
+    {
+        return manager->item(number)->url().toString();
+    }
+    else
+    {
+        return QVariant();
+    }
+}
+
+QVariant HistoryTreeModel::headerData(int section,
+                                      Qt::Orientation orientation,
+                                      int role) const
+{
+    if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
+    {
+        if(section == 0)
+        {
+            return trUtf8("Title");
+        }
+        else if(section == 1)
+        {
+            return trUtf8("URL");
+        }
+        else
+        {
+            return QVariant();
+        }
+    }
+    else
+    {
+        return QVariant();
+    }
+}

src/historytreemodel.h

+#ifndef HISTORYTREEMODEL_H
+#define HISTORYTREEMODEL_H
+
+#include <QtCore>
+#include <QtGui>
+#include <QtWebKit>
+
+class MainWindow;
+class HistoryManager;
+class HistoryItem;
+
+class HistoryTreeModel
+        : public QAbstractListModel
+{
+    Q_OBJECT
+
+public:
+    HistoryTreeModel(QObject * parent = 0);
+    int columnCount(const QModelIndex & parent = QModelIndex()) const;
+    int rowCount(const QModelIndex & parent = QModelIndex()) const;
+    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+    QVariant headerData(int section,
+                        Qt::Orientation orientation,
+                        int role = Qt::DisplayRole) const;
+};
+
+#endif // HISTORYTREEMODEL_H

src/historyview.cpp

+#include "historyview.h"
+#include "historytreemodel.h"
+#include "mainwindow.h"
+#include "tabmanager.h"
+
+HistoryView::HistoryView(QWidget * parent)
+        : QTreeView(parent)
+{
+    header()->setResizeMode(QHeaderView::Stretch);
+
+    m_model = new HistoryTreeModel(this);
+    setModel(m_model);
+
+    connect(this, SIGNAL(doubleClicked(const QModelIndex &)),
+            this, SLOT(addTab(const QModelIndex &)));
+}
+
+void HistoryView::addTab(const QModelIndex & index)
+{
+    QModelIndex newIndex = m_model->index(index.row(), 1);
+    MainWindow::tabManager()->addTab(QUrl(newIndex.data(Qt::DisplayRole).toString()));
+}

src/historyview.h

+#ifndef HISTORYVIEW_H
+#define HISTORYVIEW_H
+
+#include <QtCore>
+#include <QtGui>
+#include <QtWebKit>
+
+class HistoryTreeModel;
+class MainWindow;
+class TabManager;
+
+class HistoryView
+        : public QTreeView
+{
+    Q_OBJECT
+
+public:
+    HistoryView(QWidget * parent = 0);
+
+private:
+    HistoryTreeModel * m_model;
+
+private slots:
+    void addTab(const QModelIndex & index);
+};
+
+#endif // HISTORYVIEW_H

src/lineedit.cpp

-#include "lineedit.h"
-
-LineEdit::LineEdit(QWidget * parent)
-        : QLineEdit(parent)
-{
-}

src/lineedit.h

-#ifndef LINEEDIT_H
-#define LINEEDIT_H
-
-#include <QtCore>
-#include <QtGui>
-#include <QtWebKit>
-
-class LineEdit
-        : public QLineEdit
-{
-    Q_OBJECT
-
-public:
-    LineEdit(QWidget * parent = 0);
-};
-
-#endif // LINEEDIT_H

src/mainwindow.cpp

 #include "mainwindow.h"
 #include "tabwidget.h"
 #include "tabmanager.h"
+#include "historymanager.h"
 
 TabManager * MainWindow::m_tabManager = 0;
+HistoryManager * MainWindow::m_historyManager = 0;
 int MainWindow::m_count = 0;
 
 MainWindow::MainWindow(QWidget * parent)
     if(m_count == 1)
     {
         m_tabManager = new TabManager(m_centralWidget);
+        m_historyManager = new HistoryManager(m_centralWidget);
 
     }
 
 
     m_tabManager->setTabWidget(m_tabWidget);
     m_tabManager->load();
+    m_historyManager->load();
 }
 
 MainWindow::~MainWindow()
     if(m_count == 0)
     {
         m_tabManager->deleteLater();
+        m_historyManager->deleteLater();
     }
 }
 
     return m_tabManager;
 }
 
+HistoryManager * MainWindow::historyManager()
+{
+    return m_historyManager;
+}
+
 void MainWindow::closeEvent(QCloseEvent * /*event*/)
 {
     m_tabManager->save();
+    m_historyManager->save();
 }
 
 class TabWidget;
 class TabManager;
+class HistoryManager;
 
 class MainWindow
         : public QMainWindow
     MainWindow(QWidget * parent = 0);
     ~MainWindow();
     static TabManager * tabManager();
+    static HistoryManager * historyManager();
 
 protected:
     void closeEvent(QCloseEvent * event);
 private:
     TabWidget * m_tabWidget;
     static TabManager * m_tabManager;
+    static HistoryManager * m_historyManager;
     static int m_count;
 };
 

src/mainwindow.ui

    <rect>
     <x>0</x>
     <y>0</y>
-    <width>800</width>
-    <height>600</height>
+    <width>1000</width>
+    <height>750</height>
    </rect>
   </property>
   <property name="windowTitle">
             this, SLOT(updateIcon()));
 }
 
-QUrl Tab::url()
+QUrl Tab::url() const
 {
     return m_toolBar->url();
 }
 
-WebView * Tab::webView()
+WebView * Tab::webView() const
 {
     return m_webView;
 }
 
 public:
     Tab(const QUrl & url, QWidget * parent = 0);
-    QUrl url();
-    WebView * webView();
+    QUrl url() const;
+    WebView * webView() const;
 
 private:
     ToolBar * m_toolBar;

src/tabmanager.cpp

     m_tabWidget = tabWidget;
 }
 
-QList<QString> TabManager::closedTabTitles(int count)
+QList<QString> TabManager::closedTabTitles(int count) const
 {
     return m_closedTabTitles.mid(0, count);
 }
 
-QList<QIcon> TabManager::closedTabIcons(int count)
+QList<QIcon> TabManager::closedTabIcons(int count) const
 {
     return m_closedTabIcons.mid(0, count);
 }
 {
     if(m_tabWidget)
     {
-        Tab * tab = qobject_cast<Tab *>(m_tabWidget->widget(index));
+        Tab * tab;
+        if(index == -1)
+        {
+            tab = qobject_cast<Tab *>(m_tabWidget->widget(m_tabWidget->currentIndex()));
+        }
+        else
+        {
+            tab = qobject_cast<Tab *>(m_tabWidget->widget(index));
+        }
         if(tab)
         {
             m_closedTabs += tab;
 {
     QSettings settings("PayableOnDeath", "Surfer");
     settings.setValue("current", m_tabWidget->currentIndex());
+    settings.remove("tabs");
     settings.beginWriteArray("tabs");
     for(int i = 0; i < m_tabWidget->count(); i++)
     {
 public:
     TabManager(QObject * parent = 0);
     void setTabWidget(QTabWidget * tabWidget);
-    QList<QString> closedTabTitles(int count);
-    QList<QIcon> closedTabIcons(int count);
+    QList<QString> closedTabTitles(int count) const;
+    QList<QIcon> closedTabIcons(int count) const;
 
 private:
     QTabWidget * m_tabWidget;
     void setCurrentTab(int index);
     Tab * addTab(const QUrl & url = QUrl("about:blank"));
     Tab * insertTab(int index, const QUrl & url = QUrl("about:blank"));
-    void removeTab(int index);
+    void removeTab(int index = -1);
     void removeAllTabs();
     void restoreTab(int index = 0);
     void clearRestoreList();

src/tabwidget.cpp

     QToolBar * toolBar = new QToolBar(this);
     m_openTabAction =
             toolBar->addAction(QIcon(":/openTab.png"), trUtf8("Open new tab"));
+    m_openTabAction->setShortcut(QKeySequence::AddTab);
     connect(m_openTabAction, SIGNAL(triggered()),
             MainWindow::tabManager(), SLOT(addTab()));
+    m_closeTabAction = new QAction(trUtf8("Close this tab"), this);
+    m_closeTabAction->setShortcut(QKeySequence::Close);
+    connect(m_closeTabAction, SIGNAL(triggered()),
+            MainWindow::tabManager(), SLOT(removeTab()));
     setCornerWidget(toolBar);
 
     setMovable(true);
 private:
     TabBar * m_tabBar;
     QAction * m_openTabAction;
+    QAction * m_closeTabAction;
 };
 
 #endif // TABWIDGET_H
 #include "adressbar.h"
 #include "mainwindow.h"
 #include "tabmanager.h"
+#include "historydialog.h"
+
+HistoryDialog * ToolBar::m_historyDialog = 0;
+int ToolBar::m_count = 0;
 
 ToolBar::ToolBar(QWebHistory * history, const QUrl & url, QWidget * parent)
         : QToolBar(parent)
     m_restoreAction->setMenu(m_restoreMenu);
     addAction(m_restoreAction);
     m_history = history;
+    m_showHistoryAction =
+            addAction(QIcon(":/history.png"), trUtf8("Show history"));
+    m_count++;
+    if(m_count == 1)
+    {
+        m_historyDialog = new HistoryDialog();
+    }
 
     connect(m_goBackAction, SIGNAL(triggered()),
             this, SIGNAL(goBackRequsted()));
     connect(m_restoreAction, SIGNAL(triggered()),
             MainWindow::tabManager(), SLOT(restoreTab()));
     connect(m_restoreMenu, SIGNAL(aboutToShow()), this, SLOT(updateRestoreMenu()));
+    connect(m_showHistoryAction, SIGNAL(triggered()),
+            m_historyDialog, SLOT(show()));
 }
 
-QUrl ToolBar::url()
+ToolBar::~ToolBar()
+{
+    m_count--;
+    if(m_count == 0)
+    {
+        m_historyDialog->deleteLater();
+    }
+}
+
+QUrl ToolBar::url() const
 {
     return m_adressBar->url();
 }
 class AdressBar;
 class MainWindow;
 class TabManager;
+class HistoryDialog;
 
 class ToolBar
         : public QToolBar
 
 public:
     ToolBar(QWebHistory * history, const QUrl & url, QWidget * parent = 0);
-    QUrl url();
+    ~ToolBar();
+    QUrl url() const;
 
 private:
     QAction * m_goBackAction;
     QAction * m_restoreAction;
     QMenu * m_restoreMenu;
     QWebHistory * m_history;
+    QAction * m_showHistoryAction;
+    static HistoryDialog * m_historyDialog;
+    static int m_count;
 
 public slots:
     void setUrl(const QUrl & url);
 #include "webview.h"
 #include "mainwindow.h"
 #include "tabmanager.h"
+#include "historymanager.h"
+#include "historyitem.h"
 #include "tab.h"
 
 WebView::WebView(const QUrl & url, QWidget * parent)
         : QWebView(parent)
 {
     load(url);
+
+    connect(this, SIGNAL(urlChanged(const QUrl &)),
+            this, SLOT(updateHistory()));
 }
 
 QWebView * WebView::createWindow(QWebPage::WebWindowType /*type*/)
 {
     QWebView::load(url);
 }
+
+void WebView::updateHistory()
+{
+    QWebHistoryItem webItem = history()->currentItem();
+    HistoryItem * item =
+            new HistoryItem(webItem.url(), webItem.title(), webItem.icon(),
+                            QDateTime::currentDateTime(), MainWindow::historyManager());
+    MainWindow::historyManager()->addItem(item);
+}
 class MainWindow;
 class TabManager;
 class Tab;
+class HistoryManager;
+class HistoryItem;
 
 class WebView
         : public QWebView
 
 public slots:
     void load(const QUrl & url);
+
+private slots:
+    void updateHistory();
 };
 
 #endif // WEBVIEW_H
     src/tabmanager.cpp \
     src/tab.cpp \
     src/adressbar.cpp \
-    src/lineedit.cpp \
-    src/tabbar.cpp
+    src/tabbar.cpp \
+    src/historymanager.cpp \
+    src/historyitem.cpp \
+    src/historylistmodel.cpp \
+    src/historytreemodel.cpp \
+    src/historyview.cpp \
+    src/historydialog.cpp
 HEADERS += src/mainwindow.h \
     src/webview.h \
     src/toolbar.h \
     src/tabmanager.h \
     src/tab.h \
     src/adressbar.h \
-    src/lineedit.h \
-    src/tabbar.h
+    src/tabbar.h \
+    src/historymanager.h \
+    src/historyitem.h \
+    src/historylistmodel.h \
+    src/historytreemodel.h \
+    src/historyview.h \
+    src/historydialog.h
 FORMS += src/mainwindow.ui
 RESOURCES += icons/main.qrc
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.