]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blobdiff - src/windows/BrowserWindow.cpp
Add bookmark folders.
[PrivacyBrowserPC.git] / src / windows / BrowserWindow.cpp
index 0fdfe26375043dd813985d38200ebf64e36c3570..f85726dd9e080cdbf4f95b8b69a0aef7a8416e74 100644 (file)
 #include "ui_SettingsSpellCheck.h"
 #include "databases/BookmarksDatabase.h"
 #include "dialogs/AddBookmarkDialog.h"
+#include "dialogs/AddFolderDialog.h"
 #include "dialogs/BookmarksDialog.h"
 #include "dialogs/CookiesDialog.h"
 #include "dialogs/DomainSettingsDialog.h"
 #include "dialogs/EditBookmarkDialog.h"
+#include "dialogs/EditFolderDialog.h"
 #include "helpers/SearchEngineHelper.h"
 #include "helpers/UserAgentHelper.h"
 #include "structs/BookmarkStruct.h"
@@ -45,6 +47,7 @@
 #include <QInputDialog>
 #include <QNetworkCookie>
 #include <QMenuBar>
+#include <QMessageBox>
 #include <QShortcut>
 #include <QStatusBar>
 #include <QWebEngineFindTextResult>
@@ -110,6 +113,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer)
     searchEngineBingActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_bing"));
     searchEngineYahooActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_yahoo"));
     searchEngineCustomActionPointer = actionCollectionPointer->addAction(QLatin1String("search_engine_custom"));
+    QAction *addFolderPointer = actionCollectionPointer->addAction(QLatin1String("add_folder"));
     viewBookmarksToolBarActionPointer = actionCollectionPointer->addAction(QLatin1String("view_bookmarks_toolbar"));
     QAction *domainSettingsActionPointer = actionCollectionPointer->addAction(QLatin1String("domain_settings"));
     cookiesActionPointer = actionCollectionPointer->addAction(QLatin1String("cookies"));
@@ -189,6 +193,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer)
     searchEngineGoogleActionPointer->setText(i18nc("Search engine", "Google"));
     searchEngineBingActionPointer->setText(i18nc("Search engine", "Bing"));
     searchEngineYahooActionPointer->setText(i18nc("Search engine", "Yahoo"));
+    addFolderPointer->setText(i18nc("Add folder", "Add Folder"));
     viewBookmarksToolBarActionPointer->setText(i18nc("View bookmarks toolbar", "View Bookmarks Toolbar"));
     domainSettingsActionPointer->setText(i18nc("Domain Settings action", "Domain Settings"));
     cookiesActionPointer->setText(i18nc("The Cookies action, which also displays the number of cookies", "Cookies - %1", 0));
@@ -223,6 +228,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer)
     searchEngineYahooActionPointer->setIcon(QIcon::fromTheme(QLatin1String("im-yahoo"), QIcon::fromTheme(QLatin1String("edit-find"))));
     searchEngineCustomActionPointer->setIcon(QIcon::fromTheme(QLatin1String("edit-find")));
     zoomFactorActionPointer->setIcon(QIcon::fromTheme(QLatin1String("zoom-fit-best")));
+    addFolderPointer->setIcon(QIcon::fromTheme(QLatin1String("folder-add")));
     viewBookmarksToolBarActionPointer->setIcon(QIcon::fromTheme(QLatin1String("bookmarks")));
     domainSettingsActionPointer->setIcon(QIcon::fromTheme(QLatin1String("settings-configure"), QIcon::fromTheme(QLatin1String("preferences-desktop"))));
     cookiesActionPointer->setIcon(QIcon::fromTheme(QLatin1String("preferences-web-browser-cookies"), QIcon::fromTheme(QLatin1String("appointment-new"))));
@@ -259,6 +265,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer)
     QKeySequence ctrlShiftYKeySequence = QKeySequence(i18nc("The Yahoo search engine key sequence.", "Ctrl+Shift+Y"));
     QKeySequence ctrlShiftCKeySequence = QKeySequence(i18nc("The custom search engine key sequence.", "Ctrl+Shift+C"));
     QKeySequence ctrlAltShiftBKeySequence = QKeySequence(i18nc("The edit bookmarks key sequence.", "Ctrl+Alt+Shift+B"));
+    QKeySequence altFKeySequence = QKeySequence(i18nc("The add folder key sequence.", "Alt+F"));
     QKeySequence ctrlAltBKeySequence = QKeySequence(i18nc("The view bookmarks toolbar key sequence.", "Ctrl+Alt+B"));
     QKeySequence ctrlShiftDKeySequence = QKeySequence(i18nc("The domain settings key sequence.", "Ctrl+Shift+D"));
     QKeySequence ctrlSemicolonKeySequence = QKeySequence(i18nc("The cookies dialog key sequence.", "Ctrl+;"));
@@ -293,6 +300,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer)
     actionCollectionPointer->setDefaultShortcut(searchEngineYahooActionPointer, ctrlShiftYKeySequence);
     actionCollectionPointer->setDefaultShortcut(searchEngineCustomActionPointer, ctrlShiftCKeySequence);
     actionCollectionPointer->setDefaultShortcut(editBookmarksActionPointer, ctrlAltShiftBKeySequence);
