Open Recent, print sizes through an invalid resolution, Color Grading under Color (12.14b)
This commit is contained in:
1 parent
94b884a2ef
commit
2183348aa6
21 files changed
+717
-38
No files matched your search
@@ -1,10 +1,12 @@
|
||||
#include "IO/ProjectController.h"
|
||||
#include "IO/RecentProjects.h"
|
||||
#include "Document/ProjectWorkspace.h"
|
||||
#include "IO/ProjectStore.h"
|
||||
#include "Logging.h"
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFutureWatcher>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
@@ -187,6 +189,7 @@ void ProjectController::write(const Prepared &prepared, std::function<void(bool)
|
||||
session.history.markSaved(revision);
|
||||
session.setProjectPath(destination);
|
||||
m_saveGeneration += 1;
|
||||
RecentProjects::shared().note(destination);
|
||||
rememberProjectDigest(destination, [this, destination, landed] {
|
||||
watchProject(destination);
|
||||
externalChanges.saving = false;
|
||||
@@ -241,6 +244,12 @@ void ProjectController::open(std::optional<QString> path, std::function<void(boo
|
||||
// A folder's trailing slash would leave it without a name.
|
||||
while (source.endsWith(QLatin1Char('/')))
|
||||
source.chop(1);
|
||||
// A listed project deleted since: name it, not its manifest.
|
||||
if (!QFileInfo::exists(source)) {
|
||||
RecentProjects::shared().refresh();
|
||||
refuse(QStringLiteral("The file “%1” couldn’t be opened because there is no such file.").arg(QFileInfo(source).fileName()));
|
||||
return;
|
||||
}
|
||||
// A write in flight lands first: no read mid-save.
|
||||
finishWriting([this, end, refuse, source] {
|
||||
// Validated first: a corrupt project never discards the live document.
|
||||
@@ -258,6 +267,7 @@ void ProjectController::open(std::optional<QString> path, std::function<void(boo
|
||||
// Saving in the confirmation can replace the opened file.
|
||||
if (m_saveGeneration == previousSave || !samePlace(session.projectPath(), source)) {
|
||||
session.installProject(*first.snapshot, source);
|
||||
RecentProjects::shared().note(source);
|
||||
rememberProjectDigest(source, [this, source, end] {
|
||||
watchProject(source);
|
||||
end(true);
|
||||
@@ -270,6 +280,7 @@ void ProjectController::open(std::optional<QString> path, std::function<void(boo
|
||||
return;
|
||||
}
|
||||
session.installProject(*again.snapshot, source);
|
||||
RecentProjects::shared().note(source);
|
||||
rememberProjectDigest(source, [this, source, end] {
|
||||
watchProject(source);
|
||||
end(true);
|
||||
@@ -380,6 +391,11 @@ void ProjectController::showError(const QString &title, const QString &message,
|
||||
alert->setIcon(QMessageBox::Warning);
|
||||
alert->setText(title);
|
||||
alert->setInformativeText(message);
|
||||
// A file's name is read literally, never as markup.
|
||||
auto *words = alert->findChild<QLabel *>(QStringLiteral("qt_msgbox_informativelabel"));
|
||||
if (!words)
|
||||
throw std::logic_error("the alert has no informative label");
|
||||
words->setTextFormat(Qt::PlainText);
|
||||
alert->addButton(QStringLiteral("OK"), QMessageBox::AcceptRole);
|
||||
connect(alert, &QDialog::finished, this, std::move(then));
|
||||
alert->open();
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "IO/RecentProjects.h"
|
||||
#include <QFileInfo>
|
||||
#include <QGuiApplication>
|
||||
#include <QSettings>
|
||||
|
||||
namespace {
|
||||
const QString key = QStringLiteral("recentProjects");
|
||||
|
||||
// One place however it was reached, as Finder keeps it.
|
||||
QString resolved(const QString &path)
|
||||
{
|
||||
const QString canonical = QFileInfo(path).canonicalFilePath();
|
||||
return canonical.isEmpty() ? QFileInfo(path).absoluteFilePath() : canonical;
|
||||
}
|
||||
}
|
||||
|
||||
RecentProjects &RecentProjects::shared()
|
||||
{
|
||||
static RecentProjects recent;
|
||||
return recent;
|
||||
}
|
||||
|
||||
RecentProjects::RecentProjects()
|
||||
{
|
||||
refresh();
|
||||
// Checked again on activation; a GUI-less run has none.
|
||||
if (auto *app = qobject_cast<QGuiApplication *>(QCoreApplication::instance())) {
|
||||
connect(app, &QGuiApplication::applicationStateChanged, this, [this](Qt::ApplicationState state) {
|
||||
if (state == Qt::ApplicationActive)
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RecentProjects::note(const QString &path)
|
||||
{
|
||||
const QString place = resolved(path);
|
||||
QStringList stored = QSettings().value(key).toStringList();
|
||||
stored.removeAll(place);
|
||||
stored.prepend(place);
|
||||
store(stored.mid(0, limit));
|
||||
}
|
||||
|
||||
void RecentProjects::clear()
|
||||
{
|
||||
store({});
|
||||
}
|
||||
|
||||
void RecentProjects::refresh()
|
||||
{
|
||||
QStringList existing;
|
||||
for (const QString &path : QSettings().value(key).toStringList()) {
|
||||
if (QFileInfo::exists(path))
|
||||
existing << path;
|
||||
}
|
||||
if (existing == m_paths)
|
||||
return;
|
||||
m_paths = existing;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void RecentProjects::store(const QStringList &paths)
|
||||
{
|
||||
QSettings().setValue(key, paths);
|
||||
refresh();
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
// Swift's RecentProjects: newest first, kept in QSettings.
|
||||
class RecentProjects : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static RecentProjects &shared();
|
||||
// At most this many, as macOS keeps by default.
|
||||
static constexpr int limit = 10;
|
||||
|
||||
// The projects that still exist, newest first.
|
||||
const QStringList &paths() const { return m_paths; }
|
||||
void note(const QString &path);
|
||||
void clear();
|
||||
// Drops the projects since moved or deleted.
|
||||
void refresh();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
private:
|
||||
RecentProjects();
|
||||
void store(const QStringList &paths);
|
||||
|
||||
QStringList m_paths;
|
||||
};
|
||||
Reference in new issue
Block a user