SessionManager.cpp 19.2 KB
Newer Older
Robert Knight's avatar
Robert Knight committed
1
2
3
/*
    This source file is part of Konsole, a terminal emulator.

4
    Copyright (C) 2006-7 by Robert Knight <robertknight@gmail.com>
Robert Knight's avatar
Robert Knight committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301  USA.
*/

22
23
24
// Own
#include "SessionManager.h"

Robert Knight's avatar
   
Robert Knight committed
25
// Qt
26
#include <QtCore/QDir>
Dirk Mueller's avatar
Dirk Mueller committed
27
28
#include <QtCore/QFileInfo>
#include <QtCore/QList>
29
#include <QtCore/QSignalMapper>
Dirk Mueller's avatar
Dirk Mueller committed
30
#include <QtCore/QString>
31
#include <QtCore/QTextCodec>
Robert Knight's avatar
   
Robert Knight committed
32
33
34
35
36

// KDE
#include <klocale.h>
#include <krun.h>
#include <kshell.h>
37
#include <kconfig.h>
Robert Knight's avatar
   
Robert Knight committed
38
#include <kglobal.h>
39
40
#include <kdebug.h>
#include <kconfiggroup.h>
Robert Knight's avatar
   
Robert Knight committed
41
#include <kstandarddirs.h>
42
#include <kdesktopfile.h>
Robert Knight's avatar
   
Robert Knight committed
43
44

// Konsole
45
#include "ColorScheme.h"
46
47
#include "Session.h"
#include "History.h"
48
#include "ShellCommand.h"
Robert Knight's avatar
   
Robert Knight committed
49

50
51
using namespace Konsole;

52
#if 0
Robert Knight's avatar
   
Robert Knight committed
53

54
bool Profile::isAvailable() const
Robert Knight's avatar
   
Robert Knight committed
55
{
56
57
    //TODO:  Is it necessary to cache the result of the search?

Robert Knight's avatar
   
Robert Knight committed
58
    QString binary = KRun::binaryName( command(true) , false );
Robert Knight's avatar
   
Robert Knight committed
59
    binary = KShell::tildeExpand(binary);
Robert Knight's avatar
   
Robert Knight committed
60
61
62
63

    QString fullBinaryPath = KGlobal::dirs()->findExe(binary);

    if ( fullBinaryPath.isEmpty() )
64
        return false;
Robert Knight's avatar
   
Robert Knight committed
65
66
67
    else
        return true;
}
68
#endif
Robert Knight's avatar
   
Robert Knight committed
69

70
71
SessionManager::SessionManager()
    : _loadedAllProfiles(false)
Robert Knight's avatar
   
Robert Knight committed
72
{
73
74
75
76
77
    //map finished() signals from sessions
    _sessionMapper = new QSignalMapper(this);
    connect( _sessionMapper , SIGNAL(mapped(QObject*)) , this ,
            SLOT(sessionTerminated(QObject*)) );

78
    //load fallback profile
79
    addProfile( Profile::Ptr(new FallbackProfile) );
Robert Knight's avatar
   
Robert Knight committed
80

81
82
83
84
    //locate and load default profile
    KSharedConfigPtr appConfig = KGlobal::config();
    const KConfigGroup group = appConfig->group( "Desktop Entry" );
    QString defaultSessionFilename = group.readEntry("DefaultProfile","Shell.profile");
Robert Knight's avatar
   
Robert Knight committed
85

86
87
88
    QString path = KGlobal::dirs()->findResource("data","konsole/"+defaultSessionFilename);
    if (!path.isEmpty())
    {
89
90
91
        Profile::Ptr profile = loadProfile(path);
        if ( profile )
            _defaultProfile = profile;
92
    }
93

94
    Q_ASSERT( _types.count() > 0 );
95
    Q_ASSERT( _defaultProfile );
Robert Knight's avatar
   
Robert Knight committed
96

97
    // get shortcuts and paths of profiles associated with
98
99
    // them - this doesn't load the shortcuts themselves,
    // that is done on-demand.
100
    loadShortcuts();
Robert Knight's avatar
   
Robert Knight committed
101
}
102
Profile::Ptr SessionManager::loadProfile(const QString& shortPath)
Robert Knight's avatar
   
