-
Notifications
You must be signed in to change notification settings - Fork 61
Take the name of a file that is not there yet #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rodgco
wants to merge
8
commits into
omacom:master
Choose a base branch
from
rodgco:fix/open-missing-file
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
fbcd6cd
Take the name of a file that is not there yet
rodgco 770f714
Only take a name a file could be written to
omarchybot f4be8dc
Do not let a reload that lost its file start a new one
rodgco bf00e91
Ask before the first save replaces a file that turned up
rodgco 98f0c3f
Guard the path a refused reload leaves behind
rodgco b0bf1cc
Drop the pending close when the first save asks instead of writing
omarchybot df3274c
Carry the never-read path through a recovered snapshot
omarchybot 6bc0092
Cover the write half of the never-read snapshot round trip
omarchybot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -199,14 +199,48 @@ void Backend::openDialog() { | |
| } | ||
|
|
||
| void Backend::open(const QUrl &url) { | ||
| openPath(url, true); | ||
| } | ||
|
|
||
| void Backend::openPath(const QUrl &url, bool mayStartNewFile) { | ||
| if (!url.isLocalFile()) { | ||
| setStatus(QStringLiteral("Only local files can be opened.")); | ||
| return; | ||
| } | ||
|
|
||
| const QString targetName = QFileInfo(url.toLocalFile()).fileName(); | ||
| QFile file(url.toLocalFile()); | ||
| // A path that is not there yet is a file the writer means to start, so | ||
| // take the name for a blank document. The first save then lands where | ||
| // they said it should, instead of asking them again. | ||
| if (mayStartNewFile && !file.exists()) { | ||
| // Only where it could be written: a name under a directory that is not | ||
| // there leaves the first save with nowhere to land and no dialog. | ||
| const QFileInfo parentDirectory(QFileInfo(url.toLocalFile()).absolutePath()); | ||
| if (!parentDirectory.isDir() || !parentDirectory.isWritable()) { | ||
| setStatus(QStringLiteral("Could not open %1.").arg(targetName)); | ||
| return; | ||
| } | ||
|
|
||
| loadDocumentText(QString()); | ||
| clearRecovery(); | ||
| m_lastKnownFileContents.clear(); | ||
| m_hasKnownFileContents = false; | ||
| m_pathNeverRead = true; | ||
| setFileUrl(url); | ||
| setModified(false); | ||
| setStatus(QStringLiteral("New file %1").arg(fileName())); | ||
| return; | ||
| } | ||
|
|
||
| if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | ||
| // A reload with nothing left to read leaves this document holding a | ||
| // name and no file, and the watcher let the path go when it went. | ||
| // That is the state a new file starts in, so say so: if the file | ||
| // comes back, the next save asks rather than replacing it unseen. | ||
| if (!mayStartNewFile && !file.exists()) | ||
| m_pathNeverRead = true; | ||
|
|
||
| setStatus(QStringLiteral("Could not open %1.").arg(targetName)); | ||
| return; | ||
| } | ||
|
|
@@ -216,6 +250,7 @@ void Backend::open(const QUrl &url) { | |
| clearRecovery(); | ||
| m_lastKnownFileContents = contents; | ||
| m_hasKnownFileContents = true; | ||
| m_pathNeverRead = false; | ||
| setFileUrl(url); | ||
| watchCurrentFile(); | ||
| setModified(false); | ||
|
|
@@ -228,6 +263,20 @@ void Backend::save() { | |
| return; | ||
| } | ||
|
|
||
| // Nothing can watch a file that is not there, so a name taken for a file | ||
| // that has yet to be written is unguarded until this save: a `git pull` or | ||
| // a sync client can put something on that path in the meantime and | ||
| // QSaveFile::commit() would replace it without a word. Ask once, and only | ||
| // once -- the flag is cleared by every answer the dialog can give, so a | ||
| // file that turns out to be unreadable cannot leave the writer trapped in | ||
| // a question they have already answered. | ||
| if (m_pathNeverRead && m_fileUrl.isLocalFile() | ||
| && QFileInfo::exists(m_fileUrl.toLocalFile())) { | ||
| m_closeAfterSave = false; | ||
| emit externalFileAppeared(m_modified); | ||
| return; | ||
| } | ||
|
Comment on lines
+273
to
+278
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| saveTo(m_fileUrl); | ||
| } | ||
|
|
||
|
|
@@ -258,8 +307,13 @@ void Backend::discardRecovery() { | |
| } | ||
|
|
||
| void Backend::reloadFromDisk() { | ||
| // Reload is asked for a file we already have, so it must not go down the | ||
| // path that takes an absent name for a new document: if the file goes away | ||
| // between the "File changed" dialog opening and the click, blanking the | ||
| // editor and clearing recovery would throw away the only copy left. Say | ||
| // it could not be opened and leave the text where it is. | ||
| if (m_fileUrl.isLocalFile()) | ||
| open(m_fileUrl); | ||
| openPath(m_fileUrl, false); | ||
| } | ||
|
|
||
| void Backend::keepExternalVersion() { | ||
|
|
@@ -271,6 +325,11 @@ void Backend::keepExternalVersion() { | |
| m_lastKnownFileContents.clear(); | ||
| m_hasKnownFileContents = false; | ||
| } | ||
| // Answered, whether or not the file could be read. Failing to read it is | ||
| // not a reason to ask again: the writer said to keep their version, and | ||
| // the next save must be allowed to try, so the filesystem gets to give | ||
| // the answer instead of the dialog asking the same question forever. | ||
| m_pathNeverRead = false; | ||
| setModified(true); | ||
| scheduleRecovery(); | ||
| watchCurrentFile(); | ||
|
|
@@ -500,6 +559,7 @@ void Backend::saveTo(const QUrl &url) { | |
| m_closeAfterSave = false; | ||
| m_lastKnownFileContents = contents; | ||
| m_hasKnownFileContents = true; | ||
| m_pathNeverRead = false; | ||
| setFileUrl(url); | ||
| watchCurrentFile(); | ||
| QSettings().setValue(lastSaveDirectorySetting, | ||
|
|
@@ -532,6 +592,7 @@ void Backend::writeRecovery() { | |
| if (!file.open(QIODevice::WriteOnly)) | ||
| return; | ||
| const QJsonObject recovery{{QStringLiteral("fileUrl"), m_fileUrl.toString()}, | ||
| {QStringLiteral("pathNeverRead"), m_pathNeverRead}, | ||
| {QStringLiteral("text"), currentDocumentText()}}; | ||
| file.write(QJsonDocument(recovery).toJson(QJsonDocument::Compact)); | ||
| file.commit(); | ||
|
|
@@ -551,9 +612,17 @@ void Backend::restoreRecovery() { | |
| if (recoveredUrl.isLocalFile() && diskFile.open(QIODevice::ReadOnly)) { | ||
| m_lastKnownFileContents = diskFile.readAll(); | ||
| m_hasKnownFileContents = true; | ||
| // Reading it now says what is on the path, not that this document ever | ||
| // looked: the file can have arrived while Omawrite was gone. Only the | ||
| // snapshot knows, so a snapshot without the key predates the flag and | ||
| // names a path something was written to. | ||
| m_pathNeverRead = recovery.value(QStringLiteral("pathNeverRead")).toBool(); | ||
| } else { | ||
| m_lastKnownFileContents.clear(); | ||
| m_hasKnownFileContents = false; | ||
| // A snapshot can name a file that was never written -- the crash came | ||
| // first. That is the same unverified path a new file starts on. | ||
| m_pathNeverRead = true; | ||
| } | ||
| setFileUrl(recoveredUrl); | ||
| setModified(true); | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.