+    actionCollectionPointer->setDefaultShortcut(addFolderPointer, altFKeySequence);
     actionCollectionPointer->setDefaultShortcut(viewBookmarksToolBarActionPointer, ctrlAltBKeySequence);
     actionCollectionPointer->setDefaultShortcut(domainSettingsActionPointer, ctrlShiftDKeySequence);
     actionCollectionPointer->setDefaultShortcut(cookiesActionPointer, ctrlSemicolonKeySequence);
@@ -305,6 +313,7 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer)
     connect(viewSourceActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSource()));
     connect(viewSourceInNewTabActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewSourceInNewTab()));
     connect(zoomFactorActionPointer, SIGNAL(triggered()), this, SLOT(getZoomFactorFromUser()));
+    connect(addFolderPointer, SIGNAL(triggered()), this, SLOT(showAddFolderDialog()));
     connect(viewBookmarksToolBarActionPointer, SIGNAL(triggered()), this, SLOT(toggleViewBookmarksToolBar()));
     connect(cookiesActionPointer, SIGNAL(triggered()), this, SLOT(showCookiesDialog()));
     connect(domainSettingsActionPointer, SIGNAL(triggered()), this, SLOT(showDomainSettingsDialog()));
@@ -509,8 +518,10 @@ BrowserWindow::BrowserWindow(bool firstWindow, QString *initialUrlStringPointer)
     bookmarksMenuPointer->addSeparator();
 
     // Initialize the current bookmarks lists.