Robert Knight committed
103
{
104
105
106
107
108
109
110
111
112
113
114
115
116
    QString path = shortPath;

    // add a suggested suffix and relative prefix if missing
    QFileInfo fileInfo(path);
    if ( fileInfo.suffix().isEmpty() )
        path.append(".profile");
    if ( fileInfo.path().isEmpty() || fileInfo.path() == "." )
        path.prepend(QString("konsole")+QDir::separator());

    // if the file is not an absolute path, look it up 
    if ( !fileInfo.isAbsolute() )
        path = KStandardDirs::locate("data",path);

117
118
119
120
121
122
123
124
125
    // check that we have not already loaded this profile
    QSetIterator<Profile::Ptr> iter(_types);
    while ( iter.hasNext() )
    {
        Profile::Ptr profile = iter.next();
        if ( profile->path() == path )
            return profile;
    }

126
127
128
129
	// guard to prevent problems if a profile specifies itself as its parent
	// or if there is recursion in the "inheritance" chain
	// (eg. two profiles, A and B, specifying each other as their parents)
	static QStack<QString> recursionGuard;
130
131
	PopStackOnExit<QString> popGuardOnExit(recursionGuard);

132
	if (recursionGuard.contains(path))
133
134
135
136
	{
		kWarning() << "Ignoring attempt to load profile recursively from" << path;
		return Profile::Ptr();
	}
137
138
139
	else
		recursionGuard.push(path);

140
141
142
    // load the profile
    ProfileReader* reader = 0;
    if ( path.endsWith(".desktop") )
Alexander Rodin's avatar
   
Alexander Rodin committed
143
        reader = 0; // new KDE3ProfileReader;
144
145
    else
        reader = new KDE4ProfileReader;
146

147
    if (!reader)
148
	{
149
150
		kWarning() << "Could not create loader to read profile from" << path;
        return Profile::Ptr();
151
	}
Robert Knight's avatar
   
Robert Knight committed
152

153
    Profile::Ptr newProfile = Profile::Ptr(new Profile(defaultProfile()));
154
    newProfile->setProperty(Profile::Path,path);
Robert Knight's avatar
   
Robert Knight committed
155

156
157
    QString parentProfilePath;
    bool result = reader->readProfile(path,newProfile,parentProfilePath);
158

159
    if ( !parentProfilePath.isEmpty() )
160
    {
161
162
        Profile::Ptr parentProfile = loadProfile(parentProfilePath);
        newProfile->setParent(parentProfile);
163
    }
Robert Knight's avatar
   
Robert Knight committed
164

165
    delete reader;
166

167
    if (!result)
168
    {
169
170
		kWarning() << "Could not load profile from " << path;
        return Profile::Ptr();
Robert Knight's avatar
   
Robert Knight committed
171
    }
172
    else
173
174
175
176
	{
        addProfile(newProfile);
		return newProfile;
	}
177
}
178
179
180
181
182
183
184
QList<QString> SessionManager::availableProfilePaths() const
{
    KDE4ProfileReader reader;

    return reader.findProfiles();    
}

185
186
187
188
void SessionManager::loadAllProfiles()
{
    if ( _loadedAllProfiles )
        return;
Robert Knight's avatar
   
Robert Knight committed
189

190
191
    KDE3ProfileReader kde3Reader;
    KDE4ProfileReader kde4Reader;
192

193
194
195
196
197
198
199
    QStringList profiles;
    profiles += kde3Reader.findProfiles();
    profiles += kde4Reader.findProfiles();
    
    QListIterator<QString> iter(profiles);
    while (iter.hasNext())
        loadProfile(iter.next());
Robert Knight's avatar
   
Robert Knight committed
200

201
202
    _loadedAllProfiles = true;
}
203
204
205
void SessionManager::saveState()
{
	// save default profile
206
207
    setDefaultProfile( _defaultProfile );

208
209
210
    // save shortcuts
    saveShortcuts();

Robert Knight's avatar
   
Robert Knight committed
211
212
    // save favorites
    saveFavorites();
213
214
215
216
}
void SessionManager::closeAll()
{
    // close remaining sessions
217
    foreach( Session* session , _sessions )
218
	{
219
        session->close();
220
221
	}
	_sessions.clear();	
222
223
224
}
SessionManager::~SessionManager()
{
225
226
227
228
229
230
231
232
233
	// TODO This test sometimes fails when using KDevelop.  Look into and fix it.
	if (_sessions.count() == 0)
	{
		kWarning() << "Konsole SessionManager destroyed with sessions still alive";
		// ensure that the Session doesn't later try to call back and do things to the 
		// SessionManager
		foreach(Session* session , _sessions)
			disconnect(session , 0 , this , 0);
	}
Robert Knight's avatar
   
Robert Knight committed
234
235
}

