Profile.cpp 12.5 KB
Newer Older
1 2 3
/*
    This source file is part of Konsole, a terminal emulator.

4
    Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

    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.
*/

// Own
#include "Profile.h"

// Qt
26
#include <QtCore/QTextCodec>
27 28

// KDE
29
#include <KGlobalSettings>
30
#include <KLocalizedString>
31 32

// Konsole
33
#include "Enumeration.h"
34 35 36

using namespace Konsole;

37 38 39 40 41 42 43 44
// mappings between property enum values and names
//
// multiple names are defined for some property values,
// in these cases, the "proper" string name comes first,
// as that is used when reading/writing profiles from/to disk
//
// the other names are usually shorter versions for convenience
// when parsing konsoleprofile commands
45 46 47 48 49 50
static const char GENERAL_GROUP[]     = "General";
static const char KEYBOARD_GROUP[]    = "Keyboard";
static const char APPEARANCE_GROUP[]  = "Appearance";
static const char SCROLLING_GROUP[]   = "Scrolling";
static const char TERMINAL_GROUP[]    = "Terminal Features";
static const char CURSOR_GROUP[]      = "Cursor Options";
51
static const char INTERACTION_GROUP[] = "Interaction Options";
52
static const char ENCODING_GROUP[]    = "Encoding Options";
53

Kurt Hindenburg's avatar
Kurt Hindenburg committed
54
const Profile::PropertyInfo Profile::DefaultPropertyNames[] = {
55
    // General
Kurt Hindenburg's avatar
Kurt Hindenburg committed
56
    { Path , "Path" , 0 , QVariant::String }
57
    , { Name , "Name" , GENERAL_GROUP , QVariant::String }
58
    , { UntranslatedName, "UntranslatedName" , 0 , QVariant::String }
59 60 61
    , { Icon , "Icon" , GENERAL_GROUP , QVariant::String }
    , { Command , "Command" , 0 , QVariant::String }
    , { Arguments , "Arguments" , 0 , QVariant::StringList }
62
    , { MenuIndex, "MenuIndex" , 0, QVariant::String }
63 64 65
    , { Environment , "Environment" , GENERAL_GROUP , QVariant::StringList }
    , { Directory , "Directory" , GENERAL_GROUP , QVariant::String }
    , { LocalTabTitleFormat , "LocalTabTitleFormat" , GENERAL_GROUP , QVariant::String }
66
    , { LocalTabTitleFormat , "tabtitle" , 0 , QVariant::String }
67
    , { RemoteTabTitleFormat , "RemoteTabTitleFormat" , GENERAL_GROUP , QVariant::String }
68
    , { ShowTerminalSizeHint , "ShowTerminalSizeHint" , GENERAL_GROUP , QVariant::Bool }
69
    , { SaveGeometryOnExit , "SaveGeometryOnExit" , GENERAL_GROUP , QVariant::Bool }
70
    , { StartInCurrentSessionDir , "StartInCurrentSessionDir" , GENERAL_GROUP , QVariant::Bool }
71
    , { SilenceSeconds, "SilenceSeconds" , GENERAL_GROUP , QVariant::Int }
72 73
    , { TerminalColumns, "TerminalColumns" , GENERAL_GROUP , QVariant::Int }
    , { TerminalRows, "TerminalRows" , GENERAL_GROUP , QVariant::Int }
74

75 76
    // Appearance
    , { Font , "Font" , APPEARANCE_GROUP , QVariant::Font }
77
    , { ColorScheme , "ColorScheme" , APPEARANCE_GROUP , QVariant::String }
78
    , { ColorScheme , "colors" , 0 , QVariant::String }
79
    , { AntiAliasFonts, "AntiAliasFonts" , APPEARANCE_GROUP , QVariant::Bool }
80
    , { BoldIntense, "BoldIntense", APPEARANCE_GROUP, QVariant::Bool }
81

82
    // Keyboard
83
    , { KeyBindings , "KeyBindings" , KEYBOARD_GROUP , QVariant::String }
84

85 86
    // Scrolling
    , { HistoryMode , "HistoryMode" , SCROLLING_GROUP , QVariant::Int }
Kurt Hindenburg's avatar
Kurt Hindenburg committed
87
    , { HistorySize , "HistorySize" , SCROLLING_GROUP , QVariant::Int }
88
    , { ScrollBarPosition , "ScrollBarPosition" , SCROLLING_GROUP , QVariant::Int }
89

Kurt Hindenburg's avatar
Kurt Hindenburg committed
90
    // Terminal Features
91
    , { BlinkingTextEnabled , "BlinkingTextEnabled" , TERMINAL_GROUP , QVariant::Bool }
92
    , { FlowControlEnabled , "FlowControlEnabled" , TERMINAL_GROUP , QVariant::Bool }
93
    , { BidiRenderingEnabled , "BidiRenderingEnabled" , TERMINAL_GROUP , QVariant::Bool }
94
    , { BlinkingCursorEnabled , "BlinkingCursorEnabled" , TERMINAL_GROUP , QVariant::Bool }
95
    , { BellMode , "BellMode" , TERMINAL_GROUP , QVariant::Int }
96

Kurt Hindenburg's avatar
Kurt Hindenburg committed
97
    // Cursor
98
    , { UseCustomCursorColor , "UseCustomCursorColor" , CURSOR_GROUP , QVariant::Bool}
99 100
    , { CursorShape , "CursorShape" , CURSOR_GROUP , QVariant::Int}
    , { CustomCursorColor , "CustomCursorColor" , CURSOR_GROUP , QVariant::Color }
101

102
    // Interaction
103
    , { WordCharacters , "WordCharacters" , INTERACTION_GROUP , QVariant::String }
104
    , { TripleClickMode , "TripleClickMode" , INTERACTION_GROUP , QVariant::Int }
105
    , { UnderlineLinksEnabled , "UnderlineLinksEnabled" , INTERACTION_GROUP , QVariant::Bool }
106 107 108 109
    , { AutoCopySelectedText , "AutoCopySelectedText" , INTERACTION_GROUP , QVariant::Bool }
    , { PasteFromSelectionEnabled , "PasteFromSelectionEnabled" , INTERACTION_GROUP , QVariant::Bool }
    , { PasteFromClipboardEnabled , "PasteFromClipboardEnabled" , INTERACTION_GROUP , QVariant::Bool }
    , { MiddleClickPasteMode, "MiddleClickPasteMode" , INTERACTION_GROUP , QVariant::Int }
110

111
    // Encoding
112
    , { DefaultEncoding , "DefaultEncoding" , ENCODING_GROUP , QVariant::String }
113

114
    , { (Property)0 , 0 , 0, QVariant::Invalid }
115 116
};

