File indexing completed on 2024-05-19 05:05:44
0001 /*************************************************************************** 0002 * SPDX-License-Identifier: GPL-2.0-or-later 0003 * * 0004 * SPDX-FileCopyrightText: 2004-2020 Thomas Fischer <fischer@unix-ag.uni-kl.de> 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, * 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0014 * GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License * 0017 * along with this program; if not, see <https://www.gnu.org/licenses/>. * 0018 ***************************************************************************/ 0019 0020 #include "associatedfiles.h" 0021 0022 #include <QFileInfo> 0023 #include <QDir> 0024 0025 #include <KIO/CopyJob> 0026 #include <KJobWidgets> 0027 0028 #include <Preferences> 0029 #include "logging_networking.h" 0030 0031 QString AssociatedFiles::relativeFilename(const QUrl &documentUrl, const QUrl &baseUrl) { 0032 if (!documentUrl.isValid()) { 0033 /// Document URL has to point to a file location or URL but is invalid 0034 return QString(); 0035 } 0036 if (!baseUrl.isValid() || baseUrl.isRelative()) { 0037 /// Base URL has to point to an absolute file location or URL and must be valid 0038 return documentUrl.url(QUrl::PreferLocalFile); 0039 } 0040 if (documentUrl.scheme() != baseUrl.scheme() || (documentUrl.scheme() != QStringLiteral("file") && documentUrl.host() != baseUrl.host())) { 0041 /// Document URL and base URL do not match (protocol, host, ...) 0042 return documentUrl.url(QUrl::PreferLocalFile); 0043 } 0044 0045 /// First, resolve the provided document URL to an absolute URL 0046 /// using the given base URL 0047 QUrl internaldocumentUrl = documentUrl; 0048 if (internaldocumentUrl.isRelative()) 0049 internaldocumentUrl = baseUrl.resolved(internaldocumentUrl); 0050 0051 /// Get the absolute path of the base URL 0052 const QString baseUrlDirectory = QFileInfo(baseUrl.path()).absolutePath(); 0053 0054 /// Let QDir calculate the relative directory 0055 return QDir(baseUrlDirectory).relativeFilePath(internaldocumentUrl.path()); 0056 } 0057 0058 QString AssociatedFiles::absoluteFilename(const QUrl &documentUrl, const QUrl &baseUrl) { 0059 if (!documentUrl.isValid()) { 0060 /// Document URL has to point to a file location or URL but is invalid 0061 return QString(); 0062 } 0063 if (documentUrl.isRelative() && (!baseUrl.isValid() || baseUrl.isRelative())) { 0064 /// Base URL has to point to an absolute, valid file location or URL if the document URL is relative 0065 return documentUrl.url(QUrl::PreferLocalFile); 0066 } 0067 if (!documentUrl.isRelative() && (documentUrl.scheme() != baseUrl.scheme() || (documentUrl.scheme() != QStringLiteral("file") && documentUrl.host() != baseUrl.host()))) { 0068 /// Document URL and base URL do not match (protocol, host, ...), but necessary if the document URL is relative 0069 return documentUrl.url(QUrl::PreferLocalFile); 0070 } 0071 0072 /// Resolve the provided document URL to an absolute URL 0073 /// using the given base URL 0074 QUrl internaldocumentUrl = documentUrl; 0075 if (internaldocumentUrl.isRelative()) 0076 internaldocumentUrl = baseUrl.resolved(internaldocumentUrl); 0077 0078 return internaldocumentUrl.url(QUrl::PreferLocalFile); 0079 } 0080 0081 QString AssociatedFiles::insertUrl(const QUrl &documentUrl, QSharedPointer<Entry> &entry, const File *bibTeXFile, PathType pathType) { 0082 const QString finalUrl = computeAssociateString(documentUrl, bibTeXFile, pathType); 0083 0084 bool alreadyContained = false; 0085 for (QMap<QString, Value>::ConstIterator it = entry->constBegin(); !alreadyContained && it != entry->constEnd(); ++it) { 0086 const Value v = it.value(); 0087 for (Value::ConstIterator vit = v.constBegin(); !alreadyContained && vit != v.constEnd(); ++vit) { 0088 if (PlainTextValue::text(*vit) == finalUrl) 0089 alreadyContained = true; 0090 } 0091 } 0092 if (!alreadyContained) { 0093 const QString field = documentUrl.isLocalFile() ? (Preferences::instance().bibliographySystem() == Preferences::BibliographySystem::BibTeX ? Entry::ftLocalFile : Entry::ftFile) : Entry::ftUrl; 0094 Value value = entry->value(field); 0095 value.append(QSharedPointer<VerbatimText>(new VerbatimText(finalUrl))); 0096 entry->insert(field, value); 0097 } 0098 0099 return finalUrl; 0100 } 0101 0102 QString AssociatedFiles::computeAssociateString(const QUrl &documentUrl, const File *bibTeXFile, PathType pathType) { 0103 const QUrl baseUrl = bibTeXFile != nullptr && bibTeXFile->hasProperty(File::Url) ? bibTeXFile->property(File::Url).toUrl() : QUrl(); 0104 return pathType == PathType::Absolute ? absoluteFilename(documentUrl, baseUrl) : relativeFilename(documentUrl, baseUrl); 0105 } 0106 0107 QPair<QUrl, QUrl> AssociatedFiles::computeSourceDestinationUrls(const QUrl &sourceUrl, const QString &entryId, const File *bibTeXFile, RenameOperation renameOperation, const QString &userDefinedFilename) 0108 { 0109 if (entryId.isEmpty() && renameOperation == RenameOperation::EntryId) { 0110 /// If no entry id was given but still a rename after entry id was requested, 0111 /// revert choice and enforce keeping the original name 0112 renameOperation = RenameOperation::KeepName; 0113 } 0114 0115 const QUrl bibTeXFileUrl = bibTeXFile != nullptr && bibTeXFile->hasProperty(File::Url) ? bibTeXFile->property(File::Url).toUrl() : QUrl(); 0116 if (!bibTeXFileUrl.isValid()) return QPair<QUrl, QUrl>(); 0117 0118 /// If URL of document to be associated is relative and current file has an URL, resolve relative URL 0119 const QUrl absoluteSourceUrl = sourceUrl.isRelative() ? bibTeXFileUrl.resolved(sourceUrl) : sourceUrl; 0120 0121 /// Compute the filename for the move/copy operation's target 0122 const QFileInfo internalSourceInfo(absoluteSourceUrl.path()); 0123 QString filename = internalSourceInfo.fileName(); 0124 QString suffix = internalSourceInfo.suffix(); 0125 if (suffix.isEmpty()) 0126 suffix = QStringLiteral("html"); 0127 if (filename.isEmpty() || renameOperation == RenameOperation::EntryId) 0128 filename = entryId + QLatin1Char('.') + suffix; 0129 if (filename.isEmpty() || renameOperation == RenameOperation::UserDefined) 0130 filename = userDefinedFilename; 0131 0132 /// Assemble the target URL from the bibliography's URL and the filename as computed above 0133 QUrl targetUrl = bibTeXFileUrl; 0134 const QString targetPath = QFileInfo(targetUrl.path()).absolutePath(); 0135 targetUrl.setPath(targetPath + QDir::separator() + filename); 0136 0137 return QPair<QUrl, QUrl>(absoluteSourceUrl, targetUrl); 0138 } 0139 0140 QUrl AssociatedFiles::copyDocument(const QUrl &sourceUrl, const QString &entryId, const File *bibTeXFile, RenameOperation renameOperation, MoveCopyOperation moveCopyOperation, QWidget *widget, const QString &userDefinedFilename) 0141 { 0142 if (moveCopyOperation == MoveCopyOperation::None) 0143 /// If nothing to be copied or moved, the target URL is equal to the source URL 0144 return sourceUrl; 0145 0146 const QPair<QUrl, QUrl> r = computeSourceDestinationUrls(sourceUrl, entryId, bibTeXFile, renameOperation, userDefinedFilename); 0147 const QUrl internalSourceUrl = r.first, targetUrl = r.second; 0148 0149 bool success = true; 0150 if (internalSourceUrl.isLocalFile() && targetUrl.isLocalFile()) { 0151 QFile(targetUrl.path()).remove(); 0152 success &= QFile::copy(internalSourceUrl.path(), targetUrl.path()); 0153 if (success && moveCopyOperation == MoveCopyOperation::Move) { 0154 success &= QFile(internalSourceUrl.path()).remove(); 0155 } 0156 } else if (internalSourceUrl.isValid() && targetUrl.isValid()) { 0157 // FIXME non-blocking 0158 KIO::CopyJob *moveCopyJob = moveCopyOperation == MoveCopyOperation::Move ? KIO::move(sourceUrl, targetUrl, KIO::HideProgressInfo | KIO::Overwrite) : KIO::copy(sourceUrl, targetUrl, KIO::HideProgressInfo | KIO::Overwrite); 0159 KJobWidgets::setWindow(moveCopyJob, widget); 0160 success &= moveCopyJob->exec(); 0161 } else { 0162 qCWarning(LOG_KBIBTEX_NETWORKING) << "Either sourceUrl or targetUrl is invalid"; 0163 return QUrl(); 0164 } 0165 0166 if (!success) return QUrl(); ///< either copy/move or delete operation failed 0167 0168 return targetUrl; 0169 }