1/* This file is part of the KDE project
2 Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
3 Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#include "kateapp.h"
21#include "kateapp.moc"
22
23#include "katedocmanager.h"
24#include "katepluginmanager.h"
25#include "kateviewmanager.h"
26#include "katesession.h"
27#include "katemainwindow.h"
28#include "kateappcommands.h"
29
30#include <kate/application.h>
31
32#include <kdeversion.h>
33#include <KCmdLineArgs>
34#include <KConfig>
35#include <KTipDialog>
36#include <kdebug.h>
37#include <KMessageBox>
38#include <KLocale>
39#include <KStartupInfo>
40
41#include <QFileInfo>
42#include <QTextCodec>
43
44#include <stdlib.h>
45#include <sys/types.h>
46#include <unistd.h>
47#include "kateappadaptor.h"
48
49KateApp::KateApp (KCmdLineArgs *args)
50 : KApplication ()
51 , m_shouldExit(false)
52 , m_args (args)
53{
54 setQuitOnLastWindowClosed (false);
55
56 // application interface
57 m_application = new Kate::Application (this);
58
59 // doc man
60 m_docManager = new KateDocManager (this);
61
62 // init all normal plugins
63 m_pluginManager = new KatePluginManager (this);
64
65 // session manager up
66 m_sessionManager = new KateSessionManager (this);
67
68 // dbus
69 m_adaptor = new KateAppAdaptor( this );
70
71 // real init
72 initKate ();
73
74 m_appCommands = KateAppCommands::self();
75}
76
77KateApp::~KateApp ()
78{
79 // unregister...
80 m_adaptor->emitExiting ();
81 QDBusConnection::sessionBus().unregisterObject( QLatin1String("/MainApplication") );
82 delete m_adaptor;
83
84 // l8r, app commands
85 delete m_appCommands;
86
87 // cu session manager
88 delete m_sessionManager;
89
90 // cu plugin manager
91 delete m_pluginManager;
92
93 // delete this now, or we crash
94 delete m_docManager;
95
96 // cu kate app
97 delete m_application;
98}
99
100KateApp *KateApp::self ()
101{
102 return static_cast<KateApp *>(kapp);
103}
104
105Kate::Application *KateApp::application ()
106{
107 return m_application;
108}
109
110/**
111 * Has always been the Kate Versioning Scheme:
112 * KDE X.Y.Z contains Kate X-1.Y.Z
113 */
114QString KateApp::kateVersion (bool fullVersion)
115{
116 return fullVersion ? QString ("%1.%2.%3").arg(KDE::versionMajor() - 1).arg(KDE::versionMinor()).arg(KDE::versionRelease())
117 : QString ("%1.%2").arg(KDE::versionMajor() - 1).arg(KDE::versionMinor());
118}
119
120void KateApp::initKate ()
121{
122
123 kDebug() << "Setting KATE_PID: '" << getpid() << "'";
124 ::setenv( "KATE_PID", QString("%1").arg(getpid()).toLatin1(), 1 );
125
126 // handle restore different
127 if (isSessionRestored())
128 {
129 restoreKate ();
130 }
131 else
132 {
133 // let us handle our command line args and co ;)
134 // we can exit here if session chooser decides
135 if (!startupKate ())
136 {
137 kDebug() << "startupKate returned false";
138 m_shouldExit = true;
139 return ;
140 }
141 }
142
143 // application dbus interface
144 QDBusConnection::sessionBus().registerObject( QLatin1String("/MainApplication"), this );
145}
146
147void KateApp::restoreKate ()
148{
149 // activate again correct session!!!
150 QString lastSession (sessionConfig()->group("General").readEntry ("Last Session", QString()));
151 sessionManager()->activateSession (KateSession::Ptr(new KateSession (sessionManager(), lastSession)), false, false, false);
152
153 // plugins
154 KatePluginManager::self ()->loadConfig (sessionConfig());
155
156 // restore the files we need
157 m_docManager->restoreDocumentList (sessionConfig());
158
159 // restore all windows ;)
160 for (int n = 1; KMainWindow::canBeRestored(n); n++)
161 newMainWindow(sessionConfig(), QString ("%1").arg(n));
162
163 // oh, no mainwindow, create one, should not happen, but make sure ;)
164 if (mainWindows() == 0)
165 newMainWindow ();
166}
167
168bool KateApp::startupKate ()
169{
170 // user specified session to open
171 if (m_args->isSet ("startanon"))
172 {
173 sessionManager()->activateSession (sessionManager()->giveSession (""), false, false);
174 }
175 else if (m_args->isSet ("start"))
176 {
177 sessionManager()->activateSession (sessionManager()->giveSession (m_args->getOption("start")), false, false);
178 }
179 else if (!m_args->isSet( "stdin" ) && (m_args->count() == 0)) // only start session if no files specified
180 {
181 // let the user choose session if possible
182 if (!sessionManager()->chooseSession ())
183 {
184 kDebug() << "chooseSession returned false, exiting";
185 // we will exit kate now, notify the rest of the world we are done
186#ifdef Q_WS_X11
187 KStartupInfo::appStarted (startupId());
188#endif
189 return false;
190 }
191 }
192 else
193 {
194 sessionManager()->activateSession( KateSession::Ptr(new KateSession (sessionManager(), QString())), false, false );
195 }
196
197 // oh, no mainwindow, create one, should not happen, but make sure ;)
198 if (mainWindows() == 0)
199 newMainWindow ();
200
201 // notify about start
202#ifdef Q_WS_X11
203 KStartupInfo::setNewStartupId( activeMainWindow(), startupId());
204#endif
205 QTextCodec *codec = m_args->isSet("encoding") ? QTextCodec::codecForName(m_args->getOption("encoding").toUtf8()) : 0;
206
207 bool tempfileSet = KCmdLineArgs::isTempFileSet();
208
209 KTextEditor::Document *doc = 0;
210 const QString codec_name = codec ? codec->name() : QString();
211 KateDocManager::self()->setSuppressOpeningErrorDialogs(true);
212 QList<KUrl> urls;
213 for (int z = 0; z < m_args->count(); z++)
214 {
215 // this file is no local dir, open it, else warn
216 const bool noDir = !m_args->url(z).isLocalFile() || !QFileInfo (m_args->url(z).toLocalFile()).isDir();
217
218 if (noDir) {
219 urls << m_args->url(z);
220 } else {
221 KMessageBox::sorry( activeMainWindow(),
222 i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.", m_args->url(z).url()) );
223 }
224 }
225 doc = activeMainWindow()->viewManager()->openUrls(urls, codec_name, tempfileSet);
226 KateDocManager::self()->setSuppressOpeningErrorDialogs(false);
227
228 // handle stdin input
229 if( m_args->isSet( "stdin" ) )
230 {
231 QTextStream input(stdin, QIODevice::ReadOnly);
232
233 // set chosen codec
234 if (codec)
235 input.setCodec (codec);
236
237 QString line;
238 QString text;
239
240 do
241 {
242 line = input.readLine();
243 text.append( line + '\n' );
244 }
245 while( !line.isNull() );
246
247 openInput (text);
248 }
249 else if ( doc )
250 activeMainWindow()->viewManager()->activateView( doc );
251
252 if ( activeMainWindow()->viewManager()->viewCount () == 0 )
253 activeMainWindow()->viewManager()->activateView(m_docManager->document (0));
254
255 int line = 0;
256 int column = 0;
257 bool nav = false;
258
259 if (m_args->isSet ("line"))
260 {
261 line = m_args->getOption ("line").toInt() - 1;
262 nav = true;
263 }
264
265 if (m_args->isSet ("column"))
266 {
267 column = m_args->getOption ("column").toInt() - 1;
268 nav = true;
269 }
270
271 if (nav && activeMainWindow()->viewManager()->activeView ())
272 activeMainWindow()->viewManager()->activeView ()->setCursorPosition (KTextEditor::Cursor (line, column));
273
274 // show the nice tips
275 KTipDialog::showTip(activeMainWindow());
276
277 activeMainWindow()->setAutoSaveSettings();
278
279 kDebug() << "KateApplication::init finished successful";
280 return true;
281}
282
283void KateApp::shutdownKate (KateMainWindow *win)
284{
285 if (!win->queryClose_internal())
286 return;
287
288 sessionManager()->saveActiveSession(true);
289
290 // cu main windows
291 while (!m_mainWindows.isEmpty())
292 {
293 // mainwindow itself calls KateApp::removeMainWindow(this)
294 delete m_mainWindows[0];
295 }
296
297 quit ();
298}
299
300KatePluginManager *KateApp::pluginManager()
301{
302 return m_pluginManager;
303}
304
305KateDocManager *KateApp::documentManager ()
306{
307 return m_docManager;
308}
309
310KateSessionManager *KateApp::sessionManager ()
311{
312 return m_sessionManager;
313}
314
315bool KateApp::openUrl (const KUrl &url, const QString &encoding, bool isTempFile)
316{
317 return openDocUrl(url,encoding,isTempFile);
318}
319
320KTextEditor::Document* KateApp::openDocUrl (const KUrl &url, const QString &encoding, bool isTempFile)
321{
322 KateMainWindow *mainWindow = activeMainWindow ();
323
324 if (!mainWindow)
325 return 0;
326
327 QTextCodec *codec = encoding.isEmpty() ? 0 : QTextCodec::codecForName(encoding.toLatin1());
328
329 // this file is no local dir, open it, else warn
330 bool noDir = !url.isLocalFile() || !QFileInfo (url.toLocalFile()).isDir();
331
332 KTextEditor::Document *doc=0;
333
334 if (noDir)
335 {
336 // show no errors...
337 documentManager()->setSuppressOpeningErrorDialogs (true);
338
339 // open a normal file
340 if (codec)
341 doc=mainWindow->viewManager()->openUrl( url, codec->name(), true, isTempFile);
342 else
343 doc=mainWindow->viewManager()->openUrl( url, QString(), true, isTempFile );
344
345 // back to normal....
346 documentManager()->setSuppressOpeningErrorDialogs (false);
347 }
348 else
349 KMessageBox::sorry( mainWindow,
350 i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.", url.url()) );
351
352 return doc;
353}
354
355bool KateApp::setCursor (int line, int column)
356{
357 KateMainWindow *mainWindow = activeMainWindow ();
358
359 if (!mainWindow)
360 return false;
361
362 if (mainWindow->viewManager()->activeView ())
363 mainWindow->viewManager()->activeView ()->setCursorPosition (KTextEditor::Cursor (line, column));
364
365 return true;
366}
367
368bool KateApp::openInput (const QString &text)
369{
370 activeMainWindow()->viewManager()->openUrl( KUrl(), "", true );
371
372 if (!activeMainWindow()->viewManager()->activeView ())
373 return false;
374
375 KTextEditor::Document *doc = activeMainWindow()->viewManager()->activeView ()->document();
376
377 if (!doc)
378 return false;
379
380 return doc->setText (text);
381}
382
383KateMainWindow *KateApp::newMainWindow (KConfig *sconfig_, const QString &sgroup_)
384{
385 KConfig *sconfig = sconfig_ ? sconfig_ : KGlobal::config().data();
386 QString sgroup = !sgroup_.isEmpty() ? sgroup_ : "MainWindow0";
387
388 KateMainWindow *mainWindow = new KateMainWindow (sconfig, sgroup);
389 mainWindow->show ();
390
391 return mainWindow;
392}
393
394void KateApp::addMainWindow (KateMainWindow *mainWindow)
395{
396 m_mainWindows.push_back (mainWindow);
397 m_mainWindowsInterfaces.push_back (mainWindow->mainWindow());
398}
399
400void KateApp::removeMainWindow (KateMainWindow *mainWindow)
401{
402 m_mainWindowsInterfaces.removeAll(mainWindow->mainWindow());
403 m_mainWindows.removeAll(mainWindow);
404}
405
406KateMainWindow *KateApp::activeMainWindow ()
407{
408 if (m_mainWindows.isEmpty())
409 return 0;
410
411 int n = m_mainWindows.indexOf (static_cast<KateMainWindow *>(activeWindow()));
412
413 if (n < 0)
414 n = 0;
415
416 return m_mainWindows[n];
417}
418
419int KateApp::mainWindows () const
420{
421 return m_mainWindows.size();
422}
423
424int KateApp::mainWindowID(KateMainWindow *window)
425{
426 for (int i = 0;i < m_mainWindows.size();i++)
427 if (window == m_mainWindows[i]) return i;
428 return -1;
429}
430
431KateMainWindow *KateApp::mainWindow (int n)
432{
433 if (n < m_mainWindows.size())
434 return m_mainWindows[n];
435
436 return 0;
437}
438
439void KateApp::emitDocumentClosed(const QString& token)
440{
441 m_adaptor->emitDocumentClosed(token);
442}
443
444// kate: space-indent on; indent-width 2; replace-tabs on;
445