File indexing completed on 2024-04-28 05:27:03
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> 0023 #include <KConfigGroup> 0024 #include <KIconButton> 0025 #include <KIconDialog> 0026 #include <KLineEdit> 0027 #include <KLocalizedString> 0028 #include <KSharedConfig> 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 connect(serviceListWidget, &KServiceListWidget::multiApply, this, &FileTypeDetails::multiApply); 0123 firstLayout->addWidget(serviceListWidget, 5); 0124 0125 // Second tab - Embedding 0126 QWidget *secondWidget = new QWidget(m_tabWidget); 0127 QVBoxLayout *secondLayout = new QVBoxLayout(secondWidget); 0128 0129 m_autoEmbedBox = new QGroupBox(i18n("Left Click Action in Konqueror"), secondWidget); 0130 secondLayout->addWidget(m_autoEmbedBox); 0131 0132 m_autoEmbedBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); 0133 0134 QRadioButton *embViewerRadio = new QRadioButton(i18n("Show file in embedded viewer")); 0135 QRadioButton *sepViewerRadio = new QRadioButton(i18n("Show file in separate viewer")); 0136 m_rbGroupSettings = new QRadioButton(QStringLiteral("Use settings for '%1' group")); 0137 0138 m_chkAskSave = new QCheckBox(i18n("Ask whether to save to disk instead (only for Konqueror browser)")); 0139 connect(m_chkAskSave, &QAbstractButton::toggled, this, &FileTypeDetails::slotAskSaveToggled); 0140 0141 m_autoEmbedGroup = new QButtonGroup(m_autoEmbedBox); 0142 m_autoEmbedGroup->addButton(embViewerRadio, 0); 0143 m_autoEmbedGroup->addButton(sepViewerRadio, 1); 0144 m_autoEmbedGroup->addButton(m_rbGroupSettings, 2); 0145 connect(m_autoEmbedGroup, &QButtonGroup::idClicked, this, &FileTypeDetails::slotAutoEmbedClicked); 0146 0147 vbox = new QVBoxLayout(m_autoEmbedBox); 0148 vbox->addWidget(embViewerRadio); 0149 vbox->addWidget(sepViewerRadio); 0150 vbox->addWidget(m_rbGroupSettings); 0151 vbox->addWidget(m_chkAskSave); 0152 0153 m_autoEmbedBox->setWhatsThis( 0154 i18n("Here you can configure what the Konqueror file manager" 0155 " will do when you click on a file of this type. Konqueror can either display the file in" 0156 " an embedded viewer, or start up a separate application. If set to 'Use settings for G group'," 0157 " the file manager will behave according to the settings of the group G to which this type belongs;" 0158 " for instance, 'image' if the current file type is image/png. Dolphin" 0159 " always shows files in a separate viewer.")); 0160 0161 embedServiceListWidget = new KServiceListWidget(KServiceListWidget::SERVICELIST_SERVICES, secondWidget); 0162 // embedServiceListWidget->setMinimumHeight( serviceListWidget->sizeHint().height() ); 0163 connect(embedServiceListWidget, &KServiceListWidget::changed, this, &FileTypeDetails::changed); 0164 connect(embedServiceListWidget, &KServiceListWidget::multiApply, this, &FileTypeDetails::multiApply); 0165 secondLayout->addWidget(embedServiceListWidget); 0166 0167 m_tabWidget->addTab(firstWidget, i18n("&General")); 0168 m_tabWidget->addTab(secondWidget, i18n("&Embedding")); 0169 } 0170 0171 void FileTypeDetails::updateRemoveButton() 0172 { 0173 removeExtButton->setEnabled(extensionLB->count() > 0); 0174 } 0175 0176 void FileTypeDetails::updateIcon(const QString &icon) 0177 { 0178 if (!m_mimeTypeData) { 0179 return; 0180 } 0181 0182 m_mimeTypeData->setUserSpecifiedIcon(icon); 0183 0184 if (m_item) { 0185 m_item->setIcon(icon); 0186 } 0187 0188 Q_EMIT changed(true); 0189 } 0190 0191 void FileTypeDetails::updateDescription(const QString &desc) 0192 { 0193 if (!m_mimeTypeData) { 0194 return; 0195 } 0196 0197 m_mimeTypeData->setComment(desc); 0198 0199 Q_EMIT changed(true); 0200 } 0201 0202 void FileTypeDetails::addExtension() 0203 { 0204 if (!m_mimeTypeData) { 0205 return; 0206 } 0207 0208 bool ok; 0209 QString ext = QInputDialog::getText(this, i18n("Add New Extension"), i18n("Extension:"), QLineEdit::Normal, QStringLiteral("*."), &ok); 0210 if (ok) { 0211 extensionLB->addItem(ext); 0212 QStringList patt = m_mimeTypeData->patterns(); 0213 patt += ext; 0214 m_mimeTypeData->setPatterns(patt); 0215 updateRemoveButton(); 0216 Q_EMIT changed(true); 0217 } 0218 } 0219 0220 void FileTypeDetails::removeExtension() 0221 { 0222 if (extensionLB->currentRow() == -1) { 0223 return; 0224 } 0225 if (!m_mimeTypeData) { 0226 return; 0227 } 0228 QStringList patt = m_mimeTypeData->patterns(); 0229 patt.removeAll(extensionLB->currentItem()->text()); 0230 m_mimeTypeData->setPatterns(patt); 0231 delete extensionLB->takeItem(extensionLB->currentRow()); 0232 updateRemoveButton(); 0233 Q_EMIT changed(true); 0234 } 0235 0236 void FileTypeDetails::slotAutoEmbedClicked(int button) 0237 { 0238 if (!m_mimeTypeData || (button > 2)) { 0239 return; 0240 } 0241 0242 m_mimeTypeData->setAutoEmbed((MimeTypeData::AutoEmbed)button); 0243 0244 updateAskSave(); 0245 0246 Q_EMIT changed(true); 0247 } 0248 0249 void FileTypeDetails::updateAskSave() 0250 { 0251 if (!m_mimeTypeData) { 0252 return; 0253 } 0254 QMimeDatabase db; 0255 0256 MimeTypeData::AutoEmbed autoEmbed = m_mimeTypeData->autoEmbed(); 0257 if (m_mimeTypeData->isMeta() && autoEmbed == MimeTypeData::UseGroupSetting) { 0258 // Resolve by looking at group (we could cache groups somewhere to avoid the re-parsing?) 0259 autoEmbed = MimeTypeData(m_mimeTypeData->majorType()).autoEmbed(); 0260 } 0261 0262 const QString mimeType = m_mimeTypeData->name(); 0263 0264 QString dontAskAgainName; 0265 if (autoEmbed == MimeTypeData::Yes) { // Embedded 0266 dontAskAgainName = QStringLiteral("askEmbedOrSave") + mimeType; 0267 } else { 0268 dontAskAgainName = QStringLiteral("askSave") + mimeType; 0269 } 0270 0271 KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("filetypesrc"), KConfig::NoGlobals); 0272 // default value 0273 bool ask = config->group("Notification Messages").readEntry(dontAskAgainName, QString()).isEmpty(); 0274 // per-mimetype override if there's one 0275 m_mimeTypeData->getAskSave(ask); 0276 0277 bool neverAsk = false; 0278 0279 if (autoEmbed == MimeTypeData::Yes) { 0280 const QMimeType mime = db.mimeTypeForName(mimeType); 0281 if (mime.isValid()) { 0282 // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC 0283 // NOTE: Keep this function in sync with 0284 // kparts/src/browseropenorsavequestion.cpp BrowserOpenOrSaveQuestionPrivate::autoEmbedMimeType 0285 0286 // Don't ask for: 0287 // - html (even new tabs would ask, due to about:blank!) 0288 // - dirs obviously (though not common over HTTP :), 0289 // - images (reasoning: no need to save, most of the time, because fast to see) 0290 // e.g. postscript is different, because takes longer to read, so 0291 // it's more likely that the user might want to save it. 0292 // - multipart/* ("server push", see kmultipart) 0293 // clang-format off 0294 if (mime.inherits(QStringLiteral("text/html")) 0295 || mime.inherits(QStringLiteral("application/xml")) 0296 || mime.inherits(QStringLiteral("inode/directory")) 0297 || mimeType.startsWith(QLatin1String("image")) 0298 || mime.inherits(QStringLiteral("multipart/x-mixed-replace")) 0299 || mime.inherits(QStringLiteral("multipart/replace"))) { 0300 neverAsk = true; 0301 } 0302 // clang-format on 0303 } 0304 } 0305 0306 m_chkAskSave->blockSignals(true); 0307 m_chkAskSave->setChecked(ask && !neverAsk); 0308 m_chkAskSave->setEnabled(!neverAsk); 0309 m_chkAskSave->blockSignals(false); 0310 } 0311 0312 void FileTypeDetails::slotAskSaveToggled(bool askSave) 0313 { 0314 if (!m_mimeTypeData) { 0315 return; 0316 } 0317 0318 m_mimeTypeData->setAskSave(askSave); 0319 Q_EMIT changed(true); 0320 } 0321 0322 void FileTypeDetails::setMimeTypeData(MimeTypeData *mimeTypeData, TypesListItem *item) 0323 { 0324 m_mimeTypeData = mimeTypeData; 0325 m_item = item; // can be 0 0326 Q_ASSERT(mimeTypeData); 0327 m_mimeTypeLabel->setText(i18n("File type %1", mimeTypeData->name())); 0328 if (iconButton) { 0329 iconButton->setIcon(mimeTypeData->icon()); 0330 iconButton->setToolTip(mimeTypeData->icon()); 0331 } else { 0332 iconLabel->setPixmap(QIcon::fromTheme(mimeTypeData->icon()).pixmap(KIconLoader::SizeLarge)); 0333 } 0334 description->setText(mimeTypeData->comment()); 0335 m_rbGroupSettings->setText(i18n("Use settings for '%1' group", mimeTypeData->majorType())); 0336 extensionLB->clear(); 0337 addExtButton->setEnabled(true); 0338 removeExtButton->setEnabled(false); 0339 0340 serviceListWidget->setMimeTypeData(mimeTypeData); 0341 embedServiceListWidget->setMimeTypeData(mimeTypeData); 0342 m_autoEmbedGroup->button(mimeTypeData->autoEmbed())->setChecked(true); 0343 m_rbGroupSettings->setEnabled(mimeTypeData->canUseGroupSetting()); 0344 0345 extensionLB->addItems(mimeTypeData->patterns()); 0346 0347 updateAskSave(); 0348 } 0349 0350 void FileTypeDetails::enableExtButtons() 0351 { 0352 removeExtButton->setEnabled(true); 0353 } 0354 0355 void FileTypeDetails::refresh() 0356 { 0357 if (!m_mimeTypeData) { 0358 return; 0359 } 0360 0361 // Called when ksycoca has been updated -> refresh data, then widgets 0362 m_mimeTypeData->refresh(); 0363 setMimeTypeData(m_mimeTypeData, m_item); 0364 } 0365 0366 void FileTypeDetails::allowMultiApply(bool allow) 0367 { 0368 serviceListWidget->allowMultiApply(allow); 0369 embedServiceListWidget->allowMultiApply(allow); 0370 } 0371 0372 #include "moc_filetypedetails.cpp"