1 /*
2 SPDX-FileCopyrightText: 2006 Adam Treat <treat@kde.org>
3 SPDX-FileCopyrightText: 2007 Alexander Dymo <adymo@kdevelop.org>
4 SPDX-FileCopyrightText: 2015 Kevin Funk <kfunk@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8
9 #include "partcontroller.h"
10
11 #include <QAction>
12 #include <QMimeDatabase>
13 #include <QMimeType>
14
15 #include <KActionCollection>
16 #include <KToggleAction>
17 #include <KLocalizedString>
18 #include <KMimeTypeTrader>
19
20 #include <KParts/Part>
21
22 #include <KTextEditor/View>
23 #include <KTextEditor/Editor>
24 #include <KTextEditor/Document>
25
26 #include "core.h"
27 #include "textdocument.h"
28 #include "debug.h"
29 #include "uicontroller.h"
30 #include "mainwindow.h"
31 #include <interfaces/isession.h>
32 #include <interfaces/iuicontroller.h>
33 #include <interfaces/idocumentcontroller.h>
34 #include <sublime/area.h>
35
36 namespace KDevelop
37 {
38
39 class PartControllerPrivate
40 {
41 public:
PartControllerPrivate(Core * core)42 explicit PartControllerPrivate(Core* core)
43 : m_core(core)
44 {}
45
46 bool m_showTextEditorStatusBar = false;
47 QString m_editor;
48 QStringList m_textTypes;
49
50 Core* const m_core;
51 };
52
PartController(Core * core,QWidget * toplevel)53 PartController::PartController(Core *core, QWidget *toplevel)
54 : IPartController(toplevel)
55 , d_ptr(new PartControllerPrivate(core))
56
57 {
58 setObjectName(QStringLiteral("PartController"));
59
60 //Cache this as it is too expensive when creating parts
61 // KConfig * config = Config::standard();
62 // config->setGroup( "General" );
63 //
64 // d->m_textTypes = config->readEntry( "TextTypes", QStringList() );
65 //
66 // config ->setGroup( "Editor" );
67 // d->m_editor = config->readPathEntry( "EmbeddedKTextEditor", QString() );
68
69 // required early because some actions are checkable and need to be initialized
70 loadSettings(false);
71
72 if (!(Core::self()->setupFlags() & Core::NoUi))
73 setupActions();
74 }
75
76 PartController::~PartController() = default;
77
showTextEditorStatusBar() const78 bool PartController::showTextEditorStatusBar() const
79 {
80 Q_D(const PartController);
81
82 return d->m_showTextEditorStatusBar;
83 }
84
setShowTextEditorStatusBar(bool show)85 void PartController::setShowTextEditorStatusBar(bool show)
86 {
87 Q_D(PartController);
88
89 if (d->m_showTextEditorStatusBar == show)
90 return;
91
92 d->m_showTextEditorStatusBar = show;
93
94 // update
95 const auto areas = Core::self()->uiControllerInternal()->allAreas();
96 for (Sublime::Area* area : areas) {
97 const auto views = area->views();
98 for (Sublime::View* view : views) {
99 if (!view->hasWidget())
100 continue;
101
102 auto textView = qobject_cast<KTextEditor::View*>(view->widget());
103 if (textView) {
104 textView->setStatusBarEnabled(show);
105 }
106 }
107 }
108
109 // also notify active view that it should update the "view status"
110 auto* textView = qobject_cast<TextView*>(Core::self()->uiControllerInternal()->activeSublimeWindow()->activeView());
111 if (textView) {
112 emit textView->statusChanged(textView);
113 }
114 }
115
116 //MOVE BACK TO DOCUMENTCONTROLLER OR MULTIBUFFER EVENTUALLY
isTextType(const QMimeType & mimeType)117 bool PartController::isTextType(const QMimeType& mimeType)
118 {
119 Q_D(PartController);
120
121 bool isTextType = false;
122 if (d->m_textTypes.contains(mimeType.name()))
123 {
124 isTextType = true;
125 }
126
127 // is this regular text - open in editor
128 return ( isTextType
129 || mimeType.inherits(QStringLiteral("text/plain"))
130 || mimeType.inherits(QStringLiteral("text/html"))
131 || mimeType.inherits(QStringLiteral("application/x-zerosize")));
132 }
133
editorPart() const134 KTextEditor::Editor* PartController::editorPart() const
135 {
136 return KTextEditor::Editor::instance();
137 }
138
createTextPart()139 KTextEditor::Document* PartController::createTextPart()
140 {
141 return editorPart()->createDocument(this);
142 }
143
createPart(const QString & mimeType,const QString & partType,const QString & className,const QString & preferredName)144 KParts::Part* PartController::createPart( const QString & mimeType,
145 const QString & partType,
146 const QString & className,
147 const QString & preferredName )
148 {
149 KPluginFactory * editorFactory = findPartFactory(
150 mimeType,
151 partType,
152 preferredName );
153
154 if ( !className.isEmpty() && editorFactory )
155 {
156 return editorFactory->create<KParts::Part>(
157 nullptr,
158 this,
159 className);
160 }
161
162 return nullptr;
163 }
164
canCreatePart(const QUrl & url)165 bool PartController::canCreatePart(const QUrl& url)
166 {
167 if (!url.isValid()) return false;
168
169 QString mimeType;
170 if ( url.isEmpty() )
171 mimeType = QStringLiteral("text/plain");
172 else
173 mimeType = QMimeDatabase().mimeTypeForUrl(url).name();
174
175 KService::List offers = KMimeTypeTrader::self()->query(
176 mimeType,
177 QStringLiteral("KParts/ReadOnlyPart") );
178
179 return offers.count() > 0;
180 }
181
createPart(const QUrl & url,const QString & preferredPart)182 KParts::Part* PartController::createPart( const QUrl & url, const QString& preferredPart )
183 {
184 qCDebug(SHELL) << "creating part with url" << url << "and pref part:" << preferredPart;
185 QString mimeType;
186 if ( url.isEmpty() )
187 //create a part for empty text file
188 mimeType = QStringLiteral("text/plain");
189 else if ( !url.isValid() )
190 return nullptr;
191 else
192 mimeType = QMimeDatabase().mimeTypeForUrl(url).name();
193
194 KParts::Part* part = createPart( mimeType, preferredPart );
195 if (!part) {
196 return nullptr;
197 }
198
199 // only ReadOnlyParts are supported by PartController
200 static_cast<KParts::ReadOnlyPart*>(part)->openUrl(url);
201
202 // restrict keyboard shortcuts to the KParts view
203 const auto actions = part->actionCollection()->actions();
204 for (auto* action : actions) {
205 if (action->shortcutContext() != Qt::WidgetShortcut) {
206 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
207 }
208 }
209
210 return part;
211 }
212
loadSettings(bool projectIsLoaded)213 void PartController::loadSettings( bool projectIsLoaded )
214 {
215 Q_D(PartController);
216
217 Q_UNUSED( projectIsLoaded );
218
219 KConfigGroup cg(KSharedConfig::openConfig(), "UiSettings");
220 d->m_showTextEditorStatusBar = cg.readEntry("ShowTextEditorStatusBar", false);
221 }
222
saveSettings(bool projectIsLoaded)223 void PartController::saveSettings( bool projectIsLoaded )
224 {
225 Q_D(PartController);
226
227 Q_UNUSED( projectIsLoaded );
228
229 KConfigGroup cg(KSharedConfig::openConfig(), "UiSettings");
230 cg.writeEntry("ShowTextEditorStatusBar", d->m_showTextEditorStatusBar);
231 }
232
initialize()233 void PartController::initialize()
234 {
235 }
236
cleanup()237 void PartController::cleanup()
238 {
239 saveSettings(false);
240 }
241
setupActions()242 void PartController::setupActions()
243 {
244 Q_D(PartController);
245
246 KActionCollection* actionCollection =
247 d->m_core->uiControllerInternal()->defaultMainWindow()->actionCollection();
248
249 QAction* action;
250
251 action = KStandardAction::showStatusbar(this, SLOT(setShowTextEditorStatusBar(bool)), actionCollection);
252 action->setWhatsThis(i18nc("@info:whatsthis", "Use this command to show or hide the view's statusbar."));
253 action->setChecked(showTextEditorStatusBar());
254 }
255
256 }
257
258