Kurt Hindenburg's avatar
Kurt Hindenburg committed
117 118
QHash<QString, Profile::PropertyInfo> Profile::_propertyInfoByName;
QHash<Profile::Property, Profile::PropertyInfo> Profile::_infoByProperty;
119 120 121 122 123

void Profile::fillTableWithDefaultNames()
{
    static bool filledDefaults = false;

Kurt Hindenburg's avatar
Kurt Hindenburg committed
124
    if (filledDefaults)
125 126
        return;

127
    const PropertyInfo* iter = DefaultPropertyNames;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
128 129 130
    while (iter->name != 0) {
        registerProperty(*iter);
        iter++;
131 132
    }

Kurt Hindenburg's avatar
Kurt Hindenburg committed
133
    filledDefaults = true;
134
}
135 136

FallbackProfile::FallbackProfile()
Kurt Hindenburg's avatar
Kurt Hindenburg committed
137
    : Profile()
138 139
{
    // Fallback settings
Kurt Hindenburg's avatar
Kurt Hindenburg committed
140
    setProperty(Name, i18n("Shell"));
141
    setProperty(UntranslatedName, "Shell");
Kurt Hindenburg's avatar
Kurt Hindenburg committed
142
    // magic path for the fallback profile which is not a valid
143
    // non-directory file name
Kurt Hindenburg's avatar
Kurt Hindenburg committed
144 145 146
    setProperty(Path, "FALLBACK/");
    setProperty(Command, qgetenv("SHELL"));
    setProperty(Arguments, QStringList() << qgetenv("SHELL"));
Jekyll Wu's avatar
Jekyll Wu committed
147
    setProperty(Icon, "utilities-terminal");
Kurt Hindenburg's avatar
Kurt Hindenburg committed
148
    setProperty(Environment, QStringList() << "TERM=xterm");
149
    setProperty(LocalTabTitleFormat, "%d : %n");
Kurt Hindenburg's avatar
Kurt Hindenburg committed
150 151 152 153 154 155
    setProperty(RemoteTabTitleFormat, "(%u) %H");
    setProperty(ShowTerminalSizeHint, true);
    setProperty(SaveGeometryOnExit, true);
    setProperty(StartInCurrentSessionDir, true);
    setProperty(MenuIndex, "0");
    setProperty(SilenceSeconds, 10);
156 157
    setProperty(TerminalColumns, 80);
    setProperty(TerminalRows, 40);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
158 159 160 161 162

    setProperty(KeyBindings, "default");
    setProperty(ColorScheme, "Linux"); //use DarkPastels when is start support blue ncurses UI properly
    setProperty(Font, KGlobalSettings::fixedFont());

163
    setProperty(HistoryMode, Enum::FixedSizeHistory);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
164
    setProperty(HistorySize, 1000);
165
    setProperty(ScrollBarPosition, Enum::ScrollBarRight);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
166 167 168 169

    setProperty(FlowControlEnabled, true);
    setProperty(BlinkingTextEnabled, true);
    setProperty(UnderlineLinksEnabled, true);
170 171 172 173
    setProperty(AutoCopySelectedText, false);
    setProperty(PasteFromSelectionEnabled, true);
    setProperty(PasteFromClipboardEnabled, false);
    setProperty(MiddleClickPasteMode, Enum::PasteFromX11Selection);
174
    setProperty(TripleClickMode, Enum::SelectWholeLine);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
175 176 177

    setProperty(BlinkingCursorEnabled, false);
    setProperty(BidiRenderingEnabled, true);
178
    setProperty(CursorShape, Enum::BlockCursor);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
179 180
    setProperty(UseCustomCursorColor, false);
    setProperty(CustomCursorColor, Qt::black);
181
    setProperty(BellMode, Enum::NotifyBell);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
182 183 184 185

    setProperty(DefaultEncoding, QString(QTextCodec::codecForLocale()->name()));
    setProperty(AntiAliasFonts, true);
    setProperty(BoldIntense, true);
186

187
    // default taken from KDE 3
Kurt Hindenburg's avatar
Kurt Hindenburg committed
188
    setProperty(WordCharacters, ":@-./_~?&=%+#");
189 190 191 192

    // Fallback should not be shown in menus
    setHidden(true);
}
193
Profile::Profile(Profile::Ptr parent)
194
    : _parent(parent)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
