mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-06 03:39:51 +00:00
New option to configure how much time we keep a closed sprite on RAM
This commit is contained in:
parent
a7a9d05de3
commit
c7d1e4a472
@ -133,7 +133,9 @@
|
||||
<option id="data_recovery" type="bool" default="true" />
|
||||
<option id="data_recovery_period" type="double" default="2.0" />
|
||||
<option id="keep_edited_sprite_data" type="bool" default="true" />
|
||||
<option id="keep_edited_sprite_data_lifespan" type="int" default="7" />
|
||||
<option id="keep_edited_sprite_data_for" type="int" default="7" />
|
||||
<option id="keep_closed_sprite_on_memory" type="bool" default="true" />
|
||||
<option id="keep_closed_sprite_on_memory_for" type="double" default="15.0" />
|
||||
<option id="show_full_path" type="bool" default="true" />
|
||||
<option id="timeline_position" type="TimelinePosition" default="TimelinePosition::BOTTOM" />
|
||||
<option id="timeline_layer_panel_width" type="int" default="100" />
|
||||
|
@ -137,6 +137,7 @@ Aseprite
|
||||
END
|
||||
restart_by_preferences_save_recovery_data_period = Automatically save recovery data every X minutes
|
||||
restart_by_preferences_keep_edited_sprite_data_lifespan = Keep edited sprite data for X days
|
||||
restart_by_preferences_keep_closed_sprite_on_memory_for = Keep closed sprite on memory for X minutes
|
||||
restore_all_shortcuts = <<<END
|
||||
Warning
|
||||
<<Do you want to restore all keyboard shortcuts
|
||||
@ -937,6 +938,7 @@ Check this option to get
|
||||
this old menus behavior.
|
||||
END
|
||||
color_bar_entries_separator = Draw a separation between each palette entry
|
||||
recover_files = Recover Files
|
||||
auto_save_recovery_data = Automatically save recovery data every
|
||||
auto_save_recovery_data_tooltip = <<<END
|
||||
With this option you can recover your documents
|
||||
@ -950,6 +952,9 @@ END
|
||||
10_minutes = 10 Minutes
|
||||
15_minutes = 15 Minutes
|
||||
30_minutes = 30 Minutes
|
||||
1_hour = 1 Hour
|
||||
4_hours = 4 Hours
|
||||
8_hours = 8 Hours
|
||||
keep_edited_sprite_data = Keep edited sprite data for
|
||||
keep_edited_sprite_data_tooltip = <<<END
|
||||
With this option you can re-open edited documents
|
||||
@ -967,6 +972,12 @@ show_full_path_tooltip = <<<END
|
||||
Uncheck this option if you would prefer to hide
|
||||
full path on UI (e.g. useful for live streaming)
|
||||
END
|
||||
keep_closed_sprite_on_memory = Keep closed sprite on memory for
|
||||
keep_closed_sprite_on_memory_tooltip = <<<END
|
||||
When you close a sprite, it will be kept on memory just in case if you
|
||||
have closed the sprite by mistake, so you can "undo" the close action
|
||||
using "File > Reopen Closed File" menu option.
|
||||
END
|
||||
default_extension_for = Default extension for:
|
||||
save_default_extension = File > Save:
|
||||
export_image_default_extension = File > Export (one image):
|
||||
|
@ -67,32 +67,7 @@
|
||||
text="@.color_bar_entries_separator"
|
||||
tooltip="@.color_bar_entries_separator"
|
||||
pref="color_bar.entries_separator" />
|
||||
<grid columns="2">
|
||||
<check id="enable_data_recovery"
|
||||
text="@.auto_save_recovery_data"
|
||||
tooltip="@.auto_save_recovery_data_tooltip" />
|
||||
<combobox id="data_recovery_period">
|
||||
<listitem text="@.10_seconds" value="0.1667" />
|
||||
<listitem text="@.30_seconds" value="0.5" />
|
||||
<listitem text="@.1_minute" value="1" />
|
||||
<listitem text="@.2_minutes" value="2" />
|
||||
<listitem text="@.5_minutes" value="5" />
|
||||
<listitem text="@.10_minutes" value="10" />
|
||||
<listitem text="@.15_minutes" value="15" />
|
||||
<listitem text="@.30_minutes" value="30" />
|
||||
</combobox>
|
||||
<check id="keep_edited_sprite_data"
|
||||
text="@.keep_edited_sprite_data"
|
||||
tooltip="@.keep_edited_sprite_data_tooltip" />
|
||||
<combobox id="keep_edited_sprite_data_lifespan">
|
||||
<listitem text="@.1_day" value="1" />
|
||||
<listitem text="@.2_days" value="2" />
|
||||
<listitem text="@.3_days" value="3" />
|
||||
<listitem text="@.1_week" value="7" />
|
||||
<listitem text="@.2_weeks" value="14" />
|
||||
<listitem text="@.1_month" value="30" />
|
||||
</combobox>
|
||||
</grid>
|
||||
|
||||
<separator horizontal="true" />
|
||||
<link id="locate_file" text="@.locate_file" />
|
||||
<link id="locate_crash_folder" text="@.locate_crash_folder" />
|
||||
@ -101,7 +76,6 @@
|
||||
<!-- Files -->
|
||||
<vbox id="section_files">
|
||||
<separator text="@.section_files" horizontal="true" />
|
||||
|
||||
<label text="@.default_extension_for" />
|
||||
<grid columns="2">
|
||||
<label text="@.save_default_extension" />
|
||||
@ -129,6 +103,51 @@
|
||||
text="@.show_full_path"
|
||||
tooltip="@.show_full_path_tooltip" />
|
||||
</grid>
|
||||
|
||||
<separator text="@.recover_files" horizontal="true" />
|
||||
<grid columns="2">
|
||||
<check id="enable_data_recovery"
|
||||
text="@.auto_save_recovery_data"
|
||||
tooltip="@.auto_save_recovery_data_tooltip" />
|
||||
<combobox id="data_recovery_period">
|
||||
<listitem text="@.10_seconds" value="0.1667" />
|
||||
<listitem text="@.30_seconds" value="0.5" />
|
||||
<listitem text="@.1_minute" value="1" />
|
||||
<listitem text="@.2_minutes" value="2" />
|
||||
<listitem text="@.5_minutes" value="5" />
|
||||
<listitem text="@.10_minutes" value="10" />
|
||||
<listitem text="@.15_minutes" value="15" />
|
||||
<listitem text="@.30_minutes" value="30" />
|
||||
</combobox>
|
||||
<check id="keep_edited_sprite_data"
|
||||
text="@.keep_edited_sprite_data"
|
||||
tooltip="@.keep_edited_sprite_data_tooltip" />
|
||||
<combobox id="keep_edited_sprite_data_for">
|
||||
<listitem text="@.1_day" value="1" />
|
||||
<listitem text="@.2_days" value="2" />
|
||||
<listitem text="@.3_days" value="3" />
|
||||
<listitem text="@.1_week" value="7" />
|
||||
<listitem text="@.2_weeks" value="14" />
|
||||
<listitem text="@.1_month" value="30" />
|
||||
</combobox>
|
||||
<check id="keep_closed_sprite_on_memory"
|
||||
text="@.keep_closed_sprite_on_memory"
|
||||
tooltip="@.keep_closed_sprite_on_memory_tooltip" />
|
||||
<combobox id="keep_closed_sprite_on_memory_for">
|
||||
<listitem text="@.10_seconds" value="0.1667" />
|
||||
<listitem text="@.30_seconds" value="0.5" />
|
||||
<listitem text="@.1_minute" value="1" />
|
||||
<listitem text="@.2_minutes" value="2" />
|
||||
<listitem text="@.5_minutes" value="5" />
|
||||
<listitem text="@.10_minutes" value="10" />
|
||||
<listitem text="@.15_minutes" value="15" />
|
||||
<listitem text="@.30_minutes" value="30" />
|
||||
<listitem text="@.1_hour" value="60" />
|
||||
<listitem text="@.4_hours" value="240" />
|
||||
<listitem text="@.8_hours" value="480" />
|
||||
</combobox>
|
||||
</grid>
|
||||
|
||||
</vbox>
|
||||
|
||||
<!-- Color -->
|
||||
|
@ -195,6 +195,7 @@ if(ENABLE_UI)
|
||||
set(ui_app_files
|
||||
app_brushes.cpp
|
||||
app_menus.cpp
|
||||
closed_docs.cpp
|
||||
commands/cmd_about.cpp
|
||||
commands/cmd_add_color.cpp
|
||||
commands/cmd_advanced_mode.cpp
|
||||
|
@ -420,7 +420,7 @@ void App::run()
|
||||
// Destroy all documents from the UIContext.
|
||||
std::vector<Doc*> docs;
|
||||
#ifdef ENABLE_UI
|
||||
for (Doc* doc : m_modules->m_context.closedDocs())
|
||||
for (Doc* doc : m_modules->m_context.getAndRemoveAllClosedDocs())
|
||||
docs.push_back(doc);
|
||||
#endif
|
||||
for (Doc* doc : m_modules->m_context.documents())
|
||||
|
166
src/app/closed_docs.cpp
Normal file
166
src/app/closed_docs.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/closed_docs.h"
|
||||
#include "app/doc.h"
|
||||
#include "app/pref/preferences.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#define CLOSEDOC_TRACE(...)
|
||||
|
||||
namespace app {
|
||||
|
||||
ClosedDocs::ClosedDocs()
|
||||
: m_done(false)
|
||||
{
|
||||
CLOSEDOC_TRACE("CLOSEDOC: Init");
|
||||
|
||||
const auto& pref = Preferences::instance();
|
||||
if (pref.general.dataRecovery())
|
||||
m_dataRecoveryPeriodMSecs = int(1000.0*60.0*pref.general.dataRecoveryPeriod());
|
||||
else
|
||||
m_dataRecoveryPeriodMSecs = 0;
|
||||
|
||||
if (pref.general.keepClosedSpriteOnMemory())
|
||||
m_keepClosedDocAliveForMSecs = int(1000.0*60.0*pref.general.keepClosedSpriteOnMemoryFor());
|
||||
else
|
||||
m_keepClosedDocAliveForMSecs = 0;
|
||||
}
|
||||
|
||||
ClosedDocs::~ClosedDocs()
|
||||
{
|
||||
CLOSEDOC_TRACE("CLOSEDOC: Exit");
|
||||
|
||||
if (m_thread.joinable()) {
|
||||
CLOSEDOC_TRACE("CLOSEDOC: Join thread");
|
||||
|
||||
m_done = true;
|
||||
m_cv.notify_one();
|
||||
m_thread.join();
|
||||
|
||||
CLOSEDOC_TRACE("CLOSEDOC: Join done");
|
||||
}
|
||||
|
||||
ASSERT(m_docs.empty());
|
||||
}
|
||||
|
||||
bool ClosedDocs::hasClosedDocs()
|
||||
{
|
||||
bool result;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
result = !m_docs.empty();
|
||||
}
|
||||
CLOSEDOC_TRACE("CLOSEDOC: Has closed docs?",
|
||||
(result ? "true": "false"));
|
||||
return result;
|
||||
}
|
||||
|
||||
void ClosedDocs::addClosedDoc(Doc* doc)
|
||||
{
|
||||
CLOSEDOC_TRACE("CLOSEDOC: Add closed doc", doc);
|
||||
|
||||
ASSERT(doc != nullptr);
|
||||
ASSERT(doc->context() == nullptr);
|
||||
|
||||
ClosedDoc closedDoc = { doc, base::current_tick() };
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_docs.insert(m_docs.begin(), std::move(closedDoc));
|
||||
|
||||
if (!m_thread.joinable())
|
||||
m_thread = std::thread([this]{ backgroundThread(); });
|
||||
else
|
||||
m_cv.notify_one();
|
||||
}
|
||||
|
||||
Doc* ClosedDocs::reopenLastClosedDoc()
|
||||
{
|
||||
Doc* doc = nullptr;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (!m_docs.empty()) {
|
||||
doc = m_docs.front().doc;
|
||||
m_docs.erase(m_docs.begin());
|
||||
}
|
||||
CLOSEDOC_TRACE(" -> ", doc);
|
||||
}
|
||||
CLOSEDOC_TRACE("CLOSEDOC: Reopen last closed doc", doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
std::vector<Doc*> ClosedDocs::getAndRemoveAllClosedDocs()
|
||||
{
|
||||
std::vector<Doc*> docs;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
CLOSEDOC_TRACE("CLOSEDOC: Get and remove all closed", m_docs.size(), "docs");
|
||||
for (const ClosedDoc& closedDoc : m_docs)
|
||||
docs.push_back(closedDoc.doc);
|
||||
m_docs.clear();
|
||||
m_done = true;
|
||||
m_cv.notify_one();
|
||||
}
|
||||
return docs;
|
||||
}
|
||||
|
||||
void ClosedDocs::backgroundThread()
|
||||
{
|
||||
CLOSEDOC_TRACE("CLOSEDOC: [BG] Background thread start");
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
while (!m_done) {
|
||||
base::tick_t now = base::current_tick();
|
||||
base::tick_t waitForMSecs = std::numeric_limits<base::tick_t>::max();
|
||||
|
||||
for (auto it=m_docs.begin(); it != m_docs.end(); ) {
|
||||
const ClosedDoc& closedDoc = *it;
|
||||
|
||||
base::tick_t diff = now - closedDoc.timestamp;
|
||||
if (diff >= m_keepClosedDocAliveForMSecs) {
|
||||
if (m_dataRecoveryPeriodMSecs == 0 ||
|
||||
closedDoc.doc->isFullyBackedUp()) {
|
||||
// Finally delete the document (this is the place where we
|
||||
// delete all documents created/loaded by the user)
|
||||
CLOSEDOC_TRACE("CLOSEDOC: [BG] Delete doc", closedDoc.doc);
|
||||
delete closedDoc.doc;
|
||||
it = m_docs.erase(it);
|
||||
}
|
||||
else {
|
||||
waitForMSecs = std::min(waitForMSecs, m_dataRecoveryPeriodMSecs);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
else {
|
||||
waitForMSecs = std::min(waitForMSecs, m_keepClosedDocAliveForMSecs-diff);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (waitForMSecs < std::numeric_limits<base::tick_t>::max()) {
|
||||
CLOSEDOC_TRACE("CLOSEDOC: [BG] Wait for", waitForMSecs, "milliseconds");
|
||||
|
||||
ASSERT(!m_docs.empty());
|
||||
m_cv.wait_for(lock, std::chrono::milliseconds(waitForMSecs));
|
||||
}
|
||||
else {
|
||||
CLOSEDOC_TRACE("CLOSEDOC: [BG] Wait for condition variable");
|
||||
|
||||
ASSERT(m_docs.empty());
|
||||
m_cv.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
CLOSEDOC_TRACE("CLOSEDOC: [BG] Background thread end");
|
||||
}
|
||||
|
||||
} // namespace app
|
62
src/app/closed_docs.h
Normal file
62
src/app/closed_docs.h
Normal file
@ -0,0 +1,62 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_CLOSED_DOCS_H_INCLUDED
|
||||
#define APP_CLOSED_DOCS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/time.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace app {
|
||||
|
||||
class Doc;
|
||||
|
||||
// Handle the list of closed docs:
|
||||
// * When a document is closed, we keep it for some time so the user
|
||||
// can undo the close command without losing the undo history.
|
||||
// * For the first closed document, a thread is launched to wait
|
||||
// until we can definitely delete the doc after X minutes (like a
|
||||
// garbage collector).
|
||||
// * If the document was not restore, we delete it from memory, if
|
||||
// the document was restore, we remove it from the m_docs.
|
||||
class ClosedDocs {
|
||||
public:
|
||||
ClosedDocs();
|
||||
~ClosedDocs();
|
||||
|
||||
bool hasClosedDocs();
|
||||
void addClosedDoc(Doc* doc);
|
||||
Doc* reopenLastClosedDoc();
|
||||
|
||||
// Called at the very end to get all closed docs, remove them from
|
||||
// the list of closed docs, and stop the thread.
|
||||
std::vector<Doc*> getAndRemoveAllClosedDocs();
|
||||
|
||||
private:
|
||||
void backgroundThread();
|
||||
|
||||
struct ClosedDoc {
|
||||
Doc* doc;
|
||||
base::tick_t timestamp;
|
||||
};
|
||||
|
||||
bool m_done;
|
||||
base::tick_t m_dataRecoveryPeriodMSecs;
|
||||
base::tick_t m_keepClosedDocAliveForMSecs;
|
||||
std::vector<ClosedDoc> m_docs;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_cv;
|
||||
std::thread m_thread;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -245,6 +245,9 @@ public:
|
||||
if (m_pref.general.keepEditedSpriteData())
|
||||
keepEditedSpriteData()->setSelected(true);
|
||||
|
||||
if (m_pref.general.keepClosedSpriteOnMemory())
|
||||
keepClosedSpriteOnMemory()->setSelected(true);
|
||||
|
||||
if (m_pref.general.showFullPath())
|
||||
showFullPath()->setSelected(true);
|
||||
|
||||
@ -252,9 +255,13 @@ public:
|
||||
dataRecoveryPeriod()->findItemIndexByValue(
|
||||
base::convert_to<std::string>(m_pref.general.dataRecoveryPeriod())));
|
||||
|
||||
keepEditedSpriteDataLifespan()->setSelectedItemIndex(
|
||||
keepEditedSpriteDataLifespan()->findItemIndexByValue(
|
||||
base::convert_to<std::string>(m_pref.general.keepEditedSpriteDataLifespan())));
|
||||
keepEditedSpriteDataFor()->setSelectedItemIndex(
|
||||
keepEditedSpriteDataFor()->findItemIndexByValue(
|
||||
base::convert_to<std::string>(m_pref.general.keepEditedSpriteDataFor())));
|
||||
|
||||
keepClosedSpriteOnMemoryFor()->setSelectedItemIndex(
|
||||
keepClosedSpriteOnMemoryFor()->findItemIndexByValue(
|
||||
base::convert_to<std::string>(m_pref.general.keepClosedSpriteOnMemoryFor())));
|
||||
|
||||
if (m_pref.editor.zoomFromCenterWithWheel())
|
||||
zoomFromCenterWithWheel()->setSelected(true);
|
||||
@ -486,15 +493,24 @@ public:
|
||||
warnings += "<<- " + Strings::alerts_restart_by_preferences_save_recovery_data_period();
|
||||
}
|
||||
|
||||
int newLifespan = base::convert_to<int>(keepEditedSpriteDataLifespan()->getValue());
|
||||
int newLifespan = base::convert_to<int>(keepEditedSpriteDataFor()->getValue());
|
||||
if (keepEditedSpriteData()->isSelected() != m_pref.general.keepEditedSpriteData() ||
|
||||
newLifespan != m_pref.general.keepEditedSpriteDataLifespan()) {
|
||||
newLifespan != m_pref.general.keepEditedSpriteDataFor()) {
|
||||
m_pref.general.keepEditedSpriteData(keepEditedSpriteData()->isSelected());
|
||||
m_pref.general.keepEditedSpriteDataLifespan(newLifespan);
|
||||
m_pref.general.keepEditedSpriteDataFor(newLifespan);
|
||||
|
||||
warnings += "<<- " + Strings::alerts_restart_by_preferences_keep_edited_sprite_data_lifespan();
|
||||
}
|
||||
|
||||
newLifespan = base::convert_to<int>(keepClosedSpriteOnMemoryFor()->getValue());
|
||||
if (keepClosedSpriteOnMemory()->isSelected() != m_pref.general.keepClosedSpriteOnMemory() ||
|
||||
newLifespan != m_pref.general.keepClosedSpriteOnMemoryFor()) {
|
||||
m_pref.general.keepClosedSpriteOnMemory(keepClosedSpriteOnMemory()->isSelected());
|
||||
m_pref.general.keepClosedSpriteOnMemoryFor(newLifespan);
|
||||
|
||||
warnings += "<<- " + Strings::alerts_restart_by_preferences_keep_closed_sprite_on_memory_for();
|
||||
}
|
||||
|
||||
m_pref.editor.zoomFromCenterWithWheel(zoomFromCenterWithWheel()->isSelected());
|
||||
m_pref.editor.zoomFromCenterWithKeys(zoomFromCenterWithKeys()->isSelected());
|
||||
m_pref.editor.showScrollbars(showScrollbars()->isSelected());
|
||||
|
@ -34,19 +34,15 @@ ReopenClosedFileCommand::ReopenClosedFileCommand()
|
||||
bool ReopenClosedFileCommand::onEnabled(Context* ctx)
|
||||
{
|
||||
if (auto uiCtx = dynamic_cast<UIContext*>(ctx)) {
|
||||
const auto& docs = uiCtx->closedDocs();
|
||||
return (!docs.empty());
|
||||
return uiCtx->hasClosedDocs();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReopenClosedFileCommand::onExecute(Context* ctx)
|
||||
{
|
||||
if (auto uiCtx = dynamic_cast<UIContext*>(ctx)) {
|
||||
const auto& docs = uiCtx->closedDocs();
|
||||
if (!docs.empty())
|
||||
uiCtx->reopenClosedDoc(docs.front());
|
||||
}
|
||||
if (auto uiCtx = dynamic_cast<UIContext*>(ctx))
|
||||
uiCtx->reopenLastClosedDoc();
|
||||
}
|
||||
|
||||
Command* CommandFactory::createReopenClosedFileCommand()
|
||||
|
@ -97,7 +97,7 @@ void BackupObserver::onRemoveDocument(Doc* doc)
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
base::remove_from_container(m_documents, doc);
|
||||
}
|
||||
if (m_config->keepEditedSpriteData)
|
||||
if (m_config->keepEditedSpriteDataFor > 0)
|
||||
m_closedDocs.push_back(doc);
|
||||
else
|
||||
m_session->removeDocument(doc);
|
||||
@ -119,7 +119,8 @@ void BackupObserver::backgroundThread()
|
||||
while (!m_done) {
|
||||
m_wakeup.wait_for(lock, std::chrono::seconds(waitFor));
|
||||
|
||||
TRACE("RECO: Start backup process for %d documents\n", m_documents.size());
|
||||
TRACE("RECO: Start backup process for %d documents\n",
|
||||
m_documents.size() + m_closedDocs.size());
|
||||
|
||||
SwitchBackupIcon icon;
|
||||
base::Chrono chrono;
|
||||
@ -133,8 +134,15 @@ void BackupObserver::backgroundThread()
|
||||
if (!m_closedDocs.empty()) {
|
||||
for (auto it=m_closedDocs.begin(); it != m_closedDocs.end(); ) {
|
||||
Doc* doc = *it;
|
||||
if (saveDocData(doc))
|
||||
|
||||
TRACE("RECO: Save backup data for %p...\n", doc);
|
||||
|
||||
if (saveDocData(doc)) {
|
||||
TRACE("RECO: Doc %p is fully backed up\n", doc);
|
||||
|
||||
it = m_closedDocs.erase(it);
|
||||
doc->markAsBackedUp();
|
||||
}
|
||||
else {
|
||||
somethingLocked = true;
|
||||
++it;
|
||||
@ -161,8 +169,8 @@ bool BackupObserver::saveDocData(Doc* doc)
|
||||
else if (!m_session->saveDocumentChanges(doc)) {
|
||||
TRACE("RECO: Document '%d' backup was canceled by UI\n", doc->id());
|
||||
}
|
||||
#ifdef TEST_BACKUP_INTEGRITY
|
||||
else {
|
||||
#ifdef TEST_BACKUP_INTEGRITY
|
||||
DocReader reader(doc, 500);
|
||||
std::unique_ptr<Doc> copy(
|
||||
m_session->restoreBackupDocById(doc->id(), nullptr));
|
||||
@ -188,9 +196,9 @@ bool BackupObserver::saveDocData(Doc* doc)
|
||||
else {
|
||||
TRACE("RECO: No differences\n");
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
TRACE("RECO: Document '%d' is locked\n", doc->id());
|
||||
|
@ -37,8 +37,10 @@ DataRecovery::DataRecovery(Context* ctx)
|
||||
{
|
||||
auto& pref = Preferences::instance();
|
||||
m_config.dataRecoveryPeriod = pref.general.dataRecoveryPeriod();
|
||||
m_config.keepEditedSpriteData = pref.general.keepEditedSpriteData();
|
||||
m_config.keepEditedSpriteDataLifespan = pref.general.keepEditedSpriteDataLifespan();
|
||||
if (pref.general.keepEditedSpriteData())
|
||||
m_config.keepEditedSpriteDataFor = pref.general.keepEditedSpriteDataFor();
|
||||
else
|
||||
m_config.keepEditedSpriteDataFor = 0;
|
||||
|
||||
ResourceFinder rf;
|
||||
rf.includeUserDir(base::join_path("sessions", ".").c_str());
|
||||
|
@ -15,8 +15,7 @@ namespace crash {
|
||||
// avoid accessing to Preferences from a non-UI thread.
|
||||
struct RecoveryConfig {
|
||||
double dataRecoveryPeriod;
|
||||
bool keepEditedSpriteData;
|
||||
int keepEditedSpriteDataLifespan;
|
||||
int keepEditedSpriteDataFor;
|
||||
};
|
||||
|
||||
} // namespace crash
|
||||
|
@ -140,17 +140,17 @@ bool Session::isCrashedSession()
|
||||
|
||||
bool Session::isOldSession()
|
||||
{
|
||||
if (!m_config->keepEditedSpriteData)
|
||||
if (m_config->keepEditedSpriteDataFor <= 0)
|
||||
return true;
|
||||
|
||||
std::string verfile = verFilename();
|
||||
if (!base::is_file(verfile))
|
||||
return true;
|
||||
|
||||
int lifespan = m_config->keepEditedSpriteDataLifespan;
|
||||
int lifespanDays = m_config->keepEditedSpriteDataFor;
|
||||
base::Time sessionTime = base::get_modification_time(verfile);
|
||||
|
||||
return (sessionTime.addDays(lifespan) < base::current_time());
|
||||
return (sessionTime.addDays(lifespanDays) < base::current_time());
|
||||
}
|
||||
|
||||
bool Session::isEmpty()
|
||||
@ -183,7 +183,7 @@ void Session::close()
|
||||
|
||||
// If we don't have to keep the sprite data, just remove it from
|
||||
// the disk.
|
||||
if (!m_config->keepEditedSpriteData)
|
||||
if (m_config->keepEditedSpriteDataFor == 0)
|
||||
removeFromDisk();
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
|
@ -75,8 +75,15 @@ void Doc::setContext(Context* ctx)
|
||||
removeFromContext();
|
||||
|
||||
m_ctx = ctx;
|
||||
if (ctx)
|
||||
if (ctx) {
|
||||
// Remove the flag that indicates that this doc is fully backed
|
||||
// up, because now we are inside a context, so the user can change
|
||||
// it again and the backup will be outdated.
|
||||
if (m_flags & kFullyBackedUp)
|
||||
m_flags ^= kFullyBackedUp;
|
||||
|
||||
ctx->documents().add(this);
|
||||
}
|
||||
|
||||
onContextChanged();
|
||||
}
|
||||
@ -227,6 +234,16 @@ void Doc::setInhibitBackup(const bool inhibitBackup)
|
||||
m_flags &= ~kInhibitBackup;
|
||||
}
|
||||
|
||||
void Doc::markAsBackedUp()
|
||||
{
|
||||
m_flags |= kFullyBackedUp;
|
||||
}
|
||||
|
||||
bool Doc::isFullyBackedUp() const
|
||||
{
|
||||
return (m_flags & kFullyBackedUp ? true: false);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Loaded options from file
|
||||
|
||||
|
@ -63,6 +63,7 @@ namespace app {
|
||||
kAssociatedToFile = 1, // This sprite is associated to a file in the file-system
|
||||
kMaskVisible = 2, // The mask wasn't hidden by the user
|
||||
kInhibitBackup = 4, // Inhibit the backup process
|
||||
kFullyBackedUp = 8, // Full backup was done
|
||||
};
|
||||
public:
|
||||
Doc(Sprite* sprite);
|
||||
@ -122,6 +123,9 @@ namespace app {
|
||||
bool inhibitBackup() const;
|
||||
void setInhibitBackup(const bool inhibitBackup);
|
||||
|
||||
void markAsBackedUp();
|
||||
bool isFullyBackedUp() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Loaded options from file
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/ui_context.h"
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/doc.h"
|
||||
#include "app/modules/editors.h"
|
||||
@ -24,7 +26,6 @@
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "app/ui/workspace.h"
|
||||
#include "app/ui/workspace_tabs.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/mutex.h"
|
||||
#include "doc/sprite.h"
|
||||
|
||||
@ -225,15 +226,22 @@ Editor* UIContext::activeEditor()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void UIContext::reopenClosedDoc(Doc* doc)
|
||||
bool UIContext::hasClosedDocs()
|
||||
{
|
||||
auto it = std::find(m_closedDocs.begin(), m_closedDocs.end(), doc);
|
||||
ASSERT(it != m_closedDocs.end());
|
||||
if (it != m_closedDocs.end())
|
||||
m_closedDocs.erase(it);
|
||||
return m_closedDocs.hasClosedDocs();
|
||||
}
|
||||
|
||||
// Put the document in the context again.
|
||||
doc->setContext(this);
|
||||
void UIContext::reopenLastClosedDoc()
|
||||
{
|
||||
if (Doc* doc = m_closedDocs.reopenLastClosedDoc()) {
|
||||
// Put the document in the context again.
|
||||
doc->setContext(this);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Doc*> UIContext::getAndRemoveAllClosedDocs()
|
||||
{
|
||||
return m_closedDocs.getAndRemoveAllClosedDocs();
|
||||
}
|
||||
|
||||
void UIContext::onAddDocument(Doc* doc)
|
||||
@ -312,7 +320,8 @@ void UIContext::onCloseDocument(Doc* doc)
|
||||
{
|
||||
ASSERT(doc != nullptr);
|
||||
ASSERT(doc->context() == nullptr);
|
||||
m_closedDocs.insert(m_closedDocs.begin(), doc);
|
||||
|
||||
m_closedDocs.addClosedDoc(doc);
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define APP_UI_CONTEXT_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/closed_docs.h"
|
||||
#include "app/context.h"
|
||||
#include "app/docs_observer.h"
|
||||
|
||||
@ -44,9 +45,9 @@ namespace app {
|
||||
// new one if it's necessary.
|
||||
Editor* getEditorFor(Doc* document);
|
||||
|
||||
// Returns the list of closed docs in this session.
|
||||
const std::vector<Doc*>& closedDocs() const { return m_closedDocs; }
|
||||
void reopenClosedDoc(Doc* doc);
|
||||
bool hasClosedDocs();
|
||||
void reopenLastClosedDoc();
|
||||
std::vector<Doc*> getAndRemoveAllClosedDocs();
|
||||
|
||||
protected:
|
||||
void onAddDocument(Doc* doc) override;
|
||||
@ -59,7 +60,7 @@ namespace app {
|
||||
|
||||
private:
|
||||
DocView* m_lastSelectedView;
|
||||
std::vector<Doc*> m_closedDocs;
|
||||
ClosedDocs m_closedDocs;
|
||||
|
||||
static UIContext* m_instance;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user