-    bookmarksMenuCurrentActionList = QList<QAction*>();
-    bookmarksToolBarCurrentActionList = QList<QAction*>();
+    bookmarksMenuActionList = QList<QPair<QMenu *, QAction *> *>();
+    bookmarksMenuSubmenuList = QList<QPair<QMenu *, QMenu *> *>();
+    bookmarksToolBarActionList = QList<QAction*>();
+    bookmarksToolBarSubfolderActionList = QList<QPair<QMenu *, QAction * > *>();
 
     // Set the bookmarks toolbar context menu policy.
     bookmarksToolBarPointer->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -606,7 +617,7 @@ void BrowserWindow::decrementZoom()
 void BrowserWindow::editBookmarks() const
 {
     // Instantiate an edit bookmarks dialog.
-    BookmarksDialog *bookmarksDialogPointer = new BookmarksDialog(tabWidgetPointer->getCurrentTabFavoritIcon());
+    BookmarksDialog *bookmarksDialogPointer = new BookmarksDialog(tabWidgetPointer->getCurrentTabTitle(), tabWidgetPointer->getCurrentTabUrl(), tabWidgetPointer->getCurrentTabFavoritIcon());
 
     // Update the displayed bookmarks when edited.
     connect(bookmarksDialogPointer, SIGNAL(bookmarkUpdated()), this, SLOT(populateBookmarks()));
@@ -797,71 +808,366 @@ void BrowserWindow::newWindow() const
 void BrowserWindow::populateBookmarks()
 {
     // Remove all the current menu bookmarks.
-    for (QAction *bookmarkAction : bookmarksMenuCurrentActionList)
+    for (QPair<QMenu *, QAction *> *bookmarkPairPointer : bookmarksMenuActionList)
     {
         // Remove the bookmark.
-        bookmarksMenuPointer->removeAction(bookmarkAction);
+        bookmarkPairPointer->first->removeAction(bookmarkPairPointer->second);
+    }
+
+    // Remove all the current menu subfolders.
+    for (QPair<QMenu *, QMenu *> *submenuPairPointer : bookmarksMenuSubmenuList)
+    {
+        // Remove the submenu from the parent menu.
+        submenuPairPointer->first->removeAction(submenuPairPointer->second->menuAction());
+    }
+
+    // Remove all the current toolbar subfolders.
+    for (QPair<QMenu *, QAction *> *subfolderPairPointer : bookmarksToolBarSubfolderActionList)
+    {
+        // Remove the action from the subfolder.
+        subfolderPairPointer->first->removeAction(subfolderPairPointer->second);
     }
 
     // Remove all the current toolbar bookmarks.
-    for (QAction *bookmarkAction : bookmarksToolBarCurrentActionList)
+    for (QAction *bookmarkAction : bookmarksToolBarActionList)
     {
         // Remove the bookmark.
         bookmarksToolBarPointer->removeAction(bookmarkAction);
     }
 
     // Clear the current bookmark lists.
-    bookmarksMenuCurrentActionList.clear();
-    bookmarksToolBarCurrentActionList.clear();
+    bookmarksMenuActionList.clear();
+    bookmarksMenuSubmenuList.clear();
+    bookmarksToolBarActionList.clear();
+    bookmarksToolBarSubfolderActionList.clear();
 
-    // Get a list of the bookmarks.
-    std::list<BookmarkStruct> *bookmarkListPointer = BookmarksDatabase::getBookmarks();
+    // Populate the bookmarks subfolders, beginning with the root folder (`0`);
+    populateBookmarksMenuSubfolders(0, bookmarksMenuPointer);
 
-    // Populate the bookmarks menu.
-    for (BookmarkStruct bookmarkStruct : *bookmarkListPointer)
+    // Populate the bookmarks toolbar.
+    populateBookmarksToolBar();
+
+    // Get a handle for the bookmark toolbar layout.
+    QLayout *bookmarksToolBarLayoutPointer = bookmarksToolBarPointer->layout();
+
+    // Get the count of the bookmarks.
+    int bookmarkCount = bookmarksToolBarLayoutPointer->count();
+
+    // Set the layout of each bookmark to be left aligned.
+    for(int i = 0; i < bookmarkCount; ++i)
+        bookmarksToolBarLayoutPointer->itemAt(i)->setAlignment(Qt::AlignLeft);
+}
+
+void BrowserWindow::populateBookmarksMenuSubfolders(const double folderId, QMenu *menuPointer)
+{
+    // Get the folder contents.
+    QList<BookmarkStruct> *folderContentsListPointer = BookmarksDatabase::getFolderContents(folderId);
+
+    // Populate the bookmarks menu and toolbar.
+    for (BookmarkStruct bookmarkStruct : *folderContentsListPointer)
     {
-        // Get the bookmark URL.
-        QString bookmarkUrl = bookmarkStruct.bookmarkUrl;
+        // Process the item according to the type.
+        if (bookmarkStruct.isFolder)  // This item is a folder.
+        {
+            // Add a submenu to the menu.
+            QMenu *submenuPointer = menuPointer->addMenu(bookmarkStruct.favoriteIcon, bookmarkStruct.name);
+
+            // Add the submenu to the beginning of the list of menus to be deleted on repopulate.
+            bookmarksMenuSubmenuList.prepend(new QPair<QMenu *, QMenu *>(menuPointer, submenuPointer));
+
+            // Populate any subfolders.
+            populateBookmarksMenuSubfolders(bookmarkStruct.folderId, submenuPointer);
+        }
+        else  // This item is a bookmark.
+        {
+            // Add the bookmark to the menu.
+            QAction *menuBookmarkActionPointer = menuPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name, [=]
+                {
+                    // Remove the focus from the URL line edit.
+                    urlLineEditPointer->clearFocus();
+
+                    // Load the URL.
+                    tabWidgetPointer->loadUrlFromLineEdit(bookmarkStruct.url);
+                }
+            );
+
+            // Add the actions to the beginning of the list of bookmarks to be deleted on repopulate.
+            bookmarksMenuActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, menuBookmarkActionPointer));
+        }
+    }
+}
+
+void BrowserWindow::populateBookmarksToolBar()
+{
+    // Get the root folder contents (which has a folder ID of `0`).
+    QList<BookmarkStruct> *folderContentsListPointer = BookmarksDatabase::getFolderContents(0);
+
+    // Populate the bookmarks toolbar.
+    for (BookmarkStruct bookmarkStruct : *folderContentsListPointer)
+    {
+        // Process the item according to the type.
+        if (bookmarkStruct.isFolder)  // This item is a folder.
+        {
+            // Add the subfolder action.
+            QAction *toolBarSubfolderActionPointer = bookmarksToolBarPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name);
+
+            // Add the bookmark database ID to the toolbar action.
+            toolBarSubfolderActionPointer->setData(bookmarkStruct.databaseId);
+
+            // Add the action to the beginning of the list of actions to be deleted on repopulate.
+            bookmarksToolBarActionList.prepend(toolBarSubfolderActionPointer);
+
+            // Create a subfolder menu.
+            QMenu *subfolderMenuPointer = new QMenu();
+
+            // Add the menu to the action.
+            toolBarSubfolderActionPointer->setMenu(subfolderMenuPointer);
+
+            // Add the submenu to the toolbar menu list.
+            bookmarksToolBarMenuList.append(new QPair<QMenu *, const double>(subfolderMenuPointer, bookmarkStruct.folderId));
+
+            // Set the popup mode for the menu.
+            dynamic_cast<QToolButton *>(bookmarksToolBarPointer->widgetForAction(toolBarSubfolderActionPointer))->setPopupMode(QToolButton::InstantPopup);
+
+            // Populate the subfolder.
+            populateBookmarksToolBarSubfolders(bookmarkStruct.folderId, subfolderMenuPointer);
+        }
+        else  // This item is a bookmark.
+        {
+            // Add the bookmark to the toolbar.
+            QAction *toolBarBookmarkActionPointer = bookmarksToolBarPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name, [=]
+                {
+                    // Remove the focus from the URL line edit.
+                    urlLineEditPointer->clearFocus();
+
+                    // Load the URL.
+                    tabWidgetPointer->loadUrlFromLineEdit(bookmarkStruct.url);
+                }
+            );
+
+            // Add the bookmark database ID to the toolbar action.
+            toolBarBookmarkActionPointer->setData(bookmarkStruct.databaseId);
+
+            // Add the actions to the beginning of the current bookmarks lists.
+            bookmarksToolBarActionList.prepend(toolBarBookmarkActionPointer);
+        }
+    }
+
+    // Add the extra items to the toolbar folder menus.  The first item in the pair is the menu pointer.  The second is the folder ID.
+    for (QPair<QMenu *, const double> *menuAndFolderIdPairPointer : bookmarksToolBarMenuList)
+    {
+        // Add a separator.
+        menuAndFolderIdPairPointer->first->addSeparator();
+
+        // Add the open folder in new tabs action to the menu.
+        menuAndFolderIdPairPointer->first->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("The open folder in new tabs action", "Open Folder in New Tabs"), [=]
+            {
+                // Get all the folder URLs.
+                QList<QString> *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(menuAndFolderIdPairPointer->second);
+
+                // Open the URLs in new tabs.  `true` removes the URL line edit focus, `false` does not load a background tab.
+                for (QString url : *folderUrlsListPointer)
+                    tabWidgetPointer->addTab(true, false, url);
+            }
+        );
+
+        // Add the open folder in background tabs action to the menu.
+        menuAndFolderIdPairPointer->first->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("The open folder in background tabs action", "Open Folder in Background Tabs"), [=]
+            {
+                // Get all the folder URLs.
+                QList<QString> *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(menuAndFolderIdPairPointer->second);
+
+                // Open the URLs in new tabs.  `true` removes the URL line edit focus, `true` loads a background tab.
+                for (QString url : *folderUrlsListPointer)
+                    tabWidgetPointer->addTab(true, true, url);
+            }
+        );
+
+        // Add the open folder in new window action to the menu.
+        menuAndFolderIdPairPointer->first->addAction(QIcon::fromTheme(QLatin1String("window-new")), i18nc("The open folder in new window action", "Open Folder in New Window"), [=]
+            {
+                // Get all the folder URLs.
+                QList<QString> *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(menuAndFolderIdPairPointer->second);
+
+                // Create a new browser window.
+                BrowserWindow *browserWindowPointer = new BrowserWindow(false, &folderUrlsListPointer->first());
+
+                // Get a count of the folder URLs.
+                const int folderUrls = folderUrlsListPointer->count();
 
-        // Add the bookmark to the menu.
-        QAction *menuBookmarkActionPointer = bookmarksMenuPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.bookmarkName, [=]
+                // Load all the other URLs.  `true` removes the URL line edit focus, `true` loads a background tab.
+                for (int i = 1; i < folderUrls; ++i)
+                    browserWindowPointer->tabWidgetPointer->addTab(true, true, folderUrlsListPointer->value(i));
+
+                // Show the new browser window.
+                browserWindowPointer->show();
+            }
+        );
+
+        // Add a separator.
+        menuAndFolderIdPairPointer->first->addSeparator();
+
+        // Add the add bookmark action to the menu.
+        menuAndFolderIdPairPointer->first->addAction(QIcon::fromTheme(QLatin1String("bookmark-new")), i18nc("The add bookmark action", "Add Bookmark"), [=]
             {
-                // Remove the focus from the URL line edit.
-                urlLineEditPointer->clearFocus();
+                // Instantiate an add bookmark dialog.
+                AddBookmarkDialog *addBookmarkDialogPointer = new AddBookmarkDialog(tabWidgetPointer->getCurrentTabTitle(), tabWidgetPointer->getCurrentTabUrl(),
+                                                                                    tabWidgetPointer->getCurrentTabFavoritIcon(), menuAndFolderIdPairPointer->second);
+
+                // Update the displayed bookmarks when a new one is added.
+                connect(addBookmarkDialogPointer, SIGNAL(bookmarkAdded()), this, SLOT(populateBookmarks()));
 
-                // Load the URL.
-                tabWidgetPointer->loadUrlFromLineEdit(bookmarkUrl);
+                // Show the dialog.
+                addBookmarkDialogPointer->show();
             }
         );
 