195
    , _hidden(false)
196 197
{
}
198 199 200
void Profile::clone(Profile::Ptr profile, bool differentOnly)
{
    const PropertyInfo* properties = DefaultPropertyNames;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
201
    while (properties->name != 0) {
202 203
        Property current = properties->property;
        QVariant otherValue = profile->property<QVariant>(current);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
204 205 206 207 208 209 210 211 212
        switch (current) {
        case Name:
        case Path:
            break;
        default:
            if (!differentOnly ||
                    property<QVariant>(current) != otherValue) {
                setProperty(current, otherValue);
            }
213 214 215 216
        }
        properties++;
    }
}
217 218 219
Profile::~Profile()
{
}
Kurt Hindenburg's avatar
Kurt Hindenburg committed
220 221 222 223 224 225 226 227
bool Profile::isHidden() const
{
    return _hidden;
}
void Profile::setHidden(bool hidden)
{
    _hidden = hidden;
}
228

Kurt Hindenburg's avatar
Kurt Hindenburg committed
229 230 231 232 233 234 235 236
void Profile::setParent(Profile::Ptr parent)
{
    _parent = parent;
}
const Profile::Ptr Profile::parent() const
{
    return _parent;
}
237 238 239 240 241

bool Profile::isEmpty() const
{
    return _propertyValues.isEmpty();
}
Kurt Hindenburg's avatar
Kurt Hindenburg committed
242
QHash<Profile::Property, QVariant> Profile::setProperties() const
243 244 245 246 247
{
    return _propertyValues;
}
void Profile::setProperty(Property property , const QVariant& value)
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
248
    _propertyValues.insert(property, value);
249 250 251 252 253 254 255 256
}
bool Profile::isPropertySet(Property property) const
{
    return _propertyValues.contains(property);
}

