Profile.cpp 13.6 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
#include <QtCore/QRegularExpression>
28 29

// KDE
30
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
31
#include <QFontDatabase>
32 33

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

using namespace Konsole;

38 39 40 41 42 43 44 45
// 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
46 47 48 49 50 51
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";
52
static const char INTERACTION_GROUP[] = "Interaction Options";
53
static const char ENCODING_GROUP[]    = "Encoding Options";
54

Kurt Hindenburg's avatar
Kurt Hindenburg committed
55
const Profile::PropertyInfo Profile::DefaultPropertyNames[] = {
56
    // General
Kurt Hindenburg's avatar
Kurt Hindenburg committed
57
    { Path , "Path" , 0 , QVariant::String }
58
    , { Name , "Name" , GENERAL_GROUP , QVariant::String }
59
    , { UntranslatedName, "UntranslatedName" , 0 , QVariant::String }
60 61 62
    , { Icon , "Icon" , GENERAL_GROUP , QVariant::String }
    , { Command , "Command" , 0 , QVariant::String }
    , { Arguments , "Arguments" , 0 , QVariant::StringList }
63
    , { MenuIndex, "MenuIndex" , 0, QVariant::String }
64 65 66
    , { Environment , "Environment" , GENERAL_GROUP , QVariant::StringList }
    , { Directory , "Directory" , GENERAL_GROUP , QVariant::String }
    , { LocalTabTitleFormat , "LocalTabTitleFormat" , GENERAL_GROUP , QVariant::String }
67
    , { LocalTabTitleFormat , "tabtitle" , 0 , QVariant::String }
68
    , { RemoteTabTitleFormat , "RemoteTabTitleFormat" , GENERAL_GROUP , QVariant::String }
69
    , { ShowTerminalSizeHint , "ShowTerminalSizeHint" , 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
    , { UseFontLineCharacters, "UseFontLineChararacters", APPEARANCE_GROUP, QVariant::Bool }
82
    , { LineSpacing , "LineSpacing" , APPEARANCE_GROUP , QVariant::Int }
83

84
    // Keyboard
85
    , { KeyBindings , "KeyBindings" , KEYBOARD_GROUP , QVariant::String }
86

87 88
    // Scrolling
    , { HistoryMode , "HistoryMode" , SCROLLING_GROUP , QVariant::Int }
Kurt Hindenburg's avatar
Kurt Hindenburg committed
89
    , { HistorySize , "HistorySize" , SCROLLING_GROUP , QVariant::Int }
90
    , { ScrollBarPosition , "ScrollBarPosition" , SCROLLING_GROUP , QVariant::Int }
91
    , { ScrollFullPage , "ScrollFullPage" , SCROLLING_GROUP , QVariant::Bool }
92

Kurt Hindenburg's avatar
Kurt Hindenburg committed
93
    // Terminal Features
94
    , { EnableUrlHints , "EnableUrlHints" , TERMINAL_GROUP , QVariant::Bool }
95
    , { BlinkingTextEnabled , "BlinkingTextEnabled" , TERMINAL_GROUP , QVariant::Bool }
96
    , { FlowControlEnabled , "FlowControlEnabled" , TERMINAL_GROUP , QVariant::Bool }
97
    , { BidiRenderingEnabled , "BidiRenderingEnabled" , TERMINAL_GROUP , QVariant::Bool }
98
    , { BlinkingCursorEnabled , "BlinkingCursorEnabled" , TERMINAL_GROUP , QVariant::Bool }
99
    , { BellMode , "BellMode" , TERMINAL_GROUP , QVariant::Int }
100

Kurt Hindenburg's avatar
Kurt Hindenburg committed
101
    // Cursor
102
    , { UseCustomCursorColor , "UseCustomCursorColor" , CURSOR_GROUP , QVariant::Bool}
103 104
    , { CursorShape , "CursorShape" , CURSOR_GROUP , QVariant::Int}
    , { CustomCursorColor , "CustomCursorColor" , CURSOR_GROUP , QVariant::Color }
105

106
    // Interaction
107
    , { WordCharacters , "WordCharacters" , INTERACTION_GROUP , QVariant::String }
108
    , { TripleClickMode , "TripleClickMode" , INTERACTION_GROUP , QVariant::Int }
109
    , { UnderlineLinksEnabled , "UnderlineLinksEnabled" , INTERACTION_GROUP , QVariant::Bool }
110
    , { OpenLinksByDirectClickEnabled , "OpenLinksByDirectClickEnabled" , INTERACTION_GROUP , QVariant::Bool }
111
    , { CtrlRequiredForDrag, "CtrlRequiredForDrag" , INTERACTION_GROUP , QVariant::Bool }
112
    , { DropUrlsAsText , "DropUrlsAsText" , INTERACTION_GROUP , QVariant::Bool }
113
    , { AutoCopySelectedText , "AutoCopySelectedText" , INTERACTION_GROUP , QVariant::Bool }
114
    , { TrimTrailingSpacesInSelectedText , "TrimTrailingSpacesInSelectedText" , INTERACTION_GROUP , QVariant::Bool }
115 116 117
    , { PasteFromSelectionEnabled , "PasteFromSelectionEnabled" , INTERACTION_GROUP , QVariant::Bool }
    , { PasteFromClipboardEnabled , "PasteFromClipboardEnabled" , INTERACTION_GROUP , QVariant::Bool }
    , { MiddleClickPasteMode, "MiddleClickPasteMode" , INTERACTION_GROUP , QVariant::Int }
118
    , { MouseWheelZoomEnabled, "MouseWheelZoomEnabled", INTERACTION_GROUP, QVariant::Bool }
119

120
    // Encoding
121
    , { DefaultEncoding , "DefaultEncoding" , ENCODING_GROUP , QVariant::String }
122

123
    , { (Property)0 , 0 , 0, QVariant::Invalid }
124 125
};

126 127
QHash<QString, Profile::PropertyInfo> Profile::PropertyInfoByName;
QHash<Profile::Property, Profile::PropertyInfo> Profile::PropertyInfoByProperty;
128 129 130 131 132

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

Kurt Hindenburg's avatar
Kurt Hindenburg committed
133
    if (filledDefaults)
134 135
        return;

136
    const PropertyInfo* iter = DefaultPropertyNames;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
137 138 139
    while (iter->name != 0) {
        registerProperty(*iter);
        iter++;
140 141
    }

Kurt Hindenburg's avatar
Kurt Hindenburg committed
142
    filledDefaults = true;
143
}
144 145

