1/* This file is part of the KDE project
2 Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17*/
18
19#include "config.h"
20
21#include "katesession.h"
22#include "katesession.moc"
23
24#include "kateapp.h"
25#include "katemainwindow.h"
26#include "katedocmanager.h"
27#include "katepluginmanager.h"
28#include "katerunninginstanceinfo.h"
29
30#include <KStandardDirs>
31#include <KLocale>
32#include <kdebug.h>
33#include <KDirWatch>
34#include <KInputDialog>
35#include <KIconLoader>
36#include <KMessageBox>
37#include <KCodecs>
38#include <KStandardGuiItem>
39#include <KPushButton>
40#include <KMenu>
41#include <KActionCollection>
42#include <KIO/NetAccess>
43#include <KIO/CopyJob>
44#include <KStringHandler>
45
46#include <QDir>
47#include <QLabel>
48#include <QCheckBox>
49#include <QVBoxLayout>
50#include <QHBoxLayout>
51#include <QStyle>
52#include <QtAlgorithms>
53
54#include <unistd.h>
55#include <time.h>
56
57
58bool katesessions_compare_sessions_ptr(const KateSession::Ptr &s1, const KateSession::Ptr &s2) {
59 return KStringHandler::naturalCompare(s1->sessionName(),s2->sessionName())==-1;
60}
61
62//BEGIN KateSession
63
64KateSession::KateSession (KateSessionManager *manager, const QString &fileName)
65 : m_sessionFileRel (fileName)
66 , m_documents (0)
67 , m_manager (manager)
68 , m_readConfig (0)
69 , m_writeConfig (0)
70{
71 m_sessionName = QUrl::fromPercentEncoding(QFile::encodeName(fileName));
72 m_sessionName.chop(12);//.katesession==12
73 init ();
74}
75
76void KateSession::init ()
77{
78 // given file exists, use it to load some stuff ;)
79 if (!m_sessionFileRel.isEmpty() && KGlobal::dirs()->exists(sessionFile ()))
80 {
81 KConfig config (sessionFile (), KConfig::SimpleConfig);
82
83 // get the document count
84 m_documents = config.group("Open Documents").readEntry("Count", 0);
85
86 return;
87 }
88
89 if (!m_sessionFileRel.isEmpty() && !KGlobal::dirs()->exists(sessionFile ()))
90 kDebug() << "Warning, session file not found: " << m_sessionFileRel;
91}
92
93KateSession::~KateSession ()
94{
95 delete m_readConfig;
96 delete m_writeConfig;
97}
98
99QString KateSession::sessionFile () const
100{
101 if (m_sessionFileRel.isEmpty()) {
102 return QString();
103 }
104
105 return m_manager->sessionsDir() + '/' + m_sessionFileRel;
106}
107
108bool KateSession::create (const QString &name, bool force)
109{
110 if (!force && (name.isEmpty() || !m_sessionFileRel.isEmpty()))
111 return false;
112
113 delete m_writeConfig;
114 m_writeConfig = 0;
115
116 delete m_readConfig;
117 m_readConfig = 0;
118
119 m_sessionName = name;
120 QString oldSessionFileRel = m_sessionFileRel;
121 m_sessionFileRel = QUrl::toPercentEncoding(name, "", ".") + QString(".katesession");
122 if (KGlobal::dirs()->exists(sessionFile ()))
123 {
124 m_sessionFileRel = oldSessionFileRel;
125 return false;
126 }
127
128 // create the file, write name to it!
129 KConfig config (sessionFile (), KConfig::SimpleConfig);
130// config.group("General").writeEntry ("Name", m_sessionName);
131 config.sync ();
132
133 // reinit ourselfs ;)
134 init ();
135
136 return true;
137}
138
139bool KateSession::rename (const QString &name)
140{
141 if (name.isEmpty () || m_sessionFileRel.isEmpty())
142 return false;
143
144 if (name == m_sessionName) return true;
145 QString oldRel = m_sessionFileRel;
146 QString oldSessionFile = sessionFile();
147 m_sessionFileRel = QUrl::toPercentEncoding(name, "", ".") + QString(".katesession");
148 if (KGlobal::dirs()->exists(sessionFile ()))
149 {
150 m_sessionFileRel = oldRel;
151 return false;
152 }
153 KUrl srcUrl(QString("file://"));
154 srcUrl.addPath(oldSessionFile);
155 KUrl destUrl(QString("file://"));
156 destUrl.addPath(sessionFile());
157 KIO::CopyJob *job = KIO::move(srcUrl, destUrl, KIO::HideProgressInfo);
158 if ( ! KIO::NetAccess::synchronousRun(job, 0) )
159 {
160 m_sessionFileRel = oldRel;
161 return false;
162 }
163 m_sessionName = name;
164 delete m_writeConfig;
165 m_writeConfig=0;
166 delete m_readConfig;
167 m_readConfig=0;
168 return true;
169}
170
171KConfig *KateSession::configRead ()
172{
173 if (m_sessionFileRel.isEmpty())
174 return KGlobal::config().data();
175
176 if (m_readConfig)
177 return m_readConfig;
178
179 return m_readConfig = new KConfig (sessionFile (), KConfig::SimpleConfig);
180}
181
182KConfig *KateSession::configWrite ()
183{
184 if (m_sessionFileRel.isEmpty())
185 return KGlobal::config().data();
186
187 if (m_writeConfig)
188 return m_writeConfig;
189
190 m_writeConfig = new KConfig (sessionFile (), KConfig::SimpleConfig);
191
192 return m_writeConfig;
193}
194
195void KateSession::makeAnonymous()
196{
197 delete m_readConfig;
198 m_readConfig = 0;
199
200 delete m_writeConfig;
201 m_writeConfig = 0;
202
203 m_sessionFileRel.clear();
204 m_sessionName.clear();
205}
206
207//END KateSession
208
209
210//BEGIN KateSessionManager
211
212KateSessionManager::KateSessionManager (QObject *parent)
213 : QObject (parent)
214 , m_sessionsDir (KStandardDirs::locateLocal( "data", "kate/sessions"))
215 , m_activeSession (new KateSession (this, QString()))
216{
217 kDebug() << "LOCAL SESSION DIR: " << m_sessionsDir;
218
219 // create dir if needed
220 KGlobal::dirs()->makeDir (m_sessionsDir);
221}
222
223KateSessionManager::~KateSessionManager()
224{}
225
226KateSessionManager *KateSessionManager::self()
227{
228 return KateApp::self()->sessionManager ();
229}
230
231void KateSessionManager::dirty (const QString &)
232{
233 updateSessionList ();
234}
235
236void KateSessionManager::updateSessionList ()
237{
238 m_sessionList.clear ();
239
240 // Let's get a list of all session we have atm
241 QDir dir (m_sessionsDir, "*.katesession");
242
243 for (unsigned int i = 0; i < dir.count(); ++i)
244 {
245 KateSession *session = new KateSession (this, dir[i]);
246 if (m_activeSession)
247 if (session->sessionName()==m_activeSession->sessionName())
248 {
249 delete session;
250 session=m_activeSession.data();
251 }
252 m_sessionList.append (KateSession::Ptr(session));
253
254 //kDebug () << "FOUND SESSION: " << session->sessionName() << " FILE: " << session->sessionFile() << " dir[i];" << dir[i];
255 }
256
257 qSort(m_sessionList.begin(), m_sessionList.end(), katesessions_compare_sessions_ptr);
258}
259
260bool KateSessionManager::activateSession (KateSession::Ptr session,
261 bool closeLast,
262 bool saveLast,
263 bool loadNew)
264{
265 if ( (!session->sessionName().isEmpty()) && (m_activeSession!=session)) {
266 //check if the requested session is already open in another instance
267 KateRunningInstanceMap instances;
268 if (!fillinRunningKateAppInstances(&instances))
269 {
270 KMessageBox::error(0,i18n("Internal error: there is more than one instance open for a given session."));
271 return false;
272 }
273
274 if (instances.contains(session->sessionName()))
275 {
276 if (KMessageBox::questionYesNo(0,i18n("Session '%1' is already opened in another kate instance, change there instead of reopening?",session->sessionName()),
277 QString(),KStandardGuiItem::yes(),KStandardGuiItem::no(),"katesessionmanager_switch_instance")==KMessageBox::Yes)
278 {
279 instances[session->sessionName()]->dbus_if->call("activate");
280 cleanupRunningKateAppInstanceMap(&instances);
281 return false;
282 }
283 }
284
285 cleanupRunningKateAppInstanceMap(&instances);
286 }
287 // try to close last session
288 if (closeLast)
289 {
290 if (KateApp::self()->activeMainWindow())
291 {
292 if (!KateApp::self()->activeMainWindow()->queryClose_internal())
293 return true;
294 }
295 }
296
297 // save last session or not?
298 if (saveLast)
299 saveActiveSession ();
300
301 // really close last
302 if (closeLast)
303 KateDocManager::self()->closeAllDocuments ();
304
305 // set the new session
306 m_activeSession = session;
307
308 if (loadNew)
309 {
310 // open the new session
311 KConfig *sc = activeSession()->configRead();
312 const bool loadDocs = (sc != KGlobal::config().data()); // do not load docs for new sessions
313
314 // if we have no session config object, try to load the default
315 // (anonymous/unnamed sessions)
316 if ( !sc )
317 sc = KGlobal::config().data();
318 // load plugin config + plugins
319 KatePluginManager::self()->loadConfig (sc);
320
321 if (sc && loadDocs)
322 KateApp::self()->documentManager()->restoreDocumentList (sc);
323
324 // window config
325 KConfigGroup c(KGlobal::config(), "General");
326
327 if (c.readEntry("Restore Window Configuration", true))
328 {
329 // a new, named session, read settings of the default session.
330 if ( ! sc->hasGroup("Open MainWindows") )
331 sc = KGlobal::config().data();
332
333 int wCount = sc->group("Open MainWindows").readEntry("Count", 1);
334
335 for (int i = 0; i < wCount; ++i)
336 {
337 if (i >= KateApp::self()->mainWindows())
338 {
339 KateApp::self()->newMainWindow(sc, QString ("MainWindow%1").arg(i));
340 }
341 else
342 {
343 KateApp::self()->mainWindow(i)->readProperties(KConfigGroup(sc, QString ("MainWindow%1").arg(i) ));
344 }
345
346 KateApp::self()->mainWindow(i)->restoreWindowConfig(KConfigGroup(sc, QString ("MainWindow%1 Settings").arg(i)));
347 }
348
349 // remove mainwindows we need no longer...
350 if (wCount > 0)
351 {
352 while (wCount < KateApp::self()->mainWindows())
353 delete KateApp::self()->mainWindow(KateApp::self()->mainWindows() - 1);
354 }
355 }
356 }
357
358 emit sessionChanged();
359 return true;
360}
361
362KateSession::Ptr KateSessionManager::giveSession (const QString &name)
363{
364 if (name.isEmpty())
365 return KateSession::Ptr(new KateSession (this, QString()));
366
367 updateSessionList();
368
369 for (int i = 0; i < m_sessionList.count(); ++i)
370 {
371 if (m_sessionList[i]->sessionName() == name)
372 return m_sessionList[i];
373 }
374
375 KateSession::Ptr s(new KateSession (this, QString()));
376 s->create (name);
377 return s;
378}
379
380// helper function to save the session to a given config object
381static void saveSessionTo(KConfig *sc)
382{
383 // save plugin configs and which plugins to load
384 KatePluginManager::self()->writeConfig(sc);
385
386 // save document configs + which documents to load
387 KateDocManager::self()->saveDocumentList (sc);
388
389 sc->group("Open MainWindows").writeEntry ("Count", KateApp::self()->mainWindows ());
390
391 // save config for all windows around ;)
392 bool saveWindowConfig = KConfigGroup(KGlobal::config(), "General").readEntry("Restore Window Configuration", true);
393 for (int i = 0; i < KateApp::self()->mainWindows (); ++i )
394 {
395 KConfigGroup cg(sc, QString ("MainWindow%1").arg(i) );
396 KateApp::self()->mainWindow(i)->saveProperties (cg);
397 if (saveWindowConfig)
398 KateApp::self()->mainWindow(i)->saveWindowConfig(KConfigGroup(sc, QString ("MainWindow%1 Settings").arg(i)));
399 }
400
401 sc->sync();
402
403 /**
404 * try to sync file to disk
405 */
406 QFile fileToSync (sc->name());
407 if (fileToSync.open (QIODevice::ReadOnly)) {
408#ifndef Q_OS_WIN
409 // ensure that the file is written to disk
410#ifdef HAVE_FDATASYNC
411 fdatasync (fileToSync.handle());
412#else
413 fsync (fileToSync.handle());
414#endif
415#endif
416 }
417}
418
419bool KateSessionManager::saveActiveSession (bool rememberAsLast)
420{
421// if (activeSession()->isAnonymous())
422// newSessionName();
423
424 KConfig *sc = activeSession()->configWrite();
425
426 if (!sc)
427 return false;
428
429 saveSessionTo(sc);
430
431 if (rememberAsLast)
432 {
433 KSharedConfig::Ptr c = KGlobal::config();
434 c->group("General").writeEntry ("Last Session", activeSession()->sessionFileRelative());
435 c->sync ();
436 }
437 return true;
438}
439
440bool KateSessionManager::chooseSession ()
441{
442 bool success = true;
443
444 // app config
445 KConfigGroup c(KGlobal::config(), "General");
446
447 // get last used session, default to default session
448 QString lastSession (c.readEntry ("Last Session", QString()));
449 QString sesStart (c.readEntry ("Startup Session", "manual"));
450
451 // uhh, just open last used session, show no chooser
452 if (sesStart == "last")
453 {
454 activateSession (KateSession::Ptr(new KateSession (this, lastSession)), false, false);
455 return success;
456 }
457
458 // start with empty new session
459 // also, if no sessions exist
460 if (sesStart == "new" || sessionList().size() == 0)
461 {
462 activateSession (KateSession::Ptr(new KateSession (this, QString())), false, false);
463 return success;
464 }
465
466 KateSessionChooser *chooser = new KateSessionChooser (0, lastSession);
467
468 bool retry = true;
469 int res = 0;
470 while (retry)
471 {
472 res = chooser->exec ();
473
474 switch (res)
475 {
476 case KateSessionChooser::resultOpen:
477 {
478 KateSession::Ptr s = chooser->selectedSession ();
479
480 if (!s)
481 {
482 KMessageBox::error (chooser, i18n("No session selected to open."), i18n ("No Session Selected"));
483 break;
484 }
485
486 success = activateSession (s, false, false);
487 retry = false;
488 break;
489 }
490
491 // exit the app lateron
492 case KateSessionChooser::resultQuit:
493 success = false;
494 retry = false;
495 break;
496
497 case KateSessionChooser::resultNew: {
498 success = true;
499 retry = false;
500 activateSession (KateSession::Ptr(new KateSession (this, QString())), false, false);
501 break;
502 }
503
504 case KateSessionChooser::resultCopy: {
505 KateSession::Ptr s = chooser->selectedSession ();
506 if (!s) {
507 KMessageBox::error (chooser, i18n("No session selected to copy."), i18n ("No Session Selected"));
508 break;
509 }
510
511 success = true;
512 retry = false;
513 activateSession (s, false, false);
514 s->makeAnonymous();
515 // emit signal again, now we are anonymous
516 emit sessionChanged();
517 break;
518 }
519
520 default:
521 activateSession (KateSession::Ptr(new KateSession (this, QString())), false, false) ;
522 retry = false;
523 break;
524 }
525 }
526
527 // write back our nice boolean :)
528 if (success && chooser->reopenLastSession ())
529 {
530 KConfigGroup generalConfig(KGlobal::config(), "General");
531
532 if (res == KateSessionChooser::resultOpen)
533 generalConfig.writeEntry ("Startup Session", "last");
534 else if (res == KateSessionChooser::resultNew)
535 generalConfig.writeEntry ("Startup Session", "new");
536
537 generalConfig.sync ();
538 }
539
540 delete chooser;
541
542 return success;
543}
544
545void KateSessionManager::sessionNew ()
546{
547 activateSession (KateSession::Ptr(new KateSession (this, "")));
548}
549
550void KateSessionManager::sessionOpen ()
551{
552 KateSessionOpenDialog *chooser = new KateSessionOpenDialog (0);
553
554 int res = chooser->exec ();
555
556 if (res == KateSessionOpenDialog::resultCancel)
557 {
558 delete chooser;
559 return;
560 }
561
562 KateSession::Ptr s = chooser->selectedSession ();
563
564 if (s)
565 activateSession (s);
566
567 delete chooser;
568}
569
570void KateSessionManager::sessionSave ()
571{
572 // if the active session is valid, just save it :)
573 if (saveActiveSession ())
574 return;
575
576 sessionSaveAs();
577}
578
579void KateSessionManager::sessionSaveAs ()
580{
581 newSessionName();
582 saveActiveSession ();
583 emit sessionChanged();
584}
585
586bool KateSessionManager::newSessionName()
587{
588 bool alreadyExists = false;
589 QString name;
590 do {
591 bool ok = false;
592 name = KInputDialog::getText (
593 i18n("Specify New Name for Current Session"),
594 alreadyExists ? i18n("There is already an existing session with your chosen name.\nPlease choose a different one\nSession name:") : i18n("Session name:")
595 , name, &ok);
596
597 if (!ok)
598 return false;
599
600 if (name.isEmpty())
601 KMessageBox::sorry (0, i18n("To save a session, you must specify a name."), i18n ("Missing Session Name"));
602
603 alreadyExists = true;
604 }
605 while (!activeSession()->create (name, true));
606 return true;
607}
608
609void KateSessionManager::sessionManage ()
610{
611 KateSessionManageDialog *dlg = new KateSessionManageDialog (0);
612
613 dlg->exec ();
614
615 delete dlg;
616}
617
618//END KateSessionManager
619
620//BEGIN CHOOSER DIALOG
621
622class KateSessionChooserItem : public QTreeWidgetItem
623{
624 public:
625 KateSessionChooserItem (QTreeWidget *tw, KateSession::Ptr s)
626 : QTreeWidgetItem (tw, QStringList(s->sessionName()))
627 , session (s)
628 {
629 QString docs;
630 docs.setNum (s->documents());
631 setText (1, docs);
632 }
633
634 KateSession::Ptr session;
635};
636
637KateSessionChooser::KateSessionChooser (QWidget *parent, const QString &lastSession)
638 : KDialog ( parent )
639{
640 setCaption( i18n ("Session Chooser") );
641 setButtons( User1 | User2 | User3 );
642 setButtonGuiItem( User1, KStandardGuiItem::quit() );
643 setButtonGuiItem( User2, KGuiItem (i18n ("Open Session"), "document-open") );
644 setButtonGuiItem( User3, KGuiItem (i18n ("New Session"), "document-new") );
645
646 //showButtonSeparator(true);
647 QFrame *page = new QFrame (this);
648 QVBoxLayout *tll = new QVBoxLayout(page);
649 page->setMinimumSize (400, 200);
650 setMainWidget(page);
651
652 m_sessions = new QTreeWidget (page);
653 tll->addWidget(m_sessions);
654 QStringList header;
655 header << i18n("Session Name");
656 header << i18nc("The number of open documents", "Open Documents");
657 m_sessions->setHeaderLabels(header);
658 m_sessions->setRootIsDecorated( false );
659 m_sessions->setItemsExpandable( false );
660 m_sessions->setAllColumnsShowFocus( true );
661 m_sessions->setSelectionBehavior(QAbstractItemView::SelectRows);
662 m_sessions->setSelectionMode (QAbstractItemView::SingleSelection);
663
664 connect (m_sessions, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(selectionChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
665
666 QMenu* popup = new QMenu(this);
667 button(KDialog::User3)->setDelayedMenu(popup);
668 QAction *a = popup->addAction(i18n("Use selected session as template"));
669 connect(a, SIGNAL(triggered()), this, SLOT(slotCopySession()));
670
671 const KateSessionList &slist (KateSessionManager::self()->sessionList());
672 kDebug()<<"Last session is:"<<lastSession;
673 for (int i = 0; i < slist.count(); ++i)
674 {
675 KateSessionChooserItem *item = new KateSessionChooserItem (m_sessions, slist[i]);
676
677 kDebug()<<"Session added to chooser:"<<slist[i]->sessionName()<<"........"<<slist[i]->sessionFileRelative();
678 if (slist[i]->sessionFileRelative() == lastSession)
679 m_sessions->setCurrentItem (item);
680 }
681
682 m_sessions->resizeColumnToContents(0);
683
684 m_useLast = new QCheckBox (i18n ("&Always use this choice"), page);
685 tll->addWidget(m_useLast);
686
687 setResult (resultNone);
688
689 // trigger action update
690 selectionChanged (NULL, NULL);
691 connect(this, SIGNAL(user1Clicked()), this, SLOT(slotUser1()));
692 connect(this, SIGNAL(user2Clicked()), this, SLOT(slotUser2()));
693 connect(m_sessions, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotUser2()));
694 connect(this, SIGNAL(user3Clicked()), this, SLOT(slotUser3()));
695 enableButton (KDialog::User2, m_sessions->currentIndex().isValid());
696
697 setDefaultButton(KDialog::User2);
698 setEscapeButton(KDialog::User1);
699 setButtonFocus(KDialog::User2);
700}
701
702KateSessionChooser::~KateSessionChooser ()
703{}
704
705void KateSessionChooser::slotCopySession()
706{
707 done(resultCopy);
708}
709
710KateSession::Ptr KateSessionChooser::selectedSession ()
711{
712 KateSessionChooserItem *item = static_cast<KateSessionChooserItem *>(m_sessions->currentItem ());
713
714 if (!item)
715 return KateSession::Ptr();
716
717 return item->session;
718}
719
720bool KateSessionChooser::reopenLastSession ()
721{
722 return m_useLast->isChecked ();
723}
724
725void KateSessionChooser::slotUser2 ()
726{
727 done (resultOpen);
728}
729
730void KateSessionChooser::slotUser3 ()
731{
732 done (resultNew);
733}
734
735void KateSessionChooser::slotUser1 ()
736{
737 done (resultQuit);
738}
739
740void KateSessionChooser::selectionChanged(QTreeWidgetItem *current, QTreeWidgetItem *)
741{
742 enableButton (KDialog::User2, current);
743}
744
745//END CHOOSER DIALOG
746
747//BEGIN OPEN DIALOG
748
749KateSessionOpenDialog::KateSessionOpenDialog (QWidget *parent)
750 : KDialog ( parent )
751
752{
753 setCaption( i18n ("Open Session") );
754 setButtons( User1 | User2 );
755 setButtonGuiItem( User1, KStandardGuiItem::cancel() );
756 // don't use KStandardGuiItem::open() here which has trailing ellipsis!
757 setButtonGuiItem( User2, KGuiItem( i18n("&Open"), "document-open") );
758 setDefaultButton( KDialog::User2 );
759 enableButton( KDialog::User2, false );
760 //showButtonSeparator(true);
761 /*QFrame *page = new QFrame (this);
762 page->setMinimumSize (400, 200);
763 setMainWidget(page);
764
765 QHBoxLayout *hb = new QHBoxLayout (page);
766
767 QVBoxLayout *vb = new QVBoxLayout ();
768 hb->addItem(vb);*/
769 m_sessions = new QTreeWidget (this);
770 m_sessions->setMinimumSize(400, 200);
771 setMainWidget(m_sessions);
772 //vb->addWidget(m_sessions);
773 QStringList header;
774 header << i18n("Session Name");
775 header << i18nc("The number of open documents", "Open Documents");
776 m_sessions->setHeaderLabels(header);
777 m_sessions->setRootIsDecorated( false );
778 m_sessions->setItemsExpandable( false );
779 m_sessions->setAllColumnsShowFocus( true );
780 m_sessions->setSelectionBehavior(QAbstractItemView::SelectRows);
781 m_sessions->setSelectionMode (QAbstractItemView::SingleSelection);
782
783 const KateSessionList &slist (KateSessionManager::self()->sessionList());
784 for (int i = 0; i < slist.count(); ++i)
785 {
786 new KateSessionChooserItem (m_sessions, slist[i]);
787 }
788 m_sessions->resizeColumnToContents(0);
789
790 setResult (resultCancel);
791 connect(this, SIGNAL(user1Clicked()), this, SLOT(slotUser1()));
792 connect(this, SIGNAL(user2Clicked()), this, SLOT(slotUser2()));
793 connect(m_sessions, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(selectionChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
794 connect(m_sessions, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotUser2()));
795
796}
797
798KateSessionOpenDialog::~KateSessionOpenDialog ()
799{}
800
801KateSession::Ptr KateSessionOpenDialog::selectedSession ()
802{
803 KateSessionChooserItem *item = static_cast<KateSessionChooserItem *>(m_sessions->currentItem ());
804
805 if (!item)
806 return KateSession::Ptr();
807
808 return item->session;
809}
810
811void KateSessionOpenDialog::slotUser1 ()
812{
813 done (resultCancel);
814}
815
816void KateSessionOpenDialog::slotUser2 ()
817{
818 done (resultOk);
819}
820
821void KateSessionOpenDialog::selectionChanged(QTreeWidgetItem *current, QTreeWidgetItem *)
822{
823 enableButton (KDialog::User2, current);
824}
825
826//END OPEN DIALOG
827
828//BEGIN MANAGE DIALOG
829
830KateSessionManageDialog::KateSessionManageDialog (QWidget *parent)
831 : KDialog ( parent )
832{
833 setCaption( i18n ("Manage Sessions") );
834 setButtons( User1 | User2 );
835 setButtonGuiItem( User1, KStandardGuiItem::close() );
836 // don't use KStandardGuiItem::open() here which has trailing ellipsis!
837 setButtonGuiItem( User2, KGuiItem( i18n("&Open"), "document-open") );
838
839 setDefaultButton(KDialog::User1);
840 QFrame *page = new QFrame (this);
841 page->setMinimumSize (400, 200);
842 setMainWidget(page);
843
844 QHBoxLayout *hb = new QHBoxLayout (page);
845 hb->setSpacing (KDialog::spacingHint());
846
847 m_sessions = new QTreeWidget (page);
848 hb->addWidget(m_sessions);
849 m_sessions->setColumnCount(2);
850 QStringList header;
851 header << i18n("Session Name");
852 header << i18nc("The number of open documents", "Open Documents");
853 m_sessions->setHeaderLabels(header);
854 m_sessions->setRootIsDecorated( false );
855 m_sessions->setItemsExpandable( false );
856 m_sessions->setAllColumnsShowFocus( true );
857 m_sessions->setSelectionBehavior(QAbstractItemView::SelectRows);
858 m_sessions->setSelectionMode (QAbstractItemView::SingleSelection);
859
860 connect (m_sessions, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(selectionChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
861
862 updateSessionList ();
863 m_sessions->resizeColumnToContents(0);
864
865 QVBoxLayout *vb = new QVBoxLayout ();
866 hb->addItem(vb);
867 vb->setSpacing (KDialog::spacingHint());
868
869 m_rename = new KPushButton (i18n("&Rename..."), page);
870 connect (m_rename, SIGNAL(clicked()), this, SLOT(rename()));
871 vb->addWidget (m_rename);
872
873 m_del = new KPushButton (KStandardGuiItem::del (), page);
874 connect (m_del, SIGNAL(clicked()), this, SLOT(del()));
875 vb->addWidget (m_del);
876
877 vb->addStretch ();
878
879 // trigger action update
880 selectionChanged (NULL, NULL);
881 connect(this, SIGNAL(user1Clicked()), this, SLOT(slotUser1()));
882 connect(this, SIGNAL(user2Clicked()), this, SLOT(open()));
883}
884
885KateSessionManageDialog::~KateSessionManageDialog ()
886{}
887
888void KateSessionManageDialog::slotUser1 ()
889{
890 done (0);
891}
892
893void KateSessionManageDialog::selectionChanged (QTreeWidgetItem *current, QTreeWidgetItem *)
894{
895 const bool validItem = (current != NULL);
896
897 m_rename->setEnabled (validItem);
898 m_del->setEnabled (validItem && (static_cast<KateSessionChooserItem*>(current))->session!=KateSessionManager::self()->activeSession());
899 button(User2)->setEnabled (validItem);
900}
901
902void KateSessionManageDialog::rename ()
903{
904 KateSessionChooserItem *item = static_cast<KateSessionChooserItem *>(m_sessions->currentItem ());
905
906 if (!item)
907 return;
908
909 bool ok = false;
910 QString name = KInputDialog::getText (i18n("Specify New Name for Session"), i18n("Session name:"), item->session->sessionName(), &ok);
911
912 if (!ok)
913 return;
914
915 if (name.isEmpty())
916 {
917 KMessageBox::sorry (this, i18n("To save a session, you must specify a name."), i18n ("Missing Session Name"));
918 return;
919 }
920
921 if (item->session->rename (name)) {
922 if (item->session==KateSessionManager::self()->activeSession()) {
923 emit KateSessionManager::self()->sessionChanged();
924 }
925 updateSessionList ();
926 }
927 else
928 KMessageBox::sorry(this, i18n("The session could not be renamed to \"%1\", there already exists another session with the same name", name), i18n("Session Renaming"));
929}
930
931void KateSessionManageDialog::del ()
932{
933 KateSessionChooserItem *item = static_cast<KateSessionChooserItem *>(m_sessions->currentItem ());
934
935 if (!item)
936 return;
937
938 QFile::remove (item->session->sessionFile());
939 KateSessionManager::self()->updateSessionList ();
940 updateSessionList ();
941}
942
943void KateSessionManageDialog::open ()
944{
945 KateSessionChooserItem *item = static_cast<KateSessionChooserItem *>(m_sessions->currentItem ());
946
947 if (!item)
948 return;
949
950 hide();
951 KateSessionManager::self()->activateSession (item->session);
952 done(0);
953}
954
955void KateSessionManageDialog::updateSessionList ()
956{
957 m_sessions->clear ();
958
959 const KateSessionList &slist (KateSessionManager::self()->sessionList());
960 for (int i = 0; i < slist.count(); ++i)
961 {
962 new KateSessionChooserItem (m_sessions, slist[i]);
963 }
964}
965
966//END MANAGE DIALOG
967
968
969KateSessionsAction::KateSessionsAction(const QString& text, QObject* parent)
970 : KActionMenu(text, parent)
971{
972 connect(menu(), SIGNAL(aboutToShow()), this, SLOT(slotAboutToShow()));
973
974 sessionsGroup = new QActionGroup( menu() );
975
976 // reason for Qt::QueuedConnection: when switching session with N mainwindows
977 // to e.g. 1 mainwindow, the last N - 1 mainwindows are deleted. Invoking
978 // a session switch without queued connection deletes a mainwindow in which
979 // the current code path is executed ---> crash. See bug #227008.
980 connect(sessionsGroup, SIGNAL(triggered(QAction*)), this, SLOT(openSession(QAction*)), Qt::QueuedConnection);
981
982 connect(KateSessionManager::self(), SIGNAL(sessionChanged()), this, SLOT(slotSessionChanged()));
983 setDisabled(KateSessionManager::self()->sessionList().size() == 0);
984}
985
986void KateSessionsAction::slotAboutToShow()
987{
988 qDeleteAll( sessionsGroup->actions() );
989
990 const KateSessionList &slist (KateSessionManager::self()->sessionList());
991 for (int i = 0; i < slist.count(); ++i)
992 {
993 QString sessionName = slist[i]->sessionName();
994 sessionName.replace("&", "&&");
995 QAction *action = new QAction( sessionName, sessionsGroup );
996 action->setData(QVariant(i));
997 menu()->addAction (action);
998 }
999}
1000
1001void KateSessionsAction::openSession (QAction *action)
1002{
1003 const KateSessionList &slist (KateSessionManager::self()->sessionList());
1004
1005 int i = action->data().toInt();
1006 if (i >= slist.count())
1007 return;
1008
1009 KateSessionManager::self()->activateSession(slist[i]);
1010}
1011
1012void KateSessionsAction::slotSessionChanged()
1013{
1014 setDisabled(KateSessionManager::self()->sessionList().size() == 0);
1015}
1016
1017// kate: space-indent on; indent-width 2; replace-tabs on;
1018