diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | bd9e6617827818fd043452c08c606f07b78014a0 (patch) | |
tree | 425bb4c3168f9c02f10150f235d2cb998dcc6108 /scheck/scheck.cpp | |
download | tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.tar.gz tdesdk-bd9e6617827818fd043452c08c606f07b78014a0.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdesdk@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'scheck/scheck.cpp')
-rw-r--r-- | scheck/scheck.cpp | 2762 |
1 files changed, 2762 insertions, 0 deletions
diff --git a/scheck/scheck.cpp b/scheck/scheck.cpp new file mode 100644 index 00000000..8915205c --- /dev/null +++ b/scheck/scheck.cpp @@ -0,0 +1,2762 @@ +/* + * $Id$ + * + * KDE3 Style Guide compliance check "Style", v0.0.1 + * Copyright (C) 2002 Maksim Orlovich <orlovich@cs.rochester.edu> + * (C) 2002 Ryan Cumming <ryan@completely.kicks-ass.org> + * + * + * Based on the KDE3 HighColor Style (version 1.0): + * Copyright (C) 2001-2002 Karol Szwed <gallium@kde.org> + * (C) 2001-2002 Fredrik Höglund <fredrik@kde.org> + * + * Drawing routines adapted from the KDE2 HCStyle, + * Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org> + * (C) 2000 Dirk Mueller <mueller@kde.org> + * (C) 2001 Martijn Klingens <klingens@kde.org> + * + * Portions of code are from the Qt GUI Toolkit, Copyright (C) 1992-2003 Trolltech AS. + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + */ + +#include <stdlib.h> + +#include <qdict.h> +#include <qdrawutil.h> +#include <qpainter.h> +#include <qpointarray.h> +#include <qstyleplugin.h> +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qfontmetrics.h> +#include <qgroupbox.h> +#include <qheader.h> +#include <qlabel.h> +#include <qmenubar.h> +#include <qobjectlist.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qregexp.h> +#include <qscrollbar.h> +#include <qslider.h> +#include <qstylesheet.h> +#include <qtabbar.h> +#include <qtimer.h> +#include <qtoolbutton.h> +#include <qtoolbar.h> +#include <qpopupmenu.h> +#include <qwidgetlist.h> + +#include <kdrawutil.h> +#include <kaccelmanager.h> +#include <kpixmapeffect.h> +#include <kapplication.h> +#include <kaboutdata.h> + +#include "scheck.h" +#include "scheck.moc" +#include "bitmaps.h" + +// -- Style Plugin Interface ------------------------- +class StyleCheckStylePlugin : public QStylePlugin +{ + public: + StyleCheckStylePlugin() {} + ~StyleCheckStylePlugin() {} + + QStringList keys() const + { + return QStringList() << "Check"; + } + + QStyle* create( const QString& key ) + { + if ( key == "check" ) + return new StyleCheckStyle( ); + + + return 0; + } +}; + +KDE_Q_EXPORT_PLUGIN( StyleCheckStylePlugin ) +// --------------------------------------------------- + + +// ### Remove globals +static QBitmap lightBmp; +static QBitmap grayBmp; +static QBitmap dgrayBmp; +static QBitmap centerBmp; +static QBitmap maskBmp; +static QBitmap xBmp; + +static const int itemFrame = 1; +static const int itemHMargin = 3; +static const int itemVMargin = 0; +static const int arrowHMargin = 6; +static const int rightBorder = 12; + +// --------------------------------------------------------------------------- + +#include <qvaluevector.h> + +enum ColonMode +{ + ColonlessWidget = 0, + BuddiedWidget = 1, + BuddylessWidget = 2 +}; + +enum AccelMode +{ + NoAccels = 0, + HasAccels = 1 +}; + +enum TitleType +{ + ShortTitle = 0, + LongTitle = 1 +}; + +namespace +{ + + class StyleGuideViolation + { + private: + int m_position; + int m_severity; // 0 = error 1 = warning + public: + enum Severity + { + Error = 0, + Warning = 1, + AccelConflict = 2, + AccelSuggestion = 3, + Untranslated = 4 + }; + + StyleGuideViolation() {} + StyleGuideViolation(int _position, int _severity = Error): m_position(_position), m_severity(_severity) + {} + + operator int() const + { + return m_position; + } + + int position() const + { + return m_position; + } + + int severity() const + { + return m_severity; + } + }; + + class LowerCaseWords + { + private: + static QDict<bool>* m_words; + public: + static QDict<bool>* words() + { + if (!m_words) + { + m_words = new QDict<bool>; + // Prepositions under five letters, except from & under + m_words->insert( "for", (bool*)1); + m_words->insert( "in", (bool*)1); + m_words->insert( "with", (bool*)1); + m_words->insert( "to", (bool*)1); + m_words->insert( "of", (bool*)1); + m_words->insert( "on", (bool*)1); + m_words->insert( "at", (bool*)1); + m_words->insert( "by", (bool*)1); + m_words->insert( "into", (bool*)1); + m_words->insert( "per", (bool*)1); + m_words->insert( "vs", (bool*)1); + + // Conjunctions + m_words->insert( "and", (bool*)1); + m_words->insert( "or", (bool*)1); + m_words->insert( "nor", (bool*)1); + m_words->insert( "but", (bool*)1); + m_words->insert( "if", (bool*)1); + + // Articles + m_words->insert( "the", (bool*)1); + m_words->insert( "a", (bool*)1); + m_words->insert( "as", (bool*)1); + m_words->insert( "an", (bool*)1); + + // Misc + m_words->insert( "http", (bool*)1); + } + return m_words; + } + }; + + QDict<bool>* LowerCaseWords::m_words = 0; + + class ExplicitCaseWords + { + private: + static QDict<const char>* m_words; + public: + static QDict<const char>* words() + { + if (!m_words) + { + // Store the words like this: + // "lowercase", "CorrectCase" + m_words = new QDict<const char>(61); + // week day names + m_words->insert( "monday", "Monday"); + m_words->insert( "tuesday", "Tuesday"); + m_words->insert( "wednesday", "Wednesday"); + m_words->insert( "thursday", "Thursday"); + m_words->insert( "friday", "Friday"); + m_words->insert( "saturday", "Saturday"); + m_words->insert( "sunday", "Sunday"); + + // month names + m_words->insert( "january", "January"); + m_words->insert( "february", "February"); + m_words->insert( "march", "March"); + m_words->insert( "april", "April"); + m_words->insert( "may", "May"); + m_words->insert( "june", "June"); + m_words->insert( "july", "July"); + m_words->insert( "august", "August"); + m_words->insert( "september", "September"); + m_words->insert( "october", "October"); + m_words->insert( "november", "November"); + m_words->insert( "december", "December"); + + // displayed KDE names not matched by acronym algorithm + m_words->insert( "konqueror", "Konqueror"); + m_words->insert( "kicker", "Kicker"); + m_words->insert( "kopete", "Kopete"); + m_words->insert( "kate", "Kate"); + m_words->insert( "konsole", "Konsole"); + m_words->insert( "kontour", "Kontour"); + m_words->insert( "kiten", "Kiten"); + m_words->insert( "kooka", "Kooka"); + m_words->insert( "noatun", "Noatun"); + + // computer + m_words->insert( "ctrl", "Ctrl"); + m_words->insert( "java", "Java"); + m_words->insert( "javascript", "JavaScript"); + m_words->insert( "qt", "Qt"); + m_words->insert( "doxygen", "Doxygen"); + m_words->insert( "linux", "Linux"); + m_words->insert( "unix", "UNIX"); + m_words->insert( "internet", "Internet"); + m_words->insert( "web", "Web"); + m_words->insert( "motif", "Motif"); + m_words->insert( "x11", "X11"); + m_words->insert( "socks", "SOCKS"); + m_words->insert( "xing", "Xing"); + m_words->insert( "yamaha", "Yamaha"); + m_words->insert( "hz", "Hz"); + m_words->insert( "khz", "KHz"); + m_words->insert( "mhz", "MHz"); + m_words->insert( "macos", "MacOS"); + m_words->insert( "microsoft", "Microsoft"); + m_words->insert( "adobe", "Adobe"); + m_words->insert( "postscript", "PostScript"); + m_words->insert( "ghostscript", "Ghostscript"); + m_words->insert( "vcard", "vCard"); + m_words->insert( "midi", "MIDI"); + m_words->insert( "isdn", "ISDN"); + m_words->insert( "cd-rom", "CD-ROM"); + } + return m_words; + } + }; + + QDict<const char>* ExplicitCaseWords::m_words = 0; +} + +static bool xxMode; + +static QColor severityColor(int severity) +{ + if (severity == StyleGuideViolation::Error) + { + return Qt::red; + } + else if (severity == StyleGuideViolation::AccelConflict) + { + return QColor(255, 128, 0); + } + else if (severity == StyleGuideViolation::AccelSuggestion) + { + return Qt::green; + } + else if (severity == StyleGuideViolation::Untranslated) + { + return QColor(255, 0, 255); + } + else + { + return Qt::yellow; + } +} + +// Removes '&' style accelerators from text strings +static void removeAccelerators(QString &str) +{ + for (unsigned int p = 0; p < str.length(); p++) + { + if (str[p] == '&') + { + str = str.mid(0, p) + str.mid(p+1); + // Skip the next letter, as && mean a literal "&" + p++; + } + } +} + + +static void removeXX(QString &str) +{ + str.replace("xx",""); // simple but atm best working +} + +static QString removedXX(QString str) +{ + if (xxMode) + removeXX(str); + return str; +} + +static QString stripAccelViolations(QString str) +{ + int conflict_pos = str.find("(&&)"); + if (conflict_pos >= 0) + { + str = str.mid(0, conflict_pos) + str.mid(conflict_pos+4); + } + + int suggestion_pos = str.find("(!)"); + if (suggestion_pos >= 0) + { + str = str.mid(0, suggestion_pos) + str.mid(suggestion_pos+3); + } + + return str; +} + +// Must be passed a string with its accelerators removed +QString findAccelViolations(QString str, QValueVector<StyleGuideViolation> &violations) +{ + int conflict_pos = str.find("(&)"); + + if (conflict_pos >= 0) + str = str.mid(0, conflict_pos) + str.mid(conflict_pos+3); + + int suggestion_pos = str.find("(!)"); + if (suggestion_pos >= 0) + { + str = str.mid(0, suggestion_pos) + str.mid(suggestion_pos+3); + violations.push_back(StyleGuideViolation(suggestion_pos, StyleGuideViolation::AccelSuggestion)); + + // Conditionally "relocate" the conflict + if (conflict_pos >= suggestion_pos) + { + conflict_pos -= 3; + } + } + + if (conflict_pos >= 0) + violations.push_back(StyleGuideViolation(conflict_pos, StyleGuideViolation::AccelConflict)); + + return str; +} + +QString findUntranslatedViolations(QString str, QValueVector<StyleGuideViolation> &violations) +{ + if (str.find("xx")!=-1) + removeXX(str); + else { + for (unsigned int c=0; c<str.length(); c++) + violations.push_back(StyleGuideViolation(c, StyleGuideViolation::Untranslated)); + } + + return str; +} + +static QValueVector<StyleGuideViolation> checkSentenceStyle(QString str, ColonMode mode = ColonlessWidget, AccelMode accelMode = HasAccels) +{ + QValueVector<StyleGuideViolation> violations; + bool afterWhiteSpace = true; + bool firstChar = true; + bool inQuote = false; + + if (xxMode) + str = findUntranslatedViolations(str, violations); + + if (accelMode == HasAccels) + { + // We care not for accelerators while parsing for capitialization + removeAccelerators(str); + str = findAccelViolations(str, violations); + } + + for (unsigned int c=0; c<str.length(); c++) + { + // Don't parse within quotes + if (inQuote) + { + if (str[c] == '\"') + { + // The quote is over, return to normal operation + inQuote = false; + afterWhiteSpace = false; + continue; + } + } + else if (str[c].isSpace()) + { + if (afterWhiteSpace) + { + // Discourage multiple spaces + violations.push_back(c); + } + + afterWhiteSpace = true; + } + else if (str[c] == '\"') + { + // Beginning of a quote + // This disables parsing until the next quotation mark is found + inQuote = true; + afterWhiteSpace = false; + firstChar = false; + } + else if ((str[c] == '.') || (str[c] == ':') || (str[c] == ';') || (str[c] == '?') || (str[c] == '!') || (str[c] == ',')) + { + // Is this a new sentence? + if ((str[c] == '.') || (str[c] == '?') || (str[c] == '!')) + { + // Periods not followed by whitespace are probably + // separators in IP addresses or URLs, and they don't + // need any more false positives than they already + // have ;) + if (((c + 1) < str.length()) && (str[c + 1].isSpace())) + { + // We're a new sentence + firstChar = true; + } + } + + if (afterWhiteSpace && c) + { + // Tsk tsk, we shouldn't have punctuation after whitespace + violations.push_back(c - 1); + } + + afterWhiteSpace = false; + } + else + { + if (afterWhiteSpace) //We don't check for fOO and things like that, just first letters.. + { + // Try to extract the whole word.. + QString word = QString::null; + for (unsigned int l = c+1; l<str.length(); l++) + { + if (!str[l].isLetter() && !str[l].isNumber() && str[l] != '&' && str[l] != '-') + { + word = str.mid(c, l - c); + break; + } + } + + if (word.isNull()) //Looks like goes to end of string.. + { + word = str.mid ( c ); + } + + // Check if it's in the explicit case word list + const char *correctWord = ExplicitCaseWords::words()->find(word.lower()); + + // Actual captialization checking + if (correctWord) + { + // We have been told explictly how to capitalize this word + // This overides the next checks + for (unsigned int x = 0;x < word.length();x++) + { + if (word[x] != correctWord[x]) + { + violations.push_back(c + x); + } + } + } + else if (str[c].category() == QChar::Letter_Lowercase) //Lowercase character.. + { + if (firstChar) + violations.push_back(c); + } + else if (str[c].category() == QChar::Letter_Uppercase) + { + if (!firstChar) //A possible violation -- can be a proper name.. + { + //Check whether more capitalized words in here.. To guess acronyms. + bool acronym = false; + for (unsigned int d = c+1; d < str.length(); d++) + { + if (str[d].isSpace() ) + break; + if (str[d].category() == QChar::Letter_Uppercase) + { + acronym = true; + break; + } + } + if (!acronym) + violations.push_back(c); + } + } + } + firstChar = false; + afterWhiteSpace = false; + } + } + + bool endWithColon = false; + int colonIndex = -1; + + for (int c = str.length() - 1; c>=0; c--) + { + if (str[c] == ':') + { + endWithColon = true; + colonIndex = c; + break; + } + if (!str[c].isSpace()) + break; + } + + if ( mode == ColonlessWidget && endWithColon) //Sometimes checkbox is also a label.. So we'll make a colon a warning + { + violations.push_back(StyleGuideViolation(colonIndex,StyleGuideViolation::Warning)); + } + + if (mode == BuddiedWidget && !endWithColon) //We have a buddy but lack a colon --> wrong + { + violations.push_back(-1); + } + + if (mode == BuddylessWidget && endWithColon) //We have no buddy but we do have a colon -- potential error + { + violations.push_back(StyleGuideViolation(colonIndex,StyleGuideViolation::Warning)); + } + + return violations; +} + +static QValueVector<StyleGuideViolation> checkTitleStyle(QString str, TitleType titleType = ShortTitle, AccelMode accelMode = NoAccels) +{ + QValueVector<StyleGuideViolation> violations; + bool afterWhiteSpace = true; + + if (xxMode) + str = findUntranslatedViolations(str, violations); + + if (accelMode == HasAccels) + { + // We care not for accelerators while parsing for capitialization + removeAccelerators(str); + str = findAccelViolations(str, violations); + } + + for (unsigned int c=0; c<str.length(); c++) + { + if (str[c].isSpace()) + { + if (afterWhiteSpace) + { + // Discourage multiple spaces + violations.push_back(c); + } + + afterWhiteSpace = true; + } + else if ((str[c] == '.') || (str[c] == ';') || (str[c] == '?') || (str[c] == '!')) + { + // '!' Is used for marking conficting accels + if ((accelMode = HasAccels) && (str[c] == '!')) + { + afterWhiteSpace = false; + continue; + } + + // Periods/colons not followed by whitespace are probably + // separators in IP addresses or URLs, and they don't + // need any more false positives than they already + // have ;) + + // Check for multiple sentences + if (((c + 1) < str.length()) && (str[c + 1].isSpace())) + { + violations.push_back(c); + continue; + } + + // Check for sentence punctuation at the end of a string, + // being sure not to tag ellipses + if ((c == str.length() - 1) && (str.right(3) != "...")) + violations.push_back(c); + } + else + { + if (c==str.length()-1 && str[c] == ':') + { + violations.push_back(c); + continue; + } + if (afterWhiteSpace) //We don't check for fOO and things like that, just first letters.. + { + bool lastWord = false; + + //Now, try to extract the whole word.. + QString word = QString::null; + for (unsigned int l = c+1; l<str.length(); l++) + { + if (!str[l].isLetter() && !str[l].isNumber() && str[l] != '&' && str[l] != '-') + { + word = str.mid(c, l - c); + if (str.mid(l)=="...") + lastWord=true; + break; + } + } + + if (word.isNull()) //Looks like goes to end of string.. + { + word = str.mid ( c ); + lastWord = true; + } + + QString lower_word = word.lower(); + + // Check if it's in the explicit case word list + const char *correctWord = ExplicitCaseWords::words()->find(lower_word); + + if ((titleType == ShortTitle) && (lower_word=="and" || lower_word=="a" || lower_word=="an" || lower_word=="the")) + { + // This words are 'red flagged' for short titles + for (unsigned int i = 0;i < word.length();i++) + violations.push_back(StyleGuideViolation(c + i,StyleGuideViolation::Warning)); + } + + if (correctWord) + { + // We're an uppercase word, and may have an unusual + // capitalization (ie, JavaScript) + for (unsigned int x = 0;x < word.length();x++) + { + if (word[x] != correctWord[x]) + violations.push_back(c + x); + } + } + else if (c && !lastWord && LowerCaseWords::words()->find(word.lower())) + { + // We're a lowercase word + if (str[c].category() == QChar::Letter_Uppercase) + violations.push_back(c); + } + else + { + if (str[c].category() == QChar::Letter_Lowercase) + violations.push_back(c); + } + } + + afterWhiteSpace = false; + } + } + + return violations; +} + + +static void renderViolations(const QValueVector<StyleGuideViolation>& violations, QPainter* p, QRect r, int flags, QString text) +{ + + if (xxMode) + removeXX(text); + + if (violations.size()>0) + { + p->save(); + QFontMetrics qfm = p->fontMetrics (); + + QString parStr = text; + int len = text.length(); + + /***** + Begin code snipped from QPainter, somewhat modified + */ + + + // str.setLength() always does a deep copy, so the replacement code below is safe. + parStr.setLength( len ); + // compatible behaviour to the old implementation. Replace tabs by spaces + QChar *chr = (QChar*)parStr.unicode(); + int l = len; + while ( l-- ) + { + if ( *chr == '\t' || *chr == '\r' || *chr == '\n' ) + *chr = ' '; + chr++; + } + + + if ( flags & Qt::ShowPrefix ) + { + parStr = removedXX(stripAccelViolations(parStr)); + removeAccelerators(parStr); + } + + int w = qfm.width( parStr ); + int h = qfm.height(); + + int xoff = r.x(); + int yoff = r.y() + qfm.ascent(); + + if ( flags & Qt::AlignBottom ) + yoff += r.height() - h; + else if ( flags & Qt::AlignVCenter ) + yoff += ( r.height() - h ) / 2; + if ( flags & Qt::AlignRight ) + xoff += r.width() - w; + else if ( flags & Qt::AlignHCenter ) + xoff += ( r.width() - w ) / 2; + + + + /***** + end code snipped from QPainter... + */ + + int yt = yoff - h; + int yb = yoff;; + + + QRect bnd(xoff, yoff - h, w, h); + + for (unsigned int v = 0; v < violations.size(); v++) + { + if (violations[v] != -1) + { + int left = bnd.left() + + qfm.width(parStr, violations[v]) - 1; + + + int right = bnd.left() + + qfm.width(parStr, violations[v] + 1) - 1; + + + //int right = r.x() + qfm.width(text, violations[v]+1); + //int left = r.x() + qfm.width(text, violations[v]); + + p->fillRect( left, yt, right - left + 1, yb - yt + 1, severityColor(violations[v].severity()) ); + } + else + { + int right = bnd.right(); + + int centerX = right - 1; + int leftX = centerX-h/4; + int rightX = centerX + h/4; + p->setPen(severityColor(violations[v].severity())); + p->drawLine ( leftX, yt + 1, rightX, yt + 1 ); + p->drawLine ( leftX, yt + h/2, rightX, yt + h/2 + 1); + p->drawLine ( leftX, yt+ 1, leftX, yt + h/2 + 1); + p->drawLine ( rightX, yt+ 1, rightX, yt + h/2 + 1); + + p->drawLine ( leftX, yb - h/2, rightX, yb - h/2); + p->drawLine ( leftX, yb, rightX, yb); + p->drawLine ( leftX, yb - h/2, leftX, yb); + p->drawLine ( rightX, yb - h/2, rightX, yb); + } + } + p->restore(); + } +} + +StyleCheckTitleWatcher::StyleCheckTitleWatcher() +{ + QTimer* checkTimer = new QTimer(this); + connect( checkTimer, SIGNAL(timeout()), this, SLOT(slotCheck()) ); + checkTimer->start(1000); +} + + +void StyleCheckTitleWatcher::addWatched(QWidget* w) +{ + watched.push_back(w); + watchedTitles.push_back(w->caption()); +} + +QString StyleCheckTitleWatcher::cleanErrorMarkers(QString in) +{ + //We add # to denote an error...So now remove it.. It helps us check whether it's the same caption as before.. + QString out = ""; + for (unsigned int c = 0; c < in.length(); c++) + { + if (in[c] != '|') + out += in[c]; + } + + return out; +} + +void StyleCheckTitleWatcher::slotCheck() +{ + for (unsigned int c=0; c<watched.size(); c++) + { + if (!watched[c].isNull() ) + { + + QString cleaned = cleanErrorMarkers(watched[c]->caption()); + if (cleaned != watchedTitles[c]) + { + watchedTitles[c] = watched[c]->caption(); + QValueVector<StyleGuideViolation> violations = checkTitleStyle(watched[c]->caption(), LongTitle, NoAccels); + if (violations.size() == 0) + continue; + + QString out = ""; + QString in = watched[c]->caption(); + int prev = -1; + for (unsigned int v = 0; v < violations.size(); v++) + { + out += in.mid(prev + 1, violations[v] - prev - 1); //Add interval that followed last one.. + out += '|'; + out += in[violations[v]]; + out += '|'; + prev = violations[v]; + } + + out += in.mid(prev + 1); //Add the tail.. + + watched[c]->setCaption(out); + } //If changed. + } //If not null.. + } //for all watched +} + + +StyleCheckStyle::StyleCheckStyle( ) + : KStyle( 0 , ThreeButtonScrollBar ) +{ + hoverWidget = 0L; + topLevelAccelManageTimer = new QTimer(this); + connect(topLevelAccelManageTimer, SIGNAL(timeout()), this, SLOT(slotAccelManage())); + watcher = new StyleCheckTitleWatcher; + xxMode = (QString(getenv("KDE_LANG"))=="xx"); +} + + +StyleCheckStyle::~StyleCheckStyle() +{ + delete watcher; +} + +//We walk down the widget tree until we find something we render, and sic KAccelManager in programmer's mode on those +void StyleCheckStyle::accelManageRecursive(QWidget* widget) +{ + if (&widget->style() == this) + { + KAcceleratorManager::manage(widget, true); + return; + } + + const QObjectList* children = widget->children(); + if (!children) + return; + QObjectListIterator iter(*children); + + QObject* walk; + while ((walk = iter.current())) + { + if (walk->isWidgetType()) + accelManageRecursive(static_cast<QWidget*>(walk)); + ++iter; + } +} + + +void StyleCheckStyle::slotAccelManage() +{ + //Walk through top-levels + QWidgetList* topLevels = QApplication::topLevelWidgets(); + if (!topLevels) + return; + + QWidgetListIt iter(*topLevels); + + QWidget* walk; + while ((walk = iter.current())) + { + accelManageRecursive(walk); + ++iter; + } + +} + + +void StyleCheckStyle::polish(QWidget* widget) +{ + /* Having a global view on the widget makes accel + easier to catch. However, just intruding on the main window + is wrong since a style can be used for a subwindow. The upshot is that we defer + accel management to a timer, until things stabilize, and then walk from top-levels down + */ + topLevelAccelManageTimer->start(200, true); + // + + // Put in order of highest occurance to maximise hit rate + if (widget->inherits("QPushButton")) { + widget->installEventFilter(this); + } + + if (widget->inherits("QLabel")) + { + widget->installEventFilter(this); + } + + if (widget->inherits("QGroupBox")) + { + widget->installEventFilter(this); + } + + if (widget->inherits("QMainWindow") || widget->inherits("QDialog" ) ) + { + watcher->addWatched(widget); + } + + KStyle::polish( widget ); +} + + +void StyleCheckStyle::unPolish(QWidget* widget) +{ + if (widget->inherits("QPushButton")) { + widget->removeEventFilter(this); + } + + if (widget->inherits("QLabel")) + { + widget->removeEventFilter(this); + } + + if (widget->inherits("QGroupBox")) + { + widget->removeEventFilter(this); + } + + + + KStyle::unPolish( widget ); +} + + + +// This function draws primitive elements as well as their masks. +void StyleCheckStyle::drawPrimitive( PrimitiveElement pe, + QPainter *p, + const QRect &r, + const QColorGroup &cg, + SFlags flags, + const QStyleOption& opt ) const +{ + bool down = flags & Style_Down; + bool on = flags & Style_On; + + switch(pe) + { + // BUTTONS + // ------------------------------------------------------------------- + case PE_ButtonDefault: { + int x1, y1, x2, y2; + r.coords( &x1, &y1, &x2, &y2 ); + + // Button default indicator + p->setPen( cg.shadow() ); + p->drawLine( x1+1, y1, x2-1, y1 ); + p->drawLine( x1, y1+1, x1, y2-1 ); + p->drawLine( x1+1, y2, x2-1, y2 ); + p->drawLine( x2, y1+1, x2, y2-1 ); + break; + } + + case PE_ButtonDropDown: + case PE_ButtonTool: { + bool sunken = on || down; + int x,y,w,h; + r.rect(&x, &y, &w, &h); + int x2 = x+w-1; + int y2 = y+h-1; + QPen oldPen = p->pen(); + + // Outer frame (round style) + p->setPen(cg.shadow()); + p->drawLine(x+1,y,x2-1,y); + p->drawLine(x,y+1,x,y2-1); + p->drawLine(x+1,y2,x2-1,y2); + p->drawLine(x2,y+1,x2,y2-1); + + // Bevel + p->setPen(sunken ? cg.mid() : cg.light()); + p->drawLine(x+1, y+1, x2-1, y+1); + p->drawLine(x+1, y+1, x+1, y2-1); + p->setPen(sunken ? cg.light() : cg.mid()); + p->drawLine(x+2, y2-1, x2-1, y2-1); + p->drawLine(x2-1, y+2, x2-1, y2-1); + + p->fillRect(x+2, y+2, w-4, h-4, cg.button()); + + p->setPen( oldPen ); + break; + } + + // PUSH BUTTON + // ------------------------------------------------------------------- + case PE_ButtonCommand: { + bool sunken = on || down; + int x, y, w, h; + r.rect(&x, &y, &w, &h); + + if ( sunken ) + kDrawBeButton( p, x, y, w, h, cg, true, + &cg.brush(QColorGroup::Mid) ); + + else if ( flags & Style_MouseOver ) { + QBrush brush(cg.button().light(110)); + kDrawBeButton( p, x, y, w, h, cg, false, &brush ); + } + + // "Flat" button + else if (!(flags & (Style_Raised | Style_Sunken))) + p->fillRect(r, cg.button()); + + else + kDrawBeButton(p, x, y, w, h, cg, false, + &cg.brush(QColorGroup::Button)); + break; + } + + + // BEVELS + // ------------------------------------------------------------------- + case PE_ButtonBevel: { + int x,y,w,h; + r.rect(&x, &y, &w, &h); + bool sunken = on || down; + int x2 = x+w-1; + int y2 = y+h-1; + + // Outer frame + p->setPen(cg.shadow()); + p->drawRect(r); + + // Bevel + p->setPen(sunken ? cg.mid() : cg.light()); + p->drawLine(x+1, y+1, x2-1, y+1); + p->drawLine(x+1, y+1, x+1, y2-1); + p->setPen(sunken ? cg.light() : cg.mid()); + p->drawLine(x+2, y2-1, x2-1, y2-1); + p->drawLine(x2-1, y+2, x2-1, y2-1); + + if (w > 4 && h > 4) { + if (sunken) + p->fillRect(x+2, y+2, w-4, h-4, cg.button()); + else + renderGradient( p, QRect(x+2, y+2, w-4, h-4), + cg.button(), flags & Style_Horizontal ); + } + break; + } + + + // FOCUS RECT + // ------------------------------------------------------------------- + case PE_FocusRect: { + p->drawWinFocusRect( r ); + break; + } + + + // HEADER SECTION + // ------------------------------------------------------------------- + case PE_HeaderSection: { + // Temporary solution for the proper orientation of gradients. + bool horizontal = true; + if (p && p->device()->devType() == QInternal::Widget) { + QHeader* hdr = dynamic_cast<QHeader*>(p->device()); + if (hdr) + horizontal = hdr->orientation() == Horizontal; + } + + int x,y,w,h; + r.rect(&x, &y, &w, &h); + bool sunken = on || down; + int x2 = x+w-1; + int y2 = y+h-1; + QPen oldPen = p->pen(); + + // Bevel + p->setPen(sunken ? cg.mid() : cg.light()); + p->drawLine(x, y, x2-1, y); + p->drawLine(x, y, x, y2-1); + p->setPen(sunken ? cg.light() : cg.mid()); + p->drawLine(x+1, y2-1, x2-1, y2-1); + p->drawLine(x2-1, y+1, x2-1, y2-1); + p->setPen(cg.shadow()); + p->drawLine(x, y2, x2, y2); + p->drawLine(x2, y, x2, y2); + + if (sunken) + p->fillRect(x+1, y+1, w-3, h-3, cg.button()); + else + renderGradient( p, QRect(x+1, y+1, w-3, h-3), + cg.button(), !horizontal ); + p->setPen( oldPen ); + break; + } + + + // SCROLLBAR + // ------------------------------------------------------------------- + case PE_ScrollBarSlider: { + // Small hack to ensure scrollbar gradients are drawn the right way. + flags ^= Style_Horizontal; + + drawPrimitive(PE_ButtonBevel, p, r, cg, flags | Style_Enabled | Style_Raised); + + // Draw a scrollbar riffle (note direction after above changes) + // HighColor & Default scrollbar + if (flags & Style_Horizontal) { + if (r.height() >= 15) { + int x = r.x()+3; + int y = r.y() + (r.height()-7)/2; + int x2 = r.right()-3; + p->setPen(cg.light()); + p->drawLine(x, y, x2, y); + p->drawLine(x, y+3, x2, y+3); + p->drawLine(x, y+6, x2, y+6); + + p->setPen(cg.mid()); + p->drawLine(x, y+1, x2, y+1); + p->drawLine(x, y+4, x2, y+4); + p->drawLine(x, y+7, x2, y+7); + } + } else { + if (r.width() >= 15) { + int y = r.y()+3; + int x = r.x() + (r.width()-7)/2; + int y2 = r.bottom()-3; + p->setPen(cg.light()); + p->drawLine(x, y, x, y2); + p->drawLine(x+3, y, x+3, y2); + p->drawLine(x+6, y, x+6, y2); + + p->setPen(cg.mid()); + p->drawLine(x+1, y, x+1, y2); + p->drawLine(x+4, y, x+4, y2); + p->drawLine(x+7, y, x+7, y2); + } + } + break; + } + + + case PE_ScrollBarAddPage: + case PE_ScrollBarSubPage: { + int x, y, w, h; + r.rect(&x, &y, &w, &h); + int x2 = x+w-1; + int y2 = y+h-1; + + p->setPen(cg.shadow()); + + if (flags & Style_Horizontal) { + p->drawLine(x, y, x2, y); + p->drawLine(x, y2, x2, y2); + renderGradient(p, QRect(x, y+1, w, h-2), + cg.mid(), false); + } else { + p->drawLine(x, y, x, y2); + p->drawLine(x2, y, x2, y2); + renderGradient(p, QRect(x+1, y, w-2, h), + cg.mid(), true); + } + break; + } + + + case PE_ScrollBarAddLine: { + drawPrimitive( PE_ButtonBevel, p, r, cg, (flags & Style_Enabled) | + ((flags & Style_Down) ? Style_Down : Style_Raised) ); + + drawPrimitive( ((flags & Style_Horizontal) ? PE_ArrowRight : PE_ArrowDown), + p, r, cg, flags ); + break; + } + + + case PE_ScrollBarSubLine: { + drawPrimitive( PE_ButtonBevel, p, r, cg, (flags & Style_Enabled) | + ((flags & Style_Down) ? Style_Down : Style_Raised) ); + + drawPrimitive( ((flags & Style_Horizontal) ? PE_ArrowLeft : PE_ArrowUp), + p, r, cg, flags ); + break; + } + + + // CHECKBOX (indicator) + // ------------------------------------------------------------------- + case PE_Indicator: { + + bool enabled = flags & Style_Enabled; + bool nochange = flags & Style_NoChange; + + if (xBmp.isNull()) { + xBmp = QBitmap(7, 7, x_bits, true); + xBmp.setMask(xBmp); + } + + int x,y,w,h; + x=r.x(); y=r.y(); w=r.width(); h=r.height(); + int x2 = x+w-1; + int y2 = y+h-1; + + p->setPen(cg.mid()); + p->drawLine(x, y, x2, y); + p->drawLine(x, y, x, y2); + + p->setPen(cg.light()); + p->drawLine(x2, y+1, x2, y2); + p->drawLine(x+1, y2, x2, y2); + + p->setPen(cg.shadow()); + p->drawLine(x+1, y+1, x2-1, y+1); + p->drawLine(x+1, y+1, x+1, y2-1); + + p->setPen(cg.midlight()); + p->drawLine(x2-1, y+2, x2-1, y2-1); + p->drawLine(x+2, y2-1, x2-1, y2-1); + + if ( enabled ) + p->fillRect(x+2, y+2, w-4, h-4, + down ? cg.button(): cg.base()); + else + p->fillRect(x+2, y+2, w-4, h-4, cg.background()); + + if (!(flags & Style_Off)) { + if (on) { + p->setPen(nochange ? cg.dark() : cg.text()); + p->drawPixmap(x+3, y+3, xBmp); + } + else { + p->setPen(cg.shadow()); + p->drawRect(x+2, y+2, w-4, h-4); + p->setPen(nochange ? cg.text() : cg.dark()); + p->drawLine(x+3, (y+h)/2-2, x+w-4, (y+h)/2-2); + p->drawLine(x+3, (y+h)/2, x+w-4, (y+h)/2); + p->drawLine(x+3, (y+h)/2+2, x+w-4, (y+h)/2+2); + } + } + break; + } + + + // RADIOBUTTON (exclusive indicator) + // ------------------------------------------------------------------- + case PE_ExclusiveIndicator: { + + if (lightBmp.isNull()) { + lightBmp = QBitmap(13, 13, radiooff_light_bits, true); + grayBmp = QBitmap(13, 13, radiooff_gray_bits, true); + dgrayBmp = QBitmap(13, 13, radiooff_dgray_bits, true); + centerBmp = QBitmap(13, 13, radiooff_center_bits, true); + centerBmp.setMask( centerBmp ); + } + + // Bevel + kColorBitmaps(p, cg, r.x(), r.y(), &lightBmp , &grayBmp, + NULL, &dgrayBmp); + + // The center fill of the indicator (grayed out when disabled) + if ( flags & Style_Enabled ) + p->setPen( down ? cg.button() : cg.base() ); + else + p->setPen( cg.background() ); + p->drawPixmap( r.x(), r.y(), centerBmp ); + + // Indicator "dot" + if ( on ) { + QColor color = flags & Style_NoChange ? + cg.dark() : cg.text(); + + p->setPen(color); + p->drawLine(5, 4, 7, 4); + p->drawLine(4, 5, 4, 7); + p->drawLine(5, 8, 7, 8); + p->drawLine(8, 5, 8, 7); + p->fillRect(5, 5, 3, 3, color); + } + + break; + } + + + // RADIOBUTTON (exclusive indicator) mask + // ------------------------------------------------------------------- + case PE_ExclusiveIndicatorMask: { + if (maskBmp.isNull()) { + maskBmp = QBitmap(13, 13, radiomask_bits, true); + maskBmp.setMask(maskBmp); + } + + p->setPen(Qt::color1); + p->drawPixmap(r.x(), r.y(), maskBmp); + break; + } + + + // SPLITTER/DOCKWINDOW HANDLES + // ------------------------------------------------------------------- + case PE_DockWindowResizeHandle: + case PE_Splitter: { + int x,y,w,h; + r.rect(&x, &y, &w, &h); + int x2 = x+w-1; + int y2 = y+h-1; + + p->setPen(cg.dark()); + p->drawRect(x, y, w, h); + p->setPen(cg.background()); + p->drawPoint(x, y); + p->drawPoint(x2, y); + p->drawPoint(x, y2); + p->drawPoint(x2, y2); + p->setPen(cg.light()); + p->drawLine(x+1, y+1, x+1, y2-1); + p->drawLine(x+1, y+1, x2-1, y+1); + p->setPen(cg.midlight()); + p->drawLine(x+2, y+2, x+2, y2-2); + p->drawLine(x+2, y+2, x2-2, y+2); + p->setPen(cg.mid()); + p->drawLine(x2-1, y+1, x2-1, y2-1); + p->drawLine(x+1, y2-1, x2-1, y2-1); + p->fillRect(x+3, y+3, w-5, h-5, cg.brush(QColorGroup::Background)); + break; + } + + + // GENERAL PANELS + // ------------------------------------------------------------------- + case PE_Panel: + case PE_PanelPopup: + case PE_WindowFrame: + case PE_PanelLineEdit: { + bool sunken = flags & Style_Sunken; + int lw = opt.isDefault() ? pixelMetric(PM_DefaultFrameWidth) + : opt.lineWidth(); + if (lw == 2) + { + QPen oldPen = p->pen(); + int x,y,w,h; + r.rect(&x, &y, &w, &h); + int x2 = x+w-1; + int y2 = y+h-1; + p->setPen(sunken ? cg.light() : cg.dark()); + p->drawLine(x, y2, x2, y2); + p->drawLine(x2, y, x2, y2); + p->setPen(sunken ? cg.mid() : cg.light()); + p->drawLine(x, y, x2, y); + p->drawLine(x, y, x, y2); + p->setPen(sunken ? cg.midlight() : cg.mid()); + p->drawLine(x+1, y2-1, x2-1, y2-1); + p->drawLine(x2-1, y+1, x2-1, y2-1); + p->setPen(sunken ? cg.dark() : cg.midlight()); + p->drawLine(x+1, y+1, x2-1, y+1); + p->drawLine(x+1, y+1, x+1, y2-1); + p->setPen(oldPen); + } else + KStyle::drawPrimitive(pe, p, r, cg, flags, opt); + + break; + } + + + // MENU / TOOLBAR PANEL + // ------------------------------------------------------------------- + case PE_PanelMenuBar: // Menu + case PE_PanelDockWindow: { // Toolbar + int x2 = r.x()+r.width()-1; + int y2 = r.y()+r.height()-1; + + if (opt.lineWidth()) + { + p->setPen(cg.light()); + p->drawLine(r.x(), r.y(), x2-1, r.y()); + p->drawLine(r.x(), r.y(), r.x(), y2-1); + p->setPen(cg.dark()); + p->drawLine(r.x(), y2, x2, y2); + p->drawLine(x2, r.y(), x2, y2); + + // ### Qt should specify Style_Horizontal where appropriate + renderGradient( p, QRect(r.x()+1, r.y()+1, x2-1, y2-1), + cg.button(), (r.width() < r.height()) && + (pe != PE_PanelMenuBar) ); + } + else + { + renderGradient( p, QRect(r.x(), r.y(), x2, y2), + cg.button(), (r.width() < r.height()) && + (pe != PE_PanelMenuBar) ); + } + + break; + } + + + + // TOOLBAR SEPARATOR + // ------------------------------------------------------------------- + case PE_DockWindowSeparator: { + renderGradient( p, r, cg.button(), + !(flags & Style_Horizontal)); + if ( !(flags & Style_Horizontal) ) { + p->setPen(cg.mid()); + p->drawLine(4, r.height()/2, r.width()-5, r.height()/2); + p->setPen(cg.light()); + p->drawLine(4, r.height()/2+1, r.width()-5, r.height()/2+1); + } else { + p->setPen(cg.mid()); + p->drawLine(r.width()/2, 4, r.width()/2, r.height()-5); + p->setPen(cg.light()); + p->drawLine(r.width()/2+1, 4, r.width()/2+1, r.height()-5); + } + break; + } + + + default: + { + // ARROWS + // ------------------------------------------------------------------- + if (pe >= PE_ArrowUp && pe <= PE_ArrowLeft) + { + QPointArray a; + + // HighColor & Default arrows + switch(pe) { + case PE_ArrowUp: + a.setPoints(QCOORDARRLEN(u_arrow), u_arrow); + break; + + case PE_ArrowDown: + a.setPoints(QCOORDARRLEN(d_arrow), d_arrow); + break; + + case PE_ArrowLeft: + a.setPoints(QCOORDARRLEN(l_arrow), l_arrow); + break; + + default: + a.setPoints(QCOORDARRLEN(r_arrow), r_arrow); + } + + p->save(); + if ( flags & Style_Down ) + p->translate( pixelMetric( PM_ButtonShiftHorizontal ), + pixelMetric( PM_ButtonShiftVertical ) ); + + if ( flags & Style_Enabled ) { + a.translate( r.x() + r.width() / 2, r.y() + r.height() / 2 ); + p->setPen( cg.buttonText() ); + p->drawLineSegments( a ); + } else { + a.translate( r.x() + r.width() / 2 + 1, r.y() + r.height() / 2 + 1 ); + p->setPen( cg.light() ); + p->drawLineSegments( a ); + a.translate( -1, -1 ); + p->setPen( cg.mid() ); + p->drawLineSegments( a ); + } + p->restore(); + + } else + KStyle::drawPrimitive( pe, p, r, cg, flags, opt ); + } + } +} + + +void StyleCheckStyle::drawKStylePrimitive( KStylePrimitive kpe, + QPainter* p, + const QWidget* widget, + const QRect &r, + const QColorGroup &cg, + SFlags flags, + const QStyleOption &opt ) const +{ + switch ( kpe ) + { + // TOOLBAR HANDLE + // ------------------------------------------------------------------- + case KPE_ToolBarHandle: { + int x = r.x(); int y = r.y(); + int x2 = r.x() + r.width()-1; + int y2 = r.y() + r.height()-1; + + if (flags & Style_Horizontal) { + + renderGradient( p, r, cg.button(), false); + p->setPen(cg.light()); + p->drawLine(x+1, y+4, x+1, y2-4); + p->drawLine(x+3, y+4, x+3, y2-4); + p->drawLine(x+5, y+4, x+5, y2-4); + + p->setPen(cg.mid()); + p->drawLine(x+2, y+4, x+2, y2-4); + p->drawLine(x+4, y+4, x+4, y2-4); + p->drawLine(x+6, y+4, x+6, y2-4); + + } else { + + renderGradient( p, r, cg.button(), true); + p->setPen(cg.light()); + p->drawLine(x+4, y+1, x2-4, y+1); + p->drawLine(x+4, y+3, x2-4, y+3); + p->drawLine(x+4, y+5, x2-4, y+5); + + p->setPen(cg.mid()); + p->drawLine(x+4, y+2, x2-4, y+2); + p->drawLine(x+4, y+4, x2-4, y+4); + p->drawLine(x+4, y+6, x2-4, y+6); + + } + break; + } + + + // GENERAL/KICKER HANDLE + // ------------------------------------------------------------------- + case KPE_GeneralHandle: { + int x = r.x(); int y = r.y(); + int x2 = r.x() + r.width()-1; + int y2 = r.y() + r.height()-1; + + if (flags & Style_Horizontal) { + + p->setPen(cg.light()); + p->drawLine(x+1, y, x+1, y2); + p->drawLine(x+3, y, x+3, y2); + p->drawLine(x+5, y, x+5, y2); + + p->setPen(cg.mid()); + p->drawLine(x+2, y, x+2, y2); + p->drawLine(x+4, y, x+4, y2); + p->drawLine(x+6, y, x+6, y2); + + } else { + + p->setPen(cg.light()); + p->drawLine(x, y+1, x2, y+1); + p->drawLine(x, y+3, x2, y+3); + p->drawLine(x, y+5, x2, y+5); + + p->setPen(cg.mid()); + p->drawLine(x, y+2, x2, y+2); + p->drawLine(x, y+4, x2, y+4); + p->drawLine(x, y+6, x2, y+6); + + } + break; + } + + + // SLIDER GROOVE + // ------------------------------------------------------------------- + case KPE_SliderGroove: { + const QSlider* slider = (const QSlider*)widget; + bool horizontal = slider->orientation() == Horizontal; + int gcenter = (horizontal ? r.height() : r.width()) / 2; + + QRect gr; + if (horizontal) + gr = QRect(r.x(), r.y()+gcenter-3, r.width(), 7); + else + gr = QRect(r.x()+gcenter-3, r.y(), 7, r.height()); + + int x,y,w,h; + gr.rect(&x, &y, &w, &h); + int x2=x+w-1; + int y2=y+h-1; + + // Draw the slider groove. + p->setPen(cg.dark()); + p->drawLine(x+2, y, x2-2, y); + p->drawLine(x, y+2, x, y2-2); + p->fillRect(x+2,y+2,w-4, h-4, + slider->isEnabled() ? cg.dark() : cg.mid()); + p->setPen(cg.shadow()); + p->drawRect(x+1, y+1, w-2, h-2); + p->setPen(cg.light()); + p->drawPoint(x+1,y2-1); + p->drawPoint(x2-1,y2-1); + p->drawLine(x2, y+2, x2, y2-2); + p->drawLine(x+2, y2, x2-2, y2); + break; + } + + // SLIDER HANDLE + // ------------------------------------------------------------------- + case KPE_SliderHandle: { + const QSlider* slider = (const QSlider*)widget; + bool horizontal = slider->orientation() == Horizontal; + int x,y,w,h; + r.rect(&x, &y, &w, &h); + int x2 = x+w-1; + int y2 = y+h-1; + + p->setPen(cg.mid()); + p->drawLine(x+1, y, x2-1, y); + p->drawLine(x, y+1, x, y2-1); + p->setPen(cg.shadow()); + p->drawLine(x+1, y2, x2-1, y2); + p->drawLine(x2, y+1, x2, y2-1); + + p->setPen(cg.light()); + p->drawLine(x+1, y+1, x2-1, y+1); + p->drawLine(x+1, y+1, x+1, y2-1); + p->setPen(cg.dark()); + p->drawLine(x+2, y2-1, x2-1, y2-1); + p->drawLine(x2-1, y+2, x2-1, y2-1); + p->setPen(cg.midlight()); + p->drawLine(x+2, y+2, x2-2, y+2); + p->drawLine(x+2, y+2, x+2, y2-2); + p->setPen(cg.mid()); + p->drawLine(x+3, y2-2, x2-2, y2-2); + p->drawLine(x2-2, y+3, x2-2, y2-2); + renderGradient(p, QRect(x+3, y+3, w-6, h-6), + cg.button(), !horizontal); + + // Paint riffles + if (horizontal) { + p->setPen(cg.light()); + p->drawLine(x+5, y+4, x+5, y2-4); + p->drawLine(x+8, y+4, x+8, y2-4); + p->drawLine(x+11,y+4, x+11, y2-4); + p->setPen(slider->isEnabled() ? cg.shadow(): cg.mid()); + p->drawLine(x+6, y+4, x+6, y2-4); + p->drawLine(x+9, y+4, x+9, y2-4); + p->drawLine(x+12,y+4, x+12, y2-4); + } else { + p->setPen(cg.light()); + p->drawLine(x+4, y+5, x2-4, y+5); + p->drawLine(x+4, y+8, x2-4, y+8); + p->drawLine(x+4, y+11, x2-4, y+11); + p->setPen(slider->isEnabled() ? cg.shadow() : cg.mid()); + p->drawLine(x+4, y+6, x2-4, y+6); + p->drawLine(x+4, y+9, x2-4, y+9); + p->drawLine(x+4, y+12, x2-4, y+12); + } + break; + } + + default: + KStyle::drawKStylePrimitive( kpe, p, widget, r, cg, flags, opt); + } +} + + +void StyleCheckStyle::drawControl( ControlElement element, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags flags, + const QStyleOption& opt ) const +{ + switch (element) + { + // PUSHBUTTON + // ------------------------------------------------------------------- + case CE_PushButton: { + if ( widget == hoverWidget ) + flags |= Style_MouseOver; + + QPushButton *button = (QPushButton*) widget; + QRect br = r; + bool btnDefault = button->isDefault(); + + if ( btnDefault || button->autoDefault() ) { + // Compensate for default indicator + static int di = pixelMetric( PM_ButtonDefaultIndicator ); + br.addCoords( di, di, -di, -di ); + } + + if ( btnDefault ) + drawPrimitive( PE_ButtonDefault, p, r, cg, flags ); + + drawPrimitive( PE_ButtonCommand, p, br, cg, flags ); + + break; + } + + + // PUSHBUTTON LABEL + // ------------------------------------------------------------------- + case CE_PushButtonLabel: { + const QPushButton* button = (const QPushButton*)widget; + bool active = button->isOn() || button->isDown(); + int x, y, w, h; + r.rect( &x, &y, &w, &h ); + + // Shift button contents if pushed. + if ( active ) { + x += pixelMetric(PM_ButtonShiftHorizontal, widget); + y += pixelMetric(PM_ButtonShiftVertical, widget); + flags |= Style_Sunken; + } + + // Does the button have a popup menu? + if ( button->isMenuButton() ) { + int dx = pixelMetric( PM_MenuButtonIndicator, widget ); + drawPrimitive( PE_ArrowDown, p, QRect(x + w - dx - 2, y + 2, dx, h - 4), + cg, flags, opt ); + w -= dx; + } + + // Draw the icon if there is one + if ( button->iconSet() && !button->iconSet()->isNull() ) { + QIconSet::Mode mode = QIconSet::Disabled; + QIconSet::State state = QIconSet::Off; + + if (button->isEnabled()) + mode = button->hasFocus() ? QIconSet::Active : QIconSet::Normal; + if (button->isToggleButton() && button->isOn()) + state = QIconSet::On; + + QPixmap pixmap = button->iconSet()->pixmap( QIconSet::Small, mode, state ); + p->drawPixmap( x + 4, y + h / 2 - pixmap.height() / 2, pixmap ); + int pw = pixmap.width(); + x += pw + 4; + w -= pw + 4; + } + + QValueVector<StyleGuideViolation> violations = checkTitleStyle(button->text(), ShortTitle, HasAccels); + renderViolations(violations, p, QRect(x,y,w,h), AlignCenter | ShowPrefix, button->text()); + + // Make the label indicate if the button is a default button or not + if ( active || button->isDefault() ) { + // Draw "fake" bold text - this enables the font metrics to remain + // the same as computed in QPushButton::sizeHint(), but gives + // a reasonable bold effect. + int i; + + // Text shadow + if (button->isEnabled()) // Don't draw double-shadow when disabled + for(i=0; i<2; i++) + drawItem( p, QRect(x+i+1, y+1, w, h), AlignCenter | ShowPrefix, + button->colorGroup(), button->isEnabled(), button->pixmap(), + removedXX(stripAccelViolations(button->text())), -1, + active ? &button->colorGroup().dark() : &button->colorGroup().mid() ); + + // Normal Text + for(i=0; i<2; i++) + drawItem( p, QRect(x+i, y, w, h), AlignCenter | ShowPrefix, + button->colorGroup(), button->isEnabled(), button->pixmap(), + removedXX(stripAccelViolations(button->text())), -1, + active ? &button->colorGroup().light() : &button->colorGroup().buttonText() ); + } else + drawItem( p, QRect(x, y, w, h), AlignCenter | ShowPrefix, button->colorGroup(), + button->isEnabled(), button->pixmap(), removedXX(stripAccelViolations(button->text())), -1, + active ? &button->colorGroup().light() : &button->colorGroup().buttonText() ); + + // Draw a focus rect if the button has focus + if ( flags & Style_HasFocus ) + drawPrimitive( PE_FocusRect, p, + QStyle::visualRect(subRect(SR_PushButtonFocusRect, widget), widget), + cg, flags ); + break; + } + + case CE_TabBarLabel: + { + if ( opt.isDefault() ) + break; + + const QTabBar * tb = (const QTabBar *) widget; + QTab * t = opt.tab(); + + QRect tr = r; + if ( t->identifier() == tb->currentTab() ) + tr.setBottom( tr.bottom() - + pixelMetric( QStyle::PM_DefaultFrameWidth, tb ) ); + + QValueVector<StyleGuideViolation> violations = checkTitleStyle(t->text(), ShortTitle, HasAccels); + renderViolations(violations, p, r, AlignCenter |ShowPrefix, t->text()); + + drawItem( p, tr, AlignCenter | ShowPrefix, cg, + flags & Style_Enabled, 0, removedXX(stripAccelViolations(t->text())) ); + + if ( (flags & Style_HasFocus) && !t->text().isEmpty() ) + drawPrimitive( PE_FocusRect, p, r, cg ); + break; + } + + + case CE_CheckBoxLabel: + { + const QCheckBox* checkbox = static_cast<const QCheckBox*>(widget); + + int alignment = QApplication::reverseLayout() ? AlignRight : AlignLeft; + + QValueVector<StyleGuideViolation> violations = checkSentenceStyle(checkbox->text()); + + renderViolations(violations, p, r, alignment | AlignVCenter | ShowPrefix, checkbox->text()); + + drawItem(p, r, alignment | AlignVCenter | ShowPrefix, cg, + flags & Style_Enabled, checkbox->pixmap(), removedXX(stripAccelViolations(checkbox->text()))); + + if (flags & Style_HasFocus) + { + QRect fr = visualRect(subRect(SR_CheckBoxFocusRect, widget), widget); + drawPrimitive(PE_FocusRect, p, fr, cg, flags); + } + break; + } + + case CE_RadioButtonLabel: + { + const QRadioButton* rb = static_cast<const QRadioButton*>(widget); + + int alignment = QApplication::reverseLayout() ? AlignRight : AlignLeft; + + QValueVector<StyleGuideViolation> violations = checkSentenceStyle(rb->text()); + + renderViolations(violations, p, r,alignment | AlignVCenter | ShowPrefix, rb->text()); + + drawItem(p, r, alignment | AlignVCenter | ShowPrefix, cg, + flags & Style_Enabled, rb->pixmap(), removedXX(stripAccelViolations(rb->text()))); + + if (flags & Style_HasFocus) + { + QRect fr = visualRect(subRect(SR_CheckBoxFocusRect, widget), widget); + drawPrimitive(PE_FocusRect, p, fr, cg, flags); + } + break; + } + + + // MENUBAR ITEM (sunken panel on mouse over) + // ------------------------------------------------------------------- + case CE_MenuBarItem: + { + QMenuBar *mb = (QMenuBar*)widget; + QMenuItem *mi = opt.menuItem(); + QRect pr = mb->rect(); + + bool active = flags & Style_Active; + bool focused = flags & Style_HasFocus; + + if ( active && focused ) + qDrawShadePanel(p, r.x(), r.y(), r.width(), r.height(), + cg, true, 1, &cg.brush(QColorGroup::Midlight)); + else + renderGradient( p, r, cg.button(), false, + r.x(), r.y()-1, pr.width()-2, pr.height()-2); + + QValueVector<StyleGuideViolation> violations = checkTitleStyle(mi->text(), ShortTitle, HasAccels); + renderViolations(violations, p, r, AlignCenter | AlignVCenter | ShowPrefix, mi->text()); + + drawItem( p, r, AlignCenter | AlignVCenter | ShowPrefix + | DontClip | SingleLine, cg, flags & Style_Enabled, + mi->pixmap(), removedXX(stripAccelViolations(mi->text())) ); + + break; + } + + + // POPUPMENU ITEM + // ------------------------------------------------------------------- + case CE_PopupMenuItem: { + const QPopupMenu *popupmenu = (const QPopupMenu *) widget; + + QMenuItem *mi = opt.menuItem(); + if ( !mi ) { + // Don't leave blank holes if we set NoBackground for the QPopupMenu. + // This only happens when the popupMenu spans more than one column. + if (! (widget->erasePixmap() && !widget->erasePixmap()->isNull()) ) + p->fillRect(r, cg.brush(QColorGroup::Button) ); + break; + } + + int tab = opt.tabWidth(); + int checkcol = opt.maxIconWidth(); + bool enabled = mi->isEnabled(); + bool checkable = popupmenu->isCheckable(); + bool active = flags & Style_Active; + bool etchtext = styleHint( SH_EtchDisabledText ); + bool reverse = QApplication::reverseLayout(); + int x, y, w, h; + r.rect( &x, &y, &w, &h ); + + if ( checkable ) + checkcol = QMAX( checkcol, 20 ); + + // Are we a menu item separator? + if ( mi->isSeparator() ) { + p->setPen( cg.dark() ); + p->drawLine( x, y, x+w, y ); + p->setPen( cg.light() ); + p->drawLine( x, y+1, x+w, y+1 ); + break; + } + + // Draw the menu item background + if ( active ) + qDrawShadePanel( p, x, y, w, h, cg, true, 1, + &cg.brush(QColorGroup::Midlight) ); + // Draw the transparency pixmap + else if ( widget->erasePixmap() && !widget->erasePixmap()->isNull() ) + p->drawPixmap( x, y, *widget->erasePixmap(), x, y, w, h ); + // Draw a solid background + else + p->fillRect( r, cg.button() ); + + // Do we have an icon? + if ( mi->iconSet() ) { + QIconSet::Mode mode; + QRect cr = visualRect( QRect(x, y, checkcol, h), r ); + + // Select the correct icon from the iconset + if ( active ) + mode = enabled ? QIconSet::Active : QIconSet::Disabled; + else + mode = enabled ? QIconSet::Normal : QIconSet::Disabled; + + // Do we have an icon and are checked at the same time? + // Then draw a "pressed" background behind the icon + if ( checkable && !active && mi->isChecked() ) + qDrawShadePanel( p, cr.x(), cr.y(), cr.width(), cr.height(), + cg, true, 1, &cg.brush(QColorGroup::Midlight) ); + // Draw the icon + QPixmap pixmap = mi->iconSet()->pixmap( QIconSet::Small, mode ); + QRect pmr( 0, 0, pixmap.width(), pixmap.height() ); + pmr.moveCenter( cr.center() ); + p->drawPixmap( pmr.topLeft(), pixmap ); + } + + // Are we checked? (This time without an icon) + else if ( checkable && mi->isChecked() ) { + int cx = reverse ? x+w - checkcol : x; + + // We only have to draw the background if the menu item is inactive - + // if it's active the "pressed" background is already drawn + if ( ! active ) + qDrawShadePanel( p, cx, y, checkcol, h, cg, true, 1, + &cg.brush(QColorGroup::Midlight) ); + + // Draw the checkmark + SFlags cflags = Style_Default; + cflags |= active ? Style_Enabled : Style_On; + + drawPrimitive( PE_CheckMark, p, QRect( cx + itemFrame, y + itemFrame, + checkcol - itemFrame*2, h - itemFrame*2), cg, cflags ); + } + + // Time to draw the menu item label... + int xm = itemFrame + checkcol + itemHMargin; // X position margin + + int xp = reverse ? // X position + x + tab + rightBorder + itemHMargin + itemFrame - 1 : + x + xm; + + int offset = reverse ? -1 : 1; // Shadow offset for etched text + + // Label width (minus the width of the accelerator portion) + int tw = w - xm - tab - arrowHMargin - itemHMargin * 3 - itemFrame + 1; + + // Set the color for enabled and disabled text + // (used for both active and inactive menu items) + p->setPen( enabled ? cg.buttonText() : cg.mid() ); + + // This color will be used instead of the above if the menu item + // is active and disabled at the same time. (etched text) + QColor discol = cg.mid(); + + // Does the menu item draw it's own label? + if ( mi->custom() ) { + int m = itemVMargin; + // Save the painter state in case the custom + // paint method changes it in some way + p->save(); + + // Draw etched text if we're inactive and the menu item is disabled + if ( etchtext && !enabled && !active ) { + p->setPen( cg.light() ); + mi->custom()->paint( p, cg, active, enabled, xp+offset, y+m+1, tw, h-2*m ); + p->setPen( discol ); + } + mi->custom()->paint( p, cg, active, enabled, xp, y+m, tw, h-2*m ); + p->restore(); + } + else { + QValueVector<StyleGuideViolation> ourViolations; + + QString tmpStr = mi->text(); + removeAccelerators(tmpStr); + findAccelViolations(tmpStr, ourViolations); + + // The menu item doesn't draw it's own label + QString s = stripAccelViolations(mi->text()); + + // Does the menu item have a text label? + if ( !s.isNull() ) { + int t = s.find( '\t' ); + int m = itemVMargin; + int text_flags = AlignVCenter | ShowPrefix | DontClip | SingleLine; + text_flags |= reverse ? AlignRight : AlignLeft; + + // Does the menu item have a tabstop? (for the accelerator text) + if ( t >= 0 ) { + int tabx = reverse ? x + rightBorder + itemHMargin + itemFrame : + x + w - tab - rightBorder - itemHMargin - itemFrame; + + // Draw the right part of the label (accelerator text) + if ( etchtext && !enabled && !active ) { + // Draw etched text if we're inactive and the menu item is disabled + p->setPen( cg.light() ); + p->drawText( tabx+offset, y+m+1, tab, h-2*m, text_flags, removedXX(s.mid( t+1 )) ); + p->setPen( discol ); + } + p->drawText( tabx, y+m, tab, h-2*m, text_flags, removedXX(s.mid( t+1 )) ); + s = s.left( t ); + } + + QValueVector<StyleGuideViolation> violations = checkTitleStyle(s, ShortTitle, HasAccels); + renderViolations(violations, p, QRect(xp, y+m, tw, h-2*m), text_flags, s); + renderViolations(ourViolations, p, QRect(xp, y+m, tw, h-2*m), text_flags, s); + + + // Draw the left part of the label (or the whole label + // if there's no accelerator) + if ( etchtext && !enabled && !active ) { + // Etched text again for inactive disabled menu items... + p->setPen( cg.light() ); + p->drawText( xp+offset, y+m+1, tw, h-2*m, text_flags, removedXX(s)/*, t*/ ); + p->setPen( discol ); + } + + p->drawText( xp, y+m, tw, h-2*m, text_flags, removedXX(s)/*, t*/ ); + + } + + // The menu item doesn't have a text label + // Check if it has a pixmap instead + else if ( mi->pixmap() ) { + QPixmap *pixmap = mi->pixmap(); + + // Draw the pixmap + if ( pixmap->depth() == 1 ) + p->setBackgroundMode( OpaqueMode ); + + int diffw = ( ( w - pixmap->width() ) / 2 ) + + ( ( w - pixmap->width() ) % 2 ); + p->drawPixmap( x+diffw, y+itemFrame, *pixmap ); + + if ( pixmap->depth() == 1 ) + p->setBackgroundMode( TransparentMode ); + } + } + + // Does the menu item have a submenu? + if ( mi->popup() ) { + PrimitiveElement arrow = reverse ? PE_ArrowLeft : PE_ArrowRight; + int dim = pixelMetric(PM_MenuButtonIndicator); + QRect vr = visualRect( QRect( x + w - arrowHMargin - 2*itemFrame - dim, + y + h / 2 - dim / 2, dim, dim), r ); + + // Draw an arrow at the far end of the menu item + if ( active ) { + if ( enabled ) + discol = cg.buttonText(); + + QColorGroup g2( discol, cg.highlight(), white, white, + enabled ? white : discol, discol, white ); + + drawPrimitive( arrow, p, vr, g2, Style_Enabled ); + } else + drawPrimitive( arrow, p, vr, cg, + enabled ? Style_Enabled : Style_Default ); + } + break; + } + + case CE_HeaderLabel: + { + //Most of code here shamelessly lifted from QCommonStyle. + QRect rect = r; + const QHeader* header = static_cast<const QHeader*>(widget); + int section = opt.headerSection(); + QIconSet* icon = header->iconSet( section ); + if ( icon ) + { + QPixmap pixmap = icon->pixmap( QIconSet::Small, + flags & Style_Enabled ? QIconSet::Normal : QIconSet::Disabled ); + int pixw = pixmap.width(); + int pixh = pixmap.height(); + // "pixh - 1" because of tricky integer division + QRect pixRect = rect; + pixRect.setY( rect.center().y() - (pixh - 1) / 2 ); + drawItem ( p, pixRect, AlignVCenter, cg, flags & Style_Enabled, + &pixmap, QString::null ); + rect.setLeft( rect.left() + pixw + 2 ); + } + + QString s = header->label( section ); + + QValueVector<StyleGuideViolation> violations = checkTitleStyle(s, ShortTitle, NoAccels); + renderViolations(violations, p, rect, AlignVCenter, s); + + + drawItem ( p, rect, AlignVCenter, cg, flags & Style_Enabled, + 0, s, -1, &(cg.buttonText()) ); + + break; + } + + default: + KStyle::drawControl(element, p, widget, r, cg, flags, opt); + } +} + + +void StyleCheckStyle::drawControlMask( ControlElement element, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QStyleOption& opt ) const +{ + switch (element) + { + // PUSHBUTTON MASK + // ---------------------------------------------------------------------- + case CE_PushButton: { + int x1, y1, x2, y2; + r.coords( &x1, &y1, &x2, &y2 ); + QCOORD corners[] = { x1,y1, x2,y1, x1,y2, x2,y2 }; + p->fillRect( r, color1 ); + p->setPen( color0 ); + p->drawPoints( QPointArray(4, corners) ); + break; + } + + default: + KStyle::drawControlMask(element, p, widget, r, opt); + } +} + + +void StyleCheckStyle::drawComplexControl( ComplexControl control, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QColorGroup &cg, + SFlags flags, + SCFlags controls, + SCFlags active, + const QStyleOption& opt ) const +{ + switch(control) + { + // COMBOBOX + // ------------------------------------------------------------------- + case CC_ComboBox: { + + // Draw box and arrow + if ( controls & SC_ComboBoxArrow ) { + bool sunken = (active == SC_ComboBoxArrow); + + // Draw the combo + int x,y,w,h; + r.rect(&x, &y, &w, &h); + int x2 = x+w-1; + int y2 = y+h-1; + + p->setPen(cg.shadow()); + p->drawLine(x+1, y, x2-1, y); + p->drawLine(x+1, y2, x2-1, y2); + p->drawLine(x, y+1, x, y2-1); + p->drawLine(x2, y+1, x2, y2-1); + + // Ensure the edge notches are properly colored + p->setPen(cg.button()); + p->drawPoint(x,y); + p->drawPoint(x,y2); + p->drawPoint(x2,y); + p->drawPoint(x2,y2); + + renderGradient( p, QRect(x+2, y+2, w-4, h-4), + cg.button(), false); + + p->setPen(sunken ? cg.light() : cg.mid()); + p->drawLine(x2-1, y+2, x2-1, y2-1); + p->drawLine(x+1, y2-1, x2-1, y2-1); + + p->setPen(sunken ? cg.mid() : cg.light()); + p->drawLine(x+1, y+1, x2-1, y+1); + p->drawLine(x+1, y+2, x+1, y2-2); + + // Get the button bounding box + QRect ar = QStyle::visualRect( + querySubControlMetrics(CC_ComboBox, widget, SC_ComboBoxArrow), + widget ); + + // Are we enabled? + if ( widget->isEnabled() ) + flags |= Style_Enabled; + + // Are we "pushed" ? + if ( active & Style_Sunken ) + flags |= Style_Sunken; + + drawPrimitive(PE_ArrowDown, p, ar, cg, flags); + } + + // Draw an edit field if required + if ( controls & SC_ComboBoxEditField ) + { + const QComboBox * cb = (const QComboBox *) widget; + QRect re = QStyle::visualRect( + querySubControlMetrics( CC_ComboBox, widget, + SC_ComboBoxEditField), widget ); + + // Draw the indent + if (cb->editable()) { + p->setPen( cg.dark() ); + p->drawLine( re.x(), re.y()-1, re.x()+re.width(), re.y()-1 ); + p->drawLine( re.x()-1, re.y(), re.x()-1, re.y()+re.height() ); + } + + if ( cb->hasFocus() ) { + p->setPen( cg.highlightedText() ); + p->setBackgroundColor( cg.highlight() ); + } else { + p->setPen( cg.text() ); + p->setBackgroundColor( cg.button() ); + } + + if ( cb->hasFocus() && !cb->editable() ) { + // Draw the contents + p->fillRect( re.x(), re.y(), re.width(), re.height(), + cg.brush( QColorGroup::Highlight ) ); + + QRect re = QStyle::visualRect( + subRect(SR_ComboBoxFocusRect, cb), widget); + + drawPrimitive( PE_FocusRect, p, re, cg, + Style_FocusAtBorder, QStyleOption(cg.highlight())); + } + } + break; + } + + // TOOLBUTTON + // ------------------------------------------------------------------- + case CC_ToolButton: { + const QToolButton *toolbutton = (const QToolButton *) widget; + + QRect button, menuarea; + button = querySubControlMetrics(control, widget, SC_ToolButton, opt); + menuarea = querySubControlMetrics(control, widget, SC_ToolButtonMenu, opt); + + SFlags bflags = flags, + mflags = flags; + + if (active & SC_ToolButton) + bflags |= Style_Down; + if (active & SC_ToolButtonMenu) + mflags |= Style_Down; + + if (controls & SC_ToolButton) + { + // If we're pressed, on, or raised... + if (bflags & (Style_Down | Style_On | Style_Raised)) + drawPrimitive(PE_ButtonTool, p, button, cg, bflags, opt); + + // Check whether to draw a background pixmap + else if ( toolbutton->parentWidget() && + toolbutton->parentWidget()->backgroundPixmap() && + !toolbutton->parentWidget()->backgroundPixmap()->isNull() ) + { + QPixmap pixmap = *(toolbutton->parentWidget()->backgroundPixmap()); + p->drawTiledPixmap( r, pixmap, toolbutton->pos() ); + } + else if (widget->parent()) + { + if (widget->parent()->inherits("QToolBar")) + { + QToolBar* parent = (QToolBar*)widget->parent(); + QRect pr = parent->rect(); + + renderGradient( p, r, cg.button(), + parent->orientation() == Qt::Vertical, + r.x(), r.y(), pr.width()-2, pr.height()-2); + } + else if (widget->parent()->inherits("QToolBarExtensionWidget")) + { + QWidget* parent = (QWidget*)widget->parent(); + QToolBar* toolbar = (QToolBar*)parent->parent(); + QRect tr = toolbar->rect(); + + if ( toolbar->orientation() == Qt::Horizontal ) { + renderGradient( p, r, cg.button(), false, r.x(), r.y(), + r.width(), tr.height() ); + } else { + renderGradient( p, r, cg.button(), true, r.x(), r.y(), + tr.width(), r.height() ); + } + } + } + } + + // Draw a toolbutton menu indicator if required + if (controls & SC_ToolButtonMenu) + { + if (mflags & (Style_Down | Style_On | Style_Raised)) + drawPrimitive(PE_ButtonDropDown, p, menuarea, cg, mflags, opt); + drawPrimitive(PE_ArrowDown, p, menuarea, cg, mflags, opt); + } + + if (toolbutton->hasFocus() && !toolbutton->focusProxy()) { + QRect fr = toolbutton->rect(); + fr.addCoords(3, 3, -3, -3); + drawPrimitive(PE_FocusRect, p, fr, cg); + } + + break; + } + + + default: + KStyle::drawComplexControl(control, p, widget, + r, cg, flags, controls, active, opt); + break; + } +} + + +void StyleCheckStyle::drawComplexControlMask( ComplexControl control, + QPainter *p, + const QWidget *widget, + const QRect &r, + const QStyleOption& opt ) const +{ + switch (control) + { + // COMBOBOX & TOOLBUTTON MASKS + // ------------------------------------------------------------------- + case CC_ComboBox: + case CC_ToolButton: { + int x1, y1, x2, y2; + r.coords( &x1, &y1, &x2, &y2 ); + QCOORD corners[] = { x1,y1, x2,y1, x1,y2, x2,y2 }; + p->fillRect( r, color1 ); + p->setPen( color0 ); + p->drawPoints( QPointArray(4, corners) ); + break; + } + + default: + KStyle::drawComplexControlMask(control, p, widget, r, opt); + } +} + + +QRect StyleCheckStyle::subRect(SubRect r, const QWidget *widget) const +{ + // We want the focus rect for buttons to be adjusted from + // the Qt3 defaults to be similar to Qt 2's defaults. + // ------------------------------------------------------------------- + if (r == SR_PushButtonFocusRect ) { + const QPushButton* button = (const QPushButton*) widget; + QRect wrect(widget->rect()); + int dbw1 = 0, dbw2 = 0; + + if (button->isDefault() || button->autoDefault()) { + dbw1 = pixelMetric(PM_ButtonDefaultIndicator, widget); + dbw2 = dbw1 * 2; + } + + int dfw1 = pixelMetric(PM_DefaultFrameWidth, widget) * 2, + dfw2 = dfw1 * 2; + + return QRect(wrect.x() + dfw1 + dbw1 + 1, + wrect.y() + dfw1 + dbw1 + 1, + wrect.width() - dfw2 - dbw2 - 1, + wrect.height() - dfw2 - dbw2 - 1); + } else + return KStyle::subRect(r, widget); +} + + +int StyleCheckStyle::pixelMetric(PixelMetric m, const QWidget *widget) const +{ + switch(m) + { + // BUTTONS + // ------------------------------------------------------------------- + case PM_ButtonMargin: // Space btw. frame and label + return 4; + + case PM_ButtonDefaultIndicator: { + return 3; + } + + case PM_MenuButtonIndicator: { // Arrow width + return 8; + } + + // CHECKBOXES / RADIO BUTTONS + // ------------------------------------------------------------------- + case PM_ExclusiveIndicatorWidth: // Radiobutton size + case PM_ExclusiveIndicatorHeight: + case PM_IndicatorWidth: // Checkbox size + case PM_IndicatorHeight: { + return 13; // 13x13 + } + + default: + return KStyle::pixelMetric(m, widget); + } +} + + +QSize StyleCheckStyle::sizeFromContents( ContentsType contents, + const QWidget* widget, + const QSize &contentSize, + const QStyleOption& opt ) const +{ + switch (contents) + { + // PUSHBUTTON SIZE + // ------------------------------------------------------------------ + case CT_PushButton: { + const QPushButton* button = (const QPushButton*) widget; + int w = contentSize.width(); + int h = contentSize.height(); + int bm = pixelMetric( PM_ButtonMargin, widget ); + int fw = pixelMetric( PM_DefaultFrameWidth, widget ) * 2; + + w += bm + fw + 6; // ### Add 6 to make way for bold font. + h += bm + fw; + + // Ensure we stick to standard width and heights. + if ( button->isDefault() || button->autoDefault() ) { + if ( w < 80 && !button->pixmap() ) + w = 80; + + // Compensate for default indicator + int di = pixelMetric( PM_ButtonDefaultIndicator ); + w += di * 2; + h += di * 2; + } + + if ( h < 22 ) + h = 22; + + return QSize( w, h ); + } + + + // POPUPMENU ITEM SIZE + // ----------------------------------------------------------------- + case CT_PopupMenuItem: { + if ( ! widget || opt.isDefault() ) + return contentSize; + + const QPopupMenu *popup = (const QPopupMenu *) widget; + bool checkable = popup->isCheckable(); + QMenuItem *mi = opt.menuItem(); + int maxpmw = opt.maxIconWidth(); + int w = contentSize.width(), h = contentSize.height(); + + if ( mi->custom() ) { + w = mi->custom()->sizeHint().width(); + h = mi->custom()->sizeHint().height(); + if ( ! mi->custom()->fullSpan() ) + h += 2*itemVMargin + 2*itemFrame; + } + else if ( mi->widget() ) { + } else if ( mi->isSeparator() ) { + w = 10; // Arbitrary + h = 2; + } + else { + if ( mi->pixmap() ) + h = QMAX( h, mi->pixmap()->height() + 2*itemFrame ); + else { + // Ensure that the minimum height for text-only menu items + // is the same as the icon size used by KDE. + h = QMAX( h, 16 + 2*itemFrame ); + h = QMAX( h, popup->fontMetrics().height() + + 2*itemVMargin + 2*itemFrame ); + } + + if ( mi->iconSet() ) + h = QMAX( h, mi->iconSet()->pixmap( + QIconSet::Small, QIconSet::Normal).height() + + 2 * itemFrame ); + } + + if ( ! mi->text().isNull() && mi->text().find('\t') >= 0 ) + w += 12; + else if ( mi->popup() ) + w += 2 * arrowHMargin; + + if ( maxpmw ) + w += maxpmw + 6; + if ( checkable && maxpmw < 20 ) + w += 20 - maxpmw; + if ( checkable || maxpmw > 0 ) + w += 12; + + w += rightBorder; + + return QSize( w, h ); + } + + + default: + return KStyle::sizeFromContents( contents, widget, contentSize, opt ); + } +} + + +// Fix Qt's wacky image alignment +QPixmap StyleCheckStyle::stylePixmap(StylePixmap stylepixmap, + const QWidget* widget, + const QStyleOption& opt) const +{ + switch (stylepixmap) { + case SP_TitleBarMinButton: + return QPixmap((const char **)hc_minimize_xpm); + case SP_TitleBarCloseButton: + return QPixmap((const char **)hc_close_xpm); + default: + break; + } + + return KStyle::stylePixmap(stylepixmap, widget, opt); +} + + +bool StyleCheckStyle::eventFilter( QObject *object, QEvent *event ) +{ + if (KStyle::eventFilter( object, event )) + return true; + + + // Handle push button hover effects. + QPushButton* button = dynamic_cast<QPushButton*>(object); + if ( button ) + { + if ( (event->type() == QEvent::Enter) && + (button->isEnabled()) ) { + hoverWidget = button; + button->repaint( false ); + } + else if ( (event->type() == QEvent::Leave) && + (object == hoverWidget) ) { + hoverWidget = 0L; + button->repaint( false ); + } + } + + if ( event->type() == QEvent::Paint && object->inherits("QLabel") ) + { + QLabel* lb = static_cast<QLabel*>(object); + if (lb->pixmap() || lb->picture() || lb->movie() || (lb->textFormat() == Qt::RichText) || + (lb->textFormat() == Qt::AutoText && QStyleSheet::mightBeRichText(lb->text())) ) + { + return false; + } + + QPainter p(lb); + + QRect cr = lb->contentsRect(); + + int m = lb->indent(); + if ( m < 0 && lb->frameWidth() ) // no indent, but we do have a frame + m = lb->fontMetrics().width('x') / 2 - lb->margin(); + if ( m > 0 ) + { + int hAlign = QApplication::horizontalAlignment( lb->alignment() ); + if ( hAlign & AlignLeft ) + cr.setLeft( cr.left() + m ); + if ( hAlign & AlignRight ) + cr.setRight( cr.right() - m ); + if ( lb->alignment() & AlignTop ) + cr.setTop( cr.top() + m ); + if ( lb->alignment() & AlignBottom ) + cr.setBottom( cr.bottom() - m ); + } + + QValueVector<StyleGuideViolation> violations; + + if (QCString(lb->name()) == "KJanusWidgetTitleLabel" || lb->font().bold()) + { + // We're a page title + violations = checkTitleStyle(lb->text(), LongTitle, lb->buddy() ? HasAccels : NoAccels); + } + else + { + // We're probably, maybe, not a page title label + // Further checks might be needed, depending on how often this comes up in the wild + violations = checkSentenceStyle(lb->text(), lb->buddy() ? BuddiedWidget: BuddylessWidget, lb->buddy() ? HasAccels : NoAccels); + } + + if (lb->buddy()) + { + renderViolations(violations, &p, cr,lb->alignment() | ShowPrefix, lb->text() ); + // ordinary text or pixmap label + drawItem( &p, cr, lb->alignment(), lb->colorGroup(), lb->isEnabled(), + 0, removedXX(stripAccelViolations(lb->text())) ); + } + else + { + renderViolations(violations, &p, cr,lb->alignment(), lb->text() ); + + // ordinary text or pixmap label + drawItem( &p, cr, lb->alignment(), lb->colorGroup(), lb->isEnabled(), + 0, removedXX(stripAccelViolations(lb->text())) ); + } + + p.end(); + + return true; + } + + if ( event->type() == QEvent::Paint && object->inherits("QGroupBox") ) + { + QPaintEvent * pevent = static_cast<QPaintEvent*>(event); + QGroupBox* gb = static_cast<QGroupBox*>(object); + bool nestedGroupBox = false; + QString stripped_title = removedXX(stripAccelViolations(gb->title())); + + //Walk parent hierarchy to check whether any are groupboxes too.. + QObject* parent = gb; + + // GCC suggested parentheses around assignment used as truth value + // I suggested that it could eat me. GCC won. + while ( (parent = parent->parent()) ) + { + if (parent->inherits("QGroupBox")) + { + nestedGroupBox = true; + break; + } + } + + QPainter paint( gb ); + if ( stripped_title.length() ) + { + // draw title + QFontMetrics fm = paint.fontMetrics(); + int h = fm.height(); + int tw = fm.width( stripped_title, stripped_title.length() ) + 2*fm.width(QChar(' ')); + int x; + if ( gb->alignment() & AlignHCenter ) // center alignment + x = gb->frameRect().width()/2 - tw/2; + else if ( gb->alignment() & AlignRight ) // right alignment + x = gb->frameRect().width() - tw - 8; + else if ( gb->alignment() & AlignLeft ) // left alignment + x = 8; + else + { // auto align + if( QApplication::reverseLayout() ) + x = gb->frameRect().width() - tw - 8; + else + x = 8; + } + QRect r( x, 0, tw, h ); + + QValueVector<StyleGuideViolation> violations = checkTitleStyle( gb->title(), ShortTitle, HasAccels ); + + renderViolations( violations, &paint, r, AlignCenter | ShowPrefix, gb->title() ); + + drawItem(&paint, r, AlignCenter | ShowPrefix, gb->colorGroup(), + gb->isEnabled(), 0, stripped_title ); + + paint.setClipRegion( pevent->region().subtract( r ) ); + } + + if (nestedGroupBox) + { + paint.save(); + QPen errorPen(Qt::red, 4, QPen::DashDotDotLine); + paint.setPen(errorPen); + paint.drawRect( gb->frameRect() ); + paint.restore(); + } + else + { + drawPrimitive( QStyle::PE_GroupBoxFrame, &paint, gb->frameRect(), + gb->colorGroup(), QStyle::Style_Default, + QStyleOption(gb->lineWidth(), gb->midLineWidth(), + gb->frameShape(), gb->frameShadow()) ); + } + return true; //We already drew the everything + } + + return false; +} + + +void StyleCheckStyle::renderGradient( QPainter* p, const QRect& r, + QColor clr, bool, int, int, int, int) const +{ + p->fillRect(r, clr); + return; +} + +// vim: set noet ts=4 sw=4: +// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off; |