diff --git a/src/core/coreconfig.h b/src/core/coreconfig.h
index ded4f9d2..ad15a85f 100644
--- a/src/core/coreconfig.h
+++ b/src/core/coreconfig.h
@@ -34,6 +34,7 @@ namespace vnotex
SnippetDock,
LocationListDock,
HistoryDock,
+ WindowsDock,
TagDock,
Search,
NavigationMode,
diff --git a/src/data/core/core.qrc b/src/data/core/core.qrc
index 2aa95117..cf27d264 100644
--- a/src/data/core/core.qrc
+++ b/src/data/core/core.qrc
@@ -86,6 +86,7 @@
icons/navigation_dock.svg
icons/history_dock.svg
icons/outline_dock.svg
+ icons/windows_dock.svg
icons/search_dock.svg
icons/snippet_dock.svg
icons/location_list_dock.svg
diff --git a/src/data/core/icons/windows_dock.svg b/src/data/core/icons/windows_dock.svg
new file mode 100644
index 00000000..1377d4e9
--- /dev/null
+++ b/src/data/core/icons/windows_dock.svg
@@ -0,0 +1 @@
+
diff --git a/src/data/core/vnotex.json b/src/data/core/vnotex.json
index f3435f31..6c45a7dc 100644
--- a/src/data/core/vnotex.json
+++ b/src/data/core/vnotex.json
@@ -26,6 +26,7 @@
"SnippetDock" : "Ctrl+G, S",
"LocationListDock" : "Ctrl+G, C",
"HistoryDock" : "",
+ "WindowsDock" : "",
"TagDock" : "",
"Search" : "Ctrl+Alt+F",
"NavigationMode" : "Ctrl+G, W",
@@ -91,7 +92,7 @@
],
"shortcut_leader_key" : "Ctrl+G",
"toolbar_icon_size" : 18,
- "docks_tabbar_icon_size" : 18,
+ "docks_tabbar_icon_size" : 20,
"note_management" : {
"external_node" : {
"//comment" : "Wildcard patterns of files and folders to exclude as external files",
@@ -492,7 +493,7 @@
"node_explorer_explore_mode" : 0,
"search_panel_advanced_settings_visible" : true,
"//comment" : "Docks to ignore when expanding content area of main window",
- "main_window_keep_docks_expanding_content_area": ["OutlineDock.vnotex"],
+ "main_window_keep_docks_expanding_content_area": ["OutlineDock.vnotex", "WindowsDock.vnotex"],
"snippet_panel_builtin_snippets_visible" : true,
"tag_explorer_two_columns_enabled" : false,
"new_note_default_file_type" : 0,
diff --git a/src/widgets/dockwidgethelper.cpp b/src/widgets/dockwidgethelper.cpp
index 451be3b6..84847878 100644
--- a/src/widgets/dockwidgethelper.cpp
+++ b/src/widgets/dockwidgethelper.cpp
@@ -24,6 +24,7 @@
#include "searchpanel.h"
#include "snippetpanel.h"
#include "historypanel.h"
+#include "windowspanel.h"
#include "tagexplorer.h"
#include "consoleviewer.h"
@@ -71,6 +72,8 @@ QString DockWidgetHelper::iconFileName(DockIndex p_dockIndex)
return "outline_dock.svg";
case DockIndex::HistoryDock:
return "history_dock.svg";
+ case DockIndex::WindowsDock:
+ return "windows_dock.svg";
case DockIndex::TagDock:
return "tag_dock.svg";
case DockIndex::SearchDock:
@@ -116,6 +119,8 @@ void DockWidgetHelper::setupDocks()
setupOutlineDock();
+ setupWindowsDock();
+
setupConsoleDock();
setupLocationListDock();
@@ -155,6 +160,17 @@ void DockWidgetHelper::setupOutlineDock()
m_mainWindow->addDockWidget(Qt::RightDockWidgetArea, dock);
}
+void DockWidgetHelper::setupWindowsDock()
+{
+ auto dock = createDockWidget(DockIndex::WindowsDock, tr("Open Windows"), m_mainWindow);
+
+ dock->setObjectName(QStringLiteral("WindowsDock.vnotex"));
+ dock->setAllowedAreas(Qt::AllDockWidgetAreas);
+
+ addWidgetToDock(dock, m_mainWindow->m_windowsPanel);
+ m_mainWindow->addDockWidget(Qt::RightDockWidgetArea, dock);
+}
+
void DockWidgetHelper::setupConsoleDock()
{
auto dock = createDockWidget(DockIndex::ConsoleDock, tr("Console"), m_mainWindow);
@@ -304,6 +320,10 @@ void DockWidgetHelper::setupShortcuts()
setupDockActivateShortcut(m_docks[DockIndex::SnippetDock],
coreConfig.getShortcut(CoreConfig::Shortcut::SnippetDock));
+
+ setupDockActivateShortcut(m_docks[DockIndex::WindowsDock],
+ coreConfig.getShortcut(CoreConfig::Shortcut::WindowsDock));
+
}
void DockWidgetHelper::setupDockActivateShortcut(QDockWidget *p_dock, const QString &p_keys)
diff --git a/src/widgets/dockwidgethelper.h b/src/widgets/dockwidgethelper.h
index 7920fb92..4579fd1c 100644
--- a/src/widgets/dockwidgethelper.h
+++ b/src/widgets/dockwidgethelper.h
@@ -29,6 +29,7 @@ namespace vnotex
SearchDock,
SnippetDock,
OutlineDock,
+ WindowsDock,
ConsoleDock,
LocationListDock,
MaxDock
@@ -100,6 +101,8 @@ namespace vnotex
void setupOutlineDock();
+ void setupWindowsDock();
+
void setupConsoleDock();
void setupSearchDock();
diff --git a/src/widgets/listwidget.cpp b/src/widgets/listwidget.cpp
index 7c0711c7..5b65720d 100644
--- a/src/widgets/listwidget.cpp
+++ b/src/widgets/listwidget.cpp
@@ -1,6 +1,8 @@
#include "listwidget.h"
#include
+#include
+#include
#include
#include
@@ -9,20 +11,39 @@
using namespace vnotex;
-QBrush ListWidget::s_separatorForeground;
-
-QBrush ListWidget::s_separatorBackground;
-
ListWidget::ListWidget(QWidget *p_parent)
- : QListWidget(p_parent)
+ : ListWidget(false, p_parent)
{
- initialize();
}
ListWidget::ListWidget(bool p_enhancedStyle, QWidget *p_parent)
: QListWidget(p_parent)
{
- initialize();
+ m_clickTimer = new QTimer(this);
+ m_clickTimer->setSingleShot(true);
+ connect(m_clickTimer, &QTimer::timeout,
+ this, &ListWidget::handleItemClick);
+
+ connect(this, &QListWidget::itemClicked,
+ this, [this](QListWidgetItem *item) {
+ if (m_isDoubleClick && m_clickedItem == item) {
+ // There will be a single click right after double click.
+ m_clickTimer->stop();
+ handleItemClick();
+ return;
+ }
+
+ m_isDoubleClick = false;
+ m_clickedItem = item;
+ m_clickTimer->start(QApplication::doubleClickInterval());
+ });
+
+ connect(this, &QListWidget::itemDoubleClicked,
+ this, [this](QListWidgetItem *item) {
+ m_clickTimer->stop();
+ m_isDoubleClick = true;
+ m_clickedItem = item;
+ });
if (p_enhancedStyle) {
auto delegate = new StyledItemDelegate(QSharedPointer::create(this),
@@ -32,33 +53,31 @@ ListWidget::ListWidget(bool p_enhancedStyle, QWidget *p_parent)
}
}
-void ListWidget::initialize()
-{
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
-
- const auto &themeMgr = VNoteX::getInst().getThemeMgr();
- s_separatorForeground = QColor(themeMgr.paletteColor(QStringLiteral("widgets#styleditemdelegate#separator#fg")));
- s_separatorBackground = QColor(themeMgr.paletteColor(QStringLiteral("widgets#styleditemdelegate#separator#bg")));
- }
-}
-
void ListWidget::keyPressEvent(QKeyEvent *p_event)
{
if (WidgetUtils::processKeyEventLikeVi(this, p_event)) {
return;
}
+ bool activateItem = false;
+ const int key = p_event->key();
+ if (key == Qt::Key_Return || key == Qt::Key_Enter) {
+ activateItem = true;
+ }
// On Mac OS X, it is `Command+O` to activate an item, instead of Return.
#if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
- if (p_event->key() == Qt::Key_Return) {
+ if (key == Qt::Key_O && p_event->modifiers() == Qt::ControlModifier) {
+ activateItem = true;
+ }
+#endif
+
+ if (activateItem) {
if (auto item = currentItem()) {
emit itemActivated(item);
+ emit itemActivatedPlus(item, ActivateReason::Button);
}
return;
}
-#endif
QListWidget::keyPressEvent(p_event);
}
@@ -86,11 +105,31 @@ QVector ListWidget::getVisibleItems(const QListWidget *p_widg
return items;
}
+static const QBrush &separatorForeground()
+{
+ static QBrush fg;
+ if (fg == QBrush()) {
+ const auto &themeMgr = VNoteX::getInst().getThemeMgr();
+ fg = QColor(themeMgr.paletteColor(QStringLiteral("widgets#styleditemdelegate#separator#fg")));
+ }
+ return fg;
+}
+
+static const QBrush &separatorBackground()
+{
+ static QBrush bg;
+ if (bg == QBrush()) {
+ const auto &themeMgr = VNoteX::getInst().getThemeMgr();
+ bg = QColor(themeMgr.paletteColor(QStringLiteral("widgets#styleditemdelegate#separator#bg")));
+ }
+ return bg;
+}
+
QListWidgetItem *ListWidget::createSeparatorItem(const QString &p_text)
{
QListWidgetItem *item = new QListWidgetItem(p_text, nullptr, ItemTypeSeparator);
- item->setData(Qt::ForegroundRole, s_separatorForeground);
- item->setData(Qt::BackgroundRole, s_separatorBackground);
+ item->setData(Qt::ForegroundRole, separatorForeground());
+ item->setData(Qt::BackgroundRole, separatorBackground());
item->setFlags(Qt::NoItemFlags);
return item;
}
@@ -124,3 +163,14 @@ void ListWidget::forEachItem(const QListWidget *p_widget, const std::function
+class QTimer;
+
namespace vnotex
{
class ListWidget : public QListWidget
{
Q_OBJECT
public:
+ enum ActivateReason
+ {
+ SingleClick = 0,
+ DoubleClick,
+ Button
+ };
+
explicit ListWidget(QWidget *p_parent = nullptr);
ListWidget(bool p_enhancedStyle, QWidget *p_parent = nullptr);
@@ -28,6 +37,10 @@ namespace vnotex
// @p_func: return false to abort the iteration.
static void forEachItem(const QListWidget *p_widget, const std::function &p_func);
+ signals:
+ // Item activated not by mouse clicking.
+ void itemActivatedPlus(QListWidgetItem *p_item, ActivateReason p_source);
+
protected:
void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
@@ -37,11 +50,13 @@ namespace vnotex
ItemTypeSeparator = 2000
};
- void initialize();
+ void handleItemClick();
- static QBrush s_separatorForeground;
+ QTimer *m_clickTimer = nullptr;
- static QBrush s_separatorBackground;
+ QListWidgetItem *m_clickedItem = nullptr;
+
+ bool m_isDoubleClick = false;
};
}
diff --git a/src/widgets/mainwindow.cpp b/src/widgets/mainwindow.cpp
index 06c766af..73b8f797 100644
--- a/src/widgets/mainwindow.cpp
+++ b/src/widgets/mainwindow.cpp
@@ -47,6 +47,8 @@
#include "searchpanel.h"
#include "snippetpanel.h"
#include "historypanel.h"
+#include "windowspanel.h"
+#include "windowsprovider.h"
#include
#include "searchinfoprovider.h"
#include
@@ -263,6 +265,8 @@ void MainWindow::setupDocks()
setupHistoryPanel();
+ setupWindowsPanel();
+
setupSearchPanel();
setupSnippetPanel();
@@ -304,6 +308,12 @@ void MainWindow::setupHistoryPanel()
m_historyPanel->setObjectName("HistoryPanel.vnotex");
}
+void MainWindow::setupWindowsPanel()
+{
+ m_windowsPanel = new WindowsPanel(QSharedPointer::create(m_viewArea), this);
+ m_windowsPanel->setObjectName("WindowsPanel.vnotex");
+}
+
void MainWindow::setupLocationList()
{
m_locationList = new LocationList(this);
diff --git a/src/widgets/mainwindow.h b/src/widgets/mainwindow.h
index 5b6ef2af..38ba88af 100644
--- a/src/widgets/mainwindow.h
+++ b/src/widgets/mainwindow.h
@@ -27,6 +27,7 @@ namespace vnotex
class SearchPanel;
class SnippetPanel;
class HistoryPanel;
+ class WindowsPanel;
class ExportDialog;
class ConsoleViewer;
@@ -121,6 +122,8 @@ namespace vnotex
void setupHistoryPanel();
+ void setupWindowsPanel();
+
void setupNotebookExplorer();
void setupTagExplorer();
@@ -182,6 +185,8 @@ namespace vnotex
HistoryPanel *m_historyPanel = nullptr;
+ WindowsPanel *m_windowsPanel = nullptr;
+
ExportDialog *m_exportDialog = nullptr;
QSystemTrayIcon *m_trayIcon = nullptr;
diff --git a/src/widgets/viewarea.cpp b/src/widgets/viewarea.cpp
index c94f9d3e..3ec35ccb 100644
--- a/src/widgets/viewarea.cpp
+++ b/src/widgets/viewarea.cpp
@@ -240,14 +240,17 @@ ViewSplit *ViewArea::createViewSplit(QWidget *p_parent, ID p_viewSplitId)
connect(split, &ViewSplit::viewWindowCloseRequested,
this, [this](ViewWindow *p_win) {
closeViewWindow(p_win, false, true);
+ emit windowsChanged();
});
connect(split, &ViewSplit::verticalSplitRequested,
this, [this](ViewSplit *p_split) {
splitViewSplit(p_split, SplitType::Vertical);
+ emit windowsChanged();
});
connect(split, &ViewSplit::horizontalSplitRequested,
this, [this](ViewSplit *p_split) {
splitViewSplit(p_split, SplitType::Horizontal);
+ emit windowsChanged();
});
connect(split, &ViewSplit::maximizeSplitRequested,
this, &ViewArea::maximizeViewSplit);
@@ -256,16 +259,22 @@ ViewSplit *ViewArea::createViewSplit(QWidget *p_parent, ID p_viewSplitId)
connect(split, &ViewSplit::removeSplitRequested,
this, [this](ViewSplit *p_split) {
removeViewSplit(p_split, false);
+ emit windowsChanged();
});
connect(split, &ViewSplit::removeSplitAndWorkspaceRequested,
this, [this](ViewSplit *p_split) {
removeViewSplit(p_split, true);
+ emit windowsChanged();
});
connect(split, &ViewSplit::newWorkspaceRequested,
- this, &ViewArea::newWorkspaceInViewSplit);
+ this, [this](ViewSplit *p_split) {
+ newWorkspaceInViewSplit(p_split);
+ emit windowsChanged();
+ });
connect(split, &ViewSplit::removeWorkspaceRequested,
this, [this](ViewSplit *p_split) {
removeWorkspaceInViewSplit(p_split, true);
+ emit windowsChanged();
});
connect(split, &ViewSplit::focused,
this, [this](ViewSplit *p_split) {
@@ -287,9 +296,13 @@ ViewSplit *ViewArea::createViewSplit(QWidget *p_parent, ID p_viewSplitId)
p_win->setStatusWidgetVisible(true);
}
}
+ emit windowsChanged();
});
connect(split, &ViewSplit::moveViewWindowOneSplitRequested,
- this, &ViewArea::moveViewWindowOneSplit);
+ this, [this](ViewSplit *p_split, ViewWindow *p_win, Direction p_direction) {
+ moveViewWindowOneSplit(p_split, p_win, p_direction);
+ emit windowsChanged();
+ });
return split;
}
@@ -712,7 +725,7 @@ bool ViewArea::removeWorkspaceInViewSplit(ViewSplit *p_split, bool p_insertNew)
{
// Close all the ViewWindows.
setCurrentViewSplit(p_split, true);
- auto wins = getAllViewWindows(p_split);
+ auto wins = p_split->getAllViewWindows();
for (const auto win : wins) {
if (!closeViewWindow(win, false, false)) {
return false;
@@ -1154,11 +1167,9 @@ QVector ViewArea::getAllViewWindows(ViewSplit *p_split, const View
return wins;
}
-QVector ViewArea::getAllViewWindows(ViewSplit *p_split) const
+const QVector& ViewArea::getAllViewSplits() const
{
- return getAllViewWindows(p_split, [](ViewWindow *) {
- return true;
- });
+ return m_splits;
}
QList ViewArea::getAllBuffersInViewSplits() const
@@ -1166,7 +1177,7 @@ QList ViewArea::getAllBuffersInViewSplits() const
QSet bufferSet;
for (auto split : m_splits) {
- auto wins = getAllViewWindows(split);
+ auto wins = split->getAllViewWindows();
for (auto win : wins) {
bufferSet.insert(win->getBuffer());
}
@@ -1542,3 +1553,23 @@ void ViewArea::closeFile(const QString &p_filePath, const QSharedPointer
p_event->m_response = done;
p_event->m_handled = !done;
}
+
+void ViewArea::setCurrentViewWindow(ID p_splitId, int p_windowIndex)
+{
+ auto split = findSplitById(p_splitId);
+ if (split) {
+ setCurrentViewSplit(split, true);
+ split->setCurrentViewWindow(p_windowIndex);
+ }
+}
+
+ViewSplit *ViewArea::findSplitById(ID p_splitId) const
+{
+ for (auto split : m_splits) {
+ if (split->getId() == p_splitId) {
+ return split;
+ }
+ }
+
+ return nullptr;
+}
diff --git a/src/widgets/viewarea.h b/src/widgets/viewarea.h
index faeb37fd..2982ee92 100644
--- a/src/widgets/viewarea.h
+++ b/src/widgets/viewarea.h
@@ -74,6 +74,10 @@ namespace vnotex
ViewWindow *getCurrentViewWindow() const;
+ const QVector& getAllViewSplits() const;
+
+ void setCurrentViewWindow(ID p_splitId, int p_windowIndex);
+
public slots:
void openBuffer(Buffer *p_buffer, const QSharedPointer &p_paras);
@@ -103,7 +107,7 @@ namespace vnotex
// MainWindow should set the corresponding status widget accordingly.
void statusWidgetChanged(QWidget *p_widget);
- // Count of ViewSplit is chagned.
+ // Count of ViewSplit is changed.
// Used internally.
void viewSplitsCountChanged();
@@ -112,6 +116,10 @@ namespace vnotex
// State of current view window has update.
void currentViewWindowUpdated();
+ // ViewWindow reordered/added/removed/updated.
+ // ViewSplit added/removed/updated.
+ void windowsChanged();
+
private slots:
// Return true if @p_win is closed.
// @p_removeSplitIfEmpty: whether remove the workspace and split if @p_win is that only ViewWindow left.
@@ -212,8 +220,6 @@ namespace vnotex
QVector getAllViewWindows(ViewSplit *p_split, const ViewSplit::ViewWindowSelector &p_func) const;
- QVector getAllViewWindows(ViewSplit *p_split) const;
-
void takeSnapshot(ViewAreaSession &p_session) const;
void postFirstViewSplit();
@@ -226,6 +232,8 @@ namespace vnotex
ViewSplit *findSplitByDirection(ViewSplit *p_split, Direction p_direction);
+ ViewSplit *findSplitById(ID p_splitId) const;
+
SplitType checkSplitType(const QSplitter *p_splitter) const;
void flashViewSplit(ViewSplit *p_split);
diff --git a/src/widgets/viewsplit.cpp b/src/widgets/viewsplit.cpp
index 5e5ef409..d400e714 100644
--- a/src/widgets/viewsplit.cpp
+++ b/src/widgets/viewsplit.cpp
@@ -124,7 +124,7 @@ void ViewSplit::setupCornerWidget()
m_windowListButton->setPopupMode(QToolButton::InstantPopup);
m_windowListButton->setProperty(PropertyDefs::c_actionToolButton, true);
- auto act = new QAction(s_windowListIcon, tr("Windows List"), m_windowListButton);
+ auto act = new QAction(s_windowListIcon, tr("Open Windows"), m_windowListButton);
m_windowListButton->setDefaultAction(act);
auto menu = WidgetsFactory::createMenu(m_windowListButton);
@@ -315,6 +315,18 @@ ViewWindow *ViewSplit::getViewWindow(int p_idx) const
return dynamic_cast(widget(p_idx));
}
+QVector ViewSplit::getAllViewWindows() const
+{
+ QVector wins;
+ int cnt = getViewWindowCount();
+ for (int i = 0; i < cnt; ++i) {
+ auto win = getViewWindow(i);
+ wins.push_back(win);
+ }
+
+ return wins;
+}
+
int ViewSplit::getViewWindowCount() const
{
return count();
diff --git a/src/widgets/viewsplit.h b/src/widgets/viewsplit.h
index 1c44f604..7ea03930 100644
--- a/src/widgets/viewsplit.h
+++ b/src/widgets/viewsplit.h
@@ -49,6 +49,8 @@ namespace vnotex
void setCurrentViewWindow(int p_idx);
+ QVector getAllViewWindows() const;
+
// @p_win is not deleted.
void takeViewWindow(ViewWindow *p_win);
diff --git a/src/widgets/widgets.pri b/src/widgets/widgets.pri
index d7fada38..561121c8 100644
--- a/src/widgets/widgets.pri
+++ b/src/widgets/widgets.pri
@@ -124,7 +124,9 @@ SOURCES += \
$$PWD/dialogs/deleteconfirmdialog.cpp \
$$PWD/dialogs/importfolderutils.cpp \
$$PWD/titletoolbar.cpp \
- $$PWD/viewarea.cpp
+ $$PWD/viewarea.cpp \
+ $$PWD/windowspanel.cpp \
+ $$PWD/windowsprovider.cpp
HEADERS += \
$$PWD/attachmentdragdropareaindicator.h \
@@ -256,4 +258,6 @@ HEADERS += \
$$PWD/statusbarhelper.h \
$$PWD/dialogs/deleteconfirmdialog.h \
$$PWD/titletoolbar.h \
- $$PWD/viewarea.h
+ $$PWD/viewarea.h \
+ $$PWD/windowspanel.h \
+ $$PWD/windowsprovider.h
diff --git a/src/widgets/windowspanel.cpp b/src/widgets/windowspanel.cpp
new file mode 100644
index 00000000..86c0a6f7
--- /dev/null
+++ b/src/widgets/windowspanel.cpp
@@ -0,0 +1,88 @@
+#include "windowspanel.h"
+
+#include
+#include
+
+#include
+
+#include "windowsprovider.h"
+#include "listwidget.h"
+#include "navigationmodemgr.h"
+
+using namespace vnotex;
+
+WindowsPanel::WindowsPanel(const QSharedPointer &p_provider, QWidget *p_parent)
+ : QFrame(p_parent),
+ m_provider(p_provider)
+{
+ Q_ASSERT(m_provider);
+ setupUI();
+
+ connect(m_provider.data(), &WindowsProvider::windowsChanged,
+ this, &WindowsPanel::updateWindowsList);
+}
+
+void WindowsPanel::setupUI()
+{
+ auto mainLayout = new QVBoxLayout(this);
+ WidgetUtils::setContentsMargins(mainLayout);
+
+ m_windows = new ListWidget(true, this);
+ mainLayout->addWidget(m_windows);
+
+ connect(m_windows, &ListWidget::itemActivatedPlus,
+ this, [this](QListWidgetItem *item, ListWidget::ActivateReason reason) {
+ if (reason == ListWidget::ActivateReason::Button) {
+ activateItem(item);
+ }
+ });
+ connect(m_windows, &QListWidget::itemClicked,
+ this, [this](QListWidgetItem *item) {
+ // It is fine to trigger multiple times.
+ activateItem(item);
+ });
+
+ m_navigationWrapper.reset(new NavigationModeWrapper(m_windows));
+ NavigationModeMgr::getInst().registerNavigationTarget(m_navigationWrapper.data());
+
+ setFocusProxy(m_windows);
+}
+
+void WindowsPanel::updateWindowsList()
+{
+ m_windows->clear();
+ if (!isVisible()) {
+ return;
+ }
+
+ const auto wins = m_provider->getWindows();
+ for (const auto &splitWins : wins) {
+ for (const auto &win : splitWins.m_viewWindows) {
+ addItem(splitWins.m_viewSplitId, win);
+ }
+ }
+}
+
+void WindowsPanel::addItem(ID p_viewSplitId, const WindowsProvider::WindowData &p_data)
+{
+ auto item = new QListWidgetItem(m_windows);
+
+ item->setText(p_data.m_name);
+ item->setToolTip(p_data.m_name);
+ item->setData(Qt::UserRole, p_viewSplitId);
+ item->setData(Role::UserRole2, p_data.m_index);
+}
+
+void WindowsPanel::showEvent(QShowEvent *p_event)
+{
+ QFrame::showEvent(p_event);
+
+ updateWindowsList();
+}
+
+void WindowsPanel::activateItem(QListWidgetItem *p_item)
+{
+ Q_ASSERT(p_item);
+ m_provider->setCurrentWindow(p_item->data(Qt::UserRole).toULongLong(),
+ p_item->data(Role::UserRole2).toInt());
+}
diff --git a/src/widgets/windowspanel.h b/src/widgets/windowspanel.h
new file mode 100644
index 00000000..27a5b4fc
--- /dev/null
+++ b/src/widgets/windowspanel.h
@@ -0,0 +1,43 @@
+#ifndef WINDOWSPANEL_H
+#define WINDOWSPANEL_H
+
+#include
+#include
+#include
+
+#include "navigationmodewrapper.h"
+#include "windowsprovider.h"
+
+class QListWidgetItem;
+
+namespace vnotex
+{
+ class ListWidget;
+
+ class WindowsPanel : public QFrame
+ {
+ Q_OBJECT
+ public:
+ WindowsPanel(const QSharedPointer &p_provider, QWidget *p_parent = nullptr);
+
+ protected:
+ void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
+
+ private:
+ void setupUI();
+
+ void updateWindowsList();
+
+ void addItem(ID p_viewSplitId, const WindowsProvider::WindowData &p_data);
+
+ void activateItem(QListWidgetItem *p_item);
+
+ QSharedPointer m_provider;
+
+ ListWidget *m_windows = nullptr;
+
+ QScopedPointer> m_navigationWrapper;
+ };
+}
+
+#endif // WINDOWSPANEL_H
diff --git a/src/widgets/windowsprovider.cpp b/src/widgets/windowsprovider.cpp
new file mode 100644
index 00000000..39e4f261
--- /dev/null
+++ b/src/widgets/windowsprovider.cpp
@@ -0,0 +1,46 @@
+#include "windowsprovider.h"
+
+#include "viewarea.h"
+#include "viewsplit.h"
+#include "viewwindow.h"
+
+using namespace vnotex;
+
+WindowsProvider::WindowsProvider(ViewArea *p_viewArea)
+ : QObject(nullptr),
+ m_viewArea(p_viewArea)
+{
+ Q_ASSERT(m_viewArea);
+ connect(m_viewArea, &ViewArea::windowsChanged,
+ this, &WindowsProvider::windowsChanged);
+}
+
+QVector WindowsProvider::getWindows() const
+{
+ QVector windows;
+
+ const auto& splits = m_viewArea->getAllViewSplits();
+ for (auto split : splits) {
+ auto wins = split->getAllViewWindows();
+ if (wins.empty()) {
+ continue;
+ }
+
+ windows.push_back(ViewSplitWindows());
+ auto& tmp = windows.back();
+ tmp.m_viewSplitId = split->getId();
+ for (int idx = 0; idx < wins.size(); ++idx) {
+ WindowData data;
+ data.m_index = idx;
+ data.m_name = wins[idx]->getName();
+ tmp.m_viewWindows.push_back(data);
+ }
+ }
+
+ return windows;
+}
+
+void WindowsProvider::setCurrentWindow(ID p_viewSplitId, int p_windowIndex)
+{
+ m_viewArea->setCurrentViewWindow(p_viewSplitId, p_windowIndex);
+}
diff --git a/src/widgets/windowsprovider.h b/src/widgets/windowsprovider.h
new file mode 100644
index 00000000..47320e1e
--- /dev/null
+++ b/src/widgets/windowsprovider.h
@@ -0,0 +1,46 @@
+#ifndef WINDOWSPROVIDER_H
+#define WINDOWSPROVIDER_H
+
+#include
+
+#include
+
+#include
+
+namespace vnotex
+{
+ class ViewArea;
+
+ class WindowsProvider : public QObject
+ {
+ Q_OBJECT
+ public:
+ struct WindowData
+ {
+ int m_index = -1;
+
+ QString m_name;
+ };
+
+ struct ViewSplitWindows
+ {
+ ID m_viewSplitId = 0;
+
+ QVector m_viewWindows;
+ };
+
+ explicit WindowsProvider(ViewArea *p_viewArea);
+
+ QVector getWindows() const;
+
+ void setCurrentWindow(ID p_viewSplitId, int p_windowIndex);
+
+ signals:
+ void windowsChanged();
+
+ private:
+ ViewArea *m_viewArea = nullptr;
+ };
+}
+
+#endif // WINDOWSPROVIDER_H