FallbackProfile::FallbackProfile()
Kurt Hindenburg's avatar
Kurt Hindenburg committed
146
    : Profile()
147 148
{
    // Fallback settings
149 150
    setProperty(Name, i18nc("Name of the default/builtin profile", "Default"));
    setProperty(UntranslatedName, "Default");
Kurt Hindenburg's avatar
Kurt Hindenburg committed
151
    // magic path for the fallback profile which is not a valid
152
    // non-directory file name
Kurt Hindenburg's avatar
Kurt Hindenburg committed
153 154
    setProperty(Path, "FALLBACK/");
    setProperty(Command, qgetenv("SHELL"));
155
    // See Pty.cpp on why Arguments is populated
156
    setProperty(Arguments, QStringList() << qgetenv("SHELL"));
Jekyll Wu's avatar
Jekyll Wu committed
157
    setProperty(Icon, "utilities-terminal");
158
    setProperty(Environment, QStringList() << QStringLiteral("TERM=xterm"));
159
    setProperty(LocalTabTitleFormat, "%d : %n");
Kurt Hindenburg's avatar
Kurt Hindenburg committed
160 161 162 163 164
    setProperty(RemoteTabTitleFormat, "(%u) %H");
    setProperty(ShowTerminalSizeHint, true);
    setProperty(StartInCurrentSessionDir, true);
    setProperty(MenuIndex, "0");
    setProperty(SilenceSeconds, 10);
165
    setProperty(TerminalColumns, 80);
166
    setProperty(TerminalRows, 24);
167
    setProperty(MouseWheelZoomEnabled, true);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
168 169 170

    setProperty(KeyBindings, "default");
    setProperty(ColorScheme, "Linux"); //use DarkPastels when is start support blue ncurses UI properly
Laurent Montel's avatar
Laurent Montel committed
171
    setProperty(Font, QFontDatabase::systemFont(QFontDatabase::FixedFont));
Kurt Hindenburg's avatar
Kurt Hindenburg committed
172

173
    setProperty(HistoryMode, Enum::FixedSizeHistory);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
174
    setProperty(HistorySize, 1000);
175
    setProperty(ScrollBarPosition, Enum::ScrollBarRight);
176
    setProperty(ScrollFullPage, false);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
177 178

    setProperty(FlowControlEnabled, true);
179
    setProperty(EnableUrlHints, false);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
180 181
    setProperty(BlinkingTextEnabled, true);
    setProperty(UnderlineLinksEnabled, true);
182
    setProperty(OpenLinksByDirectClickEnabled, false);
183
    setProperty(CtrlRequiredForDrag, true);
184
    setProperty(AutoCopySelectedText, false);
185
    setProperty(TrimTrailingSpacesInSelectedText, false);
186
    setProperty(DropUrlsAsText, false);
187 188 189
    setProperty(PasteFromSelectionEnabled, true);
    setProperty(PasteFromClipboardEnabled, false);
    setProperty(MiddleClickPasteMode, Enum::PasteFromX11Selection);
190
    setProperty(TripleClickMode, Enum::SelectWholeLine);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
191 192 193

    setProperty(BlinkingCursorEnabled, false);
    setProperty(BidiRenderingEnabled, true);
194
    setProperty(LineSpacing, 0);
195
    setProperty(CursorShape, Enum::BlockCursor);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
196
    setProperty(UseCustomCursorColor, false);
Alex Richardson's avatar
Alex Richardson committed
197
    setProperty(CustomCursorColor, QColor(Qt::black));
198
    setProperty(BellMode, Enum::NotifyBell);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
199 200 201 202

    setProperty(DefaultEncoding, QString(QTextCodec::codecForLocale()->name()));
    setProperty(AntiAliasFonts, true);
    setProperty(BoldIntense, true);
203
    setProperty(UseFontLineCharacters, false);
204

Kurt Hindenburg's avatar
Kurt Hindenburg committed
205
    setProperty(WordCharacters, ":@-./_~?&=%+#");
206 207 208 209

    // Fallback should not be shown in menus
    setHidden(true);
}
210
Profile::Profile(Profile::Ptr parent)
211
    : _parent(parent)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
