Fix bug #14, don't ask for saving changes when read-only commands are used.

+ Added a new attribute for each undo item (undo::Modification).
+ Each item now modifies or does not modify the document (e.g. selection
  actions do not modify the document).
+ Added an asterisk in tabs when the document is modified.
This commit is contained in:
David Capello 2011-03-26 19:58:52 -03:00
parent 4fcbc7b6df
commit f854c7acf5
24 changed files with 116 additions and 17 deletions

View File

@ -378,11 +378,22 @@ void app_rebuild_documents_tabs()
// Insert all other sprites
for (Documents::const_iterator
it = docs.begin(), end = docs.end(); it != end; ++it) {
Document* document = *it;
tabsbar->setTabText(get_filename(document->getFilename()), document);
const Document* document = *it;
app_update_document_tab(document);
}
}
void app_update_document_tab(const Document* document)
{
std::string str = get_filename(document->getFilename());
// Add an asterisk if the document is modified.
if (document->isModified())
str += "*";
tabsbar->setTabText(str.c_str(), const_cast<Document*>(document));
}
/**
* Updates the recent list menu.
*

View File

@ -87,6 +87,7 @@ private:
void app_refresh_screen(const Document* document);
void app_rebuild_documents_tabs();
void app_update_document_tab(const Document* document);
bool app_realloc_recent_list();
int app_get_current_image_type();

View File

@ -141,6 +141,7 @@ void CelPropertiesCommand::onExecute(Context* context)
cel_writer->opacity != new_opacity) {
if (undo->isEnabled()) {
undo->setLabel("Cel Opacity Change");
undo->setModification(undo::ModifyDocument);
undo->undo_int(cel_writer, &cel_writer->opacity);
}

View File

@ -56,7 +56,7 @@ void DeselectMaskCommand::onExecute(Context* context)
{
ActiveDocumentWriter document(context);
{
UndoTransaction undoTransaction(document, "Mask Deselection");
UndoTransaction undoTransaction(document, "Mask Deselection", undo::DoesntModifyDocument);
undoTransaction.deselectMask();
undoTransaction.commit();
}

View File

@ -81,6 +81,7 @@ void InvertMaskCommand::onExecute(Context* context)
/* undo */
if (undo->isEnabled()) {
undo->setLabel("Mask Invert");
undo->setModification(undo::DoesntModifyDocument);
undo->undo_set_mask(document);
}

View File

@ -88,6 +88,7 @@ void LoadMaskCommand::onExecute(Context* context)
// Add the mask change into the undo history.
if (undo->isEnabled()) {
undo->setLabel("Mask Load");
undo->setModification(undo::DoesntModifyDocument);
undo->undo_set_mask(document);
}

View File

@ -62,6 +62,7 @@ void MaskAllCommand::onExecute(Context* context)
// Undo
if (undo->isEnabled()) {
undo->setLabel("Mask All");
undo->setModification(undo::DoesntModifyDocument);
undo->undo_set_mask(document);
}

View File

@ -84,6 +84,7 @@ void MergeDownLayerCommand::onExecute(Context* context)
if (undo->isEnabled()) {
undo->setLabel("Merge Down Layer");
undo->setModification(undo::ModifyDocument);
undo->undo_open();
}

View File

@ -667,6 +667,7 @@ void PaletteEntryEditor::updateCurrentSpritePalette(const char* operationName)
// Add undo information to save the range of pal entries that will be modified.
if (undo->isEnabled()) {
undo->setLabel(operationName);
undo->setModification(undo::ModifyDocument);
undo->undo_set_palette_colors(sprite, currentSpritePalette, from, to);
}

View File

@ -64,6 +64,7 @@ void ReselectMaskCommand::onExecute(Context* context)
// Undo
if (undo->isEnabled()) {
undo->setLabel("Mask Reselection");
undo->setModification(undo::DoesntModifyDocument);
undo->undo_set_mask(document);
}

View File

@ -139,6 +139,10 @@ static void save_document_in_background(Document* document, bool mark_as_saved)
delete data->progress;
fop_free(fop);
delete data;
// Update the tab for the document. In this moment, the document is
// already marked as saved, so the * is not shown in the tab.
app_update_document_tab(document);
}
/*********************************************************************/
@ -179,9 +183,10 @@ static void save_as_dialog(Document* document, const char* dlg_title, bool mark_
/* "no": we must back to select other file-name */
}
// Change the document file name
document->setFilename(filename.c_str());
app_rebuild_documents_tabs();
// Save the document
save_document_in_background(document, mark_as_saved);
}
@ -305,7 +310,6 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
// Restore the file name.
document->setFilename(old_filename.c_str());
app_rebuild_documents_tabs();
}
//////////////////////////////////////////////////////////////////////

