File indexing completed on 2024-04-28 16:44:25
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2000, 2007 David Faure <faure@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only 0005 */ 0006 0007 // Own 0008 #include "filetypedetails.h" 0009 0010 // Qt 0011 #include <QButtonGroup> 0012 #include <QCheckBox> 0013 #include <QInputDialog> 0014 #include <QLabel> 0015 #include <QListWidget> 0016 #include <QMimeDatabase> 0017 #include <QPushButton> 0018 #include <QRadioButton> 0019 #include <QVBoxLayout> 0020 0021 // KDE 0022 #include <kconfig.h> 0023 #include <kconfiggroup.h> 0024 #include <kiconbutton.h> 0025 #include <kicondialog.h> 0026 #include <klineedit.h> 0027 #include <klocalizedstring.h> 0028 #include <ksharedconfig.h> 0029 0030 // Local 0031 #include "kservicelistwidget.h" 0032 #include "typeslistitem.h" 0033 0034 FileTypeDetails::FileTypeDetails(QWidget *parent) 0035 : QWidget(parent) 0036 , m_mimeTypeData(nullptr) 0037 , m_item(nullptr) 0038 { 0039 QVBoxLayout *topLayout = new QVBoxLayout(this); 0040 topLayout->setContentsMargins(0, 0, 0, 0); 0041 0042 m_mimeTypeLabel = new QLabel(this); 0043 m_mimeTypeLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); 0044 topLayout->addWidget(m_mimeTypeLabel, 0, Qt::AlignCenter); 0045 0046 m_tabWidget = new QTabWidget(this); 0047 topLayout->addWidget(m_tabWidget); 0048 0049 QString wtstr; 0050 // First tab - General 0051 QWidget *firstWidget = new QWidget(m_tabWidget); 0052 QVBoxLayout *firstLayout = new QVBoxLayout(firstWidget); 0053 0054 QHBoxLayout *hBox = new QHBoxLayout(); 0055 firstLayout->addLayout(hBox); 0056 0057 iconButton = new KIconButton(firstWidget); 0058 iconButton->setIconType(KIconLoader::Desktop, KIconLoader::MimeType); 0059 connect(iconButton, &KIconButton::iconChanged, this, &FileTypeDetails::updateIcon); 0060 iconButton->setWhatsThis( 0061 i18n("This button displays the icon associated" 0062 " with the selected file type. Click on it to choose a different icon.")); 0063 iconButton->setFixedSize(70, 70); 0064 iconLabel = nullptr; 0065 hBox->addWidget(iconButton); 0066 0067 QGroupBox *gb = new QGroupBox(i18n("Filename Patterns"), firstWidget); 0068 hBox->addWidget(gb); 0069 0070 hBox = new QHBoxLayout(gb); 0071 0072 extensionLB = new QListWidget(gb); 0073 connect(extensionLB, &QListWidget::itemSelectionChanged, this, &FileTypeDetails::enableExtButtons); 0074 hBox->addWidget(extensionLB); 0075 0076 extensionLB->setFixedHeight(extensionLB->minimumSizeHint().height()); 0077 0078 extensionLB->setWhatsThis( 0079 i18n("This box contains a list of patterns that can be" 0080 " used to identify files of the selected type. For example, the pattern *.txt is" 0081 " associated with the file type 'text/plain'; all files ending in '.txt' are recognized" 0082 " as plain text files.")); 0083 0084 QVBoxLayout *vbox = new QVBoxLayout(); 0085 hBox->addLayout(vbox); 0086 0087 addExtButton = new QPushButton(i18n("Add..."), gb); 0088 addExtButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); 0089 addExtButton->setEnabled(false); 0090 connect(addExtButton, &QAbstractButton::clicked, this, &FileTypeDetails::addExtension); 0091 vbox->addWidget(addExtButton); 0092 addExtButton->setWhatsThis(i18n("Add a new pattern for the selected file type.")); 0093 0094 removeExtButton = new QPushButton(i18n("Remove"), gb); 0095 removeExtButton->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); 0096 removeExtButton->setEnabled(false); 0097 connect(removeExtButton, &QAbstractButton::clicked, this, &FileTypeDetails::removeExtension); 0098 vbox->addWidget(removeExtButton); 0099 removeExtButton->setWhatsThis(i18n("Remove the selected filename pattern.")); 0100 0101 vbox->addStretch(1); 0102 0103 gb->setFixedHeight(gb->minimumSizeHint().height()); 0104 0105 description = new KLineEdit(firstWidget); 0106 description->setClearButtonEnabled(true); 0107 connect(description, &QLineEdit::textChanged, this, &FileTypeDetails::updateDescription); 0108 0109 QHBoxLayout *descriptionBox = new QHBoxLayout; 0110 descriptionBox->addWidget(new QLabel(i18n("Description:"), firstWidget)); 0111 descriptionBox->addWidget(description); 0112 firstLayout->addLayout(descriptionBox); 0113 0114 wtstr = i18n( 0115 "You can enter a short description for files of the selected" 0116 " file type (e.g. 'HTML Page'). This description will be used by applications" 0117 " like Konqueror to display directory content."); 0118 description->setWhatsThis(wtstr); 0119 0120 serviceListWidget = new KServiceListWidget(KServiceListWidget::SERVICELIST_APPLICATIONS, firstWidget); 0121 connect(serviceListWidget, &KServiceListWidget::changed, this, &FileTypeDetails::changed); 0122 firstLayout->addWidget(serviceListWidget, 5); 0123 0124 // Second tab - Embedding 0125 QWidget *secondWidget = new QWidget(m_tabWidget); 0126 QVBoxLayout *secondLayout = new QVBoxLayout(secondWidget); 0127 0128 m_autoEmbedBox = new QGroupBox(i18n("Left Click Action in Konqueror"), secondWidget); 0129 secondLayout->addWidget(m_autoEmbedBox); 0130 0131 m_autoEmbedBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); 0132 0133 QRadioButton *embViewerRadio = new QRadioButton(i18n("Show file in embedded viewer")); 0134 QRadioButton *sepViewerRadio = new QRadioButton(i18n("Show file in separate viewer")); 0135 m_rbGroupSettings = new QRadioButton(QStringLiteral("Use settings for '%1' group")); 0136 0137 m_chkAskSave = new QCheckBox(i18n("Ask whether to save to disk instead (only for Konqueror browser)")); 0138 connect(m_chkAskSave, &QAbstractButton::toggled, this, &FileTypeDetails::slotAskSaveToggled); 0139 0140 m_autoEmbedGroup = new QButtonGroup(m_autoEmbedBox); 0141 m_autoEmbedGroup->addButton(embViewerRadio, 0); 0142 m_autoEmbedGroup->addButton(sepViewerRadio, 1); 0143 m_autoEmbedGroup->addButton(m_rbGroupSettings, 2); 0144 connect(m_autoEmbedGroup, SIGNAL(buttonClicked(int)), SLOT(slotAutoEmbedClicked(int))); 0145 0146 vbox = new QVBoxLayout(m_autoEmbedBox); 0147 vbox->addWidget(embViewerRadio); 0148 vbox->addWidget(sepViewerRadio); 0149 vbox->addWidget(m_rbGroupSettings); 0150 vbox->addWidget(m_chkAskSave); 0151 0152 m_autoEmbedBox->setWhatsThis( 0153 i18n("Here you can configure what the Konqueror file manager" 0154 " will do when you click on a file of this type. Konqueror can either display the file in" 0155 " an embedded viewer, or start up a separate application. If set to 'Use settings for G group'," 0156 " the file manager will behave according to the settings of the group G to which this type belongs;" 0157 " for instance, 'image' if the current file type is image/png. Dolphin" 0158 " always shows files in a separate viewer.")); 0159 0160 embedServiceListWidget = new KServiceListWidget(KServiceListWidget::SERVICELIST_SERVICES, secondWidget); 0161 // embedServiceListWidget->setMinimumHeight( serviceListWidget->sizeHint().height() ); 0162 connect(embedServiceListWidget, &KServiceListWidget::changed, this, &FileTypeDetails::changed); 0163 secondLayout->addWidget(embedServiceListWidget); 0164 0165 m_tabWidget->addTab(firstWidget, i18n("&General")); 0166 m_tabWidget->addTab(secondWidget, i18n("&Embedding")); 0167 } 0168 0169 void FileTypeDetails::updateRemoveButton() 0170 { 0171 removeExtButton->setEnabled(extensionLB->count() > 0); 0172 } 0173 0174 void FileTypeDetails::updateIcon(const QString &icon) 0175 { 0176 if (!m_mimeTypeData) { 0177 return; 0178 } 0179 0180 m_mimeTypeData->setUserSpecifiedIcon(icon); 0181 0182 if (m_item) { 0183 m_item->setIcon(icon); 0184 } 0185 0186 Q_EMIT changed(true); 0187 } 0188 0189 void FileTypeDetails::updateDescription(const QString &desc) 0190 { 0191 if (!m_mimeTypeData) { 0192 return; 0193 } 0194 0195 m_mimeTypeData->setComment(desc); 0196 0197 Q_EMIT changed(true); 0198 } 0199 0200 void FileTypeDetails::addExtension() 0201 { 0202 if (!m_mimeTypeData) { 0203 return; 0204 } 0205 0206 bool ok; 0207 QString ext = QInputDialog::getText(this, i18n("Add New Extension"), i18n("Extension:"), QLineEdit::Normal, QStringLiteral("*."), &ok); 0208 if (ok) { 0209 extensionLB->addItem(ext); 0210 QStringList patt = m_mimeTypeData->patterns(); 0211 patt += ext; 0212 m_mimeTypeData->setPatterns(patt); 0213 updateRemoveButton(); 0214 Q_EMIT changed(true); 0215 } 0216 } 0217 0218 void FileTypeDetails::removeExtension() 0219 { 0220 if (extensionLB->currentRow() == -1) { 0221 return; 0222 } 0223 if (!m_mimeTypeData) { 0224 return; 0225 } 0226 QStringList patt = m_mimeTypeData->patterns(); 0227 patt.removeAll(extensionLB->currentItem()->text()); 0228 m_mimeTypeData->setPatterns(patt); 0229 delete extensionLB->takeItem(extensionLB->currentRow()); 0230 updateRemoveButton(); 0231 Q_EMIT changed(true); 0232 } 0233 0234 void FileTypeDetails::slotAutoEmbedClicked(int button) 0235 { 0236 if (!m_mimeTypeData || (button > 2)) { 0237 return; 0238 } 0239 0240 m_mimeTypeData->setAutoEmbed((MimeTypeData::AutoEmbed)button); 0241 0242 updateAskSave(); 0243 0244 Q_EMIT changed(true); 0245 } 0246 0247 void FileTypeDetails::updateAskSave() 0248 { 0249 if (!m_mimeTypeData) { 0250 return; 0251 } 0252 QMimeDatabase db; 0253 0254 MimeTypeData::AutoEmbed autoEmbed = m_mimeTypeData->autoEmbed(); 0255 if (m_mimeTypeData->isMeta() && autoEmbed == MimeTypeData::UseGroupSetting) { 0256 // Resolve by looking at group (we could cache groups somewhere to avoid the re-parsing?) 0257 autoEmbed = MimeTypeData(m_mimeTypeData->majorType()).autoEmbed(); 0258 } 0259 0260 const QString mimeType = m_mimeTypeData->name(); 0261 0262 QString dontAskAgainName; 0263 if (autoEmbed == MimeTypeData::Yes) { // Embedded 0264 dontAskAgainName = QStringLiteral("askEmbedOrSave") + mimeType; 0265 } else { 0266 dontAskAgainName = QStringLiteral("askSave") + mimeType; 0267 } 0268 0269 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("filetypesrc"), KConfig::NoGlobals); 0270 // default value 0271 bool ask = config->group("Notification Messages").readEntry(dontAskAgainName, QString()).isEmpty(); 0272 // per-mimetype override if there's one 0273 m_mimeTypeData->getAskSave(ask); 0274 0275 bool neverAsk = false; 0276 0277 if (autoEmbed == MimeTypeData::Yes) { 0278 const QMimeType mime = db.mimeTypeForName(mimeType); 0279 if (mime.isValid()) { 0280 // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC 0281 // NOTE: Keep this function in sync with 0282 // kparts/src/browseropenorsavequestion.cpp BrowserOpenOrSaveQuestionPrivate::autoEmbedMimeType 0283 0284 // Don't ask for: 0285 // - html (even new tabs would ask, due to about:blank!) 0286 // - dirs obviously (though not common over HTTP :), 0287 // - images (reasoning: no need to save, most of the time, because fast to see) 0288 // e.g. postscript is different, because takes longer to read, so 0289 // it's more likely that the user might want to save it. 0290 // - multipart/* ("server push", see kmultipart) 0291 // clang-format off 0292 if (mime.inherits(QStringLiteral("text/html")) 0293 || mime.inherits(QStringLiteral("application/xml")) 0294 || mime.inherits(QStringLiteral("inode/directory")) 0295 || mimeType.startsWith(QLatin1String("image")) 0296 || mime.inherits(QStringLiteral("multipart/x-mixed-replace")) 0297 || mime.inherits(QStringLiteral("multipart/replace"))) { 0298 neverAsk = true; 0299 } 0300 // clang-format on 0301 } 0302 } 0303 0304 m_chkAskSave->blockSignals(true); 0305 m_chkAskSave->setChecked(ask && !neverAsk); 0306 m_chkAskSave->setEnabled(!neverAsk); 0307 m_chkAskSave->blockSignals(false); 0308 } 0309 0310 void FileTypeDetails::slotAskSaveToggled(bool askSave) 0311 { 0312 if (!m_mimeTypeData) { 0313 return; 0314 } 0315 0316 m_mimeTypeData->setAskSave(askSave); 0317 Q_EMIT changed(true); 0318 } 0319 0320 void FileTypeDetails::setMimeTypeData(MimeTypeData *mimeTypeData, TypesListItem *item) 0321 { 0322 m_mimeTypeData = mimeTypeData; 0323 m_item = item; // can be 0 0324 Q_ASSERT(mimeTypeData); 0325 m_mimeTypeLabel->setText(i18n("File type %1", mimeTypeData->name())); 0326 if (iconButton) { 0327 iconButton->setIcon(mimeTypeData->icon()); 0328 iconButton->setToolTip(mimeTypeData->icon()); 0329 } else { 0330 iconLabel->setPixmap(QIcon::fromTheme(mimeTypeData->icon()).pixmap(KIconLoader::SizeLarge)); 0331 } 0332 description->setText(mimeTypeData->comment()); 0333 m_rbGroupSettings->setText(i18n("Use settings for '%1' group", mimeTypeData->majorType())); 0334 extensionLB->clear(); 0335 addExtButton->setEnabled(true); 0336 removeExtButton->setEnabled(false); 0337 0338 serviceListWidget->setMimeTypeData(mimeTypeData); 0339 embedServiceListWidget->setMimeTypeData(mimeTypeData); 0340 m_autoEmbedGroup->button(mimeTypeData->autoEmbed())->setChecked(true); 0341 m_rbGroupSettings->setEnabled(mimeTypeData->canUseGroupSetting()); 0342 0343 extensionLB->addItems(mimeTypeData->patterns()); 0344 0345 updateAskSave(); 0346 } 0347 0348 void FileTypeDetails::enableExtButtons() 0349 { 0350 removeExtButton->setEnabled(true); 0351 } 0352 0353 void FileTypeDetails::refresh() 0354 { 0355 if (!m_mimeTypeData) { 0356 return; 0357 } 0358 0359 // Called when ksycoca has been updated -> refresh data, then widgets 0360 m_mimeTypeData->refresh(); 0361 setMimeTypeData(m_mimeTypeData, m_item); 0362 }