212
    , _hidden(false)
213 214
{
}
215 216 217
void Profile::clone(Profile::Ptr profile, bool differentOnly)
{
    const PropertyInfo* properties = DefaultPropertyNames;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
218
    while (properties->name != 0) {
219 220
        Property current = properties->property;
        QVariant otherValue = profile->property<QVariant>(current);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
221 222 223 224 225 226 227 228 229
        switch (current) {
        case Name:
        case Path:
            break;
        default:
            if (!differentOnly ||
                    property<QVariant>(current) != otherValue) {
                setProperty(current, otherValue);
            }
230 231 232 233
        }
        properties++;
    }
}
234 235 236
Profile::~Profile()
{
}
Kurt Hindenburg's avatar
Kurt Hindenburg committed
237 238 239 240 241 242 243 244
bool Profile::isHidden() const
{
    return _hidden;
}
void Profile::setHidden(bool hidden)
{
    _hidden = hidden;
}
245

Kurt Hindenburg's avatar
Kurt Hindenburg committed
246 247 248 249 250 251 252 253
void Profile::setParent(Profile::Ptr parent)
{
    _parent = parent;
}
const Profile::Ptr Profile::parent() const
{
    return _parent;
}
254 255 256 257 258

bool Profile::isEmpty() const
{
    return _propertyValues.isEmpty();
}
Kurt Hindenburg's avatar
Kurt Hindenburg committed
259
QHash<Profile::Property, QVariant> Profile::setProperties() const
260 261 262 263 264
{
    return _propertyValues;
}
void Profile::setProperty(Property property , const QVariant& value)
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
265
    _propertyValues.insert(property, value);