View File

@ -208,6 +208,7 @@ void FilterManagerImpl::apply()
// Undo stuff
if (undo->isEnabled()) {
undo->setLabel(m_filter->getName());
undo->setModification(undo::ModifyDocument);
undo->undo_image(m_src, m_x, m_y, m_w, m_h);
}

View File

@ -134,6 +134,7 @@ void dialogs_mask_color(Document* document)
/* undo */
if (undo->isEnabled()) {
undo->setLabel("Mask by Color");
undo->setModification(undo::DoesntModifyDocument);
undo->undo_set_mask(document);
}

View File

@ -456,6 +456,9 @@ void update_screen_for_document(const Document* document)
// If it's the same palette update only the editors with the sprite.
update_editors_with_document(document);
}
// Update the tabs (maybe the modified status has been changed).
app_update_document_tab(document);
}
}

23
src/undo/modification.h Normal file
View File

@ -0,0 +1,23 @@
// ASEPRITE Undo Library
// Copyright (C) 2001-2011 David Capello
//
// This source file is ditributed under a BSD-like license, please
// read LICENSE.txt for more information.
#ifndef UNDO_MODIFICATION_H_INCLUDED
#define UNDO_MODIFICATION_H_INCLUDED
namespace undo {
// The modification flag is used to know if an Undoer item
// modifies the document's "saved state". It means that if the
// item modifies the document the user should be asked for "save
// changes" when he closes the document.
enum Modification {
ModifyDocument, // This item changes the "saved status" of the document.
DoesntModifyDocument // This item doesn't modify the document.
};
} // namespace undo
#endif // UNDO_MODIFICATION_H_INCLUDED

View File

@ -23,6 +23,7 @@ UndoHistory::UndoHistory(ObjectsContainer* objects)
m_diffSaved = 0;
m_enabled = true;
m_label = NULL;
m_modification = ModifyDocument;
m_undoers = new UndoersStack(this);
try {
@ -86,6 +87,16 @@ void UndoHistory::setLabel(const char* label)
m_label = label;
}
Modification UndoHistory::getModification()
{
return m_modification;
}
void UndoHistory::setModification(Modification mod)
{
m_modification = mod;
}
const char* UndoHistory::getNextUndoLabel() const
{
ASSERT(canUndo());
@ -120,8 +131,13 @@ void UndoHistory::runUndo(Direction direction)
do {
const char* itemLabel = NULL;
if (!undoers->empty())
itemLabel = (*undoers->begin())->getLabel();
Modification itemModification = DoesntModifyDocument;
if (!undoers->empty()) {
UndoersStack::Item* item = *undoers->begin();
itemLabel = item->getLabel();
itemModification = item->getModification();
}
Undoer* undoer = undoers->popUndoer(UndoersStack::PopFromHead);
if (!undoer)
@ -138,10 +154,12 @@ void UndoHistory::runUndo(Direction direction)
// Delete the undoer
undoer->dispose();
if (direction == UndoDirection)
m_diffCount--;
else if (direction == RedoDirection)
m_diffCount++;
if (itemModification == ModifyDocument) {
if (direction == UndoDirection)
m_diffCount--;
else if (direction == RedoDirection)
m_diffCount++;
}
} while (level);
}
@ -176,7 +194,8 @@ void UndoHistory::pushUndoer(Undoer* undoer)
int undo_size_limit = (int)get_config_int("Options", "UndoSizeLimit", 8)*1024*1024;
// More differences.
m_diffCount++;
if (m_modification == ModifyDocument)
m_diffCount++;
// Reset the "redo" stack.
clearRedo();

View File

@ -7,6 +7,7 @@
#ifndef UNDO_UNDO_HISTORY_H_INCLUDED
#define UNDO_UNDO_HISTORY_H_INCLUDED
#include "undo/modification.h"
#include "undo/undoers_collector.h"
#include <vector>
@ -45,9 +46,16 @@ public:
void clearRedo();
// Current label for next added Undoers.
const char* getLabel();
void setLabel(const char* label);
// Change the "modify saved status" flag to be assigned for next
// added items. When it is activated means that each added Undoer
// modifies the "saved status" of the document.
Modification getModification();
void setModification(Modification mod);
const char* getNextUndoLabel() const;
const char* getNextRedoLabel() const;
@ -109,6 +117,7 @@ private:
int m_diffSaved;
bool m_enabled; // Is undo enabled?
const char* m_label; // Current label to be applied to all next undo operations.
Modification m_modification; // Current label to be applied to all next undo operations.
};
} // namespace undo