236
const QList<Session*> SessionManager::sessions()
237
238
239
240
{
    return _sessions;
}

241
242
void SessionManager::updateSession(Session* session)
{
243
    Profile::Ptr info = _sessionProfiles[session]; 
244
245
246
247

    Q_ASSERT( info );

    applyProfile(session,info,false);
248
249
250
251

    // FIXME - This may update a lot more than just the session
    // of interest. 
    emit sessionUpdated(session);
252
253
}

254
Session* SessionManager::createSession(Profile::Ptr info)
Robert Knight's avatar
   
Robert Knight committed
255
{
256
    Session* session = 0;
257
    
258
259
260
261
262
	if (!info)
		info = defaultProfile();
   
    if (!_types.contains(info))
		addProfile(info);
Robert Knight's avatar
   
Robert Knight committed
263

264
265
266
    //configuration information found, create a new session based on this
    session = new Session();
    applyProfile(session,info,false);
Robert Knight's avatar
   
Robert Knight committed
267

268
269
    connect( session , SIGNAL(profileChangeCommandReceived(QString)) , this ,
            SLOT(sessionProfileCommandReceived(QString)) );
270

271
    //ask for notification when session dies
272
273
274
    _sessionMapper->setMapping(session,session);
    connect( session , SIGNAL(finished()) , _sessionMapper , 
             SLOT(map()) );
Robert Knight's avatar
   
Robert Knight committed
275

276
277
    //add session to active list
    _sessions << session;
278
	_sessionProfiles.insert(session,info);
Robert Knight's avatar
   
Robert Knight committed
279
280

    Q_ASSERT( session );
281

Robert Knight's avatar
   
Robert Knight committed
282
283
284
    return session;
}

285
void SessionManager::sessionTerminated(QObject* sessionObject)
Robert Knight's avatar
   
Robert Knight committed
286
{
287
288
289
290
    Session* session = qobject_cast<Session*>(sessionObject);

    Q_ASSERT( session );

291
    _sessions.removeAll(session);
292
    session->deleteLater();
Robert Knight's avatar
   
Robert Knight committed
293
294
}

295
QList<Profile::Ptr> SessionManager::loadedProfiles() const
Robert Knight's avatar
   
Robert Knight committed
296
{
297
    return _types.toList();
298
299
}

300
Profile::Ptr SessionManager::defaultProfile() const
301
{
302
    return _defaultProfile;
303
}
304

305
QString SessionManager::saveProfile(Profile::Ptr info)
306
{
307
    ProfileWriter* writer = new KDE4ProfileWriter;
308

309
    QString newPath = writer->getPath(info);
310

311
    writer->writeProfile(newPath,info);
312

313
    delete writer;
Robert Knight's avatar
   
Robert Knight committed
314
315

    return newPath;
316
317
}

318
void SessionManager::changeProfile(Profile::Ptr info , 
319
                                   QHash<Profile::Property,QVariant> propertyMap, bool persistant)