-        // Add the bookmark to the toolbar.
-        QAction *toolBarBookmarkActionPointer = bookmarksToolBarPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.bookmarkName, [=]
+        // Add the add folder action to the menu.
+        menuAndFolderIdPairPointer->first->addAction(QIcon::fromTheme(QLatin1String("folder-add")), i18nc("The add folder action", "Add Folder"), [=]
             {
-                // Remove the focus from the URL line edit.
-                urlLineEditPointer->clearFocus();
+                // Instantiate an add folder dialog.
+                AddFolderDialog *addFolderDialogPointer = new AddFolderDialog(tabWidgetPointer->getCurrentTabFavoritIcon(), menuAndFolderIdPairPointer->second);
+
+                // Update the displayed bookmarks when a folder is added.
+                connect(addFolderDialogPointer, SIGNAL(folderAdded()), this, SLOT(populateBookmarks()));
+
+                // Show the dialog.
+                addFolderDialogPointer->show();
+            }
+        );
+
+        // Add a separator.
+        menuAndFolderIdPairPointer->first->addSeparator();
+
+        // Add the edit folder action to the menu.
+        menuAndFolderIdPairPointer->first->addAction(QIcon::fromTheme(QLatin1String("edit-entry")), i18nc("The edit folder action", "Edit Folder"), [=]
+            {
+                // Get the current tab favorite icon.
+                QIcon currentTabFavoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon();
 
-                // Load the URL.
-                tabWidgetPointer->loadUrlFromLineEdit(bookmarkUrl);
+                // Instantiate an edit folder dialog.
+                QDialog *editFolderDialogPointer = new EditFolderDialog(BookmarksDatabase::getFolderDatabaseId(menuAndFolderIdPairPointer->second), currentTabFavoriteIcon);
+
+                // Show the dialog.
+                editFolderDialogPointer->show();
+
+                // Process bookmark events.
+                connect(editFolderDialogPointer, SIGNAL(folderSaved()), this, SLOT(populateBookmarks()));
             }
         );
 
