File indexing completed on 2024-05-19 05:00:54
0001 0002 // Own 0003 #include "kcmcss.h" 0004 0005 // Qt 0006 #include <QCheckBox> 0007 #include <QDialogButtonBox> 0008 #include <QUrl> 0009 #include <QStandardPaths> 0010 0011 // KDE 0012 #include <KColorButton> 0013 #include <KConfig> 0014 #include <KConfigGroup> 0015 #include <KUrlRequester> 0016 #include <KParts/Part> 0017 #include <KParts/OpenUrlArguments> 0018 #include <KParts/PartLoader> 0019 0020 // Local 0021 #include "template.h" 0022 0023 #include "ui_cssconfig.h" 0024 0025 class CSSConfigWidget: public QWidget, public Ui::CSSConfigWidget 0026 { 0027 public: 0028 CSSConfigWidget(QWidget *parent) : QWidget(parent) 0029 { 0030 setupUi(this); 0031 } 0032 }; 0033 0034 CSSConfig::CSSConfig(QWidget *parent, const QVariantList &) 0035 : QWidget(parent) 0036 , configWidget(new CSSConfigWidget(this)) 0037 , customDialogBase(new QDialog(this)) 0038 , customDialog(new CSSCustomDialog(customDialogBase)) 0039 { 0040 customDialogBase->setObjectName(QStringLiteral("customCSSDialog")); 0041 customDialogBase->setModal(true); 0042 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, customDialogBase); 0043 buttonBox->button(QDialogButtonBox::Close)->setDefault(true); 0044 connect(buttonBox, &QDialogButtonBox::rejected, customDialogBase, &QDialog::reject); 0045 0046 QVBoxLayout *vLayout = new QVBoxLayout(customDialogBase); 0047 vLayout->addWidget(customDialog); 0048 vLayout->addStretch(1); 0049 vLayout->addWidget(buttonBox); 0050 0051 setToolTip(i18n("<h1>Konqueror Stylesheets</h1> This module allows you to apply your own color" 0052 " and font settings to Konqueror by using" 0053 " stylesheets (CSS). You can either specify" 0054 " options or apply your own self-written" 0055 " stylesheet by pointing to its location.<br />" 0056 " Note that these settings will always have" 0057 " precedence before all other settings made" 0058 " by the site author. This can be useful to" 0059 " visually impaired people or for web pages" 0060 " that are unreadable due to bad design.")); 0061 0062 connect(configWidget->useDefault, &QAbstractButton::clicked, this, &CSSConfig::changed); 0063 connect(configWidget->useAccess, &QAbstractButton::clicked, this, &CSSConfig::changed); 0064 connect(configWidget->useUser, &QAbstractButton::clicked, this, &CSSConfig::changed); 0065 connect(configWidget->urlRequester, &KUrlRequester::textChanged, this, &CSSConfig::changed); 0066 connect(configWidget->customize, &QAbstractButton::clicked, this, &CSSConfig::slotCustomize); 0067 connect(customDialog, &CSSCustomDialog::changed, this, &CSSConfig::changed); 0068 0069 QVBoxLayout *vbox = new QVBoxLayout(this); 0070 vbox->setContentsMargins(0, 0, 0, 0); 0071 vbox->addWidget(configWidget); 0072 } 0073 0074 void CSSConfig::load() 0075 { 0076 QSignalBlocker block(customDialog); 0077 0078 KConfig *c = new KConfig(QStringLiteral("kcmcssrc"), KConfig::NoGlobals); 0079 KConfigGroup group = c->group("Stylesheet"); 0080 QString u = group.readEntry("Use", "default"); 0081 configWidget->useDefault->setChecked(u == QLatin1String("default")); 0082 configWidget->useUser->setChecked(u == QLatin1String("user")); 0083 configWidget->useAccess->setChecked(u == QLatin1String("access")); 0084 configWidget->urlRequester->setUrl(QUrl::fromUserInput(group.readEntry("SheetName"))); 0085 0086 group = c->group("Font"); 0087 customDialog->basefontsize->setEditText(QString::number(group.readEntry("BaseSize", 12))); 0088 customDialog->dontScale->setChecked(group.readEntry("DontScale", false)); 0089 0090 const QString fname(group.readEntry("Family", "Arial")); 0091 for (int i = 0; i < customDialog->fontFamily->count(); ++i) { 0092 if (customDialog->fontFamily->itemText(i) == fname) { 0093 customDialog->fontFamily->setCurrentIndex(i); 0094 break; 0095 } 0096 } 0097 0098 customDialog->sameFamily->setChecked(group.readEntry("SameFamily", false)); 0099 0100 group = c->group("Colors"); 0101 QString m = group.readEntry("Mode", "black-on-white"); 0102 customDialog->blackOnWhite->setChecked(m == QLatin1String("black-on-white")); 0103 customDialog->whiteOnBlack->setChecked(m == QLatin1String("white-on-black")); 0104 customDialog->customColor->setChecked(m == QLatin1String("custom")); 0105 0106 QColor white(Qt::white); 0107 QColor black(Qt::black); 0108 customDialog->backgroundColorButton->setColor(group.readEntry("BackColor", white)); 0109 customDialog->foregroundColorButton->setColor(group.readEntry("ForeColor", black)); 0110 customDialog->sameColor->setChecked(group.readEntry("SameColor", false)); 0111 0112 // Images 0113 group = c->group("Images"); 0114 customDialog->hideImages->setChecked(group.readEntry("Hide", false)); 0115 customDialog->hideBackground->setChecked(group.readEntry("HideBackground", true)); 0116 0117 delete c; 0118 } 0119 0120 void CSSConfig::save() 0121 { 0122 // write to config file 0123 KConfig *c = new KConfig(QStringLiteral("kcmcssrc"), KConfig::NoGlobals); 0124 KConfigGroup group = c->group("Stylesheet"); 0125 if (configWidget->useDefault->isChecked()) { 0126 group.writeEntry("Use", "default"); 0127 } 0128 if (configWidget->useUser->isChecked()) { 0129 group.writeEntry("Use", "user"); 0130 } 0131 if (configWidget->useAccess->isChecked()) { 0132 group.writeEntry("Use", "access"); 0133 } 0134 group.writeEntry("SheetName", configWidget->urlRequester->url().url()); 0135 0136 group = c->group("Font"); 0137 group.writeEntry("BaseSize", customDialog->basefontsize->currentText()); 0138 group.writeEntry("DontScale", customDialog->dontScale->isChecked()); 0139 group.writeEntry("SameFamily", customDialog->sameFamily->isChecked()); 0140 group.writeEntry("Family", customDialog->fontFamily->currentText()); 0141 0142 group = c->group("Colors"); 0143 if (customDialog->blackOnWhite->isChecked()) { 0144 group.writeEntry("Mode", "black-on-white"); 0145 } 0146 if (customDialog->whiteOnBlack->isChecked()) { 0147 group.writeEntry("Mode", "white-on-black"); 0148 } 0149 if (customDialog->customColor->isChecked()) { 0150 group.writeEntry("Mode", "custom"); 0151 } 0152 group.writeEntry("BackColor", customDialog->backgroundColorButton->color()); 0153 group.writeEntry("ForeColor", customDialog->foregroundColorButton->color()); 0154 group.writeEntry("SameColor", customDialog->sameColor->isChecked()); 0155 0156 group = c->group("Images"); 0157 group.writeEntry("Hide", customDialog->hideImages->isChecked()); 0158 group.writeEntry("HideBackground", customDialog->hideBackground->isChecked()); 0159 0160 c->sync(); 0161 delete c; 0162 0163 // generate CSS template 0164 QString dest; 0165 const QString templ(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kcmcss/template.css"))); 0166 if (!templ.isEmpty()) { 0167 CSSTemplate css(templ); 0168 dest = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kcmcss/"; 0169 QDir().mkpath(dest); 0170 dest += QLatin1String("override.css"); 0171 css.expandToFile(dest, customDialog->cssDict()); 0172 } 0173 0174 // make konqueror use the right stylesheet 0175 c = new KConfig(QStringLiteral("konquerorrc"), KConfig::NoGlobals); 0176 group = c->group("HTML Settings"); 0177 group.writeEntry("UserStyleSheetEnabled", !configWidget->useDefault->isChecked()); 0178 0179 if (configWidget->useUser->isChecked()) { 0180 group.writeEntry("UserStyleSheet", configWidget->urlRequester->url().url()); 0181 } 0182 if (configWidget->useAccess->isChecked()) { 0183 group.writeEntry("UserStyleSheet", dest); 0184 } 0185 0186 c->sync(); 0187 delete c; 0188 } 0189 0190 void CSSConfig::defaults() 0191 { 0192 configWidget->useDefault->setChecked(true); 0193 configWidget->useUser->setChecked(false); 0194 configWidget->useAccess->setChecked(false); 0195 configWidget->urlRequester->setUrl(QUrl()); 0196 0197 customDialog->basefontsize->setEditText(QString::number(12)); 0198 customDialog->dontScale->setChecked(false); 0199 0200 const QString fname(QStringLiteral("Arial")); 0201 for (int i = 0; i < customDialog->fontFamily->count(); ++i) { 0202 if (customDialog->fontFamily->itemText(i) == fname) { 0203 customDialog->fontFamily->setCurrentIndex(i); 0204 break; 0205 } 0206 } 0207 0208 customDialog->sameFamily->setChecked(false); 0209 customDialog->blackOnWhite->setChecked(true); 0210 customDialog->whiteOnBlack->setChecked(false); 0211 customDialog->customColor->setChecked(false); 0212 customDialog->backgroundColorButton->setColor(Qt::white); 0213 customDialog->foregroundColorButton->setColor(Qt::black); 0214 customDialog->sameColor->setChecked(false); 0215 0216 customDialog->hideImages->setChecked(false); 0217 customDialog->hideBackground->setChecked(true); 0218 } 0219 0220 static QString px(int i, double scale) 0221 { 0222 QString px; 0223 px.setNum(static_cast<int>(i * scale)); 0224 px += QLatin1String("px"); 0225 return px; 0226 } 0227 0228 QMap<QString, QString> CSSCustomDialog::cssDict() 0229 { 0230 QMap<QString, QString> dict; 0231 0232 // Fontsizes ------------------------------------------------------ 0233 0234 int bfs = basefontsize->currentText().toInt(); 0235 dict.insert(QStringLiteral("fontsize-base"), px(bfs, 1.0)); 0236 0237 if (dontScale->isChecked()) { 0238 dict.insert(QStringLiteral("fontsize-small-1"), px(bfs, 1.0)); 0239 dict.insert(QStringLiteral("fontsize-large-1"), px(bfs, 1.0)); 0240 dict.insert(QStringLiteral("fontsize-large-2"), px(bfs, 1.0)); 0241 dict.insert(QStringLiteral("fontsize-large-3"), px(bfs, 1.0)); 0242 dict.insert(QStringLiteral("fontsize-large-4"), px(bfs, 1.0)); 0243 dict.insert(QStringLiteral("fontsize-large-5"), px(bfs, 1.0)); 0244 } else { 0245 // TODO: use something harmonic here 0246 dict.insert(QStringLiteral("fontsize-small-1"), px(bfs, 0.8)); 0247 dict.insert(QStringLiteral("fontsize-large-1"), px(bfs, 1.2)); 0248 dict.insert(QStringLiteral("fontsize-large-2"), px(bfs, 1.4)); 0249 dict.insert(QStringLiteral("fontsize-large-3"), px(bfs, 1.5)); 0250 dict.insert(QStringLiteral("fontsize-large-4"), px(bfs, 1.6)); 0251 dict.insert(QStringLiteral("fontsize-large-5"), px(bfs, 1.8)); 0252 } 0253 0254 // Colors -------------------------------------------------------- 0255 0256 if (customColor->isChecked()) { 0257 dict.insert(QStringLiteral("background-color"), backgroundColorButton->color().name()); 0258 dict.insert(QStringLiteral("foreground-color"), foregroundColorButton->color().name()); 0259 } else { 0260 const char *blackOnWhiteFG[2] = {"White", "Black"}; 0261 bool bw = blackOnWhite->isChecked(); 0262 dict.insert(QStringLiteral("foreground-color"), QLatin1String(blackOnWhiteFG[bw])); 0263 dict.insert(QStringLiteral("background-color"), QLatin1String(blackOnWhiteFG[!bw])); 0264 } 0265 0266 const char *notImportant[2] = {"", "! important"}; 0267 dict.insert(QStringLiteral("force-color"), QLatin1String(notImportant[sameColor->isChecked()])); 0268 0269 // Fonts ------------------------------------------------------------- 0270 dict.insert(QStringLiteral("font-family"), fontFamily->currentText()); 0271 dict.insert(QStringLiteral("force-font"), QLatin1String(notImportant[sameFamily->isChecked()])); 0272 0273 // Images 0274 0275 const char *bgNoneImportant[2] = {"", "background-image : none ! important"}; 0276 dict.insert(QStringLiteral("display-images"), QLatin1String(bgNoneImportant[hideImages->isChecked()])); 0277 dict.insert(QStringLiteral("display-background"), QLatin1String(bgNoneImportant[hideBackground->isChecked()])); 0278 0279 return dict; 0280 } 0281 0282 void CSSConfig::slotCustomize() 0283 { 0284 customDialog->slotPreview(); 0285 customDialogBase->exec(); 0286 } 0287 0288 CSSCustomDialog::CSSCustomDialog(QWidget *parent) 0289 : QWidget(parent) 0290 { 0291 setupUi(this); 0292 connect(this, &CSSCustomDialog::changed, this, &CSSCustomDialog::slotPreview); 0293 0294 connect(basefontsize, QOverload<int>::of(&QComboBox::activated), this, &CSSCustomDialog::changed); 0295 connect(basefontsize, &QComboBox::editTextChanged, this, &CSSCustomDialog::changed); 0296 connect(dontScale, &QAbstractButton::clicked, this, &CSSCustomDialog::changed); 0297 connect(blackOnWhite, &QAbstractButton::clicked, this, &CSSCustomDialog::changed); 0298 connect(whiteOnBlack, &QAbstractButton::clicked, this, &CSSCustomDialog::changed); 0299 connect(customColor, &QAbstractButton::clicked, this, &CSSCustomDialog::changed); 0300 connect(foregroundColorButton, &KColorButton::changed, this, &CSSCustomDialog::changed); 0301 connect(backgroundColorButton, &KColorButton::changed, this, &CSSCustomDialog::changed); 0302 connect(fontFamily, QOverload<int>::of(&QComboBox::activated), this, &CSSCustomDialog::changed); 0303 connect(fontFamily, &QComboBox::editTextChanged, this, &CSSCustomDialog::changed); 0304 connect(sameFamily, &QAbstractButton::clicked, this, &CSSCustomDialog::changed); 0305 connect(sameColor, &QAbstractButton::clicked, this, &CSSCustomDialog::changed); 0306 connect(hideImages, &QAbstractButton::clicked, this, &CSSCustomDialog::changed); 0307 connect(hideBackground, &QAbstractButton::clicked, this, &CSSCustomDialog::changed); 0308 0309 //QStringList fonts; 0310 //KFontChooser::getFontList(fonts, 0); 0311 //fontFamily->addItems(fonts); 0312 part = KParts::PartLoader::instantiatePartForMimeType<KParts::ReadOnlyPart>(QStringLiteral("text/html"), nullptr, this).plugin; 0313 QVBoxLayout *l = new QVBoxLayout(previewBox); 0314 l->addWidget(part->widget()); 0315 } 0316 0317 static QUrl toDataUri(const QString &content, const QByteArray &contentType) 0318 { 0319 QByteArray data("data:"); 0320 data += contentType; 0321 data += ";charset=utf-8;base64,"; 0322 data += content.toUtf8().toBase64(); 0323 return QUrl::fromEncoded(data); 0324 } 0325 0326 void CSSCustomDialog::slotPreview() 0327 { 0328 const QString templ(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kcmcss/template.css"))); 0329 0330 if (templ.isEmpty()) { 0331 return; 0332 } 0333 0334 CSSTemplate css(templ); 0335 0336 QString data(i18n("<html>\n<head>\n<style>\n<!--\n" 0337 "%1" 0338 "\n-->\n</style>\n</head>\n" 0339 "<body>\n" 0340 "<h1>Heading 1</h1>\n" 0341 "<h2>Heading 2</h2>\n" 0342 "<h3>Heading 3</h3>\n" 0343 "\n" 0344 "<p>User-defined stylesheets allow increased\n" 0345 "accessibility for visually handicapped\n" 0346 "people.</p>\n" 0347 "\n" 0348 "</body>\n" 0349 "</html>\n", css.expandToString(cssDict()))); 0350 0351 KParts::OpenUrlArguments args(part->arguments()); 0352 args.setReload(true); // Make sure the content is always freshly reloaded. 0353 part->setArguments(args); 0354 part->openUrl(toDataUri(data, "text/html")); 0355 } 0356