320
{
321
    Q_ASSERT(info); 
322

323
    // insert the changes into the existing Profile instance
324
325
326
327
328
329
    QListIterator<Profile::Property> iter(propertyMap.keys());
    while ( iter.hasNext() )
    {
        const Profile::Property property = iter.next();
        info->setProperty(property,propertyMap[property]);
    }
330
331
    
    // apply the changes to existing sessions
332
    applyProfile(info,true);
333

334
    // notify the world about the change
335
    emit profileChanged(info);
336

337
338
339
340
	// save changes to disk, unless the profile is hidden, in which case
	// it has no file on disk 
    if ( persistant && !info->isHidden() )
	{
341
        info->setProperty(Profile::Path,saveProfile(info));
342
	}
343
}
344
void SessionManager::applyProfile(Profile::Ptr info , bool modifiedPropertiesOnly)
345
346
347
348
349
{
    QListIterator<Session*> iter(_sessions);
    while ( iter.hasNext() )
    {
        Session* next = iter.next();
350
        if ( _sessionProfiles[next] == info )
351
352
353
            applyProfile(next,info,modifiedPropertiesOnly);        
    }
}
354
355
356
357
358
Profile::Ptr SessionManager::sessionProfile(Session* session) const
{
	return _sessionProfiles[session];
}
void SessionManager::setSessionProfile(Session* session, Profile::Ptr profile)
359
{
360
361
362
363
364
365
366
367
	_sessionProfiles[session] = profile;
	updateSession(session);
}
void SessionManager::applyProfile(Session* session, const Profile::Ptr info , bool modifiedPropertiesOnly)
{
	Q_ASSERT(info);

    _sessionProfiles[session] = info;
368

369
370
	ShouldApplyProperty apply(info,modifiedPropertiesOnly);

371
    // Basic session settings
372
373
	if ( apply.shouldApply(Profile::Name) )
		session->setTitle(Session::NameRole,info->name());
374

375
    if ( apply.shouldApply(Profile::Command) )
376
377
        session->setProgram(info->command());

378
    if ( apply.shouldApply(Profile::Arguments) )
379
380
        session->setArguments(info->arguments());

381
    if ( apply.shouldApply(Profile::Directory) )
382
383
        session->setInitialWorkingDirectory(info->defaultWorkingDirectory());

384
    if ( apply.shouldApply(Profile::Environment) )
385
386
387
388
389
390
391
392
	{
		// add environment variable containing home directory of current profile
		// (if specified)
		QStringList environment = info->property<QStringList>(Profile::Environment);
		environment << QString("PROFILEHOME=%1").arg(info->defaultWorkingDirectory());

        session->setEnvironment(environment);
	}
393

394
    if ( apply.shouldApply(Profile::Icon) )
395
        session->setIconName(info->icon());
396

397
    // Key bindings
398
399
    if ( apply.shouldApply(Profile::KeyBindings) )
        session->setKeyBindings(info->property<QString>(Profile::KeyBindings));
400

401
    // Tab formats
402
    if ( apply.shouldApply(Profile::LocalTabTitleFormat) )
403
        session->setTabTitleFormat( Session::LocalTabTitle ,
404
405
                                    info->property<QString>(Profile::LocalTabTitleFormat));
    if ( apply.shouldApply(Profile::RemoteTabTitleFormat) )
406
        session->setTabTitleFormat( Session::RemoteTabTitle ,
407
                                    info->property<QString>(Profile::RemoteTabTitleFormat));
408
409

    // Scrollback / history
410
    if ( apply.shouldApply(Profile::HistoryMode) || apply.shouldApply(Profile::HistorySize) ) 
411
    {
412
        int mode = info->property<int>(Profile::HistoryMode);
413
414
415
        switch ((Profile::HistoryModeEnum)mode)
        {
            case Profile::DisableHistory:
416
                    session->setHistoryType( HistoryTypeNone() );
417
418
419
                break;
            case Profile::FixedSizeHistory:
                {
420
                    int lines = info->property<int>(Profile::HistorySize);
421
                    session->setHistoryType( HistoryTypeBuffer(lines) );
422
423
424
                }
                break;
            case Profile::UnlimitedHistory:
425
                    session->setHistoryType( HistoryTypeFile() );
426
427
428
429
430
                break;
        }
    }

    // Terminal features
431
432
    if ( apply.shouldApply(Profile::FlowControlEnabled) )
        session->setFlowControlEnabled( info->property<bool>(Profile::FlowControlEnabled) );
433
434

    // Encoding
435
    if ( apply.shouldApply(Profile::DefaultEncoding) )
436
    {
437
        QByteArray name = info->property<QString>(Profile::DefaultEncoding).toUtf8();
438
439
        session->setCodec( QTextCodec::codecForName(name) );
    } 
440
441
}

442
void SessionManager::addProfile(Profile::Ptr type)
443
{
444
    if ( _types.isEmpty() )
445
        _defaultProfile = type;
446
 
447
    _types.insert(type);
448

449
    emit profileAdded(type);
450
451
}

