From c82539e331d7a90a3202e9f9b40f0486de84fdbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Mon, 15 Apr 2024 16:35:05 +0200 Subject: [PATCH] Display read-only state of open files using a lock icon This should be mostly helpful for people using a VCS like Perforce or Subversion, which may require a file to be checked out or locked before it can be edited. For now the read-only icon is a lock, which is common, but it may be confusing for Subversion users since they actually need to lock the file to make it writable. --- NEWS.md | 1 + src/tiled/document.cpp | 15 ++++++++++++++- src/tiled/document.h | 10 ++++++++++ src/tiled/documentmanager.cpp | 29 +++++++++++++++++++---------- src/tiled/documentmanager.h | 3 +++ 5 files changed, 47 insertions(+), 11 deletions(-) diff --git a/NEWS.md b/NEWS.md index 0ba778fcf0..168618e165 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,7 @@ * Added --project command-line parameter for use when exporting (#3797) * Added group layer names in "Move Object to Layer" menu (#3454) +* Added lock icon to open tabs for which the file is read-only * Made adding "Copy" when duplicating optional and disabled by default (#3917) * Layer names are now trimmed when edited in the UI, to avoid accidental whitespace * Scripting: Added API for working with worlds (#3539) diff --git a/src/tiled/document.cpp b/src/tiled/document.cpp index a014f02181..ef0b7b404c 100644 --- a/src/tiled/document.cpp +++ b/src/tiled/document.cpp @@ -41,9 +41,13 @@ Document::Document(DocumentType type, const QString &fileName, : QObject(parent) , mType(type) , mFileName(fileName) - , mCanonicalFilePath(QFileInfo(mFileName).canonicalFilePath()) , mUndoStack(new QUndoStack(this)) { + const QFileInfo fileInfo { fileName }; + mLastSaved = fileInfo.lastModified(); + mCanonicalFilePath = fileInfo.canonicalFilePath(); + mReadOnly = !fileInfo.isWritable(); + if (!mCanonicalFilePath.isEmpty()) sDocumentInstances.insert(mCanonicalFilePath, this); @@ -310,6 +314,15 @@ void Document::setChangedOnDisk(bool changedOnDisk) mChangedOnDisk = changedOnDisk; } +void Document::setReadOnly(bool readOnly) +{ + if (mReadOnly == readOnly) + return; + + mReadOnly = readOnly; + emit isReadOnlyChanged(readOnly); +} + } // namespace Tiled #include "moc_document.cpp" diff --git a/src/tiled/document.h b/src/tiled/document.h index 5adfd9930c..29995c5069 100644 --- a/src/tiled/document.h +++ b/src/tiled/document.h @@ -115,6 +115,9 @@ class Document : public QObject, bool changedOnDisk() const; void setChangedOnDisk(bool changedOnDisk); + bool isReadOnly() const; + void setReadOnly(bool readOnly); + virtual QString lastExportFileName() const = 0; virtual void setLastExportFileName(const QString &fileName) = 0; @@ -132,6 +135,7 @@ class Document : public QObject, void fileNameChanged(const QString &fileName, const QString &oldFileName); void modifiedChanged(); + void isReadOnlyChanged(bool readOnly); void currentObjectSet(Object *object); void currentObjectChanged(Object *object); @@ -176,6 +180,7 @@ class Document : public QObject, QUndoStack * const mUndoStack; + bool mReadOnly = false; bool mModified = false; bool mChangedOnDisk = false; bool mIgnoreBrokenLinks = false; @@ -233,6 +238,11 @@ inline bool Document::changedOnDisk() const return mChangedOnDisk; } +inline bool Document::isReadOnly() const +{ + return mReadOnly; +} + inline const QHash &Document::documentInstances() { return sDocumentInstances; diff --git a/src/tiled/documentmanager.cpp b/src/tiled/documentmanager.cpp index 36599578ee..d8a902e899 100644 --- a/src/tiled/documentmanager.cpp +++ b/src/tiled/documentmanager.cpp @@ -62,7 +62,6 @@ #include #include #include -#include #include #include #include @@ -85,6 +84,7 @@ DocumentManager *DocumentManager::maybeInstance() DocumentManager::DocumentManager(QObject *parent) : QObject(parent) + , mLockedIcon(QLatin1String(":images/16/locked.png")) , mTilesetDocumentsModel(new TilesetDocumentsModel(this)) , mWidget(new QWidget) , mNoEditorWidget(new NoEditorWidget(mWidget)) @@ -100,6 +100,8 @@ DocumentManager::DocumentManager(QObject *parent) Q_ASSERT(!mInstance); mInstance = this; + mLockedIcon.addFile(QStringLiteral(":images/24/locked.png")); + mBrokenLinksWidget->setVisible(false); mTabBar->setExpanding(false); @@ -571,15 +573,12 @@ int DocumentManager::insertDocument(int index, const DocumentPtr &document) if (Editor *editor = mEditorForType.value(document->type())) editor->addDocument(documentPtr); - QString tabText = document->displayName(); - if (document->isModified()) - tabText.prepend(QLatin1Char('*')); - - const int documentIndex = mTabBar->insertTab(index, tabText); - mTabBar->setTabToolTip(documentIndex, document->fileName()); + mTabBar->insertTab(index, QString()); + updateDocumentTab(documentPtr); connect(documentPtr, &Document::fileNameChanged, this, &DocumentManager::fileNameChanged); connect(documentPtr, &Document::modifiedChanged, this, [=] { updateDocumentTab(documentPtr); }); + connect(documentPtr, &Document::isReadOnlyChanged, this, [=] { updateDocumentTab(documentPtr); }); connect(documentPtr, &Document::saved, this, &DocumentManager::onDocumentSaved); if (auto *mapDocument = qobject_cast(documentPtr)) { @@ -592,7 +591,7 @@ int DocumentManager::insertDocument(int index, const DocumentPtr &document) emit documentOpened(documentPtr); - return documentIndex; + return index; } /** @@ -1022,12 +1021,18 @@ void DocumentManager::updateDocumentTab(Document *document) if (index == -1) return; + QIcon tabIcon = document->isReadOnly() ? mLockedIcon : QIcon(); QString tabText = document->displayName(); + QString tabToolTip = document->fileName(); + if (document->isModified()) tabText.prepend(QLatin1Char('*')); + if (document->isReadOnly()) + tabToolTip = tr("%1 [read-only]").arg(tabToolTip); + mTabBar->setTabIcon(index, tabIcon); mTabBar->setTabText(index, tabText); - mTabBar->setTabToolTip(index, document->fileName()); + mTabBar->setTabToolTip(index, tabToolTip); } void DocumentManager::onDocumentSaved() @@ -1117,9 +1122,13 @@ void DocumentManager::fileChanged(const QString &fileName) return; const auto &document = mDocuments.at(index); + const QFileInfo fileInfo { fileName }; + + // Always update potentially changed read-only state + document->setReadOnly(!fileInfo.isWritable()); // Ignore change event when it seems to be our own save - if (QFileInfo(fileName).lastModified() == document->lastSaved()) + if (fileInfo.lastModified() == document->lastSaved()) return; // Automatically reload when there are no unsaved changes diff --git a/src/tiled/documentmanager.h b/src/tiled/documentmanager.h index d81ac8df0f..bdc02fea17 100644 --- a/src/tiled/documentmanager.h +++ b/src/tiled/documentmanager.h @@ -25,6 +25,7 @@ #include "tilesetdocument.h" #include +#include #include #include #include @@ -222,6 +223,8 @@ public slots: MapDocument *openMapFile(const QString &path); TilesetDocument *openTilesetFile(const QString &path); + QIcon mLockedIcon; + QVector mDocuments; QMap mWorldDocuments; TilesetDocumentsModel *mTilesetDocumentsModel;