File indexing completed on 2024-05-05 05:45:46
0001 /* 0002 SPDX-FileCopyrightText: 2001-2005, 2009 Otto Bruggeman <bruggie@gmail.com> 0003 SPDX-FileCopyrightText: 2001-2003 John Firebaugh <jfirebaugh@kde.org> 0004 SPDX-FileCopyrightText: 2004 Jeff Snyder <jeff@caffeinated.me.uk> 0005 SPDX-FileCopyrightText: 2007-2011 Kevin Kofler <kevin.kofler@chello.at> 0006 SPDX-FileCopyrightText: 2012 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "kompare_part.h" 0012 0013 #include <QDialog> 0014 #include <QLayout> 0015 #include <QWidget> 0016 #include <QMenu> 0017 #include <QPainter> 0018 #include <QPrinter> 0019 #include <QPageLayout> 0020 #include <QPrintDialog> 0021 #include <QPrintPreviewDialog> 0022 #include <QTemporaryDir> 0023 #include <QTemporaryFile> 0024 0025 #include <KPluginMetaData> 0026 #include <KActionCollection> 0027 #include <KJobWidgets> 0028 #include <KLocalizedString> 0029 #include <KMessageBox> 0030 #include <KSharedConfig> 0031 #include <KStandardAction> 0032 #include <KStandardShortcut> 0033 #include <KStandardGuiItem> 0034 #include <KXMLGUIFactory> 0035 0036 #include <KIO/CopyJob> 0037 #include <KIO/StatJob> 0038 #include <KIO/FileCopyJob> 0039 #include <KIO/MkdirJob> 0040 0041 #include <KompareDiff2/DiffModel> 0042 #include <KompareDiff2/DiffSettings> 0043 0044 #include <komparepartdebug.h> 0045 #include "komparelistview.h" 0046 #include "kompareconnectwidget.h" 0047 #include "viewsettings.h" 0048 #include "kompareprefdlg.h" 0049 #include "komparesaveoptionswidget.h" 0050 #include "komparesplitter.h" 0051 #include "kompareview.h" 0052 0053 using namespace KompareDiff2; 0054 0055 ViewSettings* KomparePart::m_viewSettings = nullptr; 0056 KompareDiff2::DiffSettings* KomparePart::m_diffSettings = nullptr; 0057 0058 KomparePart::KomparePart(QWidget* parentWidget, QObject* parent, const KPluginMetaData& metaData, Modus modus) : 0059 KParts::ReadWritePart(parent, metaData), 0060 m_info() 0061 { 0062 // set our XML-UI resource file 0063 setXMLFile(QStringLiteral("komparepartui.rc")); 0064 0065 if (!m_viewSettings) { 0066 m_viewSettings = new ViewSettings(nullptr); 0067 } 0068 if (!m_diffSettings) { 0069 m_diffSettings = new KompareDiff2::DiffSettings(); 0070 } 0071 0072 readProperties(KSharedConfig::openConfig().data()); 0073 0074 m_view = new KompareView(m_viewSettings, parentWidget); 0075 m_view->setContextMenuPolicy(Qt::CustomContextMenu); 0076 connect(m_view, &QWidget::customContextMenuRequested, 0077 this, &KomparePart::onContextMenuRequested); 0078 setWidget(m_view); 0079 m_splitter = m_view->splitter(); 0080 0081 // This creates the "Model creator" and connects the signals and slots 0082 m_modelList = new KompareDiff2::ModelList(m_diffSettings, this, (modus == ReadWriteModus)); 0083 0084 const auto modelListActions = m_modelList->actionCollection()->actions(); 0085 for (QAction* action : modelListActions) { 0086 actionCollection()->addAction(action->objectName(), action); 0087 } 0088 connect(m_modelList, &ModelList::status, 0089 this, &KomparePart::slotSetStatus); 0090 connect(m_modelList, &ModelList::setStatusBarModelInfo, 0091 this, &KomparePart::setStatusBarModelInfo); 0092 connect(m_modelList, &ModelList::error, 0093 this, &KomparePart::slotShowError); 0094 connect(m_modelList, &ModelList::applyAllDifferences, 0095 this, &KomparePart::updateActions); 0096 connect(m_modelList, static_cast<void(ModelList::*)(bool)>(&ModelList::applyDifference), 0097 this, &KomparePart::updateActions); 0098 connect(m_modelList, &ModelList::applyAllDifferences, 0099 this, &KomparePart::appliedChanged); 0100 connect(m_modelList, static_cast<void(ModelList::*)(bool)>(&ModelList::applyDifference), 0101 this, &KomparePart::appliedChanged); 0102 connect(m_modelList, &ModelList::updateActions, this, &KomparePart::updateActions); 0103 0104 // This is the stuff to connect the "interface" of the kompare part to the model inside 0105 connect(m_modelList, &ModelList::modelsChanged, 0106 this, &KomparePart::modelsChanged); 0107 0108 typedef void(ModelList::*void_ModelList_argModelDiff)(const DiffModel*, const Difference*); 0109 typedef void(ModelList::*void_ModelList_argDiffBool)(const Difference*, bool); 0110 typedef void(KompareSplitter::*void_KompareSplitter_argModelDiff)(const DiffModel*, const Difference*); 0111 typedef void(KompareSplitter::*void_KompareSplitter_argDiffBool)(const Difference*, bool); 0112 typedef void(KomparePart::*void_KomparePart_argModelDiff)(const DiffModel*, const Difference*); 0113 typedef void(KomparePart::*void_KomparePart_argDiffBool)(const Difference*, bool); 0114 connect(m_modelList, static_cast<void_ModelList_argModelDiff>(&ModelList::setSelection), 0115 this, static_cast<void_KomparePart_argModelDiff>(&KomparePart::setSelection)); 0116 connect(this, static_cast<void_KomparePart_argModelDiff>(&KomparePart::selectionChanged), 0117 m_modelList, static_cast<void_ModelList_argModelDiff>(&ModelList::slotSelectionChanged)); 0118 0119 connect(m_modelList, static_cast<void(ModelList::*)(const Difference*)>(&ModelList::setSelection), 0120 this, static_cast<void(KomparePart::*)(const Difference*)>(&KomparePart::setSelection)); 0121 connect(this, static_cast<void(KomparePart::*)(const Difference*)>(&KomparePart::selectionChanged), 0122 m_modelList, static_cast<void(ModelList::*)(const Difference*)>(&ModelList::slotSelectionChanged)); 0123 0124 connect(m_modelList, static_cast<void(ModelList::*)(bool)>(&ModelList::applyDifference), 0125 this, static_cast<void(KomparePart::*)(bool)>(&KomparePart::applyDifference)); 0126 connect(m_modelList, &ModelList::applyAllDifferences, 0127 this, &KomparePart::applyAllDifferences); 0128 connect(m_modelList, static_cast<void_ModelList_argDiffBool>(&ModelList::applyDifference), 0129 this, static_cast<void_KomparePart_argDiffBool>(&KomparePart::applyDifference)); 0130 connect(m_modelList, &ModelList::diffString, 0131 this, &KomparePart::diffString); 0132 0133 connect(this, &KomparePart::kompareInfo, m_modelList, &ModelList::slotKompareInfo); 0134 0135 // Here we connect the splitter to the modellist 0136 connect(m_modelList, static_cast<void_ModelList_argModelDiff>(&ModelList::setSelection), 0137 m_splitter, static_cast<void_KompareSplitter_argModelDiff>(&KompareSplitter::slotSetSelection)); 0138 // connect(m_splitter, SIGNAL(selectionChanged(const KompareDiff2::Difference*,const KompareDiff2::Difference*)), 0139 // m_modelList, SLOT(slotSelectionChanged(const KompareDiff2::Difference*,const KompareDiff2::Difference*))); 0140 connect(m_modelList, static_cast<void(ModelList::*)(const Difference*)>(&ModelList::setSelection), 0141 m_splitter, static_cast<void(KompareSplitter::*)(const Difference*)>(&KompareSplitter::slotSetSelection)); 0142 connect(m_splitter, static_cast<void(KompareSplitter::*)(const Difference*)>(&KompareSplitter::selectionChanged), 0143 m_modelList, static_cast<void(ModelList::*)(const Difference*)>(&ModelList::slotSelectionChanged)); 0144 0145 connect(m_modelList, static_cast<void(ModelList::*)(bool)>(&ModelList::applyDifference), 0146 m_splitter, static_cast<void(KompareSplitter::*)(bool)>(&KompareSplitter::slotApplyDifference)); 0147 connect(m_modelList, &ModelList::applyAllDifferences, 0148 m_splitter, &KompareSplitter::slotApplyAllDifferences); 0149 connect(m_modelList, static_cast<void_ModelList_argDiffBool>(&ModelList::applyDifference), 0150 m_splitter, static_cast<void_KompareSplitter_argDiffBool>(&KompareSplitter::slotApplyDifference)); 0151 connect(this, &KomparePart::configChanged, m_splitter, &KompareSplitter::configChanged); 0152 0153 setupActions(modus); 0154 0155 // we are read-write by default -> uhm what if we are opened by lets say konq in RO mode ? 0156 // Then we should not be doing this... 0157 setReadWrite((modus == ReadWriteModus)); 0158 0159 // we are not modified since we haven't done anything yet 0160 setModified(false); 0161 } 0162 0163 KomparePart::~KomparePart() 0164 { 0165 // This is the only place allowed to call cleanUpTemporaryFiles 0166 // because before there might still be a use for them (when swapping) 0167 cleanUpTemporaryFiles(); 0168 } 0169 0170 void KomparePart::setupActions(Modus modus) 0171 { 0172 // create our actions 0173 0174 if (modus == ReadWriteModus) { 0175 m_saveAll = actionCollection()->addAction(QStringLiteral("file_save_all"), this, &KomparePart::saveAll); 0176 m_saveAll->setIcon(QIcon::fromTheme(QStringLiteral("document-save-all"))); 0177 m_saveAll->setText(i18nc("@action", "Save &All")); 0178 m_saveDiff = actionCollection()->addAction(QStringLiteral("file_save_diff"), this, &KomparePart::saveDiff); 0179 m_saveDiff->setText(i18nc("@action", "Save &Diff...")); 0180 m_swap = actionCollection()->addAction(QStringLiteral("file_swap"), this, &KomparePart::slotSwap); 0181 m_swap->setText(i18nc("@action", "Swap Source with Destination")); 0182 } else { 0183 m_saveAll = nullptr; 0184 m_saveDiff = nullptr; 0185 m_swap = nullptr; 0186 } 0187 m_diffStats = actionCollection()->addAction(QStringLiteral("file_diffstats"), this, &KomparePart::slotShowDiffstats); 0188 m_diffStats->setText(i18nc("@action", "Show Statistics")); 0189 m_diffRefresh = actionCollection()->addAction(QStringLiteral("file_refreshdiff"), this, &KomparePart::slotRefreshDiff); 0190 m_diffRefresh->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); 0191 m_diffRefresh->setText(i18nc("@action", "Refresh Diff")); 0192 actionCollection()->setDefaultShortcuts(m_diffRefresh, KStandardShortcut::reload()); 0193 0194 m_print = KStandardAction::print(this, &KomparePart::slotFilePrint, actionCollection()); 0195 m_printPreview = KStandardAction::printPreview(this, &KomparePart::slotFilePrintPreview, actionCollection()); 0196 KStandardAction::preferences(this, &KomparePart::optionsPreferences, actionCollection()); 0197 } 0198 0199 void KomparePart::updateActions() 0200 { 0201 if (m_saveAll) m_saveAll->setEnabled(m_modelList->hasUnsavedChanges()); 0202 if (m_saveDiff) m_saveDiff->setEnabled(m_modelList->mode() == KompareDiff2::ComparingFiles || m_modelList->mode() == KompareDiff2::ComparingDirs); 0203 if (m_swap) m_swap->setEnabled(m_modelList->mode() == KompareDiff2::ComparingFiles || m_modelList->mode() == KompareDiff2::ComparingDirs); 0204 m_diffRefresh->setEnabled(m_modelList->mode() == KompareDiff2::ComparingFiles || m_modelList->mode() == KompareDiff2::ComparingDirs); 0205 m_diffStats->setEnabled(m_modelList->modelCount() > 0); 0206 m_print->setEnabled(m_modelList->modelCount() > 0); // If modellist has models then we have something to print, it's that simple. 0207 m_printPreview->setEnabled(m_modelList); 0208 } 0209 0210 void KomparePart::setEncoding(const QString& encoding) 0211 { 0212 qCDebug(KOMPAREPART) << "Encoding: " << encoding; 0213 m_modelList->setEncoding(encoding); 0214 } 0215 0216 bool KomparePart::openDiff(const QUrl& url) 0217 { 0218 qCDebug(KOMPAREPART) << "Url = " << url.url(); 0219 0220 m_info.mode = KompareDiff2::ShowingDiff; 0221 m_info.source = url; 0222 bool result = false; 0223 fetchURL(url, true); 0224 0225 Q_EMIT kompareInfo(&m_info); 0226 0227 if (!m_info.localSource.isEmpty()) 0228 { 0229 qCDebug(KOMPAREPART) << "Download succeeded "; 0230 result = m_modelList->openDiff(m_info.localSource); 0231 updateActions(); 0232 updateCaption(); 0233 updateStatus(); 0234 } 0235 else 0236 { 0237 qCDebug(KOMPAREPART) << "Download failed !"; 0238 } 0239 0240 return result; 0241 } 0242 0243 bool KomparePart::openDiff(const QString& diffOutput) 0244 { 0245 bool value = false; 0246 0247 m_info.mode = KompareDiff2::ShowingDiff; 0248 0249 Q_EMIT kompareInfo(&m_info); 0250 0251 if (m_modelList->parseAndOpenDiff(diffOutput) == 0) 0252 { 0253 value = true; 0254 updateActions(); 0255 updateCaption(); 0256 updateStatus(); 0257 } 0258 0259 return value; 0260 } 0261 0262 bool KomparePart::openDiff3(const QUrl& diff3Url) 0263 { 0264 // FIXME: Implement this !!! 0265 qCDebug(KOMPAREPART) << "Not implemented yet. Filename is: " << diff3Url; 0266 return false; 0267 } 0268 0269 bool KomparePart::openDiff3(const QString& diff3Output) 0270 { 0271 // FIXME: Implement this !!! 0272 qCDebug(KOMPAREPART) << "Not implemented yet. diff3 output is: "; 0273 qCDebug(KOMPAREPART) << diff3Output; 0274 return false; 0275 } 0276 0277 bool KomparePart::fetchURL(const QUrl& url, bool addToSource) 0278 { 0279 // Default value if there is an error is "", we rely on it! 0280 QString tempFileName; 0281 // Only in case of error do we set result to false, don't forget!! 0282 bool result = true; 0283 QTemporaryDir* tmpDir = nullptr; 0284 0285 if (!url.isLocalFile()) 0286 { 0287 KIO::StatJob* statJob = KIO::stat(url); 0288 KJobWidgets::setWindow(statJob, widget()); 0289 if (statJob->exec()) 0290 { 0291 KIO::UDSEntry node; 0292 node = statJob->statResult(); 0293 if (!node.isDir()) 0294 { 0295 tmpDir = new QTemporaryDir(QDir::tempPath() + QLatin1String("/kompare")); 0296 tmpDir->setAutoRemove(true); 0297 tempFileName = tmpDir->path() + QLatin1Char('/') + url.fileName(); 0298 KIO::FileCopyJob* copyJob = KIO::file_copy(url, QUrl::fromLocalFile(tempFileName)); 0299 KJobWidgets::setWindow(copyJob, widget()); 0300 if (! copyJob->exec()) 0301 { 0302 qDebug() << "download error " << copyJob->errorString(); 0303 slotShowError(i18n("<qt>The URL <b>%1</b> cannot be downloaded.</qt>", url.toDisplayString())); 0304 tempFileName.clear(); // Not sure if download has already touched this tempFileName when there is an error 0305 result = false; 0306 } 0307 } 0308 else 0309 { 0310 tmpDir = new QTemporaryDir(QDir::tempPath() + QLatin1String("/kompare")); 0311 tmpDir->setAutoRemove(true); // Yes this is the default but just to make sure 0312 KIO::CopyJob* copyJob = KIO::copy(url, QUrl::fromLocalFile(tmpDir->path())); 0313 KJobWidgets::setWindow(copyJob, widget()); 0314 if (! copyJob->exec()) 0315 { 0316 slotShowError(i18n("<qt>The URL <b>%1</b> cannot be downloaded.</qt>", url.toDisplayString())); 0317 delete tmpDir; 0318 tmpDir = nullptr; 0319 result = false; 0320 } 0321 else 0322 { 0323 tempFileName = tmpDir->path(); 0324 qCDebug(KOMPAREPART) << "tempFileName = " << tempFileName; 0325 // If a directory is copied into QTemporaryDir then the directory in 0326 // here is what I need to add to tempFileName 0327 QDir dir(tempFileName); 0328 QStringList entries = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); 0329 if (entries.size() == 1) // More than 1 entry in here means big problems!!! 0330 { 0331 if (!tempFileName.endsWith(QLatin1Char('/'))) 0332 tempFileName += QLatin1Char('/'); 0333 tempFileName += entries.at(0); 0334 tempFileName += QLatin1Char('/'); 0335 } 0336 else 0337 { 0338 qCDebug(KOMPAREPART) << "Yikes, nothing downloaded?"; 0339 delete tmpDir; 0340 tmpDir = nullptr; 0341 tempFileName.clear(); 0342 result = false; 0343 } 0344 } 0345 } 0346 } 0347 } 0348 else 0349 { 0350 // is Local already, check if exists 0351 if (QFile::exists(url.toLocalFile())) { 0352 tempFileName = url.toLocalFile(); 0353 } else { 0354 slotShowError(i18n("<qt>The URL <b>%1</b> does not exist on your system.</qt>", url.toDisplayString())); 0355 result = false; 0356 } 0357 } 0358 0359 if (addToSource) 0360 { 0361 m_info.localSource = tempFileName; 0362 m_info.sourceQTempDir = tmpDir; 0363 } 0364 else 0365 { 0366 m_info.localDestination = tempFileName; 0367 m_info.destinationQTempDir = tmpDir; 0368 } 0369 0370 return result; 0371 } 0372 0373 void KomparePart::cleanUpTemporaryFiles() 0374 { 0375 qCDebug(KOMPAREPART) << "Cleaning temporary files."; 0376 if (!m_info.localSource.isEmpty()) 0377 { 0378 if (m_info.sourceQTempDir) 0379 { 0380 delete m_info.sourceQTempDir; 0381 m_info.sourceQTempDir = nullptr; 0382 } 0383 m_info.localSource.clear(); 0384 } 0385 if (!m_info.localDestination.isEmpty()) 0386 { 0387 if (!m_info.destinationQTempDir) 0388 { 0389 delete m_info.destinationQTempDir; 0390 m_info.destinationQTempDir = nullptr; 0391 } 0392 m_info.localDestination.clear(); 0393 } 0394 } 0395 0396 void KomparePart::compare(const QUrl& source, const QUrl& destination) 0397 { 0398 // FIXME: This is silly, i can use NetAccess::stat to figure out what it is and not 0399 // wait until i am in the modellist to determine the mode we're supposed to be in. 0400 // That should make the code more readable 0401 // I should store the QTemporaryDir(s)/File(s) in the Info struct as well and delete it at the right time 0402 m_info.source = source; 0403 m_info.destination = destination; 0404 0405 // FIXME: (Not urgent) But turn this into an enum, for now i cant find a nice name for the enum that has Source and Destination as values 0406 // For now we do not do error checking, user has already been notified and if the localString is empty then we do not diff 0407 fetchURL(source, true); 0408 fetchURL(destination, false); 0409 0410 Q_EMIT kompareInfo(&m_info); 0411 0412 compareAndUpdateAll(); 0413 } 0414 0415 void KomparePart::compareFileString(const QUrl& sourceFile, const QString& destination) 0416 { 0417 //Set the modeto specify that the source is a file, and the destination is a string 0418 m_info.mode = KompareDiff2::ComparingFileString; 0419 0420 m_info.source = sourceFile; 0421 m_info.localDestination = destination; 0422 0423 fetchURL(sourceFile, true); 0424 0425 Q_EMIT kompareInfo(&m_info); 0426 0427 compareAndUpdateAll(); 0428 } 0429 0430 void KomparePart::compareStringFile(const QString& source, const QUrl& destinationFile) 0431 { 0432 //Set the modeto specify that the source is a file, and the destination is a string 0433 m_info.mode = KompareDiff2::ComparingStringFile; 0434 0435 m_info.localSource = source; 0436 m_info.destination = destinationFile; 0437 0438 fetchURL(destinationFile, false); 0439 0440 Q_EMIT kompareInfo(&m_info); 0441 0442 compareAndUpdateAll(); 0443 } 0444 0445 void KomparePart::compareFiles(const QUrl& sourceFile, const QUrl& destinationFile) 0446 { 0447 m_info.mode = KompareDiff2::ComparingFiles; 0448 0449 m_info.source = sourceFile; 0450 m_info.destination = destinationFile; 0451 0452 // FIXME: (Not urgent) But turn this into an enum, for now i cant find a nice name for the enum that has Source and Destination as values 0453 // For now we do not do error checking, user has already been notified and if the localString is empty then we do not diff 0454 fetchURL(sourceFile, true); 0455 fetchURL(destinationFile, false); 0456 0457 Q_EMIT kompareInfo(&m_info); 0458 0459 compareAndUpdateAll(); 0460 } 0461 0462 void KomparePart::compareDirs(const QUrl& sourceDirectory, const QUrl& destinationDirectory) 0463 { 0464 m_info.mode = KompareDiff2::ComparingDirs; 0465 0466 m_info.source = sourceDirectory; 0467 m_info.destination = destinationDirectory; 0468 0469 fetchURL(sourceDirectory, true); 0470 fetchURL(destinationDirectory, false); 0471 0472 Q_EMIT kompareInfo(&m_info); 0473 0474 compareAndUpdateAll(); 0475 } 0476 0477 void KomparePart::compare3Files(const QUrl& /*originalFile*/, const QUrl& /*changedFile1*/, const QUrl& /*changedFile2*/) 0478 { 0479 // FIXME: actually implement this some day :) 0480 updateActions(); 0481 updateCaption(); 0482 updateStatus(); 0483 } 0484 0485 void KomparePart::openFileAndDiff(const QUrl& file, const QUrl& diffFile) 0486 { 0487 m_info.source = file; 0488 m_info.destination = diffFile; 0489 0490 fetchURL(file, true); 0491 fetchURL(diffFile, false); 0492 m_info.mode = KompareDiff2::BlendingFile; 0493 0494 Q_EMIT kompareInfo(&m_info); 0495 0496 compareAndUpdateAll(); 0497 } 0498 0499 void KomparePart::openDirAndDiff(const QUrl& dir, const QUrl& diffFile) 0500 { 0501 m_info.source = dir; 0502 m_info.destination = diffFile; 0503 0504 fetchURL(dir, true); 0505 fetchURL(diffFile, false); 0506 m_info.mode = KompareDiff2::BlendingDir; 0507 0508 Q_EMIT kompareInfo(&m_info); 0509 0510 if (!m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty()) 0511 { 0512 m_modelList->openDirAndDiff(); 0513 //Must this be in here? couldn't we use compareAndUpdateAll as well? 0514 updateActions(); 0515 updateCaption(); 0516 updateStatus(); 0517 } 0518 } 0519 0520 bool KomparePart::openFile() 0521 { 0522 // This is called from openURL 0523 // This is a little inefficient but i will do it anyway 0524 openDiff(url()); 0525 return true; 0526 } 0527 0528 bool KomparePart::saveAll() 0529 { 0530 bool result = m_modelList->saveAll(); 0531 updateActions(); 0532 updateCaption(); 0533 updateStatus(); 0534 return result; 0535 } 0536 0537 void KomparePart::saveDiff() 0538 { 0539 QDialog dlg(widget()); 0540 dlg.setObjectName(QStringLiteral("save_options")); 0541 dlg.setModal(true); 0542 dlg.setWindowTitle(i18nc("@title:window", "Diff Options")); 0543 QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel, &dlg); 0544 connect(buttons, &QDialogButtonBox::accepted, &dlg, &QDialog::accept); 0545 connect(buttons, &QDialogButtonBox::rejected, &dlg, &QDialog::reject); 0546 KompareSaveOptionsWidget* w = new KompareSaveOptionsWidget( 0547 m_info.localSource, 0548 m_info.localDestination, 0549 m_diffSettings, &dlg); 0550 QVBoxLayout* layout = new QVBoxLayout(&dlg); 0551 layout->addWidget(w); 0552 layout->addWidget(buttons); 0553 dlg.setLayout(layout); 0554 0555 if (dlg.exec()) { 0556 w->saveOptions(); 0557 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0558 saveProperties(config.data()); 0559 config->sync(); 0560 0561 QUrl url = QFileDialog::getSaveFileUrl(widget(), i18nc("@title:window", "Save .diff"), 0562 m_info.destination, 0563 i18n("Patch Files (*.diff *.dif *.patch)")); 0564 qCDebug(KOMPAREPART) << "URL = " << url.toDisplayString(); 0565 qCDebug(KOMPAREPART) << "Directory = " << w->directory(); 0566 qCDebug(KOMPAREPART) << "DiffSettings = " << m_diffSettings; 0567 0568 m_modelList->saveDiff(url.url(), w->directory(), m_diffSettings); 0569 } 0570 } 0571 0572 void KomparePart::slotFilePrint() 0573 { 0574 QPrinter printer; 0575 printer.setPageOrientation(QPageLayout::Landscape); 0576 QPrintDialog* dlg = new QPrintDialog(&printer, nullptr); 0577 0578 if (dlg->exec() == QDialog::Accepted) 0579 { 0580 // do some printing in qprinter 0581 slotPaintRequested(&printer); 0582 } 0583 0584 delete dlg; 0585 } 0586 0587 void KomparePart::slotFilePrintPreview() 0588 { 0589 QPrinter printer; 0590 printer.setPageOrientation(QPageLayout::Landscape); 0591 QPrintPreviewDialog dlg(&printer); 0592 0593 connect(&dlg, &QPrintPreviewDialog::paintRequested, this, &KomparePart::slotPaintRequested); 0594 0595 dlg.exec(); 0596 } 0597 0598 void KomparePart::slotPaintRequested(QPrinter* printer) 0599 { 0600 qCDebug(KOMPAREPART) << "Now paint something..."; 0601 QPainter p; 0602 p.begin(printer); 0603 0604 QSize widgetWidth = m_view->size(); 0605 qCDebug(KOMPAREPART) << "printer.width() = " << printer->width(); 0606 qCDebug(KOMPAREPART) << "widgetWidth.width() = " << widgetWidth.width(); 0607 qreal factor = ((qreal)printer->width()) / ((qreal)widgetWidth.width()); 0608 0609 qCDebug(KOMPAREPART) << "factor = " << factor; 0610 0611 p.scale(factor, factor); 0612 m_view->render(&p); 0613 0614 p.end(); 0615 qCDebug(KOMPAREPART) << "Done painting something..."; 0616 } 0617 0618 void KomparePart::slotSetStatus(enum KompareDiff2::Status status) 0619 { 0620 updateActions(); 0621 0622 switch (status) { 0623 case KompareDiff2::RunningDiff: 0624 Q_EMIT setStatusBarText(i18nc("@info:status", "Running diff...")); 0625 break; 0626 case KompareDiff2::Parsing: 0627 Q_EMIT setStatusBarText(i18nc("@info:status", "Parsing diff output...")); 0628 break; 0629 case KompareDiff2::FinishedParsing: 0630 updateStatus(); 0631 break; 0632 case KompareDiff2::FinishedWritingDiff: 0633 updateStatus(); 0634 Q_EMIT diffURLChanged(); 0635 break; 0636 default: 0637 break; 0638 } 0639 } 0640 0641 void KomparePart::onContextMenuRequested(const QPoint& pos) 0642 { 0643 QMenu* popup = static_cast<QMenu*>(factory()->container(QStringLiteral("mainPopUp"), this)); 0644 if (popup) 0645 popup->exec(m_view->mapToGlobal(pos)); 0646 } 0647 0648 void KomparePart::updateCaption() 0649 { 0650 QString source = m_info.source.toDisplayString(QUrl::PreferLocalFile); 0651 QString destination = m_info.destination.toDisplayString(QUrl::PreferLocalFile); 0652 0653 QString text; 0654 0655 switch (m_info.mode) 0656 { 0657 case KompareDiff2::ComparingFiles : 0658 case KompareDiff2::ComparingDirs : 0659 case KompareDiff2::BlendingFile : 0660 case KompareDiff2::BlendingDir : 0661 text = source + QLatin1String(" -- ") + destination; // no need to translate this " -- " 0662 break; 0663 case KompareDiff2::ShowingDiff : 0664 text = source; 0665 break; 0666 default: 0667 break; 0668 } 0669 0670 Q_EMIT setWindowCaption(text); 0671 } 0672 0673 void KomparePart::updateStatus() 0674 { 0675 QString source = m_info.source.toDisplayString(QUrl::PreferLocalFile); 0676 QString destination = m_info.destination.toDisplayString(QUrl::PreferLocalFile); 0677 0678 QString text; 0679 0680 switch (m_info.mode) 0681 { 0682 case KompareDiff2::ComparingFiles : 0683 text = i18nc("@info:status", "Comparing file %1 with file %2" , 0684 source, 0685 destination); 0686 break; 0687 case KompareDiff2::ComparingDirs : 0688 text = i18nc("@info:status", "Comparing files in %1 with files in %2" , 0689 source, 0690 destination); 0691 break; 0692 case KompareDiff2::ShowingDiff : 0693 text = i18nc("@info:status", "Viewing diff output from %1", source); 0694 break; 0695 case KompareDiff2::BlendingFile : 0696 text = i18nc("@info:status", "Blending diff output from %1 into file %2" , 0697 source, 0698 destination); 0699 break; 0700 case KompareDiff2::BlendingDir : 0701 text = i18nc("@info:status", "Blending diff output from %1 into folder %2" , 0702 m_info.source.toDisplayString(), 0703 m_info.destination.toDisplayString()); 0704 break; 0705 default: 0706 break; 0707 } 0708 0709 Q_EMIT setStatusBarText(text); 0710 } 0711 0712 void KomparePart::compareAndUpdateAll() 0713 { 0714 if (!m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty()) 0715 { 0716 switch (m_info.mode) 0717 { 0718 default: 0719 case KompareDiff2::UnknownMode: 0720 m_modelList->compare(); 0721 break; 0722 0723 case KompareDiff2::ComparingStringFile: 0724 case KompareDiff2::ComparingFileString: 0725 case KompareDiff2::ComparingFiles: 0726 case KompareDiff2::ComparingDirs: 0727 m_modelList->compare(m_info.mode); 0728 break; 0729 0730 case KompareDiff2::BlendingFile: 0731 m_modelList->openFileAndDiff(); 0732 break; 0733 } 0734 updateCaption(); 0735 updateStatus(); 0736 } 0737 updateActions(); 0738 } 0739 0740 void KomparePart::slotShowError(const QString& error) 0741 { 0742 KMessageBox::error(widget(), error); 0743 } 0744 0745 void KomparePart::slotSwap() 0746 { 0747 if (m_modelList->hasUnsavedChanges()) 0748 { 0749 int query = KMessageBox::warningTwoActionsCancel 0750 ( 0751 widget(), 0752 i18n("You have made changes to the destination file(s).\n" 0753 "Would you like to save them?"), 0754 i18nc("@title:window", "Save Changes?"), 0755 KStandardGuiItem::save(), 0756 KStandardGuiItem::discard() 0757 ); 0758 0759 if (query == KMessageBox::PrimaryAction) 0760 m_modelList->saveAll(); 0761 0762 if (query == KMessageBox::Cancel) 0763 return; // Abort prematurely so no swapping 0764 } 0765 0766 // Swap the info in the KompareDiff2::Info struct 0767 m_info.swapSourceWithDestination(); 0768 0769 // Update window caption and statusbar text 0770 updateCaption(); 0771 updateStatus(); 0772 0773 m_modelList->swap(); 0774 } 0775 0776 void KomparePart::slotRefreshDiff() 0777 { 0778 if (m_modelList->hasUnsavedChanges()) 0779 { 0780 int query = KMessageBox::warningTwoActionsCancel 0781 ( 0782 widget(), 0783 i18n("You have made changes to the destination file(s).\n" 0784 "Would you like to save them?"), 0785 i18nc("@title:window", "Save Changes?"), 0786 KStandardGuiItem::save(), 0787 KStandardGuiItem::discard(), 0788 KStandardGuiItem::cancel() 0789 ); 0790 0791 if (query == KMessageBox::Cancel) 0792 return; // Abort prematurely so no refreshing 0793 0794 if (query == KMessageBox::PrimaryAction) 0795 m_modelList->saveAll(); 0796 } 0797 0798 // For this to work properly you have to refetch the files from their (remote) locations 0799 cleanUpTemporaryFiles(); 0800 fetchURL(m_info.source, true); 0801 fetchURL(m_info.destination, false); 0802 m_modelList->refresh(); 0803 } 0804 0805 void KomparePart::slotShowDiffstats() 0806 { 0807 // Fetch all the args needed for komparestatsmessagebox 0808 // oldfile, newfile, diffformat, noofhunks, noofdiffs 0809 0810 QString oldFile; 0811 QString newFile; 0812 QString diffFormat; 0813 int filesInDiff; 0814 int noOfHunks; 0815 int noOfDiffs; 0816 0817 oldFile = m_modelList->selectedModel() ? m_modelList->selectedModel()->sourceFile() : QString(); 0818 newFile = m_modelList->selectedModel() ? m_modelList->selectedModel()->destinationFile() : QString(); 0819 0820 if (m_modelList->selectedModel()) 0821 { 0822 switch (m_info.format) { 0823 case KompareDiff2::Unified : 0824 diffFormat = i18nc("@item diff format", "Unified"); 0825 break; 0826 case KompareDiff2::Context : 0827 diffFormat = i18nc("@item diff format", "Context"); 0828 break; 0829 case KompareDiff2::RCS : 0830 diffFormat = i18nc("@item diff format", "RCS"); 0831 break; 0832 case KompareDiff2::Ed : 0833 diffFormat = i18nc("@item diff format", "Ed"); 0834 break; 0835 case KompareDiff2::Normal : 0836 diffFormat = i18nc("@item diff format", "Normal"); 0837 break; 0838 case KompareDiff2::UnknownFormat : 0839 default: 0840 diffFormat = i18nc("@item diff format", "Unknown"); 0841 break; 0842 } 0843 } 0844 else 0845 { 0846 diffFormat.clear(); 0847 } 0848 0849 filesInDiff = m_modelList->modelCount(); 0850 0851 noOfHunks = m_modelList->selectedModel() ? m_modelList->selectedModel()->hunkCount() : 0; 0852 noOfDiffs = m_modelList->selectedModel() ? m_modelList->selectedModel()->differenceCount() : 0; 0853 0854 if (m_modelList->modelCount() == 0) { // no diff loaded yet 0855 KMessageBox::information(nullptr, i18n( 0856 "No diff file, or no 2 files have been diffed. " 0857 "Therefore no stats are available."), 0858 i18nc("@title:window", "Diff Statistics"), QString(), KMessageBox::Options()); 0859 } 0860 else if (m_modelList->modelCount() == 1) { // 1 file in diff, or 2 files compared 0861 KMessageBox::information(nullptr, i18n( 0862 "Statistics:\n" 0863 "\n" 0864 "Old file: %1\n" 0865 "New file: %2\n" 0866 "\n" 0867 "Format: %3\n" 0868 "Number of hunks: %4\n" 0869 "Number of differences: %5", 0870 oldFile, newFile, diffFormat, 0871 noOfHunks, noOfDiffs), 0872 i18nc("@title:window", "Diff Statistics"), QString(), KMessageBox::Options()); 0873 } else { // more than 1 file in diff, or 2 directories compared 0874 KMessageBox::information(nullptr, ki18n( 0875 "Statistics:\n" 0876 "\n" 0877 "Number of files in diff file: %1\n" 0878 "Format: %2\n" 0879 "\n" 0880 "Current old file: %3\n" 0881 "Current new file: %4\n" 0882 "\n" 0883 "Number of hunks: %5\n" 0884 "Number of differences: %6") 0885 .subs(filesInDiff).subs(diffFormat).subs(oldFile) 0886 .subs(newFile).subs(noOfHunks).subs(noOfDiffs) 0887 .toString(), 0888 i18nc("@title:window", "Diff Statistics"), QString(), KMessageBox::Options()); 0889 } 0890 } 0891 0892 bool KomparePart::queryClose() 0893 { 0894 if (!m_modelList->hasUnsavedChanges()) return true; 0895 0896 int query = KMessageBox::warningTwoActionsCancel 0897 ( 0898 widget(), 0899 i18n("You have made changes to the destination file(s).\n" 0900 "Would you like to save them?"), 0901 i18nc("@title:window", "Save Changes?"), 0902 KStandardGuiItem::save(), 0903 KStandardGuiItem::discard(), 0904 KStandardGuiItem::cancel() 0905 ); 0906 0907 if (query == KMessageBox::Cancel) 0908 return false; 0909 0910 if (query == KMessageBox::PrimaryAction) 0911 return m_modelList->saveAll(); 0912 0913 return true; 0914 } 0915 0916 void KomparePart::setReadWrite(bool readWrite) 0917 { 0918 m_modelList->setReadWrite(readWrite); 0919 KParts::ReadWritePart::setReadWrite(readWrite); 0920 } 0921 0922 int KomparePart::readProperties(KConfig* config) 0923 { 0924 m_viewSettings->loadSettings(config); 0925 m_diffSettings->loadSettings(config); 0926 Q_EMIT configChanged(); 0927 return 0; 0928 } 0929 0930 int KomparePart::saveProperties(KConfig* config) 0931 { 0932 m_viewSettings->saveSettings(config); 0933 m_diffSettings->saveSettings(config); 0934 return 0; 0935 } 0936 0937 void KomparePart::optionsPreferences() 0938 { 0939 // show preferences 0940 KomparePrefDlg pref(m_viewSettings, m_diffSettings); 0941 0942 connect(&pref, &KomparePrefDlg::configChanged, this, &KomparePart::configChanged); 0943 0944 if (pref.exec()) 0945 Q_EMIT configChanged(); 0946 } 0947 0948 #include "moc_kompare_part.cpp"