* fixed quite a few selections bugs, most were caused by cyclic notifications,

and the mechanism to prevent them not working...
* could have fixed the "there are still listeners attached" bug (debugger drop)
  on exit, I have not seen it again, but I am not sure if it is really fixed
* introduced a way to ask the user, if changes should be saved and then
  pick up the line of thought after saving


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22269 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2007-09-21 15:21:38 +00:00
parent c4ce9e7607
commit 015a014aa7
14 changed files with 145 additions and 51 deletions

View File

@ -62,7 +62,9 @@ IconEditorApp::IconEditorApp()
fLastOpenPath(""),
fLastSavePath(""),
fLastExportPath("")
fLastExportPath(""),
fMessageAfterSave(NULL)
{
}
@ -76,6 +78,8 @@ IconEditorApp::~IconEditorApp()
delete fOpenPanel;
delete fSavePanel;
delete fMessageAfterSave;
}
// #pragma mark -
@ -84,7 +88,9 @@ IconEditorApp::~IconEditorApp()
bool
IconEditorApp::QuitRequested()
{
// TODO: ask main window if quitting is ok
if (!_CheckSaveIcon(CurrentMessage()))
return false;
_StoreSettings();
fMainWindow->Lock();
@ -103,14 +109,12 @@ IconEditorApp::MessageReceived(BMessage* message)
_MakeIconEmpty();
break;
case MSG_OPEN: {
// fOpenPanel->Refresh();
BMessage openMessage(B_REFS_RECEIVED);
fOpenPanel->SetMessage(&openMessage);
fOpenPanel->Show();
break;
}
case MSG_APPEND: {
// fOpenPanel->Refresh();
BMessage openMessage(B_REFS_RECEIVED);
openMessage.AddBool("append", true);
fOpenPanel->SetMessage(&openMessage);
@ -126,6 +130,7 @@ IconEditorApp::MessageReceived(BMessage* message)
saver = fDocument->ExportSaver();
if (saver) {
saver->Save(fDocument);
_PickUpActionBeforeSave();
break;
} // else fall through
}
@ -153,6 +158,7 @@ IconEditorApp::MessageReceived(BMessage* message)
else
fDocument->SetExportSaver(saver);
saver->Save(fDocument);
_PickUpActionBeforeSave();
}
}
_SyncPanels(fSavePanel, fOpenPanel);
@ -267,9 +273,61 @@ IconEditorApp::ArgvReceived(int32 argc, char** argv)
// #pragma mark -
// _CheckSaveIcon
bool
IconEditorApp::_CheckSaveIcon(const BMessage* currentMessage)
{
if (fDocument->IsEmpty() || fDocument->CommandStack()->IsSaved())
return true;
BAlert* alert = new BAlert("save", "Save changes to current icon?",
"Discard", "Cancel", "Save");
int32 choice = alert->Go();
switch (choice) {
case 0:
// discard
return true;
case 1:
// cancel
return false;
case 2:
default:
// cancel (save first) but pick what we were doing before
PostMessage(MSG_SAVE);
if (currentMessage) {
delete fMessageAfterSave;
fMessageAfterSave = new BMessage(*currentMessage);
}
return false;
}
}
// _PickUpActionBeforeSave
void
IconEditorApp::_PickUpActionBeforeSave()
{
if (fDocument->WriteLock()) {
fDocument->CommandStack()->Save();
fDocument->WriteUnlock();
}
if (!fMessageAfterSave)
return;
PostMessage(fMessageAfterSave);
delete fMessageAfterSave;
fMessageAfterSave = NULL;
}
// #pragma mark -
// _MakeIconEmpty
void
IconEditorApp::_MakeIconEmpty()
{
if (!_CheckSaveIcon(CurrentMessage()))
return;
bool mainWindowLocked = fMainWindow && fMainWindow->Lock();
AutoWriteLocker locker(fDocument);
@ -289,6 +347,9 @@ IconEditorApp::_MakeIconEmpty()
void
IconEditorApp::_Open(const entry_ref& ref, bool append)
{
if (!_CheckSaveIcon(CurrentMessage()))
return;
BFile file(&ref, B_READ_ONLY);
if (file.InitCheck() < B_OK)
return;
@ -390,6 +451,9 @@ void
IconEditorApp::_Open(const BMessenger& externalObserver,
const uint8* data, size_t size)
{
if (!_CheckSaveIcon(CurrentMessage()))
return;
if (!externalObserver.IsValid())
return;

View File

@ -63,6 +63,9 @@ class IconEditorApp : public BApplication {
// IconEditorApp
private:
bool _CheckSaveIcon(const BMessage* currentMessage);
void _PickUpActionBeforeSave();
void _MakeIconEmpty();
void _Open(const entry_ref& ref,
bool append = false);
@ -89,6 +92,8 @@ class IconEditorApp : public BApplication {
BString fLastOpenPath;
BString fLastSavePath;
BString fLastExportPath;
BMessage* fMessageAfterSave;
};
#endif // ICON_EDITOR_APP_H

View File

@ -215,6 +215,10 @@ case MSG_PATH_SELECTED: {
VectorPath* path;
if (message->FindPointer("path", (void**)&path) < B_OK)
path = NULL;
fPathListView->SetCurrentShape(NULL);
fStyleListView->SetCurrentShape(NULL);
fTransformerListView->SetShape(NULL);
fState->DeleteManipulators();
if (fDocument->Icon()->Paths()->HasPath(path)) {
@ -223,7 +227,8 @@ case MSG_PATH_SELECTED: {
}
break;
}
case MSG_STYLE_SELECTED: {
case MSG_STYLE_SELECTED:
case MSG_STYLE_TYPE_CHANGED: {
Style* style;
if (message->FindPointer("style", (void**)&style) < B_OK)
style = NULL;
@ -231,14 +236,13 @@ case MSG_STYLE_SELECTED: {
style = NULL;
fStyleView->SetStyle(style);
break;
}
case MSG_GRADIENT_SELECTED: {
// if there is a gradient, add a transform box around it
Gradient* gradient;
if (message->FindPointer("gradient", (void**)&gradient) < B_OK)
gradient = NULL;
fPathListView->SetCurrentShape(NULL);
fStyleListView->SetCurrentShape(NULL);
fTransformerListView->SetShape(NULL);
fState->DeleteManipulators();
Gradient* gradient = style ? style->Gradient() : NULL;
if (gradient) {
TransformGradientBox* transformBox
= new (nothrow) TransformGradientBox(fCanvasView,

View File

@ -12,7 +12,10 @@
#include "CommandStack.h"
#include "DocumentSaver.h"
#include "Icon.h"
#include "PathContainer.h"
#include "Selection.h"
#include "ShapeContainer.h"
#include "StyleContainer.h"
#include <Entry.h>
@ -112,4 +115,12 @@ Document::MakeEmpty(bool includingSavers)
}
}
// IsEmpty
bool
Document::IsEmpty() const
{
return fIcon->Styles()->CountStyles() == 0
&& fIcon->Paths()->CountPaths() == 0
&& fIcon->Shapes()->CountShapes() == 0;
}

View File

@ -57,6 +57,8 @@ class Document : public RWLocker,
void MakeEmpty(bool includingSavers = true);
bool IsEmpty() const;
private:
BPrivate::Icon::Icon* fIcon;
::CommandStack* fCommandStack;

View File

@ -533,9 +533,10 @@ DragSortableListView::MouseWheelChanged(float x, float y)
void
DragSortableListView::ObjectChanged(const Observable* object)
{
if (object != fSelection || fModifyingSelection)
if (object != fSelection || fModifyingSelection || fSyncingToSelection)
return;
//printf("%s - syncing start\n", Name());
fSyncingToSelection = true;
// try to sync to Selection
@ -567,6 +568,7 @@ DragSortableListView::ObjectChanged(const Observable* object)
}
fSyncingToSelection = false;
//printf("%s - done\n", Name());
}
// #pragma mark -
@ -813,7 +815,7 @@ DragSortableListView::SelectionChanged()
{
//printf("%s::SelectionChanged()", typeid(*this).name());
// modify global Selection
if (!fSelection)
if (!fSelection || fSyncingToSelection)
return;
fModifyingSelection = true;

View File

@ -623,7 +623,7 @@ PathListView::PathAdded(VectorPath* path, int32 index)
return;
if (_AddPath(path, index))
Select(CountItems() - 1);
Select(index);
UnlockLooper();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Haiku.
* Copyright 2006-2007, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -129,7 +129,6 @@ ShapeListView::~ShapeListView()
void
ShapeListView::SelectionChanged()
{
SimpleListView::SelectionChanged();
if (!fSyncingToSelection) {
@ -387,7 +386,8 @@ ShapeListView::ShapeAdded(Shape* shape, int32 index)
if (!LockLooper())
return;
_AddShape(shape, index);
if (_AddShape(shape, index))
Select(index);
UnlockLooper();
}

View File

@ -555,10 +555,8 @@ StyleListView::StyleAdded(Style* style, int32 index)
if (!LockLooper())
return;
// NOTE: shapes are always added at the end
// of the list, so the sorting is synced...
if (_AddStyle(style, index))
Select(CountItems() - 1);
Select(index);
UnlockLooper();
}

View File

@ -267,7 +267,7 @@ StyleView::ObjectChanged(const Observable* object)
// TODO: is this really necessary?
controlGradient->SetTransform(*fGradient);
if (*fGradient != *controlGradient) {
if (!fGradient->ColorStepsAreEqual(*controlGradient)) {
if (fCommandStack) {
fCommandStack->Perform(
new (nothrow) SetGradientCommand(
@ -279,7 +279,7 @@ StyleView::ObjectChanged(const Observable* object)
_TransferGradientStopColor();
}
} else if (object == fGradient) {
if (*fGradient != *controlGradient) {
if (!fGradient->ColorStepsAreEqual(*controlGradient)) {
fGradientControl->SetGradient(fGradient);
_MarkType(fGradientType->Menu(), fGradient->Type());
// transfer the current gradient color to the current color
@ -288,7 +288,7 @@ StyleView::ObjectChanged(const Observable* object)
} else if (object == fStyle) {
// maybe the gradient was added or removed
// or the color changed
_SetGradient(fStyle->Gradient());
_SetGradient(fStyle->Gradient(), false, true);
if (fCurrentColor && !fStyle->Gradient())
fCurrentColor->SetColor(fStyle->Color());
} else if (object == fCurrentColor) {
@ -361,7 +361,7 @@ StyleView::SetCurrentColor(CurrentColor* color)
// _SetGradient
void
StyleView::_SetGradient(Gradient* gradient, bool forceControlUpdate)
StyleView::_SetGradient(Gradient* gradient, bool forceControlUpdate, bool sendMessage)
{
if (!forceControlUpdate && fGradient == gradient)
return;
@ -387,9 +387,9 @@ StyleView::_SetGradient(Gradient* gradient, bool forceControlUpdate)
_MarkType(fGradientType->Menu(), -1);
}
if (Window()) {
BMessage message(MSG_GRADIENT_SELECTED);
message.AddPointer("gradient", (void*)fGradient);
if (sendMessage) {
BMessage message(MSG_STYLE_TYPE_CHANGED);
message.AddPointer("style", fStyle);
Window()->PostMessage(&message);
}
}

View File

@ -31,7 +31,7 @@ using namespace BPrivate::Icon;
// TODO: write lock the document when changing something...
enum {
MSG_GRADIENT_SELECTED = 'grsl',
MSG_STYLE_TYPE_CHANGED = 'stch',
};
class StyleView : public BView,
@ -59,7 +59,8 @@ class StyleView : public BView,
private:
void _SetGradient(Gradient* gradient,
bool forceControlUpdate = false);
bool forceControlUpdate = false,
bool sendMessage = false);
void _MarkType(BMenu* menu,
int32 type) const;
void _SetStyleType(int32 type);

View File

@ -72,8 +72,6 @@ AddShapesCommand::Perform()
fContainer->RemoveShape(fShapes[j]);
break;
}
if (fSelection)
fSelection->Select(fShapes[i], i > 0);
index++;
}
fShapesAdded = true;

View File

@ -227,25 +227,8 @@ Gradient::operator=(const Gradient& other)
bool
Gradient::operator==(const Gradient& other) const
{
if (Transformable::operator==(other)) {
int32 count = CountColors();
if (count == other.CountColors() &&
fType == other.fType &&
fInterpolation == other.fInterpolation &&
fInheritTransformation == other.fInheritTransformation) {
bool equal = true;
for (int32 i = 0; i < count; i++) {
color_step* ourStep = ColorAtFast(i);
color_step* otherStep = other.ColorAtFast(i);
if (*ourStep != *otherStep) {
equal = false;
break;
}
}
return equal;
}
}
if (Transformable::operator==(other))
return ColorStepsAreEqual(other);
return false;
}
@ -256,6 +239,30 @@ Gradient::operator!=(const Gradient& other) const
return !(*this == other);
}
// ColorStepsAreEqual
bool
Gradient::ColorStepsAreEqual(const Gradient& other) const
{
int32 count = CountColors();
if (count == other.CountColors() &&
fType == other.fType &&
fInterpolation == other.fInterpolation &&
fInheritTransformation == other.fInheritTransformation) {
bool equal = true;
for (int32 i = 0; i < count; i++) {
color_step* ourStep = ColorAtFast(i);
color_step* otherStep = other.ColorAtFast(i);
if (*ourStep != *otherStep) {
equal = false;
break;
}
}
return equal;
}
return false;
}
// SetColors
void
Gradient::SetColors(const Gradient& other)

View File

@ -78,6 +78,8 @@ class Gradient : public Transformable {
bool operator==(const Gradient& other) const;
bool operator!=(const Gradient& other) const;
bool ColorStepsAreEqual(
const Gradient& other) const;
void SetColors(const Gradient& other);