-        // Add the bookmark database ID to the toolbar action.
-        toolBarBookmarkActionPointer->setData(bookmarkStruct.id);
+        // Add the delete folder action to the menu.
+        menuAndFolderIdPairPointer->first->addAction(QIcon::fromTheme(QLatin1String("delete")), i18nc("Delete folder context menu entry", "Delete Folder"), [=]
+            {
+                // Get the folder database ID.
+                int folderDatabaseId = BookmarksDatabase::getFolderDatabaseId(menuAndFolderIdPairPointer->second);
+
+                // Create an items to delete list.
+                QList<int>* itemsToDeleteListPointer = new QList<int>;
+
+                // Add the folder to the list of items to delete.
+                itemsToDeleteListPointer->append(folderDatabaseId);
+
+                // Add the folder contents to the list of items to delete.
+                itemsToDeleteListPointer->append(*BookmarksDatabase::getFolderContentsDatabaseIdsRecursively(menuAndFolderIdPairPointer->second));
+
+                // Instantiate a delete dialog message box.
+                QMessageBox deleteDialogMessageBox;
+
+                // Set the icon.
+                deleteDialogMessageBox.setIcon(QMessageBox::Warning);
+
+                // Set the window title.
+                deleteDialogMessageBox.setWindowTitle(i18nc("Delete bookmarks dialog title", "Delete Bookmarks"));
 
-        // Add the actions to the current bookmarks lists.
-        bookmarksMenuCurrentActionList.append(menuBookmarkActionPointer);
-        bookmarksToolBarCurrentActionList.append(toolBarBookmarkActionPointer);
+                // Set the text.
+                deleteDialogMessageBox.setText(i18ncp("Delete bookmarks dialog main message", "Delete %1 bookmark item?", "Delete %1 bookmark items?", itemsToDeleteListPointer->count()));
+
+                // Set the informative text.
+                deleteDialogMessageBox.setInformativeText(i18nc("Delete bookmarks dialog secondary message", "This cannot be undone."));
+
+                // Set the standard buttons.
+                deleteDialogMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+
+                // Set the default button.
+                deleteDialogMessageBox.setDefaultButton(QMessageBox::No);
+
+                // Display the dialog and capture the return value.
+                int returnValue = deleteDialogMessageBox.exec();
+
+                // Delete the domain if instructed.
+                if (returnValue == QMessageBox::Yes)
+                {
+                    // Get the parent folder ID.
+                    double parentFolderId = BookmarksDatabase::getParentFolderId(folderDatabaseId);
+
+                    // Delete the folder and its contents.
+                    for (const int databaseId : *itemsToDeleteListPointer)
+                        BookmarksDatabase::deleteBookmark(databaseId);
+
+                    // Update the display order of the bookmarks in the parent folder.
+                    BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId);
+
+                    // Repopulate the bookmarks.
+                    populateBookmarks();
+                }
+            }
+        );
     }
+}
 
-    // Get a handle for the bookmark toolbar layout.
-    QLayout *bookmarksToolBarLayoutPointer = bookmarksToolBarPointer->layout();
+void BrowserWindow::populateBookmarksToolBarSubfolders(const double folderId, QMenu *menuPointer)
+{
+    // Get the folder contents.
+    QList<BookmarkStruct> *folderContentsListPointer = BookmarksDatabase::getFolderContents(folderId);
 
-    // Get the count of the bookmarks.
-    int bookmarkCount = bookmarksToolBarLayoutPointer->count();
+    // Populate the bookmarks folder.
+    for (BookmarkStruct bookmarkStruct : *folderContentsListPointer)
+    {
+        // Get the bookmark URL.
+        QString bookmarkUrl = bookmarkStruct.url;
 
-    // Set the layout of each bookmark to be left aligned.
-    for(int i = 0; i < bookmarkCount; ++i)
-        bookmarksToolBarLayoutPointer->itemAt(i)->setAlignment(Qt::AlignLeft);
+        // Process the item according to the type.
+        if (bookmarkStruct.isFolder)  // This item is a folder.
+        {
+            // Add the subfolder action.
+            QAction *toolBarSubfolderActionPointer = menuPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name);
+
+            // Add the action to the beginning of the list of actions to be deleted on repopulate.
+            bookmarksToolBarSubfolderActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, toolBarSubfolderActionPointer));
+
+            // Create a subfolder menu.
+            QMenu *subfolderMenuPointer = new QMenu();
+
+            // Add the submenu to the action.
+            toolBarSubfolderActionPointer->setMenu(subfolderMenuPointer);
+
+            // Add the submenu to the toolbar menu list.
+            bookmarksToolBarMenuList.append(new QPair<QMenu *, const double>(subfolderMenuPointer, bookmarkStruct.folderId));
+
+            // Populate the subfolder menu.
+            populateBookmarksToolBarSubfolders(bookmarkStruct.folderId, subfolderMenuPointer);
+        }
+        else  // This item is a bookmark.
+        {
+            // Add the bookmark to the folder.
+            QAction *toolBarBookmarkActionPointer = menuPointer->addAction(bookmarkStruct.favoriteIcon, bookmarkStruct.name, [=]
+                {
+                    // Remove the focus from the URL line edit.
+                    urlLineEditPointer->clearFocus();
+
+                    // Load the URL.
+                    tabWidgetPointer->loadUrlFromLineEdit(bookmarkUrl);
+                }
+            );
+
+            // Add the bookmark database ID to the toolbar action.
+            toolBarBookmarkActionPointer->setData(bookmarkStruct.databaseId);
+
+            // Add the action to the beginning of the list of actions to be deleted on repopulate.
+            bookmarksToolBarSubfolderActionList.prepend(new QPair<QMenu *, QAction *>(menuPointer, toolBarBookmarkActionPointer));
+        }
+    }
 }
 
 void BrowserWindow::refresh() const