452
bool SessionManager::deleteProfile(Profile::Ptr type)
453
{
454
455
    bool wasDefault = ( type == defaultProfile() );

456
457
    if ( type )
    {
458
459
460
461
462
        // try to delete the config file
        if ( type->isPropertySet(Profile::Path) && QFile::exists(type->path()) )
        {
            if (!QFile::remove(type->path()))
            {
463
                kWarning() << "Could not delete profile: " << type->path()
464
                    << "The file is most likely in a directory which is read-only.";
465
466

                return false;
467
468
469
            }
        }

470
471
472
473
474
475
        setFavorite(type,false);
        _types.remove(type);

		// mark the profile as hidden so that it does not show up in the 
		// Manage Profiles dialog and is not saved to disk
		type->setHidden(true);
476
477
    }

478
    // if we just deleted the default session type,
479
    // replace it with a random type from the list
480
481
    if ( wasDefault )
    {
482
        setDefaultProfile( _types.toList().first() );
483
    }
484

485
    emit profileRemoved(type);
486
487

    return true; 
488
}
489
void SessionManager::setDefaultProfile(Profile::Ptr info)
490
{
491
   Q_ASSERT ( _types.contains(info) );
492

493
   _defaultProfile = info;
494
495
496
497
498
499
500

   QString path = info->path();  
   
   if ( path.isEmpty() )
       path = KDE4ProfileWriter().getPath(info);

   QFileInfo fileInfo(path);
501

502
503
   KSharedConfigPtr config = KGlobal::config();
   KConfigGroup group = config->group("Desktop Entry");
504
   group.writeEntry("DefaultProfile",fileInfo.fileName());
505
}
506
QSet<Profile::Ptr> SessionManager::findFavorites() 
507
{
508
509
510
    if (_favorites.isEmpty())
        loadFavorites();

511
512
    return _favorites;
}
513
void SessionManager::setFavorite(Profile::Ptr info , bool favorite)
514
{
515
516
	if (!_types.contains(info))
		addProfile(info);
517

518
    if ( favorite && !_favorites.contains(info) )
519
    {
520
521
        _favorites.insert(info);
        emit favoriteStatusChanged(info,favorite);
522
    }
523
    else if ( !favorite && _favorites.contains(info) )
524
    {
525
526
        _favorites.remove(info);
        emit favoriteStatusChanged(info,favorite);
527
528
    }
}
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
void SessionManager::loadShortcuts()
{
    KSharedConfigPtr appConfig = KGlobal::config();
    KConfigGroup shortcutGroup = appConfig->group("Profile Shortcuts");

    QMap<QString,QString> entries = shortcutGroup.entryMap();

    QMapIterator<QString,QString> iter(entries);
    while ( iter.hasNext() )
    {
        iter.next();

        QKeySequence shortcut = QKeySequence::fromString(iter.key());
        QString profilePath = iter.value();

        ShortcutData data;
        data.profilePath = profilePath;

        _shortcuts.insert(shortcut,data);
    }
}
void SessionManager::saveShortcuts()
{
    KSharedConfigPtr appConfig = KGlobal::config();
    KConfigGroup shortcutGroup = appConfig->group("Profile Shortcuts");
    shortcutGroup.deleteGroup();

    QMapIterator<QKeySequence,ShortcutData> iter(_shortcuts);
    while ( iter.hasNext() )
    {
        iter.next();

        QString shortcutString = iter.key().toString();

        shortcutGroup.writeEntry(shortcutString,
                iter.value().profilePath);
    }    
}
567
void SessionManager::setShortcut(Profile::Ptr info , 
568
569
                                 const QKeySequence& keySequence )
{
570
    QKeySequence existingShortcut = shortcut(info);
571
572
573
    _shortcuts.remove(existingShortcut);

    ShortcutData data;
574
575
    data.profileKey = info;
    data.profilePath = info->path();
576
577
578
    // TODO - This won't work if the profile doesn't 
    // have a path yet
    _shortcuts.insert(keySequence,data);
579

580
	emit shortcutChanged(info,keySequence);
581
}
582
583
584
void SessionManager::loadFavorites()
{
    KSharedConfigPtr appConfig = KGlobal::config();
585
    KConfigGroup favoriteGroup = appConfig->group("Favorite Profiles");
586

587
    QSet<QString> favoriteSet;
588
589
590

    if ( favoriteGroup.hasKey("Favorites") )
    {
591
592
593
594
595
596
597
598
599
       QStringList list = favoriteGroup.readEntry("Favorites", QStringList());
       favoriteSet = QSet<QString>::fromList(list);
    }
    else
    {
       // if there is no favorites key at all, mark the 
       // supplied 'Shell.profile' as the only favorite
       favoriteSet << "Shell.profile";
    }
600

601
    // look for favorites amongst those already loaded
602
    QSetIterator<Profile::Ptr> iter(_types);
603
604
    while ( iter.hasNext() )
    {
605
606
         Profile::Ptr profile = iter.next();
         const QString& path = profile->path();
607
608
         if ( favoriteSet.contains( path ) )
         {
609
             _favorites.insert( profile );
610
611
             favoriteSet.remove(path);
         }
612
    }
613
614
615
616
    // load any remaining favorites
    QSetIterator<QString> unloadedFavoriteIter(favoriteSet);
    while ( unloadedFavoriteIter.hasNext() )
    {
617
618
619
          Profile::Ptr profile = loadProfile(unloadedFavoriteIter.next());
          if (profile)
              _favorites.insert(profile);
620
    } 
621
622
623
624
}
void SessionManager::saveFavorites()
{
    KSharedConfigPtr appConfig = KGlobal::config();
625
    KConfigGroup favoriteGroup = appConfig->group("Favorite Profiles");
626

627
    QStringList paths;
628
    QSetIterator<Profile::Ptr> keyIter(_favorites);
629
630
    while ( keyIter.hasNext() )
    {
631
        Profile::Ptr profile = keyIter.next();
632

633
        Q_ASSERT( _types.contains(profile) && profile );
634

635
        paths << profile->path();
636
637
    }

638
    favoriteGroup.writeEntry("Favorites",paths);
639
}
640
641
642
643
644
645

