00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "Profile.h"
00024
00025
00026 #include <QtCore/QFile>
00027 #include <QtCore/QFileInfo>
00028 #include <QtCore/QTextCodec>
00029
00030
00031 #include <KConfigGroup>
00032 #include <KDesktopFile>
00033 #include <KGlobal>
00034 #include <KGlobalSettings>
00035 #include <KLocale>
00036 #include <KDebug>
00037 #include <KStandardDirs>
00038
00039
00040 #include <unistd.h>
00041
00042
00043 #include "ShellCommand.h"
00044
00045 using namespace Konsole;
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 static const char* GENERAL_GROUP = "General";
00056 static const char* KEYBOARD_GROUP = "Keyboard";
00057 static const char* APPEARANCE_GROUP = "Appearance";
00058 static const char* SCROLLING_GROUP = "Scrolling";
00059 static const char* TERMINAL_GROUP = "Terminal Features";
00060 static const char* CURSOR_GROUP = "Cursor Options";
00061 static const char* INTERACTION_GROUP = "Interaction Options";
00062 static const char* ENCODING_GROUP = "Encoding Options";
00063
00064 const Profile::PropertyInfo Profile::DefaultPropertyNames[] =
00065 {
00066
00067 { Path , "Path" , 0 , QVariant::String }
00068 , { Name , "Name" , GENERAL_GROUP , QVariant::String }
00069 , { Title , "Title" , 0 , QVariant::String }
00070 , { Icon , "Icon" , GENERAL_GROUP , QVariant::String }
00071 , { Command , "Command" , 0 , QVariant::String }
00072 , { Arguments , "Arguments" , 0 , QVariant::StringList }
00073 , { Environment , "Environment" , GENERAL_GROUP , QVariant::StringList }
00074 , { Directory , "Directory" , GENERAL_GROUP , QVariant::String }
00075 , { LocalTabTitleFormat , "LocalTabTitleFormat" , GENERAL_GROUP , QVariant::String }
00076 , { LocalTabTitleFormat , "tabtitle" , 0 , QVariant::String }
00077 , { RemoteTabTitleFormat , "RemoteTabTitleFormat" , GENERAL_GROUP , QVariant::String }
00078 , { ShowMenuBar , "ShowMenuBar" , GENERAL_GROUP , QVariant::Bool }
00079 , { TabBarMode , "TabBarMode" , GENERAL_GROUP , QVariant::Int }
00080 , { TabBarPosition , "TabBarPosition" , GENERAL_GROUP , QVariant::Int }
00081 , { StartInCurrentSessionDir , "StartInCurrentSessionDir" , GENERAL_GROUP , QVariant::Bool }
00082 , { ShowNewAndCloseTabButtons, "ShowNewAndCloseTabButtons" , GENERAL_GROUP , QVariant::Bool }
00083
00084
00085 , { Font , "Font" , APPEARANCE_GROUP , QVariant::Font }
00086 , { ColorScheme , "ColorScheme" , APPEARANCE_GROUP , QVariant::String }
00087 , { ColorScheme , "colors" , 0 , QVariant::String }
00088 , { AntiAliasFonts, "AntiAliasFonts" , APPEARANCE_GROUP , QVariant::Bool }
00089
00090
00091 , { KeyBindings , "KeyBindings" , KEYBOARD_GROUP , QVariant::String }
00092
00093
00094 , { HistoryMode , "HistoryMode" , SCROLLING_GROUP , QVariant::Int }
00095 , { HistorySize , "HistorySize" , SCROLLING_GROUP , QVariant::Int }
00096 , { ScrollBarPosition , "ScrollBarPosition" , SCROLLING_GROUP , QVariant::Int }
00097
00098
00099 , { BlinkingTextEnabled , "BlinkingTextEnabled" , TERMINAL_GROUP , QVariant::Bool }
00100 , { FlowControlEnabled , "FlowControlEnabled" , TERMINAL_GROUP , QVariant::Bool }
00101 , { AllowProgramsToResizeWindow , "AllowProgramsToResizeWindow" , TERMINAL_GROUP , QVariant::Bool }
00102 , { BidiRenderingEnabled , "BidiRenderingEnabled" , TERMINAL_GROUP , QVariant::Bool }
00103 , { BlinkingCursorEnabled , "BlinkingCursorEnabled" , TERMINAL_GROUP , QVariant::Bool }
00104
00105
00106 , { UseCustomCursorColor , "UseCustomCursorColor" , CURSOR_GROUP , QVariant::Bool}
00107 , { CursorShape , "CursorShape" , CURSOR_GROUP , QVariant::Int}
00108 , { CustomCursorColor , "CustomCursorColor" , CURSOR_GROUP , QVariant::Color }
00109
00110
00111 , { WordCharacters , "WordCharacters" , INTERACTION_GROUP , QVariant::String }
00112
00113
00114 , { DefaultEncoding , "DefaultEncoding" , ENCODING_GROUP , QVariant::String }
00115
00116 , { (Property)0 , 0 , 0, QVariant::Invalid }
00117 };
00118
00119 QHash<QString,Profile::PropertyInfo> Profile::_propertyInfoByName;
00120 QHash<Profile::Property,Profile::PropertyInfo> Profile::_infoByProperty;
00121
00122 void Profile::fillTableWithDefaultNames()
00123 {
00124 static bool filledDefaults = false;
00125
00126 if ( filledDefaults )
00127 return;
00128
00129 const PropertyInfo* iter = DefaultPropertyNames;
00130 while ( iter->name != 0 )
00131 {
00132 registerProperty(*iter);
00133 iter++;
00134 }
00135
00136 filledDefaults = true;
00137 }
00138
00139 FallbackProfile::FallbackProfile()
00140 : Profile()
00141 {
00142
00143 setProperty(Name,i18n("Shell"));
00144
00145
00146 setProperty(Path,"FALLBACK/");
00147 setProperty(Command,getenv("SHELL"));
00148 setProperty(Icon,"utilities-terminal");
00149 setProperty(Arguments,QStringList() << getenv("SHELL"));
00150 setProperty(Environment,QStringList() << "TERM=xterm");
00151 setProperty(LocalTabTitleFormat,"%d : %n");
00152 setProperty(RemoteTabTitleFormat,"%H (%u)");
00153 setProperty(TabBarMode,AlwaysShowTabBar);
00154 setProperty(TabBarPosition,TabBarBottom);
00155 setProperty(ShowMenuBar,true);
00156 setProperty(StartInCurrentSessionDir,true);
00157 setProperty(ShowNewAndCloseTabButtons,false);
00158
00159 setProperty(KeyBindings,"default");
00160 setProperty(ColorScheme,"Linux");
00161 setProperty(Font,KGlobalSettings::fixedFont());
00162
00163 setProperty(HistoryMode,FixedSizeHistory);
00164 setProperty(HistorySize,1000);
00165 setProperty(ScrollBarPosition,ScrollBarRight);
00166
00167 setProperty(FlowControlEnabled,true);
00168 setProperty(AllowProgramsToResizeWindow,true);
00169 setProperty(BlinkingTextEnabled,true);
00170
00171 setProperty(BlinkingCursorEnabled,false);
00172 setProperty(BidiRenderingEnabled,false);
00173 setProperty(CursorShape,BlockCursor);
00174 setProperty(UseCustomCursorColor,false);
00175 setProperty(CustomCursorColor,Qt::black);
00176
00177 setProperty(DefaultEncoding,QString(QTextCodec::codecForLocale()->name()));
00178 setProperty(AntiAliasFonts,true);
00179
00180
00181 setProperty(WordCharacters,":@-./_~?&=%+#");
00182
00183
00184 setHidden(true);
00185 }
00186 Profile::Profile(Profile::Ptr parent)
00187 : _parent(parent)
00188 ,_hidden(false)
00189 {
00190 }
00191 void Profile::clone(Profile::Ptr profile, bool differentOnly)
00192 {
00193 const PropertyInfo* properties = DefaultPropertyNames;
00194 while (properties->name != 0)
00195 {
00196 Property current = properties->property;
00197 QVariant otherValue = profile->property<QVariant>(current);
00198 switch (current)
00199 {
00200 case Name:
00201 case Path:
00202 break;
00203 default:
00204 if (!differentOnly ||
00205 property<QVariant>(current) !=
00206 otherValue)
00207 {
00208 setProperty(current,otherValue);
00209 }
00210 }
00211 properties++;
00212 }
00213 }
00214 Profile::~Profile()
00215 {
00216 }
00217 bool Profile::isHidden() const { return _hidden; }
00218 void Profile::setHidden(bool hidden) { _hidden = hidden; }
00219
00220 void Profile::setParent(Profile::Ptr parent) { _parent = parent; }
00221 const Profile::Ptr Profile::parent() const { return _parent; }
00222
00223 bool Profile::isEmpty() const
00224 {
00225 return _propertyValues.isEmpty();
00226 }
00227 QHash<Profile::Property,QVariant> Profile::setProperties() const
00228 {
00229 return _propertyValues;
00230 }
00231 void Profile::setProperty(Property property , const QVariant& value)
00232 {
00233 _propertyValues.insert(property,value);
00234 }
00235 bool Profile::isPropertySet(Property property) const
00236 {
00237 return _propertyValues.contains(property);
00238 }
00239
00240 bool Profile::isNameRegistered(const QString& name)
00241 {
00242
00243 fillTableWithDefaultNames();
00244
00245 return _propertyInfoByName.contains(name);
00246 }
00247
00248 Profile::Property Profile::lookupByName(const QString& name)
00249 {
00250
00251 fillTableWithDefaultNames();
00252
00253 return _propertyInfoByName[name.toLower()].property;
00254 }
00255 QString Profile::primaryNameForProperty(Property property)
00256 {
00257
00258 fillTableWithDefaultNames();
00259
00260 return _infoByProperty[property].name;
00261 }
00262 QList<QString> Profile::namesForProperty(Property property)
00263 {
00264
00265 fillTableWithDefaultNames();
00266
00267 return QList<QString>() << primaryNameForProperty(property);
00268 }
00269 void Profile::registerProperty(const PropertyInfo& info)
00270 {
00271 _propertyInfoByName.insert(QString(info.name).toLower(),info);
00272
00273
00274
00275 if ( !_infoByProperty.contains(info.property) )
00276 _infoByProperty.insert(info.property,info);
00277 }
00278
00279 QString KDE4ProfileWriter::getPath(const Profile::Ptr info)
00280 {
00281 QString newPath;
00282
00283 if ( info->isPropertySet(Profile::Path) &&
00284 info->path().startsWith(KGlobal::dirs()->saveLocation("data", "konsole/")) )
00285 {
00286 newPath = info->path();
00287 }
00288 else
00289 {
00290
00291 newPath = KGlobal::dirs()->saveLocation("data","konsole/") + info->name() + ".profile";
00292 }
00293
00294 kDebug(1211) << "Saving profile under name: " << newPath;
00295
00296 return newPath;
00297 }
00298 void KDE4ProfileWriter::writeProperties(KConfig& config,
00299 const Profile::Ptr profile,
00300 const Profile::PropertyInfo* properties)
00301 {
00302 const char* groupName = 0;
00303 KConfigGroup group;
00304
00305 while (properties->name != 0)
00306 {
00307 if (properties->group != 0)
00308 {
00309 if (groupName == 0 || strcmp(groupName,properties->group) != 0)
00310 {
00311 group = config.group(properties->group);
00312 groupName = properties->group;
00313 }
00314
00315 if ( profile->isPropertySet(properties->property) )
00316 group.writeEntry(QString(properties->name),
00317 profile->property<QVariant>(properties->property));
00318 }
00319
00320 properties++;
00321 }
00322 }
00323 bool KDE4ProfileWriter::writeProfile(const QString& path , const Profile::Ptr profile)
00324 {
00325 KConfig config(path,KConfig::NoGlobals);
00326
00327 KConfigGroup general = config.group(GENERAL_GROUP);
00328
00329
00330
00331 if ( profile->parent() )
00332 general.writeEntry("Parent",profile->parent()->path());
00333
00334 if ( profile->isPropertySet(Profile::Command)
00335 || profile->isPropertySet(Profile::Arguments) )
00336 general.writeEntry("Command",
00337 ShellCommand(profile->command(),profile->arguments()).fullCommand());
00338
00339
00340 writeProperties(config,profile,Profile::DefaultPropertyNames);
00341
00342 return true;
00343 }
00344
00345 QStringList KDE4ProfileReader::findProfiles()
00346 {
00347 return KGlobal::dirs()->findAllResources("data","konsole/*.profile",
00348 KStandardDirs::NoDuplicates);
00349 }
00350 void KDE4ProfileReader::readProperties(const KConfig& config, Profile::Ptr profile,
00351 const Profile::PropertyInfo* properties)
00352 {
00353 const char* groupName = 0;
00354 KConfigGroup group;
00355
00356 while (properties->name != 0)
00357 {
00358 if (properties->group != 0)
00359 {
00360 if (groupName == 0 || strcmp(groupName,properties->group) != 0)
00361 {
00362 group = config.group(properties->group);
00363 groupName = properties->group;
00364 }
00365
00366 QString name(properties->name);
00367
00368 if (group.hasKey(name))
00369 profile->setProperty(properties->property,
00370 group.readEntry(name,QVariant(properties->type)));
00371
00372 }
00373
00374 properties++;
00375 }
00376 }
00377
00378 bool KDE4ProfileReader::readProfile(const QString& path , Profile::Ptr profile , QString& parentProfile)
00379 {
00380 if (!QFile::exists(path))
00381 return false;
00382
00383 KConfig config(path,KConfig::NoGlobals);
00384
00385 KConfigGroup general = config.group(GENERAL_GROUP);
00386 if (general.hasKey("Parent"))
00387 parentProfile = general.readEntry("Parent");
00388
00389 if ( general.hasKey("Command") )
00390 {
00391 ShellCommand shellCommand(general.readEntry("Command"));
00392
00393 profile->setProperty(Profile::Command,shellCommand.command());
00394 profile->setProperty(Profile::Arguments,shellCommand.arguments());
00395 }
00396
00397
00398 readProperties(config,profile,Profile::DefaultPropertyNames);
00399
00400 return true;
00401 }
00402 QStringList KDE3ProfileReader::findProfiles()
00403 {
00404 return KGlobal::dirs()->findAllResources("data", "konsole/*.desktop",
00405 KStandardDirs::NoDuplicates);
00406 }
00407 bool KDE3ProfileReader::readProfile(const QString& path , Profile::Ptr profile , QString& parentProfile)
00408 {
00409 if (!QFile::exists(path))
00410 return false;
00411
00412
00413 parentProfile = QString();
00414
00415 KDesktopFile* desktopFile = new KDesktopFile(path);
00416 KConfigGroup* config = new KConfigGroup( desktopFile->desktopGroup() );
00417
00418 if ( config->hasKey("Name") )
00419 profile->setProperty(Profile::Name,config->readEntry("Name"));
00420
00421 kDebug() << "reading KDE 3 profile " << profile->name();
00422
00423 if ( config->hasKey("Icon") )
00424 profile->setProperty(Profile::Icon,config->readEntry("Icon"));
00425 if ( config->hasKey("Exec") )
00426 {
00427 const QString& fullCommand = config->readEntry("Exec");
00428 ShellCommand shellCommand(fullCommand);
00429
00430 profile->setProperty(Profile::Command,shellCommand.command());
00431 profile->setProperty(Profile::Arguments,shellCommand.arguments());
00432 }
00433 if ( config->hasKey("Schema") )
00434 {
00435 profile->setProperty(Profile::ColorScheme,config->readEntry("Schema").replace
00436 (".schema",QString()));
00437 }
00438 if ( config->hasKey("defaultfont") )
00439 {
00440 profile->setProperty(Profile::Font,config->readEntry("defaultfont"));
00441 }
00442 if ( config->hasKey("KeyTab") )
00443 {
00444 profile->setProperty(Profile::KeyBindings,config->readEntry("KeyTab"));
00445 }
00446 if ( config->hasKey("Term") )
00447 {
00448 profile->setProperty(Profile::Environment,
00449 QStringList() << "TERM="+config->readEntry("Term"));
00450 }
00451 if ( config->hasKey("Cwd") )
00452 {
00453 profile->setProperty(Profile::Directory,config->readEntry("Cwd"));
00454 }
00455
00456 delete desktopFile;
00457 delete config;
00458
00459 return true;
00460 }
00461
00462 QHash<Profile::Property,QVariant> ProfileCommandParser::parse(const QString& input)
00463 {
00464 QHash<Profile::Property,QVariant> changes;
00465
00466
00467
00468
00469
00470
00471
00472
00473 static QRegExp regExp("([a-zA-Z]+)=([^;]+)");
00474
00475 int offset = 0;
00476 while ( regExp.indexIn(input,offset) != -1 )
00477 {
00478 if ( regExp.capturedTexts().count() == 3 )
00479 {
00480 Profile::Property property = Profile::lookupByName(
00481 regExp.capturedTexts()[1]);
00482 const QString value = regExp.capturedTexts()[2];
00483 changes.insert(property,value);
00484 }
00485
00486 offset = input.indexOf(';',offset) + 1;
00487 if ( offset == 0 )
00488 break;
00489 }
00490
00491 return changes;
00492 }
00493
00494 void ProfileGroup::updateValues()
00495 {
00496 const PropertyInfo* properties = Profile::DefaultPropertyNames;
00497 while (properties->name != 0)
00498 {
00499
00500
00501
00502
00503
00504 if (_profiles.count() > 1 &&
00505 !canInheritProperty(properties->property))
00506 {
00507 properties++;
00508 continue;
00509 }
00510
00511 QVariant value;
00512 for (int i=0;i<_profiles.count();i++)
00513 {
00514 QVariant profileValue = _profiles[i]->property<QVariant>(properties->property);
00515 if (value.isNull())
00516 value = profileValue;
00517 else if (value != profileValue)
00518 {
00519 value = QVariant();
00520 break;
00521 }
00522 }
00523 Profile::setProperty(properties->property,value);
00524 properties++;
00525 }
00526 }
00527 void ProfileGroup::setProperty(Property property, const QVariant& value)
00528 {
00529 if (_profiles.count() > 1 && !canInheritProperty(property))
00530 return;
00531
00532 Profile::setProperty(property,value);
00533 foreach(Profile::Ptr profile,_profiles)
00534 profile->setProperty(property,value);
00535 }
00536
00537
00538