Profile::Property Profile::lookupByName(const QString& name)
{
257 258 259
    // insert default names into table the first time this is called
    fillTableWithDefaultNames();

260
    return _propertyInfoByName[name.toLower()].property;
261 262
}

Kurt Hindenburg's avatar
Kurt Hindenburg committed
263
void Profile::registerProperty(const PropertyInfo& info)
264
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
265
    _propertyInfoByName.insert(QString(info.name).toLower(), info);
266 267 268

    // only allow one property -> name map
    // (multiple name -> property mappings are allowed though)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
269 270
    if (!_infoByProperty.contains(info.property))
        _infoByProperty.insert(info.property, info);
271 272
}

273 274 275 276
int Profile::menuIndexAsInt() const
{
    bool ok;
    int index = menuIndex().toInt(&ok, 10);
Jekyll Wu's avatar
Jekyll Wu committed
277 278 279 280
    if (ok)
        return index;
    else
        return 0;
281 282
}

283 284 285 286
const QStringList Profile::propertiesInfoList() const
{
    QStringList info;
    const PropertyInfo* iter = DefaultPropertyNames;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
287
    while (iter->name != 0) {
288 289 290 291 292 293 294
        info << QString(iter->name) + " : " + QString(QVariant(iter->type).typeName());
        iter++;
    }

    return info;
}

Kurt Hindenburg's avatar
Kurt Hindenburg committed
295
QHash<Profile::Property, QVariant> ProfileCommandParser::parse(const QString& input)
296
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
297
    QHash<Profile::Property, QVariant> changes;
298

299 300 301 302 303 304 305
    // regular expression to parse profile change requests.
    //
    // format: property=value;property=value ...
    //
    // where 'property' is a word consisting only of characters from A-Z
    // where 'value' is any sequence of characters other than a semi-colon
    //
306
    static QRegExp regExp("([a-zA-Z]+)=([^;]+)");
307 308

    int offset = 0;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
309 310
    while (regExp.indexIn(input, offset) != -1) {
        if (regExp.capturedTexts().count() == 3) {
311
            Profile::Property property = Profile::lookupByName(
Kurt Hindenburg's avatar
Kurt Hindenburg committed
312
                                             regExp.capturedTexts()[1]);
313
            const QString value = regExp.capturedTexts()[2];
Kurt Hindenburg's avatar
Kurt Hindenburg committed
314
            changes.insert(property, value);
315 316
        }

Kurt Hindenburg's avatar
Kurt Hindenburg committed
317 318
        offset = input.indexOf(';', offset) + 1;
        if (offset == 0)
319 320 321 322 323 324
            break;
    }

    return changes;
}

325 326 327
void ProfileGroup::updateValues()
{
    const PropertyInfo* properties = Profile::DefaultPropertyNames;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
328
    while (properties->name != 0) {
329
        // the profile group does not store a value for some properties
Kurt Hindenburg's avatar
Kurt Hindenburg committed
330
        // (eg. name, path) if even they are equal between profiles -
331 332 333
        //
        // the exception is when the group has only one profile in which
        // case it behaves like a standard Profile
Kurt Hindenburg's avatar
Kurt Hindenburg committed
334 335
        if (_profiles.count() > 1 &&
                !canInheritProperty(properties->property)) {
336 337 338 339 340
            properties++;
            continue;
        }

        QVariant value;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
341
        for (int i = 0; i < _profiles.count(); i++) {
342 343
            QVariant profileValue = _profiles[i]->property<QVariant>(properties->property);
            if (value.isNull())
Kurt Hindenburg's avatar
Kurt Hindenburg committed
344 345
                value = profileValue;
            else if (value != profileValue) {
346 347 348
                value = QVariant();
                break;
            }
Kurt Hindenburg's avatar
Kurt Hindenburg committed
349 350
        }
        Profile::setProperty(properties->property, value);
351 352 353 354 355 356 357 358
        properties++;
    }
}
void ProfileGroup::setProperty(Property property, const QVariant& value)
{
    if (_profiles.count() > 1 && !canInheritProperty(property))
        return;

Kurt Hindenburg's avatar
Kurt Hindenburg committed
359
    Profile::setProperty(property, value);
Jekyll Wu's avatar
Jekyll Wu committed
360 361 362
    foreach(Profile::Ptr profile, _profiles) {
        profile->setProperty(property, value);
    }
363 364
}