@@ -894,103 +1200,285 @@ void BrowserWindow::showAddBookmarkDialog() const
     addBookmarkDialogPointer->show();
 }
 
+void BrowserWindow::showAddFolderDialog() const
+{
+    // Instantiate an add folder dialog.
+    AddFolderDialog *addFolderDialogPointer = new AddFolderDialog(tabWidgetPointer->getCurrentTabFavoritIcon());
+
+    // Update the displayed bookmarks when a folder is added.
+    connect(addFolderDialogPointer, SIGNAL(folderAdded()), this, SLOT(populateBookmarks()));
+
+    // Show the dialog.
+    addFolderDialogPointer->show();
+}
+
 void BrowserWindow::showBookmarkContextMenu(const QPoint &point)
 {
     // Get the bookmark action.
     QAction *bookmarkActionPointer = bookmarksToolBarPointer->actionAt(point);
 
-    // Check to see if an bookmark was clicked.
-    if (bookmarkActionPointer)  // A bookmark was clicked.
+    // Check to see if an action was clicked.
+    if (bookmarkActionPointer)  // An action was clicked.
     {
         // Create a bookmark context menu.
         QMenu *bookmarkContextMenuPointer = new QMenu();
 
-        // Get the bookmark ID from the action.
-        int bookmarkId = bookmarkActionPointer->data().toInt();
-
-        // Add the open in new tab action to the menu.
-        bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("Open bookmark in new tab context menu entry", "Open in New Tab"), [=]
-            {
-                // Get the bookmark.
-                BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(bookmarkId);
-
-                // Open the bookmark in a new tab.  `true` removes the URL line edit focus, `false` does not load a background tab.
-                tabWidgetPointer->addTab(true, false, bookmarkStructPointer->bookmarkUrl);
-            }
-        );
+        // Get the database ID from the action.
+        int databaseId = bookmarkActionPointer->data().toInt();
 
-        // Add the open in background tab action to the menu.
-        bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("Open bookmark in background tab context menu entry", "Open in Background Tab"), [=]
-            {
-                // Get the bookmark.
-                BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(bookmarkId);
-
-                // Open the bookmark in a new tab.  `true` removes the URL line edit focus, `true` loads a background tab.
-                tabWidgetPointer->addTab(true, true, bookmarkStructPointer->bookmarkUrl);
-            }
-        );
-
-        // Add the open in new window action to the menu.
-        bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("window-new")), i18nc("Open bookmark in new window context menu entry", "Open in New Window"), [=]
-            {
-                // Get the bookmark.
-                BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(bookmarkId);
-
-                // Create a new browser window.
-                BrowserWindow *browserWindowPointer = new BrowserWindow(false, &bookmarkStructPointer->bookmarkUrl);
+        // Create the menu according to the type.
+        if (BookmarksDatabase::isFolder(databaseId))  // A folder was clicked.
+        {
+            // Get the folder ID.
+            double folderId = BookmarksDatabase::getFolderId(databaseId);
+
+            // Add the open folder in new tabs action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("The open folder in new tabs action", "Open Folder in New Tabs"), [=]
+                {
+                    // Get all the folder URLs.
+                    QList<QString> *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(folderId);
+
+                    // Open the URLs in new tabs.  `true` removes the URL line edit focus, `false` does not load a background tab.
+                    for (QString url : *folderUrlsListPointer)
+                        tabWidgetPointer->addTab(true, false, url);
+                }
+            );
+
+            // Add the open folder in background tabs action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("The open folder in background tabs action", "Open Folder in Background Tabs"), [=]
+                {
+                    // Get all the folder URLs.
+                    QList<QString> *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(folderId);
+
+                    // Open the URLs in new tabs.  `true` removes the URL line edit focus, `true` loads a background tab.
+                    for (QString url : *folderUrlsListPointer)
+                        tabWidgetPointer->addTab(true, true, url);
+                }
+            );
+
+            // Add the open folder in new window action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("window-new")), i18nc("The open folder in new window action", "Open Folder in New Window"), [=]
+                {
+                    // Get all the folder URLs.
+                    QList<QString> *folderUrlsListPointer = BookmarksDatabase::getAllFolderUrls(folderId);
+
+                    // Create a new browser window.
+                    BrowserWindow *browserWindowPointer = new BrowserWindow(false, &folderUrlsListPointer->first());
+
+                    // Get a count of the folder URLs.
+                    const int folderUrls = folderUrlsListPointer->count();
 
-                // Show the new browser window.
-                browserWindowPointer->show();
-            }
-        );
+                    // Load all the other URLs.  `true` removes the URL line edit focus, `true` loads a background tab.
+                    for (int i = 1; i < folderUrls; ++i)
+                        browserWindowPointer->tabWidgetPointer->addTab(true, true, folderUrlsListPointer->value(i));
+
+                    // Show the new browser window.
+                    browserWindowPointer->show();
+                }
+            );
+
+            // Add a separator.
+            bookmarkContextMenuPointer->addSeparator();
+
+            // Add the add bookmark action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("bookmark-new")), i18nc("The add bookmark action", "Add Bookmark"), [=]
+                {
+                    // Instantiate an add bookmark dialog.
+                    AddBookmarkDialog *addBookmarkDialogPointer = new AddBookmarkDialog(tabWidgetPointer->getCurrentTabTitle(), tabWidgetPointer->getCurrentTabUrl(),
+                                                                                        tabWidgetPointer->getCurrentTabFavoritIcon(), folderId);
+
+                    // Update the displayed bookmarks when a new one is added.
+                    connect(addBookmarkDialogPointer, SIGNAL(bookmarkAdded()), this, SLOT(populateBookmarks()));
+
+                    // Show the dialog.
+                    addBookmarkDialogPointer->show();
+                }
+            );
+
+            // Add the add folder action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("folder-add")), i18nc("The add folder action", "Add Folder"), [=]
+                {
+                    // Instantiate an add folder dialog.
+                    AddFolderDialog *addFolderDialogPointer = new AddFolderDialog(tabWidgetPointer->getCurrentTabFavoritIcon(), folderId);
+
+                    // Update the displayed bookmarks when a folder is added.
+                    connect(addFolderDialogPointer, SIGNAL(folderAdded()), this, SLOT(populateBookmarks()));
+
+                    // Show the dialog.
+                    addFolderDialogPointer->show();
+                }
+            );
+
+            // Add a separator.
+            bookmarkContextMenuPointer->addSeparator();
+
+            // Add the edit folder action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("edit-entry")), i18nc("The edit folder action", "Edit Folder"), [=]
+                {
+                    // Get the current tab favorite icon.
+                    QIcon currentTabFavoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon();
+
+                    // Instantiate an edit folder dialog.
+                    QDialog *editFolderDialogPointer = new EditFolderDialog(BookmarksDatabase::getFolderDatabaseId(folderId), currentTabFavoriteIcon);
+
+                    // Show the dialog.
+                    editFolderDialogPointer->show();
+
+                    // Process bookmark events.
+                    connect(editFolderDialogPointer, SIGNAL(folderSaved()), this, SLOT(populateBookmarks()));
+                }
+            );
+
+            // Add the delete folder action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("delete")), i18nc("Delete folder context menu entry", "Delete Folder"), [=]
+                {
+                    // Get the folder database ID.
+                    int folderDatabaseId = BookmarksDatabase::getFolderDatabaseId(folderId);
+
+                    // Create an items to delete list.
+                    QList<int>* itemsToDeleteListPointer = new QList<int>;
+
+                    // Add the folder to the list of items to delete.
+                    itemsToDeleteListPointer->append(folderDatabaseId);
+
+                    // Add the folder contents to the list of items to delete.
+                    itemsToDeleteListPointer->append(*BookmarksDatabase::getFolderContentsDatabaseIdsRecursively(folderId));
 
-        // Add a separator.
-        bookmarkContextMenuPointer->addSeparator();
+                    // Instantiate a delete dialog message box.
+                    QMessageBox deleteDialogMessageBox;
+
+                    // Set the icon.
+                    deleteDialogMessageBox.setIcon(QMessageBox::Warning);
 
-        // Add the edit action to the menu.
-        bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("edit-entry")), i18nc("Edit bookmark context menu entry", "Edit"), [=]
-            {
-                // Get the current tab favorite icon.
-                QIcon currentTabFavoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon();
+                    // Set the window title.
+                    deleteDialogMessageBox.setWindowTitle(i18nc("Delete bookmarks dialog title", "Delete Bookmarks"));
 
-                // Instantiate an edit bookmark dialog.
-                QDialog *editBookmarkDialogPointer = new EditBookmarkDialog(bookmarkId, currentTabFavoriteIcon);
+                    // Set the text.
+                    deleteDialogMessageBox.setText(i18ncp("Delete bookmarks dialog main message", "Delete %1 bookmark item?", "Delete %1 bookmark items?", itemsToDeleteListPointer->count()));
 
-                // Show the dialog.
-                editBookmarkDialogPointer->show();
+                    // Set the informative text.
+                    deleteDialogMessageBox.setInformativeText(i18nc("Delete bookmarks dialog secondary message", "This cannot be undone."));
 
-                // Process bookmark events.
-                connect(editBookmarkDialogPointer, SIGNAL(bookmarkSaved()), this, SLOT(populateBookmarks()));
-            }
-        );
+                    // Set the standard buttons.
+                    deleteDialogMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
 
