1 /*
2 SPDX-FileCopyrightText: 2010-2011 Friedrich W. H. Kossebau <kossebau@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7 #include "oktetadocument.h"
8
9 // plugin
10 #include "oktetaplugin.h"
11 #include "oktetaview.h"
12 // Okteta
13 #include <Kasten/Okteta/ByteArrayViewProfileManager>
14 #include <Kasten/Okteta/ByteArrayViewProfileSynchronizer>
15 #include <Kasten/Okteta/ByteArrayRawFileSynchronizerFactory>
16 #include <Kasten/Okteta/ByteArrayDocument>
17 // Kasten
18 #include <Kasten/JobManager>
19 #include <Kasten/AbstractLoadJob>
20 #include <Kasten/AbstractSyncToRemoteJob>
21 #include <Kasten/AbstractSyncFromRemoteJob>
22 #include <Kasten/AbstractModelSynchronizer>
23 // KDevelop
24 #include <shell/core.h>
25 #include <shell/uicontroller.h>
26 #include <interfaces/icore.h>
27 #include <interfaces/iuicontroller.h>
28 // Sublime
29 #include <sublime/mainwindow.h>
30 #include <sublime/view.h>
31 #include <sublime/area.h>
32 #include <sublime/controller.h>
33 // KF
34 #include <KMessageBox>
35 #include <KLocalizedString>
36 #include <KTextEditor/Cursor>
37 // Qt
38 #include <QApplication>
39 #include <QMimeDatabase>
40
41
42 namespace KDevelop
43 {
44
OktetaDocument(const QUrl & url,ICore * core)45 OktetaDocument::OktetaDocument( const QUrl &url , ICore* core )
46 : Sublime::UrlDocument( core->uiController()->controller(), url )
47 , IDocument( core )
48 , mPlugin( nullptr )
49 , mByteArrayDocument( nullptr )
50 {
51 }
52
url() const53 QUrl OktetaDocument::url() const { return Sublime::UrlDocument::url(); }
54
55 // TODO: use fromContentAndUrl(ByteArrayIODevice) if document loaded
mimeType() const56 QMimeType OktetaDocument::mimeType() const { return QMimeDatabase().mimeTypeForUrl( url() ); }
57
partForView(QWidget *) const58 KParts::Part* OktetaDocument::partForView( QWidget* ) const { return nullptr; }
textDocument() const59 KTextEditor::Document* OktetaDocument::textDocument() const { return nullptr; }
cursorPosition() const60 KTextEditor::Cursor OktetaDocument::cursorPosition() const { return KTextEditor::Cursor(); }
61
state() const62 IDocument::DocumentState OktetaDocument::state() const
63 {
64 return mByteArrayDocument ?
65 ( mByteArrayDocument->synchronizer()->localSyncState() == Kasten::LocalHasChanges ?
66 IDocument::Modified :
67 IDocument::Clean ) :
68 IDocument::Clean;
69 }
70
71
save(IDocument::DocumentSaveMode mode)72 bool OktetaDocument::save( IDocument::DocumentSaveMode mode )
73 {
74 if( mode & Discard )
75 return true;
76
77 if( state() == IDocument::Clean )
78 return false;
79
80 Kasten::AbstractModelSynchronizer* synchronizer = mByteArrayDocument->synchronizer();
81
82 Kasten::AbstractSyncToRemoteJob* syncJob = synchronizer->startSyncToRemote();
83 const bool syncSucceeded = Kasten::JobManager::executeJob( syncJob );
84
85 if( syncSucceeded )
86 {
87 notifySaved();
88 notifyStateChanged();
89 }
90
91 return syncSucceeded;
92 }
93
94
reload()95 void OktetaDocument::reload()
96 {
97 Kasten::AbstractModelSynchronizer* synchronizer = mByteArrayDocument->synchronizer();
98
99 Kasten::AbstractSyncFromRemoteJob* syncJob = synchronizer->startSyncFromRemote();
100 const bool syncSucceeded = Kasten::JobManager::executeJob( syncJob );
101
102 if( syncSucceeded )
103 notifyStateChanged();
104 }
105
close(IDocument::DocumentSaveMode mode)106 bool OktetaDocument::close( IDocument::DocumentSaveMode mode )
107 {
108 bool isCanceled = false;
109 if( !(mode & Discard) )
110 {
111 if (mode & Silent)
112 {
113 if (!save(mode))
114 isCanceled = true;
115
116 }
117 else
118 {
119 if( state() == IDocument::Modified )
120 {
121 // TODO: use Kasten::*Manager
122 int code = KMessageBox::warningYesNoCancel(
123 qApp->activeWindow(),
124 i18n("The document \"%1\" has unsaved changes. Would you like to save them?", url().toLocalFile()),
125 i18nc("@title:window", "Close Document"));
126
127 if (code == KMessageBox::Yes) {
128 if (!save(mode))
129 isCanceled = true;
130
131 } else if (code == KMessageBox::Cancel)
132 isCanceled = true;
133
134 }
135 else if( state() == IDocument::DirtyAndModified )
136 {
137 if( !save(mode) )
138 isCanceled = true;
139 }
140 }
141 }
142
143 if( isCanceled )
144 return false;
145
146 //close all views and then delete ourself
147 ///@todo test this
148 const QList<Sublime::Area*>& allAreas =
149 ICore::self()->uiController()->controller()->allAreas();
150 for (Sublime::Area* area : allAreas ) {
151 const QList<Sublime::View*> areaViews = area->views();
152 for (Sublime::View* view : areaViews) {
153 if (views().contains(view))
154 {
155 area->removeView(view);
156 delete view;
157 }
158 }
159 }
160
161 // The document is deleted automatically when there are no views left
162
163 return true;
164 }
165
isActive() const166 bool OktetaDocument::isActive() const
167 {
168 return Core::self()->uiControllerInternal()->activeSublimeWindow()->activeView()->document() == this;
169 }
170
171
setCursorPosition(const KTextEditor::Cursor &)172 void OktetaDocument::setCursorPosition( const KTextEditor::Cursor& ) {}
setTextSelection(const KTextEditor::Range &)173 void OktetaDocument::setTextSelection( const KTextEditor::Range& ) {}
174
activate(Sublime::View *,KParts::MainWindow *)175 void OktetaDocument::activate( Sublime::View* /* view */, KParts::MainWindow* /* mainWindow */ )
176 {
177 notifyActivated();
178 }
179
setPlugin(OktetaPlugin * plugin)180 void OktetaDocument::setPlugin( OktetaPlugin* plugin )
181 {
182 mPlugin = plugin;
183 }
184
newView(Sublime::Document *)185 Sublime::View* OktetaDocument::newView( Sublime::Document* /* document */ )
186 {
187 if( mByteArrayDocument == nullptr )
188 {
189 auto* synchronizerFactory =
190 new Kasten::ByteArrayRawFileSynchronizerFactory();
191 Kasten::AbstractModelSynchronizer* synchronizer = synchronizerFactory->createSynchronizer();
192
193 Kasten::AbstractLoadJob* loadJob = synchronizer->startLoad( url() );
194 connect( loadJob, &Kasten::AbstractLoadJob::documentLoaded,
195 this, &OktetaDocument::onByteArrayDocumentLoaded );
196 Kasten::JobManager::executeJob( loadJob );
197
198 delete synchronizerFactory;
199 }
200
201 Kasten::ByteArrayViewProfileManager* const viewProfileManager = mPlugin->viewProfileManager();
202 auto* viewProfileSynchronizer =
203 new Kasten::ByteArrayViewProfileSynchronizer( viewProfileManager );
204 viewProfileSynchronizer->setViewProfileId( viewProfileManager->defaultViewProfileId() );
205 return new OktetaView( this, viewProfileSynchronizer );
206 }
207
closeDocument(bool silent)208 bool OktetaDocument::closeDocument(bool silent)
209 {
210 return close(silent ? Silent : Default);
211 }
212
onByteArrayDocumentLoaded(Kasten::AbstractDocument * document)213 void OktetaDocument::onByteArrayDocumentLoaded( Kasten::AbstractDocument* document )
214 {
215 if( document )
216 {
217 mByteArrayDocument = static_cast<Kasten::ByteArrayDocument*>( document );
218 connect( mByteArrayDocument->synchronizer(), &Kasten::AbstractModelSynchronizer::localSyncStateChanged,
219 this, &OktetaDocument::onByteArrayDocumentChanged );
220 }
221 }
222
onByteArrayDocumentChanged()223 void OktetaDocument::onByteArrayDocumentChanged()
224 {
225 notifyStateChanged();
226 }
227
~OktetaDocument()228 OktetaDocument::~OktetaDocument()
229 {
230 delete mByteArrayDocument;
231 }
232
233 }
234