View File

@ -50,7 +50,8 @@ void UndoersStack::pushUndoer(Undoer* undoer)
ASSERT(undoer != NULL);
try {
Item* item = new Item(m_undoHistory->getLabel(), undoer);
Item* item = new Item(m_undoHistory->getLabel(),
m_undoHistory->getModification(), undoer);
try {
m_items.insert(begin(), item);
}

View File

@ -7,6 +7,7 @@
#ifndef UNDO_UNDOERS_STACK_H_INCLUDED
#define UNDO_UNDOERS_STACK_H_INCLUDED
#include "undo/modification.h"
#include "undo/undoers_collector.h"
#include <vector>
@ -32,14 +33,18 @@ public:
class Item
{
public:
Item(const char* label, Undoer* undoer)
Item(const char* label, Modification mod, Undoer* undoer)
: m_label(label)
, m_mod(mod)
, m_undoer(undoer) { }
const char* getLabel() const { return m_label; }
Modification getModification() const { return m_mod; }
Undoer* getUndoer() const { return m_undoer; }
private:
const char* m_label;
Modification m_mod;
Undoer* m_undoer;
};

View File

@ -34,7 +34,7 @@
#include "raster/stock.h"
#include "undo/undo_history.h"
UndoTransaction::UndoTransaction(Document* document, const char* label)
UndoTransaction::UndoTransaction(Document* document, const char* label, undo::Modification modification)
{
ASSERT(label != NULL);
@ -46,6 +46,7 @@ UndoTransaction::UndoTransaction(Document* document, const char* label)
if (isEnabled()) {
m_undoHistory->setLabel(label);
m_undoHistory->setModification(modification);
m_undoHistory->undo_open();
}
}

View File

@ -20,6 +20,7 @@
#define UNDO_TRANSACTION_H_INCLUDED
#include "raster/dithering_method.h"
#include "undo/modification.h"
class Cel;
class Document;
@ -55,7 +56,7 @@ public:
// Starts a undoable sequence of operations in a transaction that
// can be committed or rollbacked. All the operations will be
// grouped in the sprite's undo as an atomic operation.
UndoTransaction(Document* document, const char* label);
UndoTransaction(Document* document, const char* label, undo::Modification mod = undo::ModifyDocument);
virtual ~UndoTransaction();
inline Sprite* getSprite() const { return m_sprite; }

View File

@ -72,6 +72,7 @@ void move_cel(DocumentWriter& document)
if (undo->isEnabled()) {
undo->setLabel("Move Cel");
undo->setModification(undo::ModifyDocument);
undo->undo_open();
undo->undo_set_layer(sprite);
@ -161,6 +162,7 @@ void copy_cel(DocumentWriter& document)
if (undo->isEnabled()) {
undo->setLabel("Move Cel");
undo->setModification(undo::ModifyDocument);
undo->undo_open();
undo->undo_set_layer(sprite);

View File

@ -156,6 +156,7 @@ int interactive_move_layer(int mode, bool use_undo, int (*callback)())
if (!editor->editor_click_cancel()) {
if (use_undo && undo->isEnabled()) {
undo->setLabel("Cel Movement");
undo->setModification(undo::ModifyDocument);
undo->undo_open();
undo->undo_int(cel, &cel->x);
undo->undo_int(cel, &cel->y);

View File

@ -1900,8 +1900,17 @@ public:
m_offset.y = -y1;
// Set undo label for any kind of undo used in the whole loop
if (m_document->getUndoHistory()->isEnabled())
if (m_document->getUndoHistory()->isEnabled()) {
m_document->getUndoHistory()->setLabel(m_tool->getText().c_str());
if (getInk()->isSelection() ||
getInk()->isEyedropper() ||
getInk()->isScrollMovement()) {
m_document->getUndoHistory()->setModification(undo::DoesntModifyDocument);
}
else
m_document->getUndoHistory()->setModification(undo::ModifyDocument);
}
}
~ToolLoopImpl()