Skip to content

Commit e55f7ff

Browse files
committed
Add ProjectWindowNavigatorAddOn
1 parent 518d48d commit e55f7ff

6 files changed

Lines changed: 237 additions & 21 deletions

File tree

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#include "projectwindownavigatoraddon.h"
2+
3+
#include <ranges>
4+
#include <algorithm>
5+
6+
#include <QQmlComponent>
7+
#include <QLoggingCategory>
8+
#include <QStandardItemModel>
9+
10+
#include <CoreApi/runtimeinterface.h>
11+
#include <CoreApi/windowsystem.h>
12+
13+
#include <SVSCraftCore/SVSCraftNamespace.h>
14+
15+
#include <coreplugin/coreinterface.h>
16+
#include <coreplugin/projectwindowinterface.h>
17+
18+
namespace Core::Internal {
19+
20+
Q_STATIC_LOGGING_CATEGORY(lcProjectWindowNavigatorAddOn, "diffscope.core.projectwindownavigatoraddon")
21+
22+
ProjectWindowNavigatorAddOn::ProjectWindowNavigatorAddOn(QObject *parent) : WindowInterfaceAddOn(parent) {
23+
m_quickPickCommandModel = new QStandardItemModel(this);
24+
}
25+
26+
ProjectWindowNavigatorAddOn::~ProjectWindowNavigatorAddOn() = default;
27+
28+
void ProjectWindowNavigatorAddOn::initialize() {
29+
auto windowInterface = windowHandle()->cast<ActionWindowInterfaceBase>();
30+
QQmlComponent component(RuntimeInterface::qmlEngine(), "DiffScope.Core", "ProjectWindowNavigatorAddOnActions");
31+
if (component.isError()) {
32+
qFatal() << component.errorString();
33+
}
34+
auto o = component.createWithInitialProperties({
35+
{"addOn", QVariant::fromValue(this)},
36+
});
37+
o->setParent(this);
38+
QMetaObject::invokeMethod(o, "registerToContext", windowInterface->actionContext());
39+
}
40+
41+
void ProjectWindowNavigatorAddOn::extensionsInitialized() {
42+
auto windowSystem = CoreInterface::windowSystem();
43+
44+
// Connect to window creation and destruction signals
45+
connect(windowSystem, &WindowSystem::windowCreated, this, [this](WindowInterface *windowInterface) {
46+
if (qobject_cast<ProjectWindowInterface *>(windowInterface)) {
47+
updateProjectWindows();
48+
}
49+
});
50+
51+
connect(windowSystem, &WindowSystem::windowAboutToDestroy, this, [this](WindowInterface *windowInterface) {
52+
if (qobject_cast<ProjectWindowInterface *>(windowInterface)) {
53+
updateProjectWindows();
54+
}
55+
});
56+
57+
// Initialize the list with current windows
58+
updateProjectWindows();
59+
}
60+
61+
bool ProjectWindowNavigatorAddOn::delayedInitialize() {
62+
return WindowInterfaceAddOn::delayedInitialize();
63+
}
64+
65+
QList<ProjectWindowInterface *> ProjectWindowNavigatorAddOn::projectWindows() const {
66+
return m_projectWindows;
67+
}
68+
69+
void ProjectWindowNavigatorAddOn::raiseWindow(ProjectWindowInterface *windowInterface) {
70+
qCDebug(lcProjectWindowNavigatorAddOn) << "Raising project window" << windowInterface;
71+
auto window = windowInterface->window();
72+
if (window->visibility() == QWindow::Minimized) {
73+
window->showNormal();
74+
}
75+
window->raise(); // TODO: what does the previous QMView::raiseWindow do to the window?
76+
window->requestActivate();
77+
}
78+
79+
void ProjectWindowNavigatorAddOn::navigateToWindow(int step) const {
80+
if (auto windowInterface = qobject_cast<ProjectWindowInterface *>(windowHandle())) {
81+
auto index = m_projectWindows.indexOf(windowInterface);
82+
if (index == -1)
83+
return;
84+
index = (index + step + m_projectWindows.size()) % m_projectWindows.size();
85+
auto target = m_projectWindows[index];
86+
raiseWindow(target);
87+
} else if (!m_projectWindows.isEmpty()) {
88+
auto target = m_projectWindows.first();
89+
raiseWindow(target);
90+
}
91+
}
92+
93+
void ProjectWindowNavigatorAddOn::showSwitchToProjectWindowCommand() const {
94+
auto windowInterface = windowHandle()->cast<ActionWindowInterfaceBase>();
95+
auto index = windowInterface->execQuickPick(m_quickPickCommandModel, "Switch to project window", 0);
96+
if (index == -1)
97+
return;
98+
raiseWindow(m_projectWindows.at(index));
99+
}
100+
101+
void ProjectWindowNavigatorAddOn::updateProjectWindows() {
102+
m_projectWindows.clear();
103+
auto windows = CoreInterface::windowSystem()->windows();
104+
std::ranges::transform(
105+
windows | std::views::filter([](auto w) { return qobject_cast<ProjectWindowInterface *>(w); }),
106+
std::back_inserter(m_projectWindows),
107+
[](auto w) { return qobject_cast<ProjectWindowInterface *>(w); }
108+
);
109+
m_quickPickCommandModel->clear();
110+
for (auto windowInterface : m_projectWindows) {
111+
auto item = new QStandardItem;
112+
item->setData(windowInterface->window()->property("documentName"), SVS::SVSCraft::CP_TitleRole);
113+
m_quickPickCommandModel->appendRow(item);
114+
}
115+
Q_EMIT projectWindowsChanged();
116+
}
117+
118+
}
119+
120+
#include "moc_projectwindownavigatoraddon.cpp"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#ifndef DIFFSCOPE_COREPLUGIN_PROJECTWINDOWNAVIGATORADDON_H
2+
#define DIFFSCOPE_COREPLUGIN_PROJECTWINDOWNAVIGATORADDON_H
3+
4+
#include <CoreApi/windowinterface.h>
5+
6+
class QStandardItemModel;
7+
8+
namespace Core {
9+
class ProjectWindowInterface;
10+
}
11+
12+
namespace Core::Internal {
13+
14+
class ProjectWindowNavigatorAddOn : public WindowInterfaceAddOn {
15+
Q_OBJECT
16+
Q_PROPERTY(QList<ProjectWindowInterface *> projectWindows READ projectWindows NOTIFY projectWindowsChanged)
17+
public:
18+
explicit ProjectWindowNavigatorAddOn(QObject *parent = nullptr);
19+
~ProjectWindowNavigatorAddOn() override;
20+
21+
void initialize() override;
22+
void extensionsInitialized() override;
23+
bool delayedInitialize() override;
24+
25+
QList<ProjectWindowInterface *> projectWindows() const;
26+
27+
Q_INVOKABLE static void raiseWindow(ProjectWindowInterface *windowInterface);
28+
Q_INVOKABLE void navigateToWindow(int step) const;
29+
Q_INVOKABLE void showSwitchToProjectWindowCommand() const;
30+
31+
Q_SIGNALS:
32+
void projectWindowsChanged();
33+
34+
private:
35+
void updateProjectWindows();
36+
37+
QList<ProjectWindowInterface *> m_projectWindows;
38+
QStandardItemModel *m_quickPickCommandModel;
39+
};
40+
41+
}
42+
43+
#endif //DIFFSCOPE_COREPLUGIN_PROJECTWINDOWNAVIGATORADDON_H