QList<QKeySequence> SessionManager::shortcuts() 
{
    return _shortcuts.keys();
}

646
Profile::Ptr SessionManager::findByShortcut(const QKeySequence& shortcut)
647
648
649
{
    Q_ASSERT( _shortcuts.contains(shortcut) );

650
    if ( !_shortcuts[shortcut].profileKey )
651
    {
652
        Profile::Ptr key = loadProfile(_shortcuts[shortcut].profilePath);
653
654
655
656
657
658
        _shortcuts[shortcut].profileKey = key;
    }

    return _shortcuts[shortcut].profileKey;
}

659
660
void SessionManager::sessionProfileCommandReceived(const QString& text)
{
Robert Knight's avatar
   
Robert Knight committed
661
662
663
664
    // FIXME: This is inefficient, it creates a new profile instance for
    // each set of changes applied.  Instead a new profile should be created
    // only the first time changes are applied to a session

665
666
667
668
669
670
    Session* session = qobject_cast<Session*>(sender());
    Q_ASSERT( session );

    ProfileCommandParser parser;
    QHash<Profile::Property,QVariant> changes = parser.parse(text);

671
    Profile::Ptr newProfile = Profile::Ptr(new Profile(_sessionProfiles[session]));
Robert Knight's avatar
   
Robert Knight committed
672
673
674
675
676
677
678
679
    
    QHashIterator<Profile::Property,QVariant> iter(changes);
    while ( iter.hasNext() )
    {
        iter.next();
        newProfile->setProperty(iter.key(),iter.value());
    } 

680
	_sessionProfiles[session] = newProfile;
681
682
}

683
QKeySequence SessionManager::shortcut(Profile::Ptr info) const
684
685
686
687
688
{
    QMapIterator<QKeySequence,ShortcutData> iter(_shortcuts);
    while (iter.hasNext())
    {
        iter.next();
689
        if ( iter.value().profileKey == info 
690
691
692
             || iter.value().profilePath == info->path() )
            return iter.key();
    }
693
694
    
    return QKeySequence();
695
696
}

Robert Knight's avatar
   
Robert Knight committed
697
698

K_GLOBAL_STATIC( SessionManager , theSessionManager )
699
700
SessionManager* SessionManager::instance()
{
Robert Knight's avatar
   
Robert Knight committed
701
	return theSessionManager;
702
703
}

704

705
#include "SessionManager.moc"