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