src/plugins/coreplugin/internal/coreplugin.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#include <coreplugin/internal/coreachievementsmodel.h>
6565
#include <coreplugin/internal/recentfileaddon.h>
6666
#include <coreplugin/internal/metadataaddon.h>
67+
#include <coreplugin/internal/projectwindownavigatoraddon.h>
6768

6869
static auto getCoreActionExtension() {
6970
return QAK_STATIC_ACTION_EXTENSION(core_actions);
@@ -384,6 +385,8 @@ namespace Core::Internal {
384385
HomeWindowInterfaceRegistry::instance()->attach<RecentFileAddOn>();
385386
ProjectWindowInterfaceRegistry::instance()->attach<RecentFileAddOn>();
386387
ProjectWindowInterfaceRegistry::instance()->attach<MetadataAddOn>();
388+
HomeWindowInterfaceRegistry::instance()->attach<ProjectWindowNavigatorAddOn>();
389+
ProjectWindowInterfaceRegistry::instance()->attach<ProjectWindowNavigatorAddOn>();
387390
}
388391

389392
void CorePlugin::initializeBehaviorPreference() {

src/plugins/coreplugin/qml/actions/GlobalActions.qml

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -86,27 +86,6 @@ ActionCollection {
8686
}
8787
}
8888

89-
ActionItem {
90-
actionId: "core.window.nextProjectWindow"
91-
Action {
92-
93-
}
94-
}
95-
96-
ActionItem {
97-
actionId: "core.window.previousProjectWindow"
98-
Action {
99-
100-
}
101-
}
102-
103-
ActionItem {
104-
actionId: "core.window.projectWindows"
105-
Menu {
106-
107-
}
108-
}
109-
11089
ActionItem {
11190
actionId: "core.aboutApp"
11291
Action {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import QtQml
2+
import QtQml.Models
3+
import QtQuick
4+
import QtQuick.Controls
5+
6+
import SVSCraft.UIComponents
7+
import SVSCraft.UIComponents.impl
8+
9+
import QActionKit
10+
11+
import DiffScope.UIShell
12+
import DiffScope.Core
13+
14+
ActionCollection {
15+
id: d
16+
required property QtObject addOn
17+
18+
ActionItem {
19+
actionId: "core.window.nextProjectWindow"
20+
Action {
21+
enabled: d.addOn.projectWindows.length !== 0
22+
onTriggered: d.addOn.navigateToWindow(1)
23+
}
24+
}
25+
26+
ActionItem {
27+
actionId: "core.window.previousProjectWindow"
28+
Action {
29+
enabled: d.addOn.projectWindows.length !== 0
30+
onTriggered: d.addOn.navigateToWindow(-1)
31+
}
32+
}
33+
34+
ActionItem {
35+
actionId: "core.window.projectWindows"
36+
Menu {
37+
id: menu
38+
Instantiator {
39+
model: DelegateModel {
40+
model: d.addOn.projectWindows
41+
delegate: Action {
42+
required property int index
43+
required property ProjectWindowInterface modelData
44+
text: (index < 9 ? `&${Qt.locale().toString(index + 1)}. ` : "") + modelData.window.documentName
45+
checkable: true
46+
checked: d.addOn.windowHandle === modelData
47+
onTriggered: () => {
48+
d.addOn.raiseWindow(modelData)
49+
}
50+
}
51+
}
52+
onObjectAdded: (index, object) => {
53+
menu.insertAction(index, object)
54+
}
55+
onObjectRemoved: (index, object) => {
56+
menu.removeAction(object)
57+
}
58+
}
59+
}
60+
}
61+
62+
ActionItem {
63+
actionId: "core.window.switchToProjectWindow"
64+
Action {
65+
enabled: d.addOn.projectWindows.length !== 0
66+
onTriggered: d.addOn.showSwitchToProjectWindowCommand()
67+
}
68+
}
69+
70+
}

src/plugins/coreplugin/res/core_actions.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@
132132
<action id="core.window.&amp;nextProjectWindow" description="Switch to the next project window" shortcut="Alt+J" />
133133
<action id="core.window.&amp;previousProjectWindow" description="Switch to the previous project window" shortcut="Alt+K" />
134134
<action id="core.window.pro&amp;jectWindows" diffscope:excludeFromCommands="true" />
135+
<action id="core.window.switchToProjectWindow^" />
135136

136137
<action id="core.documentations" text="&amp;Help" description="Show help contents" class="Help" shortcut="F1" />
137138
<action id="core.&amp;findActions^" class="Help" description="Find and trigger action by name" shortcut="Ctrl+Shift+P" />

0 commit comments

Comments
 (0)