-        // Add the copy URL action to the menu.
-        bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("edit-copy")), i18nc("Copy bookmark url context menu entry", "Copy URL"), [=]
-            {
-                // Get the bookmark.
-                BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(bookmarkId);
+                    // Set the default button.
+                    deleteDialogMessageBox.setDefaultButton(QMessageBox::No);
 
-                // Get a handle for the clipboard.
-                QClipboard *clipboard = QGuiApplication::clipboard();
+                    // Display the dialog and capture the return value.
+                    int returnValue = deleteDialogMessageBox.exec();
 
-                // Place the URL on the keyboard.
-                clipboard->setText(bookmarkStructPointer->bookmarkUrl);
-            }
-        );
+                    // Delete the domain if instructed.
+                    if (returnValue == QMessageBox::Yes)
+                    {
+                        // Get the parent folder ID.
+                        double parentFolderId = BookmarksDatabase::getParentFolderId(folderDatabaseId);
 
-        // Add a separator.
-        bookmarkContextMenuPointer->addSeparator();
+                        // Delete the folder and its contents.
+                        for (const int databaseId : *itemsToDeleteListPointer)
+                            BookmarksDatabase::deleteBookmark(databaseId);
 
-        // Add the delete action to the menu.
-        bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("delete")), i18nc("Delete bookmark context menu entry", "Delete"), [=]
-            {
-                // Delete the bookmark.
-                BookmarksDatabase::deleteBookmark(bookmarkId);
+                        // Update the display order of the bookmarks in the parent folder.
+                        BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId);
 
