/***************************************************************************
- * Copyright (C) 2005-07 by the Quassel IRC Team *
+ * Copyright (C) 2005-08 by the Quassel Project *
* devel@quassel-irc.org *
* *
* 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. *
+ * (at your option) version 3. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
+#include <QApplication>
#include "uistyle.h"
+#include "uistylesettings.h"
-UiStyle::UiStyle() {
+UiStyle::UiStyle(const QString &settingsKey) : _settingsKey(settingsKey) {
// Default format
- QTextCharFormat def;
- def.setForeground(QBrush("#000000"));
- def.setFont(QFont("Verdana",9));
-
- _formats = QVector<QTextCharFormat>(NumFormatTypes, def);
+ _defaultPlainFormat.setForeground(QBrush("#000000"));
+ _defaultPlainFormat.setFont(QFont("Monospace", QApplication::font().pointSize()));
+ _defaultPlainFormat.font().setFixedPitch(true);
+ _defaultPlainFormat.font().setStyleHint(QFont::TypeWriter);
+ setFormat(None, _defaultPlainFormat, Settings::Default);
+
+ // Load saved custom formats
+ UiStyleSettings s(_settingsKey);
+ foreach(FormatType type, s.availableFormats()) {
+ _customFormats[type] = s.customFormat(type);
+ }
// Initialize color codes according to mIRC "standard"
QStringList colors;
_formatCodes[QString("%Dcf%1").arg(idx)] = (FormatType)(FgCol00 + i);
_formatCodes[QString("%Dcb%1").arg(idx)] = (FormatType)(BgCol00 + i);
QTextCharFormat fgf, bgf;
- fgf.setForeground(QBrush(QColor(colors[i]))); _formats[FgCol00 + i] = fgf;
- bgf.setBackground(QBrush(QColor(colors[i]))); _formats[BgCol00 + i] = bgf;
+ fgf.setForeground(QBrush(QColor(colors[i]))); setFormat((FormatType)(FgCol00 + i), fgf, Settings::Default);
+ bgf.setBackground(QBrush(QColor(colors[i]))); setFormat((FormatType)(BgCol00 + i), bgf, Settings::Default);
}
// Set a few more standard formats
QTextCharFormat bold; bold.setFontWeight(QFont::Bold);
- setFormat(Bold, bold);
+ setFormat(Bold, bold, Settings::Default);
QTextCharFormat italic; italic.setFontItalic(true);
- setFormat(Italic, italic);
+ setFormat(Italic, italic, Settings::Default);
QTextCharFormat underline; underline.setFontUnderline(true);
- setFormat(Underline, underline);
+ setFormat(Underline, underline, Settings::Default);
// All other formats should be defined in derived classes.
}
}
-void UiStyle::setFormat(FormatType ftype, QTextCharFormat fmt) {
- _formats[ftype] = fmt;
+void UiStyle::setFormat(FormatType ftype, QTextCharFormat fmt, Settings::Mode mode) {
+ if(mode == Settings::Default) {
+ _defaultFormats[ftype] = fmt;
+ } else {
+ UiStyleSettings s(_settingsKey);
+ if(fmt != _defaultFormats[ftype]) {
+ _customFormats[ftype] = fmt;
+ s.setCustomFormat(ftype, fmt);
+ } else {
+ _customFormats[ftype] = QTextFormat().toCharFormat();
+ s.removeCustomFormat(ftype);
+ }
+ }
}
-QTextCharFormat UiStyle::format(FormatType ftype) const {
- return _formats[ftype];
+QTextCharFormat UiStyle::format(FormatType ftype, Settings::Mode mode) const {
+ if(mode == Settings::Custom && _customFormats.contains(ftype)) return _customFormats.value(ftype);
+ else return _defaultFormats.value(ftype, QTextCharFormat());
+}
+
+// NOTE: This function is intimately tied to the values in FormatType. Don't change this
+// until you _really_ know what you do!
+QTextCharFormat UiStyle::mergedFormat(quint32 ftype) {
+ if(_cachedFormats.contains(ftype)) return _cachedFormats[ftype];
+ if(ftype == Invalid) return QTextCharFormat();
+ // Now we construct the merged format, starting with the default
+ QTextCharFormat fmt = format(None);
+ // First: general message format
+ fmt.merge(format((FormatType)(ftype & 0x0f)));
+ // now more specific ones
+ for(quint32 mask = 0x0010; mask <= 0x2000; mask <<= 1) {
+ if(ftype & mask) fmt.merge(format((FormatType)mask));
+ }
+ // color codes!
+ if(ftype & 0x00400000) fmt.merge(format((FormatType)(ftype & 0x0f400000))); // foreground
+ if(ftype & 0x00800000) fmt.merge(format((FormatType)(ftype & 0xf0800000))); // background
+ // URL
+ if(ftype & Url) fmt.merge(format(Url));
+ return fmt;
}
UiStyle::FormatType UiStyle::formatType(const QString & code) const {
return _formatCodes.key(ftype);
}
-UiStyle::StyledText UiStyle::styleString(QString s) {
- StyledText result;
- QList<FormatType> fmtList;
- fmtList.append(None);
- QTextLayout::FormatRange curFmtRng;
- curFmtRng.format = format(None);
- result.formats.append(curFmtRng);
- int pos = 0; int length;
- int fgCol = -1, bgCol = -1; // marks current mIRC color
+// This method expects a well-formatted string, there is no error checking!
+// Since we create those ourselves, we should be pretty safe that nobody does something crappy here.
+UiStyle::StyledString UiStyle::styleString(const QString &s_) {
+ QString s = s_;
+ StyledString result;
+ result.formats.append(qMakePair(0, (quint32)None));
+ quint32 curfmt = (quint32)None;
+ int pos = 0; int length = 0;
for(;;) {
pos = s.indexOf('%', pos);
if(pos < 0) break;
- if(s[pos+1] == '%') { // escaped %, just remove one and continue
+ if(s[pos+1] == '%') { // escaped %, we just remove one and continue
s.remove(pos, 1);
pos++;
continue;
- } else if(s[pos+1] == 'D' && s[pos+2] == 'c') { // color code
- if(s[pos+3] == '-') { // color off
- if(fgCol >= 0) {
- fmtList.removeAll((FormatType)(FgCol00 + fgCol));
- fgCol = -1;
- }
- if(bgCol >= 0) {
- fmtList.removeAll((FormatType)(BgCol00 + bgCol));
- bgCol = -1;
- }
- curFmtRng.format = mergedFormat(fmtList);
+ }
+ if(s[pos+1] == 'D' && s[pos+2] == 'c') { // color code
+ if(s[pos+3] == '-') { // color off
+ curfmt &= 0x003fffff;
length = 4;
} else {
int color = 10 * s[pos+4].digitValue() + s[pos+5].digitValue();
- int *colptr; FormatType coltype;
- if(s[pos+3] == 'f') { // foreground
- colptr = &fgCol; coltype = FgCol00;
- } else { // background
- Q_ASSERT(s[pos+3] == 'b');
- colptr = &bgCol; coltype = BgCol00;
- }
- if(*colptr >= 0) {
- // color already set, remove format code and add new one
- Q_ASSERT(fmtList.contains((FormatType)(coltype + *colptr)));
- fmtList.removeAll((FormatType)(coltype + *colptr));
- fmtList.append((FormatType)(coltype + color));
- curFmtRng.format = mergedFormat(fmtList);
- } else {
- fmtList.append((FormatType)(coltype + color));
- curFmtRng.format.merge(format(fmtList.last()));
- }
- *colptr = color;
+ //TODO: use 99 as transparent color (re mirc color "standard")
+ color &= 0x0f;
+ if(pos+3 == 'f')
+ curfmt |= (color << 24) | 0x00400000;
+ else
+ curfmt |= (color << 28) | 0x00800000;
length = 6;
}
} else if(s[pos+1] == 'O') { // reset formatting
- fmtList.clear(); fmtList.append(None);
- curFmtRng.format = format(None);
- fgCol = bgCol = -1;
- length = 1;
+ curfmt &= 0x0000000f; // we keep message type-specific formatting
+ length = 2;
} else if(s[pos+1] == 'R') { // reverse
// TODO: implement reverse formatting
- length = 1;
+ length = 2;
} else { // all others are toggles
QString code = QString("%") + s[pos+1];
if(s[pos+1] == 'D') code += s[pos+2];
FormatType ftype = formatType(code);
- Q_ASSERT(ftype != Invalid);
- length = code.length();
- if(!fmtList.contains(ftype)) {
- // toggle it on
- fmtList.append(ftype);
- curFmtRng.format.merge(format(ftype));
- } else {
- // toggle it off
- fmtList.removeAll(ftype);
- curFmtRng.format = mergedFormat(fmtList);
+ if(ftype == Invalid) {
+ qWarning(qPrintable(QString("Invalid format code in string: %1").arg(s)));
+ continue;
}
+ curfmt ^= ftype;
+ length = code.length();
}
- s.remove(pos, length); // remove format code from string
- // now see if something changed and else insert the format
- if(curFmtRng.format == result.formats.last().format) continue; // no change, so we just ignore
- curFmtRng.start = pos;
- if(pos == result.formats.last().start) {
- // same starting point -> we just overwrite the old format
- result.formats.last() = curFmtRng;
- } else {
- // fix length of last format
- result.formats.last().length = pos - result.formats.last().start;
- result.formats.append(curFmtRng);
- }
+ s.remove(pos, length);
+ if(pos == result.formats.last().first)
+ result.formats.last().second = curfmt;
+ else
+ result.formats.append(qMakePair(pos, curfmt));
}
- result.formats.last().length = s.length() - result.formats.last().start;
- if(result.formats.last().length == 0) result.formats.removeLast();
result.text = s;
return result;
}
-
-QTextCharFormat UiStyle::mergedFormat(QList<FormatType> formatList) {
- QTextCharFormat fmt;
- foreach(FormatType ftype, formatList) {
- fmt.merge(format(ftype));
- }
- return fmt;
-}
-
-