266 267 268 269 270 271 272 273
}
bool Profile::isPropertySet(Property property) const
{
    return _propertyValues.contains(property);
}

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

277
    return PropertyInfoByName[name.toLower()].property;
278 279
}

Kurt Hindenburg's avatar
Kurt Hindenburg committed
280
void Profile::registerProperty(const PropertyInfo& info)
281
{
282
    PropertyInfoByName.insert(QString(info.name).toLower(), info);
283 284 285

    // only allow one property -> name map
    // (multiple name -> property mappings are allowed though)
286 287
    if (!PropertyInfoByProperty.contains(info.property))
        PropertyInfoByProperty.insert(info.property, info);
288 289
}

290 291 292 293
int Profile::menuIndexAsInt() const
{
    bool ok;
    int index = menuIndex().toInt(&ok, 10);
Jekyll Wu's avatar
Jekyll Wu committed
294 295 296 297
    if (ok)
        return index;
    else
        return 0;
298 299
}

300 301 302 303
const QStringList Profile::propertiesInfoList() const
{
    QStringList info;
    const PropertyInfo* iter = DefaultPropertyNames;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
304
    while (iter->name != 0) {
305 306 307 308 309 310 311
        info << QString(iter->name) + " : " + QString(QVariant(iter->type).typeName());
        iter++;
    }

    return info;
}

Kurt Hindenburg's avatar
Kurt Hindenburg committed
312
QHash<Profile::Property, QVariant> ProfileCommandParser::parse(const QString& input)
313
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
314
    QHash<Profile::Property, QVariant> changes;
315

316 317 318 319 320 321 322
    // 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
    //
323 324 325 326 327 328 329 330
    static const QRegularExpression regExp("([a-zA-Z]+)=([^;]+)");

    QRegularExpressionMatchIterator iterator(regExp.globalMatch(input));
    while (iterator.hasNext()) {
        QRegularExpressionMatch match(iterator.next());
        Profile::Property property = Profile::lookupByName(match.captured(1));
        const QString value = match.captured(2);
        changes.insert(property, value);
331 332 333 334 335
    }

    return changes;
}

336 337 338
void ProfileGroup::updateValues()
{
    const PropertyInfo* properties = Profile::DefaultPropertyNames;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
339
    while (properties->name != 0) {
340
        // the profile group does not store a value for some properties
Kurt Hindenburg's avatar
Kurt Hindenburg committed
341
        // (eg. name, path) if even they are equal between profiles -
342 343 344
        //
        // 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
345 346
        if (_profiles.count() > 1 &&
                !canInheritProperty(properties->property)) {
347 348 349 350 351
            properties++;
            continue;
        }

        QVariant value;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
352
        for (int i = 0; i < _profiles.count(); i++) {
353 354
            QVariant profileValue = _profiles[i]->property<QVariant>(properties->property);
            if (value.isNull())
Kurt Hindenburg's avatar
Kurt Hindenburg committed
355 356
                value = profileValue;
            else if (value != profileValue) {
357 358 359
                value = QVariant();
                break;
            }
Kurt Hindenburg's avatar
Kurt Hindenburg committed
360 361
        }
        Profile::setProperty(properties->property, value);
362 363 364 365 366 367 368 369
        properties++;
    }
}
void ProfileGroup::setProperty(Property property, const QVariant& value)
{
    if (_profiles.count() > 1 && !canInheritProperty(property))
        return;

Kurt Hindenburg's avatar
Kurt Hindenburg committed
370
    Profile::setProperty(property, value);
Jekyll Wu's avatar
Jekyll Wu committed
371 372 373
    foreach(Profile::Ptr profile, _profiles) {
        profile->setProperty(property, value);
    }
374 375
}