From dc4fe6be00757dfe3e0882d54598be4b98926404 Mon Sep 17 00:00:00 2001 From: Tri-Edge AI Date: Mon, 14 Jan 2013 06:47:46 +0200 Subject: [PATCH] Extended ResourceEdit. Signed-off-by: Matt Madia --- src/apps/resourceedit/Constants.h | 21 +- src/apps/resourceedit/DefaultTypes.cpp | 88 +- src/apps/resourceedit/DefaultTypes.h | 79 +- src/apps/resourceedit/EditWindow.cpp | 163 ++++ src/apps/resourceedit/EditWindow.h | 53 ++ src/apps/resourceedit/Jamfile | 35 +- src/apps/resourceedit/MainWindow.cpp | 782 ++++++++++++++++-- src/apps/resourceedit/MainWindow.h | 111 ++- src/apps/resourceedit/ResourceEdit.cpp | 37 +- src/apps/resourceedit/ResourceEdit.h | 5 + src/apps/resourceedit/ResourceEdit.rdef | 2 +- src/apps/resourceedit/ResourceListView.cpp | 12 +- src/apps/resourceedit/ResourceListView.h | 1 + src/apps/resourceedit/ResourceRow.cpp | 78 +- src/apps/resourceedit/ResourceRow.h | 15 +- src/apps/resourceedit/SettingsFile.cpp | 56 ++ src/apps/resourceedit/SettingsFile.h | 33 + src/apps/resourceedit/SettingsWindow.cpp | 120 +++ src/apps/resourceedit/SettingsWindow.h | 48 ++ src/apps/resourceedit/edits/AppFlagsEdit.cpp | 4 + src/apps/resourceedit/edits/AppFlagsEdit.h | 4 + src/apps/resourceedit/edits/BooleanEdit.cpp | 71 ++ src/apps/resourceedit/edits/BooleanEdit.h | 30 + src/apps/resourceedit/edits/EditView.cpp | 52 ++ src/apps/resourceedit/edits/EditView.h | 31 + src/apps/resourceedit/edits/NormalEdit.cpp | 64 ++ src/apps/resourceedit/edits/NormalEdit.h | 31 + .../{ => interface}/ImageButton.cpp | 0 .../{ => interface}/ImageButton.h | 0 .../settings/GenericSettingsView.cpp | 60 ++ .../settings/GenericSettingsView.h | 37 + src/apps/resourceedit/support/UndoContext.cpp | 175 ++++ src/apps/resourceedit/support/UndoContext.h | 55 ++ 33 files changed, 2121 insertions(+), 232 deletions(-) create mode 100644 src/apps/resourceedit/EditWindow.cpp create mode 100644 src/apps/resourceedit/EditWindow.h create mode 100644 src/apps/resourceedit/SettingsFile.cpp create mode 100644 src/apps/resourceedit/SettingsFile.h create mode 100644 src/apps/resourceedit/SettingsWindow.cpp create mode 100644 src/apps/resourceedit/SettingsWindow.h create mode 100644 src/apps/resourceedit/edits/AppFlagsEdit.cpp create mode 100644 src/apps/resourceedit/edits/AppFlagsEdit.h create mode 100644 src/apps/resourceedit/edits/BooleanEdit.cpp create mode 100644 src/apps/resourceedit/edits/BooleanEdit.h create mode 100644 src/apps/resourceedit/edits/EditView.cpp create mode 100644 src/apps/resourceedit/edits/EditView.h create mode 100644 src/apps/resourceedit/edits/NormalEdit.cpp create mode 100644 src/apps/resourceedit/edits/NormalEdit.h rename src/apps/resourceedit/{ => interface}/ImageButton.cpp (100%) rename src/apps/resourceedit/{ => interface}/ImageButton.h (100%) create mode 100644 src/apps/resourceedit/settings/GenericSettingsView.cpp create mode 100644 src/apps/resourceedit/settings/GenericSettingsView.h create mode 100644 src/apps/resourceedit/support/UndoContext.cpp create mode 100644 src/apps/resourceedit/support/UndoContext.h diff --git a/src/apps/resourceedit/Constants.h b/src/apps/resourceedit/Constants.h index 4a9766e7d7..1bb2e97590 100644 --- a/src/apps/resourceedit/Constants.h +++ b/src/apps/resourceedit/Constants.h @@ -25,13 +25,24 @@ #define MSG_CLEAR 'm015' #define MSG_SELECTALL 'm016' -#define MSG_ADD 'm020' -#define MSG_REMOVE 'm021' -#define MSG_MOVEUP 'm022' -#define MSG_MOVEDOWN 'm023' +#define MSG_ADDAPPRES 'm020' +#define MSG_SETTINGS 'm021' -#define MSG_SELECTION 'm030' +#define MSG_ADD 'm030' +#define MSG_REMOVE 'm031' +#define MSG_MOVEUP 'm032' +#define MSG_MOVEDOWN 'm033' +#define MSG_SELECTION 'm040' +#define MSG_INVOCATION 'm041' + +#define MSG_ACCEPT 'm050' +#define MSG_CANCEL 'm051' +#define MSG_IGNORE 'm052' + +#define MSG_SETTINGS_APPLY 'm022' +#define MSG_SETTINGS_REVERT 'm023' +#define MSG_SETTINGS_CLOSED 'm024' // TODO: Remove prior to release. #define DEBUG 1 diff --git a/src/apps/resourceedit/DefaultTypes.cpp b/src/apps/resourceedit/DefaultTypes.cpp index 9f7de5deae..3fed852f9c 100644 --- a/src/apps/resourceedit/DefaultTypes.cpp +++ b/src/apps/resourceedit/DefaultTypes.cpp @@ -9,84 +9,22 @@ #include -BString -toStringBOOL(const void* data) +int32 +ResourceType::FindIndex(type_code code) { - if (*(bool*)data) - return "✔ true"; - else - return "✖ false"; -} + for (int32 i = 0; kDefaultTypes[i].type != NULL; i++) + if (StringToCode(kDefaultTypes[i].code) == code) + return i; - -BString -toStringBYTE(const void* data) -{ - return (BString() << *(int8*)data); -} - - -BString -toStringSHRT(const void* data) -{ - return (BString() << *(int16*)data); -} - - -BString -toStringLONG(const void* data) -{ - return (BString() << *(int32*)data); -} - - -BString -toStringLLNG(const void* data) -{ - return (BString() << *(int64*)data); -} - - -BString -toStringUBYT(const void* data) -{ - return (BString() << *(uint8*)data); -} - - -BString -toStringUSHT(const void* data) -{ - return (BString() << *(uint16*)data); -} - - -BString -toStringULNG(const void* data) -{ - return (BString() << *(uint32*)data); -} - - -BString -toStringULLG(const void* data) -{ - return (BString() << *(uint64*)data); -} - - -BString -toStringRAWT(const void* data) -{ - return "[Raw Data]"; + return -1; } int32 -FindTypeCodeIndex(type_code code) +ResourceType::FindIndex(const char* type) { for (int32 i = 0; kDefaultTypes[i].type != NULL; i++) - if (kDefaultTypes[i].typeCode == code) + if (strcmp(kDefaultTypes[i].type, type) == 0) return i; return -1; @@ -94,8 +32,16 @@ FindTypeCodeIndex(type_code code) void -TypeCodeToString(type_code code, char* str) +ResourceType::CodeToString(type_code code, char* str) { *(type_code*)str = B_HOST_TO_BENDIAN_INT32(code); str[4] = '\0'; } + + +type_code +ResourceType::StringToCode(const char* code) +{ + // TODO: Code may be in other formats, too! Ex.: 0x4C4F4E47 + return B_BENDIAN_TO_HOST_INT32(*(int32*)code); +} diff --git a/src/apps/resourceedit/DefaultTypes.h b/src/apps/resourceedit/DefaultTypes.h index 42ebf87d77..ef51b66aa1 100644 --- a/src/apps/resourceedit/DefaultTypes.h +++ b/src/apps/resourceedit/DefaultTypes.h @@ -6,61 +6,64 @@ #define DEFAULT_TYPES_H +#include "AppFlagsEdit.h" +#include "BooleanEdit.h" +#include "EditView.h" +#include "NormalEdit.h" +#include "ResourceRow.h" + #include -struct ResourceDataType { - const char* type; - type_code typeCode; - uint32 size; - BString (*toString)(const void*); +struct ResourceType { + const char* type; + const char* code; + const char* data; + uint32 size; + EditView* edit; + + static int32 FindIndex(const char* type); + static int32 FindIndex(type_code code); + + static void CodeToString(type_code code, char* str); + static type_code StringToCode(const char* code); }; -// TODO: Rework design of this. This one sucks. -BString toStringBOOL(const void* data); -BString toStringBYTE(const void* data); -BString toStringSHRT(const void* data); -BString toStringLONG(const void* data); -BString toStringLLNG(const void* data); -BString toStringUBYT(const void* data); -BString toStringUSHT(const void* data); -BString toStringULNG(const void* data); -BString toStringULLG(const void* data); -BString toStringRAWT(const void* data); +#define LINE "", "", "", ~0, NULL +#define END NULL, NULL, NULL, 0, NULL -char * const kDefaultData[] = { - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -#define LINE "", 0, ~0 -#define END NULL, 0, 0 - -const ResourceDataType kDefaultTypes[] = { - { "bool", 'BOOL', 1, toStringBOOL }, +const ResourceType kDefaultTypes[] = { + { "app_signature", "", "application/MyApp", 18, new NormalEdit() }, + { "app_name_catalog_entry", "", "MyApp:System name:MyApp", 24, new NormalEdit() }, + //{ "app_flags", "", "None", 4, NULL }, { LINE }, - { "int8", 'BYTE', 1, toStringBYTE }, - { "int16", 'SHRT', 2, toStringSHRT }, - { "int32", 'LONG', 4, toStringLONG }, - { "int64", 'LLNG', 8, toStringLLNG }, + { "bool", "BOOL", "false", 1, new BooleanEdit() }, { LINE }, - { "uint8", 'UBYT', 1, toStringUBYT }, - { "uint16", 'USHT', 2, toStringUSHT }, - { "uint32", 'ULNG', 4, toStringULNG }, - { "uint64", 'ULLG', 8, toStringULLG }, + { "int8", "BYTE", "0", 1, new NormalEdit() }, + { "int16", "SHRT", "0", 2, new NormalEdit() }, + { "int32", "LONG", "0", 4, new NormalEdit() }, + { "int64", "LLNG", "0", 8, new NormalEdit() }, { LINE }, - { "raw", 'RAWT', 0, toStringRAWT }, + { "uint8", "UBYT", "0", 1, new NormalEdit() }, + { "uint16", "USHT", "0", 2, new NormalEdit() }, + { "uint32", "ULNG", "0", 4, new NormalEdit() }, + { "uint64", "ULLG", "0", 8, new NormalEdit() }, + { LINE }, + { "string", "CSTR", "\"\"", 0, NULL }, + { "raw", "RAWT", "", 0, NULL }, + { LINE }, + { "array", "", "", 0, NULL }, + { "message", "", "", 0, NULL }, + { "import", "", "", 0, NULL }, { END } }; -const int32 kDefaultTypeSelected = 4; +const int32 kDefaultTypeSelected = 8; // int32 #undef LINE #undef END -int32 FindTypeCodeIndex(type_code code); -void TypeCodeToString(type_code code, char* str); - #endif diff --git a/src/apps/resourceedit/EditWindow.cpp b/src/apps/resourceedit/EditWindow.cpp new file mode 100644 index 0000000000..73b03644ae --- /dev/null +++ b/src/apps/resourceedit/EditWindow.cpp @@ -0,0 +1,163 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "EditWindow.h" + +#include "Constants.h" +#include "DefaultTypes.h" +#include "EditView.h" +#include "ResourceRow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +EditWindow::EditWindow(BRect frame, ResourceRow* row) + : + BWindow(frame, "Edit Resource", + B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, 0) +{ + int32 ix = ResourceType::FindIndex(row->ResourceType()); + + fRow = row; + + fView = new BView(Bounds(), "fView", B_FOLLOW_ALL, 0); + fView->SetLayout(new BGroupLayout(B_VERTICAL)); + + fIDText = new BTextControl(BRect(0, 0, 0, 0), + "fIDText", "ID:", row->ResourceStringID(), NULL); + fIDText->SetDivider(50); + + fNameText = new BTextControl(BRect(0, 0, 0, 0), + "fNameText", "Name:", row->ResourceName(), NULL); + fNameText->SetDivider(50); + + fTypePopUp = new BPopUpMenu("(Type)"); + + // TODO: (Not so) evil redundancy. + for (int32 i = 0; kDefaultTypes[i].type != NULL; i++) { + if (kDefaultTypes[i].size == ~(uint32)0) + fTypePopUp->AddSeparatorItem(); + else + fTypePopUp->AddItem(new BMenuItem(kDefaultTypes[i].type, + new BMessage(MSG_SELECTION))); + } + // --- + + fTypePopUp->ItemAt(ix)->SetMarked(true); + + fTypeMenu = new BMenuField(BRect(0, 0, 0, 0), + "fTypeMenu", "Type:", fTypePopUp); + fTypeMenu->SetDivider(50); + + fCodeText = new BTextControl(BRect(0, 0, 0, 0), + "fCodeText", "Code:", row->ResourceStringCode(), NULL); + fCodeText->SetDivider(50); + + fEditViewBox = new BBox(BRect(0, 0, 0, 0), "fEditViewBox"); + fEditViewBox->SetLayout(new BGroupLayout(B_VERTICAL)); + + fEditView = kDefaultTypes[ix].edit; + fEditView->AttachTo(fEditViewBox); + fEditView->Edit(fRow); + + fErrorString = new BStringView(BRect(0, 0, 0, 0), + "fErrorString", ""); + + fErrorString->SetHighColor(ui_color(B_FAILURE_COLOR)); + + fCancelButton = new BButton(BRect(0, 0, 0, 0), + "fCancelButton", "Cancel", new BMessage(MSG_CANCEL)); + fOKButton = new BButton(BRect(0, 0, 0, 0), + "fOKButton", "OK", new BMessage(MSG_ACCEPT)); + + fView->AddChild(BGroupLayoutBuilder(B_VERTICAL, 8) + .Add(fIDText) + .Add(fNameText) + .Add(fTypeMenu) + .Add(fCodeText) + .Add(fEditViewBox) + .Add(fErrorString) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, 8) + .AddGlue() + .Add(fCancelButton) + .Add(fOKButton) + .SetInsets(8, 8, 8, 8) + ) + .SetInsets(8, 8, 8, 8) + ); + + AddChild(fView); + ResizeTo(250, 350); + + Show(); +} + + +EditWindow::~EditWindow() +{ + fEditView->RemoveSelf(); +} + + +void +EditWindow::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case MSG_SELECTION: + { + int32 ix = fTypePopUp->FindMarkedIndex(); + + fCodeText->SetText(kDefaultTypes[ix].code); + + fEditView->RemoveSelf(); + + fEditView = kDefaultTypes[ix].edit; + fEditView->AttachTo(fEditViewBox); + fEditView->Edit(fRow); + + break; + } + case MSG_CANCEL: + PostMessage(B_QUIT_REQUESTED); + break; + + case MSG_ACCEPT: + { + if (_Validate()) { + int32 ix = fTypePopUp->FindMarkedIndex(); + + fRow->SetResourceStringID(fIDText->Text()); + fRow->SetResourceName(fNameText->Text()); + fRow->SetResourceType(kDefaultTypes[ix].type); + fRow->SetResourceStringCode(fCodeText->Text()); + fRow->SetResourceSize(kDefaultTypes[ix].size); + + fEditView->Commit(); + + PostMessage(B_QUIT_REQUESTED); + } + + break; + } + } +} + + +bool +EditWindow::_Validate() +{ + // TODO: Implement validation of entered data. + fErrorString->SetText(""); + return true; +} diff --git a/src/apps/resourceedit/EditWindow.h b/src/apps/resourceedit/EditWindow.h new file mode 100644 index 0000000000..d104af98fb --- /dev/null +++ b/src/apps/resourceedit/EditWindow.h @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef EDIT_WINDOW_H +#define EDIT_WINDOW_H + + +#include + + +class EditView; +class ResourceRow; + +class BBox; +class BButton; +class BMenuField; +class BPopUpMenu; +class BStringView; +class BTextControl; + + +class EditWindow : public BWindow { +public: + EditWindow(BRect frame, ResourceRow* row); + ~EditWindow(); + + void MessageReceived(BMessage* msg); + +private: + ResourceRow* fRow; + + BView* fView; + + BTextControl* fIDText; + BTextControl* fNameText; + BPopUpMenu* fTypePopUp; + BMenuField* fTypeMenu; + BTextControl* fCodeText; + + EditView* fEditView; + BBox* fEditViewBox; + + BStringView* fErrorString; + + BButton* fCancelButton; + BButton* fOKButton; + + bool _Validate(); +}; + + +#endif diff --git a/src/apps/resourceedit/Jamfile b/src/apps/resourceedit/Jamfile index 9507e9ad1b..b392f77ea4 100644 --- a/src/apps/resourceedit/Jamfile +++ b/src/apps/resourceedit/Jamfile @@ -2,14 +2,46 @@ SubDir HAIKU_TOP src apps resourceedit ; UsePrivateHeaders interface shared ; +local sourceDirs = + edits + interface + settings + support +; + +local sourceDir ; + +for sourceDir in $(sourceDirs) { + SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src apps resourceedit $(sourceDir) ] ; +} + Application ResourceEdit : - DefaultTypes.cpp + # edits + AppFlagsEdit.cpp + BooleanEdit.cpp + EditView.cpp + NormalEdit.cpp + + # interface ImageButton.cpp + + # settings + GenericSettingsView.cpp + + # support + UndoContext.cpp + + # . + DefaultTypes.cpp + EditWindow.cpp MainWindow.cpp ResourceEdit.cpp ResourceListView.cpp ResourceRow.cpp + SettingsFile.cpp + SettingsWindow.cpp + main.cpp : be @@ -17,7 +49,6 @@ Application ResourceEdit translation libcolumnlistview.a $(TARGET_LIBSTDC++) - : ResourceEdit.rdef ; diff --git a/src/apps/resourceedit/MainWindow.cpp b/src/apps/resourceedit/MainWindow.cpp index d6413e3ea9..1a04e8c132 100644 --- a/src/apps/resourceedit/MainWindow.cpp +++ b/src/apps/resourceedit/MainWindow.cpp @@ -7,11 +7,17 @@ #include "MainWindow.h" #include "Constants.h" +#include "EditWindow.h" #include "ImageButton.h" #include "ResourceListView.h" #include "ResourceRow.h" +#include "SettingsFile.h" +#include "SettingsWindow.h" +#include "UndoContext.h" +#include #include +#include #include #include #include @@ -23,8 +29,8 @@ #include #include #include -#include #include +#include #include #include @@ -39,13 +45,19 @@ using namespace std; -MainWindow::MainWindow(BRect frame, BEntry* assocEntry) +MainWindow::MainWindow(BRect frame, BEntry* assocEntry, SettingsFile* settings) : - BWindow(frame, NULL, B_DOCUMENT_WINDOW, 0) + BWindow(frame, NULL, B_DOCUMENT_WINDOW, B_OUTLINE_RESIZE) { fAssocEntry = assocEntry; + fSettings = settings; + + fUndoContext = new UndoContext(); + + AdaptSettings(); fSavePanel = NULL; + fUnsavedChanges = false; fMenuBar = new BMenuBar(BRect(0, 0, 600, 1), "fMenuBar"); @@ -64,14 +76,24 @@ MainWindow::MainWindow(BRect frame, BEntry* assocEntry) fEditMenu = new BMenu("Edit", B_ITEMS_IN_COLUMN); fUndoItem = new BMenuItem("Undo", new BMessage(MSG_UNDO), 'Z'); + fUndoItem->SetEnabled(false); fRedoItem = new BMenuItem("Redo", new BMessage(MSG_REDO), 'Y'); + fRedoItem->SetEnabled(false); fCutItem = new BMenuItem("Cut", new BMessage(MSG_CUT), 'X'); + fCutItem->SetEnabled(false); fCopyItem = new BMenuItem("Copy", new BMessage(MSG_COPY), 'C'); + fCopyItem->SetEnabled(false); fPasteItem = new BMenuItem("Paste", new BMessage(MSG_PASTE), 'V'); + fPasteItem->SetEnabled(false); fClearItem = new BMenuItem("Clear", new BMessage(MSG_CLEAR)); fSelectAllItem = new BMenuItem("Select All", new BMessage(MSG_SELECTALL), 'A'); + fToolsMenu = new BMenu("Tools", B_ITEMS_IN_COLUMN); + fAddAppResourcesItem = new BMenuItem("Add app resources", + new BMessage(MSG_ADDAPPRES)); + fSettingsItem = new BMenuItem("Settings", new BMessage(MSG_SETTINGS)); + fHelpMenu = new BMenu("Help", B_ITEMS_IN_COLUMN); fResourceIDText = new BTextControl(BRect(0, 0, 47, 23).OffsetBySelf(8, 24), @@ -127,8 +149,8 @@ MainWindow::MainWindow(BRect frame, BEntry* assocEntry) fResourceList = new ResourceListView(listRect, "fResourceList", B_FOLLOW_ALL, 0); - fResourceList->AddColumn(new BIntegerColumn("ID", 48, 1, 999, - B_ALIGN_RIGHT), 0); + fResourceList->AddColumn(new BStringColumn("ID", 48, 1, 999, + B_ALIGN_LEFT), 0); fResourceList->AddColumn(new BStringColumn("Name", 156, 1, 999, B_TRUNCATE_END, B_ALIGN_LEFT), 1); fResourceList->AddColumn(new BStringColumn("Type", 56, 1, 999, @@ -140,10 +162,17 @@ MainWindow::MainWindow(BRect frame, BEntry* assocEntry) fResourceList->AddColumn(new BSizeColumn("Size", 74, 1, 999, B_ALIGN_RIGHT), 5); - fResourceList->SetLatchWidth(0); + //fResourceList->SetLatchWidth(0); fResourceList->SetTarget(this); fResourceList->SetSelectionMessage(new BMessage(MSG_SELECTION)); + fResourceList->SetInvocationMessage(new BMessage(MSG_INVOCATION)); + + fStatsString = new BStringView(BRect(3, 2, 150, 13), "fStatsString", ""); + fStatsString->SetFontSize(11.0f); + + fStatsBox = new BBox(BRect(0, 0, 150, 16), "fStatsBox"); + fStatsBox->SetBorder(B_PLAIN_BORDER); AddChild(fMenuBar); @@ -170,6 +199,11 @@ MainWindow::MainWindow(BRect frame, BEntry* assocEntry) fEditMenu->AddSeparatorItem(); fEditMenu->AddItem(fSelectAllItem); + fMenuBar->AddItem(fToolsMenu); + fToolsMenu->AddItem(fAddAppResourcesItem); + fToolsMenu->AddSeparatorItem(); + fToolsMenu->AddItem(fSettingsItem); + fMenuBar->AddItem(fHelpMenu); fToolbarView->AddChild(fResourceIDText); @@ -183,6 +217,8 @@ MainWindow::MainWindow(BRect frame, BEntry* assocEntry) AddChild(fToolbarView); AddChild(fResourceList); + fResourceList->AddStatusView(fStatsBox); + fStatsBox->AddChild(fStatsString); if (assocEntry != NULL) { _SetTitleFromEntry(); @@ -195,15 +231,57 @@ MainWindow::MainWindow(BRect frame, BEntry* assocEntry) MainWindow::~MainWindow() { - + delete fUndoContext; } bool MainWindow::QuitRequested() { - // TODO: Check if file is saved. + // CAUTION: Do not read the body of this function if you + // are known to suffer from gotophobia. + if (fUnsavedChanges) { + Activate(); + + char nameBuffer[B_FILE_NAME_LENGTH]; + + if (fAssocEntry != NULL) + fAssocEntry->GetName(nameBuffer); + else + strcpy(nameBuffer, "Untitled"); + + BString warning = ""; + warning << "Save changse to'"; + warning << nameBuffer; + warning << "' before closing?"; + + BAlert* alert = new BAlert("Save", warning.String(), + "Cancel", "Don't save", "Save", + B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); + + alert->SetShortcut(0, B_ESCAPE); + + int32 result = alert->Go(); + + switch (result) { + case 0: + return false; + case 1: + goto quit; + case 2: + { + _Save(); + + if (fUnsavedChanges) + return false; + else + goto quit; + } + } + } + + quit: BMessage* msg = new BMessage(MSG_CLOSE); msg->AddPointer("window", (void*)this); be_app->PostMessage(msg); @@ -218,15 +296,28 @@ MainWindow::SelectionChanged() fMoveUpButton->SetEnabled(false); fMoveDownButton->SetEnabled(false); fRemoveButton->SetEnabled(false); + + fCutItem->SetEnabled(false); + fCopyItem->SetEnabled(false); } else { fRemoveButton->SetEnabled(true); fMoveUpButton->SetEnabled(!fResourceList->RowAt(0)->IsSelected()); fMoveDownButton->SetEnabled(!fResourceList->RowAt( fResourceList->CountRows() - 1)->IsSelected()); + + fCutItem->SetEnabled(true); + fCopyItem->SetEnabled(true); } } +void +MainWindow::MouseDown(BPoint point) +{ + +} + + void MainWindow::MessageReceived(BMessage* msg) { @@ -282,13 +373,13 @@ MainWindow::MessageReceived(BMessage* msg) break; case MSG_UNDO: - // TODO: Implement. - PRINT(("[MSG_UNDO]: Not yet implemented.")); + fUndoContext->Undo(); + _RefreshUndoRedo(); break; case MSG_REDO: - // TODO: Implement. - PRINT(("[MSG_REDO]: Not yet implemented.")); + fUndoContext->Redo(); + _RefreshUndoRedo(); break; case MSG_CUT: @@ -307,10 +398,20 @@ MainWindow::MessageReceived(BMessage* msg) break; case MSG_CLEAR: - fResourceList->Clear(); + { + BList* rows = new BList(); + + for (int32 i = 0; i < fResourceList->CountRows(); i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + row->ActionIndex = i; + rows->AddItem(row); + } + + _Do(new RemoveAction("Clear", fResourceList, rows)); + SelectionChanged(); break; - + } case MSG_SELECTALL: { for (int32 i = 0; i < fResourceList->CountRows(); i++) @@ -319,6 +420,10 @@ MainWindow::MessageReceived(BMessage* msg) SelectionChanged(); break; } + case MSG_SETTINGS: + be_app->PostMessage(MSG_SETTINGS); + break; + case MSG_ADD: { // Thank you, François Claus :D Merry Christmas! @@ -326,67 +431,108 @@ MainWindow::MessageReceived(BMessage* msg) int32 ix = fResourceTypePopUp->FindMarkedIndex(); if (ix != -1) { + BList* rows = new BList(); + ResourceRow* row = new ResourceRow(); row->SetResourceID(_NextResourceID()); row->SetResourceType(kDefaultTypes[ix].type); - row->SetResourceTypeCode(kDefaultTypes[ix].typeCode); - row->SetResourceRawData(kDefaultData); + row->SetResourceStringCode(kDefaultTypes[ix].code); + row->SetResourceData(kDefaultTypes[ix].data); row->SetResourceSize(kDefaultTypes[ix].size); - fResourceList->AddRow(row); + row->ActionIndex = fResourceList->CountRows(NULL); + + rows->AddItem(row); + + _Do(new AddAction("Add", fResourceList, rows)); } break; } case MSG_REMOVE: { + BList* rows = new BList(); + for (int i = 0; i < fResourceList->CountRows(); i++) { - BRow* row = fResourceList->RowAt(i); + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); if (row->IsSelected()) { - fResourceList->RemoveRow(row); - i--; + row->ActionIndex = i; + rows->AddItem(row); } } + if (!rows->IsEmpty()) + _Do(new RemoveAction("Remove", fResourceList, rows)); + else + delete rows; + break; } case MSG_MOVEUP: { + BList* rows = new BList(); + for (int i = 1; i < fResourceList->CountRows(); i++) { - BRow* row = fResourceList->RowAt(i); - - if (row->IsSelected()) - fResourceList->SwapRows(i, i - 1); + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + if (row->IsSelected()) { + row->ActionIndex = i; + rows->AddItem(row); + } } - fResourceList->ClearSortColumns(); - SelectionChanged(); + _Do(new MoveUpAction("Move Up", fResourceList, rows)); + break; } case MSG_MOVEDOWN: { - for (int i = fResourceList->CountRows() - 1 - 1; i >= 0; i--) { - BRow* row = fResourceList->RowAt(i); + BList* rows = new BList(); - if (row->IsSelected()) - fResourceList->SwapRows(i, i + 1); + for (int i = 0; i < fResourceList->CountRows() - 1; i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + + if (row->IsSelected()) { + row->ActionIndex = i; + rows->AddItem(row); + } } - fResourceList->ClearSortColumns(); - SelectionChanged(); + _Do(new MoveDownAction("Move Down", fResourceList, rows)); + break; } case MSG_SELECTION: SelectionChanged(); break; + case MSG_INVOCATION: + { + BRect frame = Frame(); + + new EditWindow(BRect(frame.left + 50, frame.top + 50, + frame.left + 300, frame.top + 350), + (ResourceRow*)fResourceList->CurrentSelection()); + + break; + } + case MSG_SETTINGS_APPLY: + AdaptSettings(); + break; + default: BWindow::MessageReceived(msg); } } +void +MainWindow::AdaptSettings() +{ + fUndoContext->SetLimit(fSettings->UndoLimit); +} + + void MainWindow::_SetTitleFromEntry() { @@ -429,7 +575,7 @@ MainWindow::_Save(BEntry* entry) } } - /*BPath path; + BPath path; entry->GetPath(&path); // I wouldn't use std:: if BFile had cooler stuff. @@ -440,10 +586,10 @@ MainWindow::_Save(BEntry* entry) time_t timeNow = time(0); - out << "/-" << endl; - out << " - This file is auto-generated by Haiku ResourceEdit." << endl; - out << " - Time: " << ctime((const time_t*)&timeNow); - out << " -\" << endl; + out << "/*" << endl; + out << " * This file is auto-generated by Haiku ResourceEdit." << endl; + out << " * Time: " << ctime((const time_t*)&timeNow); + out << " */" << endl; for (int32 i = 0; i < fResourceList->CountRows(); i++) { ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); @@ -451,20 +597,22 @@ MainWindow::_Save(BEntry* entry) out << endl; out << "resource"; - if (true) { - // TODO: Implement no-ID cases. - + if (row->ResourceStringID()[0] != '\0') { out << "(" << row->ResourceID(); - if (row->ResourceName()[0] != '\0') { - out << ", \"" << row->ResourceName() << "\"" << endl; - } + if (row->ResourceName()[0] != '\0') + out << ", \"" << row->ResourceName() << "\""; - out << ") "; + out << ")"; + } else { + if (row->ResourceName()[0] != '\0') + out << "(\"" << row->ResourceName() << "\")"; } - if (row->ResourceTypeCode()[0] != '\0') - out << "#\'" << row->ResourceTypeCode() << "\' "; + out << " "; + + if (row->ResourceStringCode()[0] != '\0') + out << "#\'" << row->ResourceStringCode() << "\' "; if (strcmp(row->ResourceType(), "raw") != 0) out << row->ResourceType() << ' ' << row->ResourceData(); @@ -475,56 +623,306 @@ MainWindow::_Save(BEntry* entry) out << "}"; } - out << endl; + out << ";" << endl; } - out.close();*/ + out.close(); - // Commented out whole output section. Switching to .rsrc files to - // close Part 1 of GCI task. + // Killed code: Export to .rsrc - // TODO: Implement exporting to .rdef and/or other formats. - - - BFile* file = new BFile(entry, B_READ_WRITE | B_CREATE_FILE); + /*BFile* file = new BFile(entry, B_READ_WRITE | B_CREATE_FILE); BResources output(file, true); delete file; for (int32 i = 0; i < fResourceList->CountRows(); i++) { ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); - output.AddResource(row->ResourceTypeCode(), row->ResourceID(), + + output.AddResource(row->ResourceCode(), row->ResourceID(), row->ResourceRawData(), row->ResourceSize(), row->ResourceName()); } - output.Sync(); + output.Sync();*/ + + fUnsavedChanges = false; } void MainWindow::_Load() { - /*BPath path; + // CAUTION: Here be dragons. + + // [Initialization phase] + + BPath path; struct stat st; fAssocEntry->GetPath(&path); fAssocEntry->GetStat(&st); int fd = open(path.Path(), 0); + const char* in = (const char*)mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); - // TODO: Fix stucking bug. - // TODO: Parse data. + // [Setup phase] + + enum { + T_STATE_NORMAL, + T_STATE_COMMENT, + T_STATE_MULTILINE_COMMENT, + T_STATE_STRING, + } t_state = T_STATE_NORMAL; + + char quoteType = '\0'; + + char escChars[256]; + + for (int32 i = 0; i < 256; i++) + escChars[i] = ~(char)0; + + escChars['n'] = '\n'; + escChars['t'] = '\t'; + escChars['r'] = '\r'; + escChars['0'] = '\0'; + escChars['"'] = '\"'; + escChars['\'']= '\''; + + // TODO: Add other escape sequences? + // Multichar escape sequences cannot be resolved with this. + + BString buffer = ""; + BList* tokens = new BList(); + + BList* errors = new BList(); + // Multiple errors are allowed, but currently unused. + + BList* rows = new BList(); + + // [Tokenization phase] for (int32 i = 0; i < st.st_size - 1; i++) { - //... - }*/ + if (t_state == T_STATE_NORMAL) { + if (in[i] == ' ' || in[i] == '\t' || in[i] == '\n' + || in[i] == '\r') { - // Commented out input section. Same reason as above. + if (buffer != "") { + tokens->AddItem(new BString(buffer)); + buffer = ""; + } - // TODO: Implement importing from .rdef and/or other formats. + continue; + } - BFile* file = new BFile(fAssocEntry, B_READ_ONLY); + if (in[i] == ',' || in[i] == ';' || in[i] == '{' || in[i] == '}' + || in[i] == '(' || in[i] == ')') { + if (buffer != "") { + tokens->AddItem(new BString(buffer)); + buffer = in[i]; + tokens->AddItem(new BString(buffer)); + buffer = ""; + } + + continue; + } + + if (in[i] == '"' || in[i] == '\'') { + t_state = T_STATE_STRING; + quoteType = in[i]; + buffer += in[i]; + continue; + } + + if (in[i] == '/') { + if (in[i + 1] == '/') { + t_state = T_STATE_COMMENT; + continue; + } + + if (in[i + 1] == '*') { + t_state = T_STATE_MULTILINE_COMMENT; + continue; + } + } + + buffer += in[i]; + + } else if (t_state == T_STATE_COMMENT) { + if (in[i] == '\n') { + t_state = T_STATE_NORMAL; + continue; + } + } else if (t_state == T_STATE_MULTILINE_COMMENT) { + if (in[i] == '*' && in[i + 1] == '/') { + t_state = T_STATE_NORMAL; + i++; + continue; + } + } else if (t_state == T_STATE_STRING) { + if (in[i] == '\\' && escChars[in[i]] != ~(char)0) { + buffer += escChars[in[i]]; + i++; + continue; + } + + if (in[i] == quoteType) { + buffer += in[i]; + tokens->AddItem(new BString(buffer)); + buffer = ""; + t_state = T_STATE_NORMAL; + continue; + } + + buffer += in[i]; + } else { + // This can't even happen. + } + } + + if (t_state == T_STATE_MULTILINE_COMMENT) + errors->AddItem(new BString( + "Multi-line comment not closed by end of file.")); + else if (t_state == T_STATE_STRING) + errors->AddItem(new BString("String not closed by end of file.")); + else { + // [Parsing phase] + + for (int32 i = 0; i < tokens->CountItems(); i++) { + BString& token = *(BString*)tokens->ItemAt(i); + + if (token == "resource") { + ResourceRow* row = new ResourceRow(); + + token = *(BString*)tokens->ItemAt(++i); + + if (token[0] == '(') { + BList args; + bool wantComma = false; + + while (true) { + token = *(BString*)tokens->ItemAt(++i); + + if (token[0] == ')') + break; + + if (wantComma) { + if (token[0] != ',') { + errors->AddItem(new BString("Expected ','.")); + break; + } + + wantComma = false; + } else { + args.AddItem(tokens->ItemAt(i)); + wantComma = true; + } + } + + if (errors->CountItems() > 0) + break; + + token = *(BString*)tokens->ItemAt(++i); + + if (args.CountItems() > 2) { + errors->AddItem(new BString( + "Too many arguments for resource identifier.")); + break; + } + + if (args.CountItems() >= 1) { + BString& arg = *(BString*)args.ItemAt(0); + + if (arg[0] == '"') { + errors->AddItem(new BString( + "Resource ID cannot be a string.")); + break; + } + + row->SetResourceStringID(arg); + } + + if (args.CountItems() == 2) { + BString& arg = *(BString*)args.ItemAt(1); + + if (arg[0] != '"') { + errors->AddItem(new BString( + "Resource name must be a string.")); + break; + } + + row->SetResourceName(arg); + } + } + + if (token[0] == '#') { + if (token.Length() != 7 + || token[1] != '\'' || token[6] != '\'') { + errors->AddItem(new BString( + "Invalid syntax for resource type-code.")); + break; + } + + BString code; + token.CopyInto(code, 2, 4); + row->SetResourceStringCode(code); + + token = *(BString*)tokens->ItemAt(++i); + } + + if (token[0] == '(') { + BString& type = *(BString*)tokens->ItemAt(++i); + token = *(BString*)tokens->ItemAt(++i); + + if (token[0] != ')') { + errors->AddItem(new BString( + "Expected ')'.")); + break; + } + + row->SetResourceType(type); + } + + } else if (token == "type") { + // TODO: Implement. + } else if (token == "enum") { + // TODO: Implement. + } + } + } + + // [Result phase] + + if (errors->CountItems() > 0) { + for (int32 i = 0; i < errors->CountItems(); i++) { + BString& error = *(BString*)errors->ItemAt(i); + PRINT(("ERROR: %s\n", error.String())); + delete (BString*)tokens->ItemAt(i); + } + + delete errors; + } else { + for (int32 i = 0; i < rows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)rows->ItemAt(i); + PRINT(("[Resource]\n")); + PRINT(("id = %s\n", row->ResourceStringID())); + PRINT(("name = %s\n", row->ResourceName())); + // ... + PRINT(("\n")); + } + } + + // [Cleanup phase] + + for (int32 i = 0; i < tokens->CountItems(); i++) + delete (BString*)tokens->ItemAt(i); + + delete tokens; + + munmap((void*)in, st.st_size); + + // Killed code: Import from .rsrc + + /*BFile* file = new BFile(fAssocEntry, B_READ_ONLY); BResources input(file); delete file; @@ -538,10 +936,10 @@ MainWindow::_Load() row->SetResourceID(id); row->SetResourceName(name); row->SetResourceSize(size); - row->SetResourceTypeCode(code); + row->SetResourceCode(code); row->SetResourceRawData(input.LoadResource(code, id, &size)); fResourceList->AddRow(row); - } + }*/ } @@ -560,3 +958,255 @@ MainWindow::_NextResourceID() return currentID; } + + +void +MainWindow::_RefreshStats() +{ + const size_t kB = 1024; + const size_t MB = 1024 * 1024; + const size_t GB = 1024 * 1024 * 1024; + + size_t size = 0; + + BString text = ""; + + text << fResourceList->CountRows(); + text << " resources, "; + + for (int32 i = 0; i < fResourceList->CountRows(); i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + size += row->ResourceSize(); + } + + if (size >= GB) { + text << (double)size / GB; + text << " GB"; + } else if (size >= MB) { + text << (double)size / MB; + text << " MB"; + } else if (size >= kB) { + text << (double)size / kB; + text << " kB"; + } else { + text << size; + text << " bytes"; + } + + fStatsString->SetText(text); +} + + +void +MainWindow::_RefreshUndoRedo() +{ + if (fUndoContext->CanUndo()) { + fUndoItem->SetEnabled(true); + fUndoItem->SetLabel(fUndoContext->UndoLabel().Prepend("Undo ")); + } else { + fUndoItem->SetEnabled(false); + fUndoItem->SetLabel("Undo"); + } + + if (fUndoContext->CanRedo()) { + fRedoItem->SetEnabled(true); + fRedoItem->SetLabel(fUndoContext->RedoLabel().Prepend("Redo ")); + } else { + fRedoItem->SetEnabled(false); + fRedoItem->SetLabel("Redo"); + } +} + + +void +MainWindow::_Do(UndoContext::Action* action) +{ + fUnsavedChanges = true; + fUndoContext->Do(action); + _RefreshStats(); + _RefreshUndoRedo(); +} + + +MainWindow::AddAction::AddAction(const BString& label, + ResourceListView* list, BList* rows) + : + UndoContext::Action(label) +{ + fList = list; + fRows = rows; + fAdded = false; +} + + +MainWindow::AddAction::~AddAction() +{ + if (!fAdded) + for (int32 i = 0; i < fRows->CountItems(); i++) + delete (ResourceRow*)fRows->ItemAt(i); + + delete fRows; +} + + +void +MainWindow::AddAction::Do() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + fList->AddRow(row, row->ActionIndex, row->Parent); + } + + fAdded = true; +} + + +void +MainWindow::AddAction::Undo() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) + fList->RemoveRow((ResourceRow*)fRows->ItemAt(i)); + + fAdded = false; +} + + +MainWindow::RemoveAction::RemoveAction(const BString& label, + ResourceListView* list, BList* rows) + : + UndoContext::Action(label) +{ + fList = list; + fRows = rows; + fRemoved = false; +} + + +MainWindow::RemoveAction::~RemoveAction() +{ + if (fRemoved) + for (int32 i = 0; i < fRows->CountItems(); i++) + delete (ResourceRow*)fRows->ItemAt(i); + + delete fRows; +} + + +void +MainWindow::RemoveAction::Do() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) + fList->RemoveRow((ResourceRow*)fRows->ItemAt(i)); + + fRemoved = true; +} + + +void +MainWindow::RemoveAction::Undo() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->AddRow(row, row->ActionIndex, row->Parent); + } + + fRemoved = false; +} + +// TODO: Implement EditAction + +MainWindow::MoveUpAction::MoveUpAction(const BString& label, + ResourceListView* list, BList* rows) + : + UndoContext::Action(label) +{ + fList = list; + fRows = rows; +} + + +MainWindow::MoveUpAction::~MoveUpAction() +{ + delete fRows; +} + + +void +MainWindow::MoveUpAction::Do() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->SwapRows(row->ActionIndex, row->ActionIndex - 1, + row->Parent, row->Parent); + + row->ActionIndex--; + } + + fList->SelectionChanged(); +} + + +void +MainWindow::MoveUpAction::Undo() +{ + for (int32 i = fRows->CountItems() - 1; i >= 0; i--) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->SwapRows(row->ActionIndex, row->ActionIndex + 1, + row->Parent, row->Parent); + + row->ActionIndex++; + } + + fList->SelectionChanged(); +} + +MainWindow::MoveDownAction::MoveDownAction(const BString& label, + ResourceListView* list, BList* rows) + : + UndoContext::Action(label) +{ + fList = list; + fRows = rows; +} + + +MainWindow::MoveDownAction::~MoveDownAction() +{ + delete fRows; +} + + +void +MainWindow::MoveDownAction::Do() +{ + for (int32 i = fRows->CountItems() - 1; i >= 0; i--) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->SwapRows(row->ActionIndex, row->ActionIndex + 1, + row->Parent, row->Parent); + + row->ActionIndex++; + } + + fList->SelectionChanged(); +} + + +void +MainWindow::MoveDownAction::Undo() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->SwapRows(row->ActionIndex, row->ActionIndex - 1, + row->Parent, row->Parent); + + row->ActionIndex--; + } + + fList->SelectionChanged(); +} + diff --git a/src/apps/resourceedit/MainWindow.h b/src/apps/resourceedit/MainWindow.h index bc1523fa35..b903e1ef7a 100644 --- a/src/apps/resourceedit/MainWindow.h +++ b/src/apps/resourceedit/MainWindow.h @@ -6,12 +6,17 @@ #define MAIN_WINDOW_H +#include "UndoContext.h" + #include class ImageButton; +class ResourceListView; +class ResourceRow; +class SettingsFile; -class BColumnListView; +class BBox; class BEntry; class BFilePanel; class BMenu; @@ -20,20 +25,30 @@ class BMenuField; class BMenuItem; class BMessage; class BPopUpMenu; +class BStringView; class BTextControl; class MainWindow : public BWindow { public: - MainWindow(BRect frame, BEntry* entry); + MainWindow(BRect frame, BEntry* entry, SettingsFile* settings); ~MainWindow(); bool QuitRequested(); + void MouseDown(BPoint point); void MessageReceived(BMessage* msg); void SelectionChanged(); + void AdaptSettings(); + private: BEntry* fAssocEntry; + SettingsFile* fSettings; + + BFilePanel* fSavePanel; + bool fUnsavedChanges; + + UndoContext* fUndoContext; BMenuBar* fMenuBar; @@ -56,6 +71,10 @@ private: BMenuItem* fClearItem; BMenuItem* fSelectAllItem; + BMenu* fToolsMenu; + BMenuItem* fAddAppResourcesItem; + BMenuItem* fSettingsItem; + BMenu* fHelpMenu; BTextControl* fResourceIDText; @@ -68,9 +87,9 @@ private: ImageButton* fMoveUpButton; ImageButton* fMoveDownButton; - BColumnListView* fResourceList; - - BFilePanel* fSavePanel; + ResourceListView* fResourceList; + BBox* fStatsBox; + BStringView* fStatsString; void _SetTitleFromEntry(); void _SaveAs(); @@ -79,6 +98,88 @@ private: int32 _NextResourceID(); + void _RefreshStats(); + void _RefreshUndoRedo(); + void _Do(UndoContext::Action* action); + + class AddAction : public UndoContext::Action { + public: + AddAction(const BString& label, + ResourceListView* list, BList* rows); + ~AddAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + BList* fRows; + bool fAdded; + + }; + + class RemoveAction : public UndoContext::Action { + public: + RemoveAction(const BString& label, + ResourceListView* list, BList* rows); + ~RemoveAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + BList* fRows; + bool fRemoved; + + }; + + class EditAction : public UndoContext::Action { + public: + EditAction(const BString& label, + ResourceListView* list, + ResourceRow* rowold, ResourceRow* rownew); + ~EditAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + ResourceRow* fRowOld; + ResourceRow* fRowNew; + + }; + + class MoveUpAction : public UndoContext::Action { + public: + MoveUpAction(const BString& label, + ResourceListView* list, BList* rows); + ~MoveUpAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + BList* fRows; + + }; + + class MoveDownAction : public UndoContext::Action { + public: + MoveDownAction(const BString& label, + ResourceListView* list, BList* rows); + ~MoveDownAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + BList* fRows; + + }; }; diff --git a/src/apps/resourceedit/ResourceEdit.cpp b/src/apps/resourceedit/ResourceEdit.cpp index 2ff1a577a4..977e463797 100644 --- a/src/apps/resourceedit/ResourceEdit.cpp +++ b/src/apps/resourceedit/ResourceEdit.cpp @@ -9,6 +9,8 @@ #include "AboutWindow.h" #include "Constants.h" #include "MainWindow.h" +#include "SettingsFile.h" +#include "SettingsWindow.h" #include #include @@ -23,6 +25,11 @@ ResourceEdit::ResourceEdit() fOpenPanel = new BFilePanel(B_OPEN_PANEL, &be_app_messenger, NULL, 0, true, new BMessage(MSG_OPEN_DONE)); + + fSettings = new SettingsFile("resourceedit_settings"); + fSettings->Load(); + + fSettingsWindow = NULL; } @@ -68,11 +75,35 @@ ResourceEdit::MessageReceived(BMessage* msg) } case MSG_SAVEALL: { - for (int32 i = 0; i < fWindowList.CountItems(); i++) - ((MainWindow*)fWindowList.ItemAt(i))->PostMessage(MSG_SAVE); + for (int32 i = 0; i < fWindowList.CountItems(); i++) { + MainWindow* window = ((MainWindow*)fWindowList.ItemAt(i)); + window->PostMessage(MSG_SAVE); + } break; } + case MSG_SETTINGS: + { + if (fSettingsWindow != NULL) + fSettingsWindow->Activate(); + else + fSettingsWindow = new SettingsWindow(fSettings); + + break; + } + case MSG_SETTINGS_APPLY: + { + for (int32 i = 0; i < fWindowList.CountItems(); i++) { + MainWindow* window = ((MainWindow*)fWindowList.ItemAt(i)); + window->PostMessage(MSG_SETTINGS_APPLY); + } + + break; + } + case MSG_SETTINGS_CLOSED: + fSettingsWindow = NULL; + break; + default: BApplication::MessageReceived(msg); } @@ -98,7 +129,7 @@ ResourceEdit::ReadyToRun() void ResourceEdit::_CreateWindow(BEntry* assocEntry) { - MainWindow* window = new MainWindow(_Cascade(), assocEntry); + MainWindow* window = new MainWindow(_Cascade(), assocEntry, fSettings); fWindowList.AddItem(window); diff --git a/src/apps/resourceedit/ResourceEdit.h b/src/apps/resourceedit/ResourceEdit.h index dcdf976cff..6168fcfc2c 100644 --- a/src/apps/resourceedit/ResourceEdit.h +++ b/src/apps/resourceedit/ResourceEdit.h @@ -10,6 +10,8 @@ class MainWindow; +class SettingsFile; +class SettingsWindow; class BEntry; class BFilePanel; @@ -30,6 +32,9 @@ private: BFilePanel* fOpenPanel; + SettingsFile* fSettings; + SettingsWindow* fSettingsWindow; + void ArgvReceived(int32 argc, char* argv[]); void ReadyToRun(); diff --git a/src/apps/resourceedit/ResourceEdit.rdef b/src/apps/resourceedit/ResourceEdit.rdef index 58b821c357..c225980220 100644 --- a/src/apps/resourceedit/ResourceEdit.rdef +++ b/src/apps/resourceedit/ResourceEdit.rdef @@ -16,7 +16,7 @@ resource app_version { resource app_flags B_SINGLE_LAUNCH; -resource(1, "BEOS:FILE_TYPES") message { +resource file_types message { "types" = "text/x-vnd.Be.ResourceDef" }; diff --git a/src/apps/resourceedit/ResourceListView.cpp b/src/apps/resourceedit/ResourceListView.cpp index a329d77ca6..654de4420b 100644 --- a/src/apps/resourceedit/ResourceListView.cpp +++ b/src/apps/resourceedit/ResourceListView.cpp @@ -19,7 +19,7 @@ ResourceListView::ResourceListView(BRect rect, const char* name, BColumnListView(rect, name, resizingMode, drawFlags, border, showHorizontalScrollbar) { - + //SetMouseTrackingEnabled(true); } @@ -29,11 +29,19 @@ ResourceListView::~ResourceListView() } +void +ResourceListView::MouseDown(BPoint point) +{ + PRINT(("MouseDown()")); +} + + void ResourceListView::MessageReceived(BMessage* msg) { switch (msg->what) { - case B_SIMPLE_DATA: { + case B_SIMPLE_DATA: + { entry_ref ref; int32 n = 0; diff --git a/src/apps/resourceedit/ResourceListView.h b/src/apps/resourceedit/ResourceListView.h index 5551f82922..88657f9376 100644 --- a/src/apps/resourceedit/ResourceListView.h +++ b/src/apps/resourceedit/ResourceListView.h @@ -16,6 +16,7 @@ public: bool showHorizontalScrollbar = true); ~ResourceListView(); + void MouseDown(BPoint point); void MessageReceived(BMessage* msg); private: diff --git a/src/apps/resourceedit/ResourceRow.cpp b/src/apps/resourceedit/ResourceRow.cpp index ebe5dce9ea..ecf94f709c 100644 --- a/src/apps/resourceedit/ResourceRow.cpp +++ b/src/apps/resourceedit/ResourceRow.cpp @@ -9,14 +9,17 @@ #include #include +#include + ResourceRow::ResourceRow() : BRow() { - fRawData = NULL; + Parent = NULL; + ActionIndex = -1; - SetField(new BIntegerField(0), 0); + SetField(new BStringField(""), 0); SetField(new BStringField(""), 1); SetField(new BStringField(""), 2); SetField(new BStringField(""), 3); @@ -34,7 +37,14 @@ ResourceRow::~ResourceRow() void ResourceRow::SetResourceID(int32 id) { - ((BIntegerField*)GetField(0))->SetValue(id); + ((BStringField*)GetField(0))->SetString((BString() << id).String()); +} + + +void +ResourceRow::SetResourceStringID(const char* id) +{ + ((BStringField*)GetField(0))->SetString(id); } @@ -53,14 +63,22 @@ ResourceRow::SetResourceType(const char* type) void -ResourceRow::SetResourceTypeCode(type_code code) +ResourceRow::SetResourceCode(type_code code) { - fTypeCode = code; - TypeCodeToString(code, fTypeString); + fCode = code; + ResourceType::CodeToString(code, fTypeString); ((BStringField*)GetField(3))->SetString(fTypeString); } +void +ResourceRow::SetResourceStringCode(const char* code) +{ + fCode = ResourceType::StringToCode(code); + ((BStringField*)GetField(3))->SetString(code); +} + + void ResourceRow::SetResourceData(const char* data) { @@ -68,23 +86,6 @@ ResourceRow::SetResourceData(const char* data) } -void -ResourceRow::SetResourceRawData(const void* data) -{ - if (data == NULL) - data = kDefaultData; - - fRawData = data; - - int32 ix = FindTypeCodeIndex(ResourceTypeCode()); - - if (ix == -1) - SetResourceData("[Unknown Data]"); - else - SetResourceData(kDefaultTypes[ix].toString(fRawData)); -} - - void ResourceRow::SetResourceSize(off_t size) { @@ -95,7 +96,18 @@ ResourceRow::SetResourceSize(off_t size) int32 ResourceRow::ResourceID() { - return ((BIntegerField*)GetField(0))->Value(); + const char* strID = ResourceStringID(); + + // TODO: Check whether is numeric and resolve if not. + + return atoi(strID); +} + + +const char* +ResourceRow::ResourceStringID() +{ + return ((BStringField*)GetField(0))->String(); } @@ -114,9 +126,16 @@ ResourceRow::ResourceType() type_code -ResourceRow::ResourceTypeCode() +ResourceRow::ResourceCode() { - return fTypeCode; + return fCode; +} + + +const char* +ResourceRow::ResourceStringCode() +{ + return ((BStringField*)GetField(3))->String(); } @@ -127,13 +146,6 @@ ResourceRow::ResourceData() } -const void* -ResourceRow::ResourceRawData() -{ - return fRawData; -} - - off_t ResourceRow::ResourceSize() { diff --git a/src/apps/resourceedit/ResourceRow.h b/src/apps/resourceedit/ResourceRow.h index a9e65caa0e..26d3660ff9 100644 --- a/src/apps/resourceedit/ResourceRow.h +++ b/src/apps/resourceedit/ResourceRow.h @@ -17,24 +17,27 @@ public: ~ResourceRow(); void SetResourceID(int32 id); + void SetResourceStringID(const char* id); void SetResourceName(const char* name); void SetResourceType(const char* type); - void SetResourceTypeCode(type_code code); + void SetResourceCode(type_code code); + void SetResourceStringCode(const char* code); void SetResourceData(const char* data); - void SetResourceRawData(const void*); void SetResourceSize(off_t size); int32 ResourceID(); + const char* ResourceStringID(); const char* ResourceName(); const char* ResourceType(); - type_code ResourceTypeCode(); + type_code ResourceCode(); + const char* ResourceStringCode(); const char* ResourceData(); - const void* ResourceRawData(); off_t ResourceSize(); + ResourceRow* Parent; + int32 ActionIndex; private: - const void* fRawData; - type_code fTypeCode; + type_code fCode; char fTypeString[8]; }; diff --git a/src/apps/resourceedit/SettingsFile.cpp b/src/apps/resourceedit/SettingsFile.cpp new file mode 100644 index 0000000000..63e84b5d9d --- /dev/null +++ b/src/apps/resourceedit/SettingsFile.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "SettingsFile.h" + + +SettingsFile::SettingsFile(const char* name) +{ + find_directory(B_USER_SETTINGS_DIRECTORY, &fPath); + fPath.Append(name, true); +} + + +SettingsFile::~SettingsFile() +{ + +} + + +void +SettingsFile::Defaults() +{ + UndoLimit = 100; +} + + +void +SettingsFile::Load() +{ + fFile = new BFile(fPath.Path(), B_READ_ONLY); + + if (fFile->InitCheck() == B_OK) { + fFile->Read(&UndoLimit, sizeof(UndoLimit)); + // TODO: Add more settings here (2/3). + } else + Defaults(); + + delete fFile; +} + + +void +SettingsFile::Save() +{ + fFile = new BFile(fPath.Path(), B_WRITE_ONLY | B_CREATE_FILE); + + if (fFile->InitCheck() == B_OK) { + fFile->Write(&UndoLimit, sizeof(UndoLimit)); + // TODO: Add more settings here (3/3). + } + + delete fFile; +} diff --git a/src/apps/resourceedit/SettingsFile.h b/src/apps/resourceedit/SettingsFile.h new file mode 100644 index 0000000000..2c52232b4b --- /dev/null +++ b/src/apps/resourceedit/SettingsFile.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef SETTINGS_FILE_H +#define SETTINGS_FILE_H + + +#include +#include +#include + + +class SettingsFile +{ +public: + int32 UndoLimit; + // TODO: Add more settings here (1/3). + + SettingsFile(const char* name); + ~SettingsFile(); + + void Defaults(); + void Load(); + void Save(); + +private: + BPath fPath; + BFile* fFile; +}; + + +#endif diff --git a/src/apps/resourceedit/SettingsWindow.cpp b/src/apps/resourceedit/SettingsWindow.cpp new file mode 100644 index 0000000000..9817659cb9 --- /dev/null +++ b/src/apps/resourceedit/SettingsWindow.cpp @@ -0,0 +1,120 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "SettingsWindow.h" + +#include "Constants.h" +#include "GenericSettingsView.h" +#include "SettingsFile.h" + +#include +#include +#include +#include +#include +#include +#include + + +SettingsWindow::SettingsWindow(SettingsFile* settings) + : + BWindow(BRect(200, 150, 600, 450), "Settings", B_TITLED_WINDOW, B_NOT_RESIZABLE) +{ + fSettings = settings; + + BRect bounds = Bounds(); + + fBackView = new BView(bounds, "fBackView", B_FOLLOW_ALL, 0); + fBackView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + fListView = new BListView(BRect(8, 8, 100 + 8, bounds.bottom - 8), + "fListView", B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL); + + // TODO: Implement selecting different categories of settings. + // fListView->SetSelectionMessage(new BMessage(...)); + + fListView->AddItem(new BStringItem("Generic")); + fListView->Select(0); + + fScrollView = new BScrollView("fScrollView", fListView, B_FOLLOW_TOP_BOTTOM, + B_WILL_DRAW | B_FRAME_EVENTS, false, true); + + fGenericSettingsView = new GenericSettingsView( + BRect(132, 8, bounds.right - 8, bounds.bottom - 8 - 40), + "fGenericSettingsView", fSettings); + // TODO: Add more settings views (2/4). + + fRevertButton = new BButton(BRect(bounds.right - 152, bounds.bottom - 32, + bounds.right - 88, bounds.bottom - 8), + "fRevertButton", "Revert", + new BMessage(MSG_SETTINGS_REVERT)); + + fApplyButton = new BButton(BRect(bounds.right - 72, bounds.bottom - 32, + bounds.right - 8, bounds.bottom - 8), "fApplyButton", "Apply", + new BMessage(MSG_SETTINGS_APPLY)); + + AdaptSettings(); + + fBackView->AddChild(fScrollView); + fBackView->AddChild(fGenericSettingsView); + fBackView->AddChild(fRevertButton); + fBackView->AddChild(fApplyButton); + AddChild(fBackView); + + Show(); +} + + +SettingsWindow::~SettingsWindow() +{ + +} + + +bool +SettingsWindow::QuitRequested() +{ + be_app->PostMessage(MSG_SETTINGS_CLOSED); + return true; +} + +void +SettingsWindow::MessageReceived(BMessage* msg) +{ + switch (msg->what) + { + case MSG_SETTINGS_APPLY: + { + ApplySettings(); + fSettings->Save(); + be_app->PostMessage(MSG_SETTINGS_APPLY); + break; + } + case MSG_SETTINGS_REVERT: + { + AdaptSettings(); + fSettings->Save(); + be_app->PostMessage(MSG_SETTINGS_APPLY); + break; + } + default: + BWindow::MessageReceived(msg); + } +} + +void +SettingsWindow::ApplySettings() +{ + fGenericSettingsView->ApplySettings(); + // TODO: Add more settings views (3/4). +} + +void +SettingsWindow::AdaptSettings() +{ + fGenericSettingsView->AdaptSettings(); + // TODO: Add more settings views (4/4). +} diff --git a/src/apps/resourceedit/SettingsWindow.h b/src/apps/resourceedit/SettingsWindow.h new file mode 100644 index 0000000000..da015de5bf --- /dev/null +++ b/src/apps/resourceedit/SettingsWindow.h @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef SETTINGS_WINDOW_H +#define SETTINGS_WINDOW_H + + +#include + + +class GenericSettingsView; +class SettingsFile; + +class BButton; +class BListView; +class BScrollView; +class BView; + + +class SettingsWindow : public BWindow { +public: + SettingsWindow(SettingsFile* settings); + ~SettingsWindow(); + + bool QuitRequested(); + void MessageReceived(BMessage* msg); + + void ApplySettings(); + void AdaptSettings(); + +private: + SettingsFile* fSettings; + + BView* fBackView; + BListView* fListView; + BScrollView* fScrollView; + + GenericSettingsView* fGenericSettingsView; + // TODO: Add more settings (1/4). + + BButton* fRevertButton; + BButton* fApplyButton; + +}; + + +#endif diff --git a/src/apps/resourceedit/edits/AppFlagsEdit.cpp b/src/apps/resourceedit/edits/AppFlagsEdit.cpp new file mode 100644 index 0000000000..5a1482533a --- /dev/null +++ b/src/apps/resourceedit/edits/AppFlagsEdit.cpp @@ -0,0 +1,4 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ diff --git a/src/apps/resourceedit/edits/AppFlagsEdit.h b/src/apps/resourceedit/edits/AppFlagsEdit.h new file mode 100644 index 0000000000..5a1482533a --- /dev/null +++ b/src/apps/resourceedit/edits/AppFlagsEdit.h @@ -0,0 +1,4 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ diff --git a/src/apps/resourceedit/edits/BooleanEdit.cpp b/src/apps/resourceedit/edits/BooleanEdit.cpp new file mode 100644 index 0000000000..bf65a9335e --- /dev/null +++ b/src/apps/resourceedit/edits/BooleanEdit.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "NormalEdit.h" +#include "ResourceRow.h" + +#include +#include +#include + + +BooleanEdit::BooleanEdit() + : + EditView("BooleanEdit") +{ + +} + + +BooleanEdit::~BooleanEdit() +{ + +} + + +void +BooleanEdit::AttachTo(BView* view) +{ + EditView::AttachTo(view); + + SetLayout(new BGroupLayout(B_VERTICAL)); + + fValueCheck = new BCheckBox(BRect(0, 0, 0, 0), "fValueText", + "", NULL); + + AddChild(BGroupLayoutBuilder(B_VERTICAL, 0) + .Add(fValueCheck) + .AddGlue() + ); + + view->AddChild(this); +} + + +void +BooleanEdit::Edit(ResourceRow* row) +{ + EditView::Edit(row); + + BString data = fRow->ResourceData(); + + if (data == "" || data == "0" || data == "false") + fValueCheck->SetValue(B_CONTROL_OFF); + else + fValueCheck->SetValue(B_CONTROL_ON); +} + + +void +BooleanEdit::Commit() +{ + EditView::Commit(); + + if (fValueCheck->Value() == B_CONTROL_ON) + fRow->SetResourceData("true"); + else + fRow->SetResourceData("false"); +} diff --git a/src/apps/resourceedit/edits/BooleanEdit.h b/src/apps/resourceedit/edits/BooleanEdit.h new file mode 100644 index 0000000000..53889992bb --- /dev/null +++ b/src/apps/resourceedit/edits/BooleanEdit.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef BOOLEAN_EDIT_H +#define BOOLEAN_EDIT_H + + +#include "EditView.h" + + +class BCheckBox; + + +class BooleanEdit : public EditView { +public: + BooleanEdit(); + ~BooleanEdit(); + + void AttachTo(BView* view); + void Edit(ResourceRow* row); + void Commit(); + +private: + BCheckBox* fValueCheck; + +}; + + +#endif diff --git a/src/apps/resourceedit/edits/EditView.cpp b/src/apps/resourceedit/edits/EditView.cpp new file mode 100644 index 0000000000..dc9861aeb4 --- /dev/null +++ b/src/apps/resourceedit/edits/EditView.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "EditView.h" + + +EditView::EditView(const char* name) + : + BView(BRect(0, 0, 0, 0), name, 0, 0) +{ + // Implemented by subclasses. +} + + +EditView::~EditView() +{ + // Implemented by subclasses. +} + + +void +EditView::AttachTo(BView* view) +{ + while (true) { + BView* child = ChildAt(0); + + if (child == NULL) + break; + + child->RemoveSelf(); + } + + // Implemented by subclasses. +} + + +void +EditView::Edit(ResourceRow* row) +{ + fRow = row; + // Implemented by subclasses. +} + + +void +EditView::Commit() +{ + // Implemented by subclasses. +} diff --git a/src/apps/resourceedit/edits/EditView.h b/src/apps/resourceedit/edits/EditView.h new file mode 100644 index 0000000000..23aca74036 --- /dev/null +++ b/src/apps/resourceedit/edits/EditView.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef EDIT_VIEW_H +#define EDIT_VIEW_H + + +#include + + +class ResourceRow; + + +class EditView : public BView { +public: + EditView(const char* name); + virtual ~EditView(); + + virtual void AttachTo(BView* view); + virtual void Edit(ResourceRow* row); + virtual void Commit(); + +protected: + ResourceRow* fRow; + +}; + + +#endif + diff --git a/src/apps/resourceedit/edits/NormalEdit.cpp b/src/apps/resourceedit/edits/NormalEdit.cpp new file mode 100644 index 0000000000..fa822515bf --- /dev/null +++ b/src/apps/resourceedit/edits/NormalEdit.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "NormalEdit.h" +#include "ResourceRow.h" + +#include +#include +#include + + +NormalEdit::NormalEdit() + : + EditView("NormalEdit") +{ + +} + + +NormalEdit::~NormalEdit() +{ + +} + + +void +NormalEdit::AttachTo(BView* view) +{ + EditView::AttachTo(view); + + SetLayout(new BGroupLayout(B_VERTICAL)); + + fValueText = new BTextControl(BRect(0, 0, 0, 0), "fValueText", + "Value:", "", NULL); + fValueText->SetDivider(50); + + AddChild(BGroupLayoutBuilder(B_VERTICAL, 0) + .Add(fValueText) + .AddGlue() + ); + + view->AddChild(this); +} + + +void +NormalEdit::Edit(ResourceRow* row) +{ + EditView::Edit(row); + + fValueText->SetText(fRow->ResourceData()); +} + + +void +NormalEdit::Commit() +{ + EditView::Commit(); + + fRow->SetResourceData(fValueText->Text()); +} diff --git a/src/apps/resourceedit/edits/NormalEdit.h b/src/apps/resourceedit/edits/NormalEdit.h new file mode 100644 index 0000000000..ea5fe78e09 --- /dev/null +++ b/src/apps/resourceedit/edits/NormalEdit.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef NORMAL_EDIT_H +#define NORMAL_EDIT_H + + +#include "EditView.h" + + +class BTextControl; + +// TODO: Templatize this class and rename to NumericEdit. +//template +class NormalEdit : public EditView { +public: + NormalEdit(); + ~NormalEdit(); + + void AttachTo(BView* view); + void Edit(ResourceRow* row); + void Commit(); + +private: + BTextControl* fValueText; + +}; + + +#endif diff --git a/src/apps/resourceedit/ImageButton.cpp b/src/apps/resourceedit/interface/ImageButton.cpp similarity index 100% rename from src/apps/resourceedit/ImageButton.cpp rename to src/apps/resourceedit/interface/ImageButton.cpp diff --git a/src/apps/resourceedit/ImageButton.h b/src/apps/resourceedit/interface/ImageButton.h similarity index 100% rename from src/apps/resourceedit/ImageButton.h rename to src/apps/resourceedit/interface/ImageButton.h diff --git a/src/apps/resourceedit/settings/GenericSettingsView.cpp b/src/apps/resourceedit/settings/GenericSettingsView.cpp new file mode 100644 index 0000000000..65d3377b6c --- /dev/null +++ b/src/apps/resourceedit/settings/GenericSettingsView.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "GenericSettingsView.h" + +#include "SettingsFile.h" + +#include +#include +#include +#include + +#include + + +GenericSettingsView::GenericSettingsView(BRect frame, const char* name, + SettingsFile* settings, uint32 resizingMode, uint32 flags) + : + BView(frame, name, resizingMode, flags) +{ + fSettings = settings; + + SetLayout(new BGroupLayout(B_VERTICAL)); + + fUndoLimitText = new BTextControl(BRect(0, 0, 0, 0), "fUndoLimitText", + "Undo Limit:", NULL, NULL); + fUndoLimitText->SetDivider(100); + + // TODO: Add more controls for generic settings (2/4). + + AddChild(BGroupLayoutBuilder(B_VERTICAL, 8) + .Add(fUndoLimitText) + .AddGlue() + ); +} + + +GenericSettingsView::~GenericSettingsView() +{ + +} + + +void +GenericSettingsView::ApplySettings() +{ + fSettings->UndoLimit = atoi(fUndoLimitText->Text()); + // TODO: Add more controls for generic settings (3/4). +} + + +void +GenericSettingsView::AdaptSettings() +{ + fUndoLimitText->SetText(BString() << fSettings->UndoLimit); + // TODO: Add more controls for generic settings (4/4). +} diff --git a/src/apps/resourceedit/settings/GenericSettingsView.h b/src/apps/resourceedit/settings/GenericSettingsView.h new file mode 100644 index 0000000000..47d141127a --- /dev/null +++ b/src/apps/resourceedit/settings/GenericSettingsView.h @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef GENERIC_SETTINGS_VIEW_H +#define GENERIC_SETTINGS_VIEW_H + + +#include + + +class SettingsFile; + +class BTextControl; + + +class GenericSettingsView : public BView { +public: + GenericSettingsView(BRect frame, const char* name, + SettingsFile* settings, + uint32 resizingMode = B_FOLLOW_ALL, + uint32 flags = 0); + ~GenericSettingsView(); + + void ApplySettings(); + void AdaptSettings(); + +private: + SettingsFile* fSettings; + + BTextControl* fUndoLimitText; + // TODO: Add more controls for generic settings (1/4). + +}; + + +#endif diff --git a/src/apps/resourceedit/support/UndoContext.cpp b/src/apps/resourceedit/support/UndoContext.cpp new file mode 100644 index 0000000000..c4f6775b2d --- /dev/null +++ b/src/apps/resourceedit/support/UndoContext.cpp @@ -0,0 +1,175 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "UndoContext.h" + +#include "Constants.h" + +#include +#include + + +UndoContext::Action::Action(const BString& label) +{ + fLabel = label; +} + + +UndoContext::Action::~Action() +{ + +} + + +void +UndoContext::Action::Do() +{ + +} + + +void +UndoContext::Action::Undo() +{ + +} + + +void +UndoContext::Action::SetLabel(const BString& label) +{ + fLabel = label; +} + + +BString +UndoContext::Action::Label() const +{ + return fLabel; +} + + +UndoContext::UndoContext() +{ + fAt = 0; + fLimit = 3; + fHistory = new BList(); +} + + +UndoContext::~UndoContext() +{ + for (int32 i = 0; i < fHistory->CountItems(); i++) + delete (Action*)fHistory->ItemAt(i); + + delete fHistory; +} + + +void +UndoContext::SetLimit(int32 limit) +{ + int32 delta = fLimit - limit; + + if (limit > 1) + fLimit = limit; + else + limit = 1; + + if (delta > 0) { + for (int32 i = 0; i < delta; i++) + delete (Action*)fHistory->ItemAt(i); + + fHistory->RemoveItems(0, delta); + + if (fAt > fLimit) + fAt = fLimit; + } +} + + +int32 +UndoContext::Limit() const +{ + return fLimit; +} + + +void +UndoContext::Do(UndoContext::Action* action) +{ + int32 count = fHistory->CountItems(); + + if (fAt >= fLimit) + delete (Action*)fHistory->RemoveItem((int32)0); + else { + for (int32 i = fAt; i < count; i++) + delete (Action*)fHistory->ItemAt(i); + + fHistory->RemoveItems(fAt, count - fAt); + + fAt++; + } + + fHistory->AddItem(action); + + action->Do(); +} + + +void +UndoContext::Undo() +{ + if (!CanUndo()) + return; + + fAt--; + ((Action*)fHistory->ItemAt(fAt))->Undo(); +} + + +void +UndoContext::Redo() +{ + if (!CanRedo()) + return; + + ((Action*)fHistory->ItemAt(fAt))->Do(); + fAt++; +} + + +bool +UndoContext::CanUndo() const +{ + return fAt > 0; +} + + +bool +UndoContext::CanRedo() const +{ + return fAt < fHistory->CountItems(); +} + + +BString +UndoContext::UndoLabel() const +{ + if (CanUndo()) + return ((Action*)fHistory->ItemAt(fAt - 1))->Label(); + else + return ""; +} + +BString +UndoContext::RedoLabel() const +{ + if (CanRedo()) + return ((Action*)fHistory->ItemAt(fAt))->Label(); + else + return ""; +} diff --git a/src/apps/resourceedit/support/UndoContext.h b/src/apps/resourceedit/support/UndoContext.h new file mode 100644 index 0000000000..0146e1be48 --- /dev/null +++ b/src/apps/resourceedit/support/UndoContext.h @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef UNDO_CONTEXT_H +#define UNDO_CONTEXT_H + + +#include +#include + + +class UndoContext { +public: + class Action { + public: + Action(const BString& label); + virtual ~Action(); + + virtual void Do(); + virtual void Undo(); + + void SetLabel(const BString& label); + BString Label() const; + + private: + BString fLabel; + }; + + UndoContext(); + ~UndoContext(); + + void SetLimit(int32 limit); + int32 Limit() const; + + void Do(Action* action); + + void Undo(); + void Redo(); + + bool CanUndo() const; + bool CanRedo() const; + + BString UndoLabel() const; + BString RedoLabel() const; + +private: + int32 fAt; + int32 fLimit; + BList* fHistory; + +}; + + +#endif