Skip to content

Commit

Permalink
Display read-only state of open files using a lock icon
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bjorn committed May 24, 2024
1 parent b47a6dd commit c82539e
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 11 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
15 changes: 14 additions & 1 deletion src/tiled/document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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"
10 changes: 10 additions & 0 deletions src/tiled/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -176,6 +180,7 @@ class Document : public QObject,

QUndoStack * const mUndoStack;

bool mReadOnly = false;
bool mModified = false;
bool mChangedOnDisk = false;
bool mIgnoreBrokenLinks = false;
Expand Down Expand Up @@ -233,6 +238,11 @@ inline bool Document::changedOnDisk() const
return mChangedOnDisk;
}

inline bool Document::isReadOnly() const
{
return mReadOnly;
}

inline const QHash<QString, Document *> &Document::documentInstances()
{
return sDocumentInstances;
Expand Down
29 changes: 19 additions & 10 deletions src/tiled/documentmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
#include <QScrollBar>
#include <QStackedLayout>
#include <QTabBar>
#include <QTabWidget>
#include <QUndoGroup>
#include <QUndoStack>
#include <QVBoxLayout>
Expand All @@ -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))
Expand All @@ -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);
Expand Down Expand Up @@ -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<MapDocument*>(documentPtr)) {
Expand All @@ -592,7 +591,7 @@ int DocumentManager::insertDocument(int index, const DocumentPtr &document)

emit documentOpened(documentPtr);

return documentIndex;
return index;
}

/**
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/tiled/documentmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "tilesetdocument.h"

#include <QHash>
#include <QIcon>
#include <QList>
#include <QObject>
#include <QPointF>
Expand Down Expand Up @@ -222,6 +223,8 @@ public slots:
MapDocument *openMapFile(const QString &path);
TilesetDocument *openTilesetFile(const QString &path);

QIcon mLockedIcon;

QVector<DocumentPtr> mDocuments;
QMap<QString, WorldDocument*> mWorldDocuments;
TilesetDocumentsModel *mTilesetDocumentsModel;
Expand Down

0 comments on commit c82539e

Please sign in to comment.