-                // Repopulate the bookmarks.
-                populateBookmarks();
-            }
-        );
+                        // Repopulate the bookmarks.
+                        populateBookmarks();
+                    }
+                }
+            );
+        }
+        else  // A bookmark was clicked.
+        {
+            // Add the open in new tab action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("Open bookmark in new tab context menu entry", "Open in New Tab"), [=]
+                {
+                    // Get the bookmark.
+                    BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId);
+
+                    // Open the bookmark in a new tab.  `true` removes the URL line edit focus, `false` does not load a background tab.
+                    tabWidgetPointer->addTab(true, false, bookmarkStructPointer->url);
+                }
+            );
+
+            // Add the open in background tab action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("tab-new")), i18nc("Open bookmark in background tab context menu entry", "Open in Background Tab"), [=]
+                {
+                    // Get the bookmark.
+                    BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId);
+
+                    // Open the bookmark in a new tab.  `true` removes the URL line edit focus, `true` loads a background tab.
+                    tabWidgetPointer->addTab(true, true, bookmarkStructPointer->url);
+                }
+            );
+
+            // Add the open in new window action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("window-new")), i18nc("Open bookmark in new window context menu entry", "Open in New Window"), [=]
+                {
+                    // Get the bookmark.
+                    BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId);
+
+                    // Create a new browser window and load the first URL.  `false` indicates it is not the first browser window.
+                    BrowserWindow *browserWindowPointer = new BrowserWindow(false, &bookmarkStructPointer->url);
+
+                    // Show the new browser window.
+                    browserWindowPointer->show();
+                }
+            );
+
+            // Add a separator.
+            bookmarkContextMenuPointer->addSeparator();
+
+            // Add the edit action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("edit-entry")), i18nc("Edit bookmark context menu entry", "Edit"), [=]
+                {
+                    // Get the current tab favorite icon.
+                    QIcon currentTabFavoriteIcon = tabWidgetPointer->getCurrentTabFavoritIcon();
+
+                    // Instantiate an edit bookmark dialog.
+                    QDialog *editBookmarkDialogPointer = new EditBookmarkDialog(databaseId, currentTabFavoriteIcon);
+
+                    // Show the dialog.
+                    editBookmarkDialogPointer->show();
+
+                    // Process bookmark events.
+                    connect(editBookmarkDialogPointer, SIGNAL(bookmarkSaved()), this, SLOT(populateBookmarks()));
+                }
+            );
+
+            // Add the copy URL action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("edit-copy")), i18nc("Copy bookmark URL context menu entry", "Copy URL"), [=]
+                {
+                    // Get the bookmark.
+                    BookmarkStruct *bookmarkStructPointer = BookmarksDatabase::getBookmark(databaseId);
+
+                    // Get a handle for the clipboard.
+                    QClipboard *clipboard = QGuiApplication::clipboard();
+
+                    // Place the URL on the keyboard.
+                    clipboard->setText(bookmarkStructPointer->url);
+                }
+            );
+
+            // Add a separator.
+            bookmarkContextMenuPointer->addSeparator();
+
+            // Add the delete action to the menu.
+            bookmarkContextMenuPointer->addAction(QIcon::fromTheme(QLatin1String("delete")), i18nc("Delete bookmark context menu entry", "Delete"), [=]
+                {
+                    // Get the parent folder ID.
+                    double parentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
+
+                    // Delete the bookmark.
+                    BookmarksDatabase::deleteBookmark(databaseId);
+
+                    // Update the display order of the bookmarks in the parent folder.
+                    BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId);
+
+                    // Repopulate the bookmarks.
+                    populateBookmarks();
+                }
+            );
+        }
 
         // Delete the menu from memory when it is closed.
         bookmarkContextMenuPointer->setAttribute(Qt::WA_DeleteOnClose);