diff --git a/documentation/User Documentation.html b/documentation/User Documentation.html index a737d3e..f59fb99 100644 --- a/documentation/User Documentation.html +++ b/documentation/User Documentation.html @@ -109,42 +109,84 @@ Filer icon

Filer's User Documentation


-

FilerFiler Usage
-AutoFilerAutoFiler Usage

+

UsageDropzoneRulesAutoFilerHelpHistory



-

Filer is an automatic file organizer. It takes the files it's opened with or that are dropped on its icon and move, rename, copy or do all sorts of other things with them according to rules created by the user.

-

Filer is accompanied by AutoFiler. Instead of working on a set of files provided by the user, it can be started together with Haiku to monitor certain folders and deal with new files appearing there according to the user-defined rules.

+

Filer is an automatic file organizer. It takes the files it's opened with or that are dropped on its icon and moves, renames, copies or does all sorts of other things with them according to rules created by the user.

+

Filer is accompanied by AutoFiler. Instead of working on a set of files provided by the user, it can be started (automatically with Haiku) to monitor certain folders and deal with new files appearing there according to the user-defined rules.

+ +

+index +Usage

+

When started for the first time, you are asked if you'd like to have a few example rules by default. You can edit them to your needs or remove them altogether at any time. All settings are saved in ~/config/settings/Filer/.

+

Once you have created some rules, using Filer to process files accordingly is very simple. There are basically four ways:

+
    +
  1. From a Terminal, simply type "Filer" followed by the files you want processed.
  2. +
  3. Select the files to process, right-click them and choose Open with… | Filer from Tracker's context menu.
  4. +
  5. Select the files to process and drag&drop them on Filer's icon. You may want to create a link to Filer on the Desktop for that.
  6. +
  7. Open Filer, select the files to process and drag&drop them onto the "Dropzone". The Dropzone can also be embedded into the Desktop as a Replicant.
  8. +
+

…or have AutoFiler monitor specific folders to automatically process their incoming files according to Filer's rules.

+

Filer's interface is divided into four tabs: Dropzone, Rules, AutoFiler and Help.

+

index -Filer

+Dropzone
-Filer list of rules   Editing a rule
-

Double-clicking Filer opens the settings with a list of organization rules. When started for the first time, you are asked if you'd like to have a few example rules by default. You can edit them to your needs or remove them altogether at any time.

+Filer's dropzone + +

As described above under 4.), you can drag&drop files onto the Dropzone to have them processed according to your set of rules. If you'd like to embed this Dropzone into the Desktop, click the button Replicate dropzone….
+It opens a window to resize the dropzone to fit your needs. When that's done, drag the little Replicant handle in the bottom-right corner onto your Desktop. Make sure to have Show replicants in the Deskbar menu activated. Once on the Desktop, right-click the Replicant's handle for a menu to remove it again.

+ +

+index +Rules

+
+Filer's rules +
+

The second tab shows the list of organization rules. Every dropped file is being tested against – and if its type etc. matches processed by – each rule, top to bottom.

+

You can arrange the rules with the Move up/down buttons and Add…, Edit… and Remove them.
+Here's the window that opens to edit a rule:

+
+Editing a rule

A rule needs three items: A Description, the condition When it is applied, and what action to Do.

Click on the buttons in the "When" and "Do" boxes to explore the various options to construct the right condition and what action will be taken. You can add several conditions which will all have to be met to trigger the action. If you add several actions in the "Do" box, be aware that they are executed in order, from top to bottom.

Please read the Rule-Making Reference (also available from the Help… button) for more information on the various possibilities.

-

-index -Filer Usage

-

Once you have created some rules, using Filer to process some files accordingly is very simple. There are basically three ways:

-
    -
  1. Select the files to process, right-click them and choose Open with… | Filer from Tracker's context menu.
  2. -
  3. Select the files to process and drag&drop them on Filer's icon. You may want to create a link to Filer on the Desktop for that.
  4. -
  5. From within a Terminal, simply type "Filer" followed by the files you want processed.
  6. -
+

index AutoFiler

When AutoFiler is running, it monitors user-defined folders and executes the actions defined in the Filer rules automatically.

+
+AutoFiler settings +
+ +

The AutoFiler itself is a background application. You can activate the checkbox at the top to automatically Run AutoFiler on system startup. The button to beside it lets you start/stop it manually.

+

You can Add…, Edit… and Remove the folders that AutoFiler will monitor for incoming files.

+

index -AutoFiler Usage

-

The AutoFiler itself is a background application that normally isn't started manually. If you want to stop an already running AutoFiler, you'll have to quit it through a tool like Haiku's ProcessController or kill it from the TeamMonitor (press CTRL ALT DEL).

-

The configuration is done with the AutoFiler Settings:

+Help
-AutoFiler settings
-

You can add, edit and remove the folders that AutoFiler will monitor and use the checkbox to enable/disable the automatic launch on startup.

+The help tab + +

The last tab shows some information about Filer and offers two quick links to Help on rules and the User documentation.

+ +

+index +History

+

1.0.0 - 2008:

+ + +

1.1.0 - 03-05-2016

+ diff --git a/documentation/images/autofiler_settings.png b/documentation/images/autofiler_settings.png index 17f1671..9e3ee64 100644 Binary files a/documentation/images/autofiler_settings.png and b/documentation/images/autofiler_settings.png differ diff --git a/documentation/images/filer_dropzone.png b/documentation/images/filer_dropzone.png new file mode 100644 index 0000000..0f2383a Binary files /dev/null and b/documentation/images/filer_dropzone.png differ diff --git a/documentation/images/filer_ruleslist.png b/documentation/images/filer_ruleslist.png index 8d16f4c..9c8498e 100644 Binary files a/documentation/images/filer_ruleslist.png and b/documentation/images/filer_ruleslist.png differ diff --git a/documentation/images/help.png b/documentation/images/help.png new file mode 100644 index 0000000..110ced5 Binary files /dev/null and b/documentation/images/help.png differ diff --git a/sources/Filer/ActionView.cpp b/sources/ActionView.cpp similarity index 53% rename from sources/Filer/ActionView.cpp rename to sources/ActionView.cpp index 5c3a6b6..c80a652 100644 --- a/sources/Filer/ActionView.cpp +++ b/sources/ActionView.cpp @@ -3,129 +3,123 @@ Written by DarkWyrm , Copyright 2008 Released under the MIT license. */ -#include "ActionView.h" + #include -#include -#include #include +#include +#include #include -#include "RuleRunner.h" -#include "AutoTextControl.h" - -enum -{ - M_ACTION_CHOSEN = 'tsch', - M_SHOW_ACTION_MENU = 'sham', - M_VALUE_CHANGED = 'vlch' -}; +#include "ActionView.h" +#include "AutoTextControl.h" +#include "FilerDefs.h" +#include "RuleRunner.h" -ActionView::ActionView(const BRect &frame,const char *name, BMessage *action, - const int32 &resize,const int32 &flags) - : BView(frame,name,resize,flags | B_FRAME_EVENTS), +ActionView::ActionView(const BRect& frame, const char* name, BMessage* action, + const int32& resize, const int32& flags) + : + BView(frame, name, resize, flags | B_FRAME_EVENTS), fAction(NULL) { SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - + // Find the longest name in all the actions RuleRunner::GetActions(fActions); int32 i = 0; BString actionstr, wideststr; - while (fActions.FindString("actions",i,&actionstr) == B_OK) + while (fActions.FindString("actions", i, &actionstr) == B_OK) { i++; if (actionstr.CountChars() > wideststr.CountChars()) wideststr = actionstr; } - - fActionButton = new BButton(BRect(0,0,1,1),"actionbutton",wideststr.String(), - new BMessage(M_SHOW_ACTION_MENU)); + + fActionButton = new BButton(BRect(0, 0, 1, 1), "actionbutton", + wideststr.String(), new BMessage(MSG_SHOW_ACTION_MENU)); fActionButton->ResizeToPreferred(); AddChild(fActionButton); - + BRect rect = fActionButton->Frame(); - rect.OffsetBy(rect.Width() + 5,0); + rect.OffsetBy(rect.Width() + 5, 0); rect.right = Bounds().Width() - 10.0; if (rect.right < rect.left) rect.right = rect.left + 10; - - fValueBox = new AutoTextControl(rect,"valuebox",NULL,NULL, - new BMessage(M_VALUE_CHANGED), - B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + + fValueBox = new AutoTextControl(rect, "valuebox", NULL, NULL, + new BMessage(MSG_VALUE_CHANGED), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); AddChild(fValueBox); fValueBox->SetDivider(0); - + bool usedefaults = false; - if (action) - { + if (action) { fAction = new BMessage(*action); - + BString str; - if (fAction->FindString("name",&str) == B_OK) + if (fAction->FindString("name", &str) == B_OK) SetAction(str.String()); else usedefaults = true; - - if (!usedefaults && fAction->FindString("value",&str) == B_OK) + + if (!usedefaults && fAction->FindString("value", &str) == B_OK) fValueBox->SetText(str.String()); else usedefaults = true; - } - else + } else usedefaults = true; - - if (usedefaults) - { + + if (usedefaults) { if (!fAction) fAction = new BMessage; - + BString str; - if (fActions.FindString("actions",0,&str) == B_OK) + if (fActions.FindString("actions", 0, &str) == B_OK) SetAction(str.String()); else SetAction("Nothing"); - + fValueBox->SetText(""); } } -ActionView::~ActionView(void) +ActionView::~ActionView() { delete fAction; } void -ActionView::AttachedToWindow(void) +ActionView::AttachedToWindow() { fActionButton->SetTarget(this); fValueBox->SetTarget(this); - + // This seems stupid, but without it, fValueBox is *never* resized and I // can't find the cause of it. :( fValueBox->ResizeTo(Bounds().Width() - fValueBox->Frame().left, - fValueBox->Bounds().Height()); - if (fValueBox->Bounds().Height() < fActionButton->Bounds().Height()) - fValueBox->MoveBy(0.0,(fActionButton->Bounds().Height() - fValueBox->Bounds().Height()) / 2.0); + fValueBox->Bounds().Height()); + if (fValueBox->Bounds().Height() < fActionButton->Bounds().Height()) { + fValueBox->MoveBy(0.0, (fActionButton->Bounds().Height() + - fValueBox->Bounds().Height()) / 2.0); + } } BRect -ActionView::GetPreferredSize(void) +ActionView::GetPreferredSize() { - BRect rect(0.0,0.0,10.0,10.0); - + BRect rect(0.0, 0.0, 10.0, 10.0); + rect.bottom = fActionButton->Frame().Height(); rect.right = StringWidth("Move it to the Trash") + 5.0 + 100; - + return rect; } void -ActionView::ResizeToPreferred(void) +ActionView::ResizeToPreferred() { BRect rect = GetPreferredSize(); ResizeTo(rect.Width(),rect.Height()); @@ -133,29 +127,29 @@ ActionView::ResizeToPreferred(void) void -ActionView::MessageReceived(BMessage *msg) +ActionView::MessageReceived(BMessage* msg) { switch (msg->what) { - case M_SHOW_ACTION_MENU: + case MSG_SHOW_ACTION_MENU: { ShowActionMenu(); break; } - case M_ACTION_CHOSEN: + case MSG_ACTION_CHOSEN: { BString name; - if (msg->FindString("name",&name) == B_OK) + if (msg->FindString("name", &name) == B_OK) SetAction(name.String()); break; } - case M_VALUE_CHANGED: + case MSG_VALUE_CHANGED: { BString str; - if (fAction->FindString("value",&str) == B_OK) - fAction->ReplaceString("value",fValueBox->Text()); + if (fAction->FindString("value", &str) == B_OK) + fAction->ReplaceString("value", fValueBox->Text()); else - fAction->AddString("value",fValueBox->Text()); + fAction->AddString("value", fValueBox->Text()); break; } default: @@ -166,33 +160,30 @@ ActionView::MessageReceived(BMessage *msg) } -BMessage * -ActionView::GetAction(void) const +BMessage* +ActionView::GetAction() const { return fAction; } void -ActionView::SetAction(const char *name) +ActionView::SetAction(const char* name) { BString namestr(name); - if (fAction->FindString("name",&namestr) == B_OK) - fAction->ReplaceString("name",name); + if (fAction->FindString("name", &namestr) == B_OK) + fAction->ReplaceString("name", name); else - fAction->AddString("name",name); + fAction->AddString("name", name); fActionButton->SetLabel(name); - + namestr = name; - - if (namestr.FindFirst("…") >= 0) - { + + if (namestr.FindFirst("…") >= 0) { if (fValueBox->IsHidden()) fValueBox->Show(); - } - else - { + } else { if (!fValueBox->IsHidden()) fValueBox->Hide(); } @@ -200,35 +191,35 @@ ActionView::SetAction(const char *name) void -ActionView::ShowActionMenu(void) +ActionView::ShowActionMenu() { - BPopUpMenu *menu = new BPopUpMenu(""); - BMessage *msg; + BPopUpMenu* menu = new BPopUpMenu(""); + BMessage* msg; int32 i = 0; BString name; - while (fActions.FindString("actions",i,&name) == B_OK) + while (fActions.FindString("actions", i, &name) == B_OK) { i++; - msg = new BMessage(M_ACTION_CHOSEN); - msg->AddString("name",name.String()); + msg = new BMessage(MSG_ACTION_CHOSEN); + msg->AddString("name", name.String()); menu->AddItem(new BMenuItem(name.String(), msg)); } - + menu->SetTargetForItems(this); - - BPoint pt; + + BPoint point; uint32 buttons; - GetMouse(&pt,&buttons); - ConvertToScreen(&pt); - pt.x -= 10.0; - if (pt.x < 0.0) - pt.x = 0.0; - - pt.y -= 10.0; - if (pt.y < 0.0) - pt.y = 0.0; - + GetMouse(&point, &buttons); + ConvertToScreen(&point); + point.x -= 10.0; + if (point.x < 0.0) + point.x = 0.0; + + point.y -= 10.0; + if (point.y < 0.0) + point.y = 0.0; + menu->SetAsyncAutoDestruct(true); - menu->Go(pt,true,true,true); + menu->Go(point, true, true, true); } diff --git a/sources/ActionView.h b/sources/ActionView.h new file mode 100644 index 0000000..a1ab48b --- /dev/null +++ b/sources/ActionView.h @@ -0,0 +1,45 @@ +/* + ActionView.h: View for adjusting settings for an individual Filer action + Written by DarkWyrm , Copyright 2008 + Released under the MIT license. +*/ + +#ifndef ACTIONVIEW_H +#define ACTIONVIEW_H + +#include +#include + +class AutoTextControl; + +#include + +class ActionView : public BView +{ +public: + ActionView(const BRect& frame, const char* name, + BMessage* test = NULL, + const int32& resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, + const int32& flags = B_WILL_DRAW); + ~ActionView(); + + void AttachedToWindow(); + BRect GetPreferredSize(); + void ResizeToPreferred(); + void MessageReceived(BMessage* msg); + + BMessage* GetAction() const; + +private: + void ShowActionMenu(); + void SetAction(const char* name); + + BButton* fActionButton; + + AutoTextControl* fValueBox; + + BMessage* fAction; + BMessage fActions; +}; + +#endif // ACTIONVIEW_H diff --git a/sources/AutoFiler/AutoFiler.cpp b/sources/AutoFiler.cpp similarity index 100% rename from sources/AutoFiler/AutoFiler.cpp rename to sources/AutoFiler.cpp diff --git a/sources/AutoFiler/AutoFiler.h b/sources/AutoFiler.h similarity index 100% rename from sources/AutoFiler/AutoFiler.h rename to sources/AutoFiler.h diff --git a/sources/AutoFiler/AutoFiler.iom b/sources/AutoFiler.iom similarity index 100% rename from sources/AutoFiler/AutoFiler.iom rename to sources/AutoFiler.iom diff --git a/sources/AutoFiler/AutoFiler.rdef b/sources/AutoFiler.rdef similarity index 98% rename from sources/AutoFiler/AutoFiler.rdef rename to sources/AutoFiler.rdef index 8be205b..37d8288 100644 --- a/sources/AutoFiler/AutoFiler.rdef +++ b/sources/AutoFiler.rdef @@ -6,7 +6,7 @@ resource app_flags B_SINGLE_LAUNCH | B_BACKGROUND_APP; resource app_version { major = 1, - middle = 0, + middle = 1, minor = 0, variety = 5, diff --git a/sources/AutoFiler/AutoFilerPrefs.cpp b/sources/AutoFiler/AutoFilerPrefs.cpp deleted file mode 100644 index 1485068..0000000 --- a/sources/AutoFiler/AutoFilerPrefs.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include "PrefWindow.h" - -class App : public BApplication -{ -public: - App(void); -}; - - -App::App(void) - : BApplication("application/x-vnd.dw-AutoFilerPrefs") -{ - PrefWindow *prefwin = new PrefWindow(); - prefwin->Show(); -} - - -int -main(void) -{ - App().Run(); - return 0; -} \ No newline at end of file diff --git a/sources/AutoFiler/AutoFilerPrefs.iom b/sources/AutoFiler/AutoFilerPrefs.iom deleted file mode 100644 index a882612..0000000 Binary files a/sources/AutoFiler/AutoFilerPrefs.iom and /dev/null differ diff --git a/sources/AutoFiler/AutoFilerPrefs.rdef b/sources/AutoFiler/AutoFilerPrefs.rdef deleted file mode 100644 index 6a5e981..0000000 --- a/sources/AutoFiler/AutoFilerPrefs.rdef +++ /dev/null @@ -1,50 +0,0 @@ -resource app_signature "application/x-vnd.dw-AutoFilerPrefs"; - -resource file_types message; - -resource app_flags B_SINGLE_LAUNCH; - -resource app_version { - major = 1, - middle = 0, - minor = 0, - - variety = 5, - internal = 0, - - short_info = "Settings app for AutoFiler watcher daemon", - long_info = "Settings app for AutoFiler watcher daemon" -}; - -resource vector_icon { - $"6E6369660A0500040054020006023B019B3AA235BC243E3C71D248D17C498491" - $"00E78FE5FFC967C3020006023BA71138D0C8BBF4B83E90E64AED7C485BD7008A" - $"1D86FFB039B502000602BB6FCBB8D4C839AA71BC3992492FF148D96A00FF90F8" - $"FFFDEAFF0366006403FFC0FE03AD38AB030100000200160239F20638AB65BE3D" - $"D63F501B4A4E27488B2600EBFFAD140A0626543A464C455C4B4C603E600A0638" - $"22262E264F3C5A4E484E2A0A04262E264F3C5A3C370A043C373C5A4E484E2A0A" - $"043822262E3C374E2A0A042832284E3A573A390A042A4D2B4638492A430A042A" - $"4D365238492B460A042A4D3854384936520A042E4CBB2BC5D3BB2BC5072E4A0A" - $"042C49344D344B2C470A042A352A402B38383B0A0436442A403846383B0A042B" - $"382A403644383B0A042EBE672EBF33BB2DC03FBB2DBF730A042CBD292CBDF534" - $"3F343D08022A4E2A540221B97FBE29B97FBE29B891BE35B6F7BEFAB7B4BE80B6" - $"F7BEFAB728BFCEB6F2BF78B728BFCEB798C07BB798C07BB70AC0E7B661C228B6" - $"9DC17BB661C228B59EC1F5B59EC1F5B53BC1DBB4C3C204B4C3C204B4A8C26EB4" - $"9AC351B49AC2DEB49AC3CBB4C7C4AFB4A9C440B4C7C4AFB5A1C4BDB53EC4D8B5" - $"A1C4BDB665C486B665C486B6A1C52FB79BC62CB70EC5C2B79BC62CB72CC6D6B7" - $"2CC6D6B6F5C72CB6FAC7ABB6FAC7ABB7B6C824B980C87AB892C86EB980C87AB9" - $"D0C7B3B9CBC818B9D0C7B3B9D9C6E4B9D9C6E433C6E1BBCEC644BB3EC6A6BBCE" - $"C644BC4DC6E3BC4DC6E3BC8CC732BD05C757BD05C757BDB6C6C7BE97C531BE42" - $"C60ABE97C531BDF2C4A8BE50C4CEBDF2C4A8BD33C45CBD33C45CBD4CC408BD59" - $"C352BD59C3AEBD59C2FABD36C252BD4DC2A4BD36C252BDF3C20BBDF3C20BBE53" - $"C1E7BE9CC17EBE9CC17EBE49C0A3BD0ABF51BDBDBFE3BD0ABF51BC53BFC6BC94" - $"BF76BC53BFC6BBD4C065BBD4C065BB44C001B9D940BA96BFC4B9D940B9D0BEF1" - $"B9D0BEF1B9CCBE8BB980BE29B980BE29B980BE290204344934C2AC34C3FE314C" - $"BA6F4CB91D4C2E492EC3FF2EC2AD3146B91C46BA6E46060EA6996D062C424830" - $"4A34484238464C344F5C305E345E2C5E2C5C4F284C46110A010100000A000110" - $"1001178420040A00011030302901178420040A00011030401B01178420040A00" - $"01011001178400040A020102000A030103000A040104000A050105000A06020B" - $"06000A0202070D000A07020C08000A0302090E0815FF0A00020A0F0815FF0A08" - $"011338421C15FF01178402040A08011338421C001501178602040A0901132042" - $"1C" -}; diff --git a/sources/AutoFiler/Makefile_settings b/sources/AutoFiler/Makefile_settings deleted file mode 100644 index e514803..0000000 --- a/sources/AutoFiler/Makefile_settings +++ /dev/null @@ -1,128 +0,0 @@ -## Haiku Generic Makefile v2.6 ## - -## Fill in this file to specify the project being created, and the referenced -## Makefile-Engine will do all of the hard work for you. This handles any -## architecture of Haiku. - -# The name of the binary. -NAME = AutoFiler\ Settings - -# The type of binary, must be one of: -# APP: Application -# SHARED: Shared library or add-on -# STATIC: Static library archive -# DRIVER: Kernel driver -TYPE = APP - -# If you plan to use localization, specify the application's MIME signature. -APP_MIME_SIG = application/x-vnd.dw-AutoFilerPrefs - -# The following lines tell Pe and Eddie where the SRCS, RDEFS, and RSRCS are -# so that Pe and Eddie can fill them in for you. -#%{ -# @src->@ - -# Specify the source files to use. Full paths or paths relative to the -# Makefile can be included. All files, regardless of directory, will have -# their object files created in the common object directory. Note that this -# means this Makefile will not work correctly if two source files with the -# same name (source.c or source.cpp) are included from different directories. -# Also note that spaces in folder names do not work well with this Makefile. -SRCS = AutoFilerPrefs.cpp RefStorage.cpp PrefWindow.cpp TypedRefFilter.cpp - -# Specify the resource definition files to use. Full or relative paths can be -# used. -RDEFS = AutoFilerPrefs.rdef - -# Specify the resource files to use. Full or relative paths can be used. -# Both RDEFS and RSRCS can be utilized in the same Makefile. -RSRCS = - -# End Pe/Eddie support. -# @<-src@ -#%} - -# Specify libraries to link against. -# There are two acceptable forms of library specifications: -# - if your library follows the naming pattern of libXXX.so or libXXX.a, -# you can simply specify XXX for the library. (e.g. the entry for -# "libtracker.so" would be "tracker") -# -# - for GCC-independent linking of standard C++ libraries, you can use -# $(STDCPPLIBS) instead of the raw "stdc++[.r4] [supc++]" library names. -# -# - if your library does not follow the standard library naming scheme, -# you need to specify the path to the library and it's name. -# (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a") -LIBS = be tracker - -# Specify additional paths to directories following the standard libXXX.so -# or libXXX.a naming scheme. You can specify full paths or paths relative -# to the Makefile. The paths included are not parsed recursively, so -# include all of the paths where libraries must be found. Directories where -# source files were specified are automatically included. -LIBPATHS = - -# Additional paths to look for system headers. These use the form -# "#include
". Directories that contain the files in SRCS are -# NOT auto-included here. -SYSTEM_INCLUDE_PATHS = - -# Additional paths paths to look for local headers. These use the form -# #include "header". Directories that contain the files in SRCS are -# automatically included. -LOCAL_INCLUDE_PATHS = - -# Specify the level of optimization that you want. Specify either NONE (O0), -# SOME (O1), FULL (O2), or leave blank (for the default optimization level). -OPTIMIZE := FULL - -# Specify the codes for languages you are going to support in this -# application. The default "en" one must be provided too. "make catkeys" -# will recreate only the "locales/en.catkeys" file. Use it as a template -# for creating catkeys for other languages. All localization files must be -# placed in the "locales" subdirectory. -LOCALES = - -# Specify all the preprocessor symbols to be defined. The symbols will not -# have their values set automatically; you must supply the value (if any) to -# use. For example, setting DEFINES to "DEBUG=1" will cause the compiler -# option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" would pass -# "-DDEBUG" on the compiler's command line. -DEFINES = - -# Specify the warning level. Either NONE (suppress all warnings), -# ALL (enable all warnings), or leave blank (enable default warnings). -WARNINGS = - -# With image symbols, stack crawls in the debugger are meaningful. -# If set to "TRUE", symbols will be created. -SYMBOLS := - -# Includes debug information, which allows the binary to be debugged easily. -# If set to "TRUE", debug info will be created. -DEBUGGER := - -# Specify any additional compiler flags to be used. -COMPILER_FLAGS = -Woverloaded-virtual -funsigned-bitfields -Wwrite-strings - -# Specify any additional linker flags to be used. -LINKER_FLAGS = - -# Specify the version of this binary. Example: -# -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL" -# This may also be specified in a resource. -APP_VERSION := - -# (Only used when "TYPE" is "DRIVER"). Specify the desired driver install -# location in the /dev hierarchy. Example: -# DRIVER_PATH = video/usb -# will instruct the "driverinstall" rule to place a symlink to your driver's -# binary in ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will -# appear at /dev/video/usb when loaded. The default is "misc". -DRIVER_PATH = - -## Include the Makefile-Engine -DEVEL_DIRECTORY := \ - $(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY) -include $(DEVEL_DIRECTORY)/etc/makefile-engine diff --git a/sources/AutoFiler/PrefWindow.cpp b/sources/AutoFiler/PrefWindow.cpp deleted file mode 100644 index db21f65..0000000 --- a/sources/AutoFiler/PrefWindow.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* - Released under the MIT license. - Written by DarkWyrm , Copyright 2008 - Contributed by: Humdinger , 2016 -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "PrefWindow.h" -#include "RefStorage.h" -#include "TypedRefFilter.h" - -#include - - -const BRect kDefaultFrame(100,100,500,400); - -enum -{ - M_SHOW_ADD_PANEL = 'shaw', - M_SHOW_EDIT_PANEL = 'shew', - M_REMOVE_FOLDER = 'rmfl', - M_FOLDER_SELECTED = 'flsl', - M_FOLDER_CHOSEN = 'flch' -}; - -PrefWindow::PrefWindow(void) - : BWindow(LoadFrame(),"AutoFiler Settings",B_TITLED_WINDOW, - B_ASYNCHRONOUS_CONTROLS) -{ - LoadFolders(); - - AddShortcut('a',B_COMMAND_KEY,new BMessage(M_SHOW_ADD_PANEL)); - AddShortcut('c',B_COMMAND_KEY,new BMessage(M_SHOW_EDIT_PANEL)); - - BView *top = new BView(Bounds(),"top",B_FOLLOW_ALL,B_WILL_DRAW); - top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - AddChild(top); - - BStringView *folderLabel = new BStringView(BRect(10,5,11,6),"folderlabel", - "Automatically run Filer on the contents of these folders:"); - folderLabel->ResizeToPreferred(); - top->AddChild(folderLabel); - - BRect rect(Bounds().InsetByCopy(10,10)); - rect.top = folderLabel->Frame().bottom + 5; - rect.right -= B_V_SCROLL_BAR_WIDTH; - - fFolderList = new BListView(rect,"rulelist",B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL); - fScrollView = new BScrollView("listscroll",fFolderList, - B_FOLLOW_ALL,0,true,true); - fScrollView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - top->AddChild(fScrollView); - fFolderList->SetSelectionMessage(new BMessage(M_FOLDER_SELECTED)); - fFolderList->SetInvocationMessage(new BMessage(M_SHOW_EDIT_PANEL)); - fScrollView->ScrollBar(B_HORIZONTAL)->SetRange(0.0,0.0); - - fAutorunBox = new BCheckBox(BRect(0,0,1,1),"autorunbox","Run AutoFiler on system startup", - new BMessage, B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fAutorunBox->ResizeToPreferred(); - fAutorunBox->MoveTo((Bounds().Width() - fAutorunBox->Bounds().Width()) / 2.0, - Bounds().bottom - fAutorunBox->Bounds().Height() - 10.0); - // add as child later - - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY, &path); - path.Append(gPrefsPath); - - BNode node(path.Path()); - bool autorun = true; - if (node.InitCheck() == B_OK) - { - bool tmpbool; - if (node.ReadAttr("autorun",B_BOOL_TYPE,0,(void*)&tmpbool,sizeof(bool)) > 0) - autorun = tmpbool; - } - if (autorun) - fAutorunBox->SetValue(B_CONTROL_ON); - - fAddButton = new BButton(BRect(0,0,1,1),"addbutton","Add…", - new BMessage(M_SHOW_ADD_PANEL), - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fAddButton->ResizeToPreferred(); - fAddButton->MoveTo(10,fAutorunBox->Frame().top - 5.0 - fAddButton->Bounds().IntegerHeight()); - top->AddChild(fAddButton); - - fChangeButton = new BButton(BRect(0,0,1,1),"editbutton","Edit…", - new BMessage(M_SHOW_EDIT_PANEL), - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fChangeButton->ResizeToPreferred(); - fChangeButton->MoveTo((Bounds().Width() - fChangeButton->Bounds().Width()) / 2.0, - fAddButton->Frame().top); - top->AddChild(fChangeButton); - fChangeButton->SetEnabled(false); - - - fRemoveButton = new BButton(BRect(0,0,1,1),"removebutton","Remove", - new BMessage(M_REMOVE_FOLDER), - B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); - fRemoveButton->ResizeToPreferred(); - fRemoveButton->MoveTo(Bounds().Width() - fRemoveButton->Bounds().Width() - 10, - fAddButton->Frame().top); - top->AddChild(fRemoveButton); - fRemoveButton->SetEnabled(false); - - top->AddChild(fAutorunBox); - - fScrollView->ResizeTo(Bounds().Width() - 20.0, fAddButton->Frame().top - 10.0 - - fScrollView->Frame().top); - - float minwidth = (fRemoveButton->Bounds().Width() * 3.0) + 40; - SetSizeLimits(minwidth, 30000, 200, 30000); - -// fRefFilter = new TypedRefFilter("application/x-vnd.Be-directory",B_DIRECTORY_NODE); - fRefFilter = new TypedRefFilter("",B_DIRECTORY_NODE); - fFilePanel = new BFilePanel(B_OPEN_PANEL,new BMessenger(this), NULL,B_DIRECTORY_NODE,false, - NULL,fRefFilter); - - gRefLock.Lock(); - for (int32 i = 0; i < gRefStructList.CountItems(); i++) - { - RefStorage *refholder = (RefStorage*)gRefStructList.ItemAt(i); - fFolderList->AddItem(new BStringItem(BPath(&refholder->ref).Path())); - } - gRefLock.Unlock(); - - fFolderList->MakeFocus(); - if (fFolderList->CountItems() > 0) - fFolderList->Select(0L); -} - - -PrefWindow::~PrefWindow(void) -{ - delete fFilePanel; -} - - -bool -PrefWindow::QuitRequested(void) -{ - SaveFolders(); - SaveFrame(); - - // save autorun value - bool autorun = (fAutorunBox->Value() == B_CONTROL_ON); - - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY, &path); - path.Append(gPrefsPath); - - BNode node(path.Path()); - if (node.InitCheck() == B_OK) - node.WriteAttr("autorun",B_BOOL_TYPE,0,(void*)&autorun,sizeof(bool)); - - if (autorun) - EnableAutorun(); - else - DisableAutorun(); - - // if AutoFiler is running, tell it to refresh its folders - if (be_roster->IsRunning("application/x-vnd.dw-AutoFiler")) - { - BMessage msg(M_REFRESH_FOLDERS); - BMessenger msgr("application/x-vnd.dw-AutoFiler"); - msgr.SendMessage(&msg); - } - - - be_app->PostMessage(B_QUIT_REQUESTED); - return true; -} - - -void -PrefWindow::MessageReceived(BMessage *msg) -{ - switch (msg->what) - { - case M_SHOW_ADD_PANEL: - { - BMessage panelmsg(M_FOLDER_CHOSEN); - fFilePanel->SetMessage(&panelmsg); - fFilePanel->Show(); - break; - } - case M_SHOW_EDIT_PANEL: - { - int32 selection = fFolderList->CurrentSelection(); - if (selection < 0) - break; - - BStringItem *item = (BStringItem*)fFolderList->ItemAt(selection); - fFilePanel->SetPanelDirectory(item->Text()); - - BMessage panelmsg(M_FOLDER_CHOSEN); - panelmsg.AddInt32("index",selection); - fFilePanel->SetMessage(&panelmsg); - fFilePanel->Show(); - break; - } - case M_REMOVE_FOLDER: - { - int32 selection = fFolderList->CurrentSelection(); - if (selection < 0) - break; - - BStringItem *item = (BStringItem*)fFolderList->RemoveItem(selection); - delete item; - - gRefLock.Lock(); - RefStorage *refholder = (RefStorage*) gRefStructList.RemoveItem(selection); - delete refholder; - gRefLock.Unlock(); - - break; - } - case M_FOLDER_SELECTED: - { - int32 selection = fFolderList->CurrentSelection(); - - bool value = (selection >= 0); - - fChangeButton->SetEnabled(value); - fRemoveButton->SetEnabled(value); - - break; - } - case M_FOLDER_CHOSEN: - { - int32 index; - if (msg->FindInt32("index",&index) != B_OK) - index = -1; - - entry_ref ref; - if (msg->FindRef("refs",&ref) != B_OK) - break; - - BStringItem *item = (BStringItem*) fFolderList->ItemAt(index); - if (item) - { - gRefLock.Lock(); - RefStorage *refholder = (RefStorage*) gRefStructList.ItemAt(index); - refholder->SetData(ref); - gRefLock.Unlock(); - } - else - { - item = new BStringItem(""); - fFolderList->AddItem(item); - - gRefLock.Lock(); - gRefStructList.AddItem(new RefStorage(ref)); - gRefLock.Unlock(); - } - - item->SetText(BPath(&ref).Path()); - fFolderList->Invalidate(); - break; - } - default: - BWindow::MessageReceived(msg); - } -} - - -BRect -PrefWindow::LoadFrame(void) -{ - BRect frame(kDefaultFrame); - - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY, &path); - path.Append(gPrefsPath); - - BNode node(path.Path()); - if (node.InitCheck() == B_OK) - { - BRect r; - if (node.ReadAttr("windowframe",B_RECT_TYPE,0,(void*)&r,sizeof(BRect)) > 0) - frame = r; - } - - return frame; -} - - -void -PrefWindow::SaveFrame(void) -{ - BRect r(Frame()); - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY, &path); - path.Append(gPrefsPath); - - BNode node(path.Path()); - if (node.InitCheck() == B_OK) - node.WriteAttr("windowframe",B_RECT_TYPE,0,(void*)&r,sizeof(BRect)); -} - - -void -PrefWindow::FrameResized(float width, float height) -{ - float x = fAddButton->Frame().right + ((fRemoveButton->Frame().left - - fAddButton->Frame().right) / 2.0); - fChangeButton->MoveTo(x - (fChangeButton->Bounds().Width() / 2.0), - fAddButton->Frame().top); -} - - -void -PrefWindow::EnableAutorun(void) -{ - BDirectory destDir; - BPath destPath; - find_directory(B_USER_SETTINGS_DIRECTORY, &destPath); - - status_t ret = destPath.Append("boot"); - if (ret == B_OK) - ret = create_directory(destPath.Path(), 0777); - - ret = destPath.Append("launch"); - if (ret == B_OK) - ret = create_directory(destPath.Path(), 0777); - - if (ret == B_OK) { - destDir = BDirectory(destPath.Path()); - ret = destDir.InitCheck(); - } - - if (ret != B_OK) - return; - - destPath.Append("AutoFiler"); - - app_info info; - BPath linkPath; - be_roster->GetActiveAppInfo(&info); - BEntry entry(&info.ref); - - entry.GetPath(&linkPath); - linkPath.GetParent(&linkPath); - linkPath.Append("AutoFiler"); - destDir.CreateSymLink(destPath.Path(), linkPath.Path(), NULL); -} - - -void -PrefWindow::DisableAutorun(void) -{ - BPath path; - - if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) < B_OK) - return; - status_t ret = path.Append("boot/launch/AutoFiler"); - - if (ret == B_OK) { - BEntry entry(path.Path()); - entry.Remove(); - } -} - diff --git a/sources/AutoFiler/PrefWindow.h b/sources/AutoFiler/PrefWindow.h deleted file mode 100644 index 8466b63..0000000 --- a/sources/AutoFiler/PrefWindow.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef PREFWIN_H -#define PREFWIN_H - -#include -#include -#include -#include -#include -#include -#include - -class TypedRefFilter; - -class PrefWindow : public BWindow -{ -public: - PrefWindow(void); - ~PrefWindow(void); - bool QuitRequested(void); - void MessageReceived(BMessage *msg); - void FrameResized(float width, float height); - -private: - BRect LoadFrame(void); - void SaveFrame(void); - void EnableAutorun(void); - void DisableAutorun(void); - - BListView *fFolderList; - BScrollView *fScrollView; - - BButton *fAddButton, - *fChangeButton, - *fRemoveButton; - - BFilePanel *fFilePanel; - TypedRefFilter *fRefFilter; - - BCheckBox *fAutorunBox; -}; - -#endif diff --git a/sources/AutoFiler/TypedRefFilter.cpp b/sources/AutoFiler/TypedRefFilter.cpp deleted file mode 100644 index 1e32bb1..0000000 --- a/sources/AutoFiler/TypedRefFilter.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "TypedRefFilter.h" - -TypedRefFilter::TypedRefFilter(void) - : BRefFilter() -{ -} - - -TypedRefFilter::TypedRefFilter(const char *file_type, const uint32 &node_type) - : BRefFilter(), - fFileType(file_type), - fNodeType(node_type) -{ -} - - -TypedRefFilter::~TypedRefFilter(void) -{ -} - - -const char * -TypedRefFilter::FileType(void) const -{ - return fFileType.String(); -} - - -void -TypedRefFilter::SetFileType(const char *type) -{ - fFileType = type; -} - - -uint32 -TypedRefFilter::NodeType(void) const -{ - return fNodeType; -} - - -void -TypedRefFilter::SetNodeType(const uint32 &node_type) -{ - fNodeType = node_type; -} - - -bool -TypedRefFilter::Filter(const entry_ref *ref, BNode *node, struct stat_beos *st, - const char *filetype) -{ - // it does not match the entry filter, then we automatically kick back a false - if ( !( ((B_DIRECTORY_NODE & NodeType()) && S_ISDIR(st->st_mode)) || - ((B_FILE_NODE & NodeType()) && S_ISREG(st->st_mode)) || - ((B_SYMLINK_NODE & NodeType()) && S_ISLNK(st->st_mode)) ) ) - return false; - - // An empty file type means any file type - if (fFileType.Length() < 1) - return true; - - if (fFileType == filetype) - return true; - - return false; -} diff --git a/sources/AutoFiler/TypedRefFilter.h b/sources/AutoFiler/TypedRefFilter.h deleted file mode 100644 index 6373611..0000000 --- a/sources/AutoFiler/TypedRefFilter.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TYPED_REF_FILTER -#define TYPED_REF_FILTER - -#include -#include - -#include - -/* - This utility class is for filtering -*/ -class TypedRefFilter : public BRefFilter -{ -public: - TypedRefFilter(void); - TypedRefFilter(const char *file_type, - const uint32 &node_type = B_FILE_NODE | - B_DIRECTORY_NODE | - B_SYMLINK_NODE); - virtual ~TypedRefFilter(void); - - const char * FileType(void) const; - void SetFileType(const char *type); - - uint32 NodeType(void) const; - void SetNodeType(const uint32 &node_type); - - virtual bool Filter(const entry_ref *ref, BNode *node, - struct stat_beos *st, const char *filetype); - - -private: - BString fFileType; - uint32 fNodeType; -}; - -#endif diff --git a/sources/AutoFilerTab.cpp b/sources/AutoFilerTab.cpp new file mode 100644 index 0000000..9c3a52c --- /dev/null +++ b/sources/AutoFilerTab.cpp @@ -0,0 +1,358 @@ +/* + * Copyright 2008, 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm , Copyright 2008 + * Humdinger, humdingerb@gmail.com + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AutoFilerTab.h" +#include "FilerDefs.h" +#include "RefStorage.h" +#include "TypedRefFilter.h" + + +AutoFilerTab::AutoFilerTab() + : + BView("AutoFiler", B_SUPPORTS_LAYOUT) +{ + LoadFolders(); + _BuildLayout(); + +// fRefFilter = new TypedRefFilter("application/x-vnd.Be-directory", +// B_DIRECTORY_NODE); + fRefFilter = new TypedRefFilter("", B_DIRECTORY_NODE); + fFilePanel = new BFilePanel(B_OPEN_PANEL, new BMessenger(this), NULL, + B_DIRECTORY_NODE, false, NULL, fRefFilter); + BMessage panelMsg(MSG_FOLDER_CHOSEN); + fFilePanel->SetMessage(&panelMsg); + + gRefLock.Lock(); + for (int32 i = 0; i < gRefStructList.CountItems(); i++) + { + RefStorage* refholder = (RefStorage*)gRefStructList.ItemAt(i); + fFolderList->AddItem(new BStringItem(BPath(&refholder->ref).Path())); + } + gRefLock.Unlock(); + + fFolderList->MakeFocus(); + if (fFolderList->CountItems() > 0) + fFolderList->Select(0L); +} + + +AutoFilerTab::~AutoFilerTab() +{ + delete fFilePanel; +} + + +void +AutoFilerTab::_BuildLayout() +{ + BStringView* folderLabel = new BStringView("folderlabel", + "Automatically run Filer on the contents of these folders:"); + + fFolderList = new BListView("rulelist", B_SINGLE_SELECTION_LIST, + B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE); + fScrollView = new BScrollView("listscroll", fFolderList, + B_FRAME_EVENTS | B_WILL_DRAW, false, true); + fFolderList->SetSelectionMessage(new BMessage(MSG_FOLDER_SELECTED)); + fFolderList->SetInvocationMessage(new BMessage(MSG_SHOW_EDIT_PANEL)); + + fAutorunBox = new BCheckBox("autorunbox", + "Run AutoFiler on system startup", new BMessage); + + fStartStop = new BButton("startstop", "Start AutoFiler", + new BMessage(MSG_STARTSTOP_AUTOFILER)); + + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + path.Append(gPrefsPath); + + BNode node(path.Path()); + bool autorun = true; + if (node.InitCheck() == B_OK) { + bool tmpbool; + if (node.ReadAttr("autorun", B_BOOL_TYPE, 0, (void*)&tmpbool, + sizeof(bool)) > 0) + autorun = tmpbool; + } + if (autorun) + fAutorunBox->SetValue(B_CONTROL_ON); + + fAddButton = new BButton("addbutton", "Add" B_UTF8_ELLIPSIS, + new BMessage(MSG_SHOW_ADD_PANEL)); + + fEditButton = new BButton("editbutton", "Edit" B_UTF8_ELLIPSIS, + new BMessage(MSG_SHOW_EDIT_PANEL)); + fEditButton->SetEnabled(false); + + fRemoveButton = new BButton("removebutton", "Remove", + new BMessage(MSG_REMOVE_FOLDER)); + fRemoveButton->SetEnabled(false); + + static const float spacing = be_control_look->DefaultItemSpacing(); + BLayoutBuilder::Group<>(this, B_HORIZONTAL, B_USE_DEFAULT_SPACING) + .SetInsets(spacing) + .AddGroup(B_VERTICAL) + .AddGroup(B_HORIZONTAL) + .Add(fAutorunBox) + .Add(new BSeparatorView(B_VERTICAL)) + .Add(fStartStop) + .End() + .Add(new BSeparatorView(B_HORIZONTAL)) + .Add(folderLabel) + .Add(fScrollView) + .AddGroup(B_HORIZONTAL) + .AddGlue() + .Add(fAddButton) + .Add(fEditButton) + .Add(fRemoveButton) + .AddGlue() + .End() + .End(); +} + + +void +AutoFilerTab::AttachedToWindow() +{ +// SetFlags(Flags() | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE); + + fStartStop->SetTarget(this); + fAddButton->SetTarget(this); + fEditButton->SetTarget(this); + fRemoveButton->SetTarget(this); + + fFolderList->SetTarget(this); + fFilePanel->SetTarget(this); + + if (fFolderList->CountItems() > 0) { + BMessenger messenger(this); + BMessage msg(MSG_FOLDER_SELECTED); + messenger.SendMessage(&msg); + } + BMessage msg(MSG_UPDATE_LABEL); + fRunner = new BMessageRunner(this, &msg, 0.5 * 6000000); // x * seconds + + BView::AttachedToWindow(); +} + + +void +AutoFilerTab::DetachedFromWindow() +{ + SaveFolders(); + + // save autorun value + bool autorun = (fAutorunBox->Value() == B_CONTROL_ON); + + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + path.Append(gPrefsPath); + + BNode node(path.Path()); + if (node.InitCheck() == B_OK) { + node.WriteAttr("autorun", B_BOOL_TYPE, 0, + (void*)&autorun, sizeof(bool)); + } + if (autorun) + EnableAutorun(); + else + DisableAutorun(); + + // if AutoFiler is running, tell it to refresh its folders + if (be_roster->IsRunning("application/x-vnd.dw-AutoFiler")) + { + BMessage msg(MSG_REFRESH_FOLDERS); + BMessenger msgr("application/x-vnd.dw-AutoFiler"); + msgr.SendMessage(&msg); + } +} + + +void +AutoFilerTab::MessageReceived(BMessage* msg) +{ + switch (msg->what) + { + case MSG_STARTSTOP_AUTOFILER: + { + ToggleAutoFiler(); + break; + } + case MSG_UPDATE_LABEL: + { + UpdateAutoFilerLabel(); + break; + } + case MSG_SHOW_ADD_PANEL: + { + fFilePanel->Show(); + break; + } + case MSG_SHOW_EDIT_PANEL: + { + int32 selection = fFolderList->CurrentSelection(); + if (selection < 0) + break; + + BStringItem* item = (BStringItem*)fFolderList->ItemAt(selection); + fFilePanel->SetPanelDirectory(item->Text()); + + BMessage panelMsg(MSG_FOLDER_CHOSEN); + panelMsg.AddInt32("index", selection); + fFilePanel->SetMessage(&panelMsg); + fFilePanel->Show(); + break; + } + case MSG_REMOVE_FOLDER: + { + int32 selection = fFolderList->CurrentSelection(); + if (selection < 0) + break; + + BStringItem* item = (BStringItem*)fFolderList->RemoveItem(selection); + delete item; + + gRefLock.Lock(); + RefStorage* refholder = (RefStorage*)gRefStructList.RemoveItem(selection); + delete refholder; + gRefLock.Unlock(); + break; + } + case MSG_FOLDER_SELECTED: + { + int32 selection = fFolderList->CurrentSelection(); + bool value = (selection >= 0); + + fEditButton->SetEnabled(value); + fRemoveButton->SetEnabled(value); + break; + } + case MSG_FOLDER_CHOSEN: + { + int32 index; + if (msg->FindInt32("index", &index) != B_OK) + index = -1; + + entry_ref ref; + if (msg->FindRef("refs", &ref) != B_OK) + break; + + BStringItem* item = (BStringItem*)fFolderList->ItemAt(index); + if (item) { + gRefLock.Lock(); + RefStorage* refholder = (RefStorage*)gRefStructList.ItemAt(index); + refholder->SetData(ref); + gRefLock.Unlock(); + } else { + item = new BStringItem(""); + fFolderList->AddItem(item); + + gRefLock.Lock(); + gRefStructList.AddItem(new RefStorage(ref)); + gRefLock.Unlock(); + } + + item->SetText(BPath(&ref).Path()); + fFolderList->Invalidate(); + break; + } + default: + BView::MessageReceived(msg); + } +} + + +void +AutoFilerTab::ToggleAutoFiler() +{ + if (be_roster->IsRunning(kAutoFilerSignature)) { + BString command = "hey %app% quit"; + command.ReplaceFirst("%app%", kAutoFilerSignature); + system(command.String()); + fStartStop->SetLabel("Start AutoFiler"); + } else { + be_roster->Launch(kAutoFilerSignature); + fStartStop->SetLabel("Stop AutoFiler"); + } +} + + +void +AutoFilerTab::UpdateAutoFilerLabel() +{ + if (be_roster->IsRunning(kAutoFilerSignature)) + fStartStop->SetLabel("Stop AutoFiler"); + else + fStartStop->SetLabel("Start AutoFiler"); +} + + +void +AutoFilerTab::EnableAutorun() +{ + BDirectory destDir; + BPath destPath; + find_directory(B_USER_SETTINGS_DIRECTORY, &destPath); + + status_t ret = destPath.Append("boot"); + if (ret == B_OK) + ret = create_directory(destPath.Path(), 0777); + + ret = destPath.Append("launch"); + if (ret == B_OK) + ret = create_directory(destPath.Path(), 0777); + + if (ret == B_OK) { + destDir = BDirectory(destPath.Path()); + ret = destDir.InitCheck(); + } + + if (ret != B_OK) + return; + + destPath.Append("AutoFiler"); + + app_info info; + BPath linkPath; + be_roster->GetActiveAppInfo(&info); + BEntry entry(&info.ref); + + entry.GetPath(&linkPath); + linkPath.GetParent(&linkPath); + linkPath.Append("AutoFiler"); + destDir.CreateSymLink(destPath.Path(), linkPath.Path(), NULL); +} + + +void +AutoFilerTab::DisableAutorun() +{ + BPath path; + + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) < B_OK) + return; + status_t ret = path.Append("boot/launch/AutoFiler"); + + if (ret == B_OK) { + BEntry entry(path.Path()); + entry.Remove(); + } +} diff --git a/sources/AutoFilerTab.h b/sources/AutoFilerTab.h new file mode 100644 index 0000000..a0bd171 --- /dev/null +++ b/sources/AutoFilerTab.h @@ -0,0 +1,56 @@ +/* + * Copyright 2008, 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm , Copyright 2008 + * Humdinger, humdingerb@gmail.com + */ + +#ifndef AUTOFILERTAB_H +#define AUTOFILERTAB_H + +#include +#include +#include +#include +#include +#include + +class TypedRefFilter; + +class AutoFilerTab : public BView +{ +public: + AutoFilerTab(); + ~AutoFilerTab(); + + virtual void AttachedToWindow(); + virtual void DetachedFromWindow(); + void MessageReceived(BMessage* msg); + +private: + void _BuildLayout(); + + void EnableAutorun(); + void DisableAutorun(); + + void ToggleAutoFiler(); + void UpdateAutoFilerLabel(); + + BListView* fFolderList; + BScrollView* fScrollView; + + BCheckBox* fAutorunBox; + BButton* fStartStop; + + BButton* fAddButton; + BButton* fEditButton; + BButton* fRemoveButton; + + BFilePanel* fFilePanel; + TypedRefFilter* fRefFilter; + BMessageRunner* fRunner; +}; + +#endif // AUTOFILERTAB_H diff --git a/sources/Filer/AutoTextControl.cpp b/sources/AutoTextControl.cpp similarity index 51% rename from sources/Filer/AutoTextControl.cpp rename to sources/AutoTextControl.cpp index de35229..50b6cd8 100644 --- a/sources/Filer/AutoTextControl.cpp +++ b/sources/AutoTextControl.cpp @@ -3,6 +3,7 @@ Written by DarkWyrm , Copyright 2007 Released under the MIT license. */ + #include "AutoTextControl.h" #include #include @@ -12,19 +13,23 @@ static property_info sProperties[] = { { "CharacterLimit", { B_GET_PROPERTY, 0 }, { B_DIRECT_SPECIFIER, 0 }, - "Returns the maximum number of characters that the AutoTextControl will allow.", + "Returns the maximum number of characters " + "that the AutoTextControl will allow.", 0, { B_INT32_TYPE } }, { "CharacterLimit", { B_SET_PROPERTY, 0 }, { B_DIRECT_SPECIFIER, 0}, - "Sets the maximum number of characters that the AutoTextControl will allow.", + "Sets the maximum number of characters " + "that the AutoTextControl will allow.", 0, { B_INT32_TYPE } }, }; -AutoTextControl::AutoTextControl(const BRect &frame, const char *name, const char *label, - const char *text, BMessage *msg, uint32 resize, uint32 flags) - : BTextControl(frame,name,label,text,msg,resize,flags), +AutoTextControl::AutoTextControl(const BRect& frame, const char* name, + const char* label, const char* text, BMessage* msg, uint32 resize, + uint32 flags) + : + BTextControl(frame ,name, label, text, msg, resize, flags), fFilter(NULL), fCharLimit(0) { @@ -32,7 +37,7 @@ AutoTextControl::AutoTextControl(const BRect &frame, const char *name, const cha } -AutoTextControl::~AutoTextControl(void) +AutoTextControl::~AutoTextControl() { if (Window()) Window()->RemoveCommonFilter(fFilter); @@ -41,16 +46,17 @@ AutoTextControl::~AutoTextControl(void) } -AutoTextControl::AutoTextControl(BMessage *data) - : BTextControl(data) +AutoTextControl::AutoTextControl(BMessage* data) + : + BTextControl(data) { - if (data->FindInt32("_charlimit",(int32*)&fCharLimit) != B_OK) + if (data->FindInt32("_charlimit", (int32*)&fCharLimit) != B_OK) fCharLimit = 0; } -BArchivable * -AutoTextControl::Instantiate(BMessage *data) +BArchivable* +AutoTextControl::Instantiate(BMessage* data) { if (validate_instantiation(data, "AutoTextControl")) return new AutoTextControl(data); @@ -60,41 +66,41 @@ AutoTextControl::Instantiate(BMessage *data) status_t -AutoTextControl::Archive(BMessage *data, bool deep) const +AutoTextControl::Archive(BMessage* data, bool deep) const { - status_t status = BTextControl::Archive(data,deep); - + status_t status = BTextControl::Archive(data, deep); + if (status == B_OK) - status = data->AddInt32("_charlimit",fCharLimit); - + status = data->AddInt32("_charlimit", fCharLimit); + if (status == B_OK) - status = data->AddString("class","AutoTextControl"); - + status = data->AddString("class", "AutoTextControl"); + return status; } status_t -AutoTextControl::GetSupportedSuites(BMessage *msg) +AutoTextControl::GetSupportedSuites(BMessage* msg) { - msg->AddString("suites","suite/vnd.DW-autotextcontrol"); - + msg->AddString("suites", "suite/vnd.DW-autotextcontrol"); + BPropertyInfo prop_info(sProperties); - msg->AddFlat("messages",&prop_info); + msg->AddFlat("messages", &prop_info); return BTextControl::GetSupportedSuites(msg); } -BHandler * -AutoTextControl::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier, - int32 form, const char *property) +BHandler* +AutoTextControl::ResolveSpecifier(BMessage* msg, int32 index, + BMessage* specifier, int32 form, const char* property) { return BControl::ResolveSpecifier(msg, index, specifier, form, property); } void -AutoTextControl::AttachedToWindow(void) +AutoTextControl::AttachedToWindow() { BTextControl::AttachedToWindow(); if (fFilter) @@ -103,95 +109,98 @@ AutoTextControl::AttachedToWindow(void) void -AutoTextControl::DetachedFromWindow(void) +AutoTextControl::DetachedFromWindow() { if (fFilter) Window()->RemoveCommonFilter(fFilter); + BTextControl::DetachedFromWindow(); } void -AutoTextControl::SetCharacterLimit(const uint32 &limit) +AutoTextControl::SetCharacterLimit(const uint32& limit) { fCharLimit = limit; } uint32 -AutoTextControl::GetCharacterLimit(const uint32 &limit) +AutoTextControl::GetCharacterLimit(const uint32& limit) { return fCharLimit; } void -AutoTextControl::SetFilter(AutoTextControlFilter *filter) +AutoTextControl::SetFilter(AutoTextControlFilter* filter) { if (fFilter) { if (Window()) Window()->RemoveCommonFilter(fFilter); delete fFilter; } - + fFilter = filter; if (Window()) Window()->AddCommonFilter(fFilter); } -AutoTextControlFilter::AutoTextControlFilter(AutoTextControl *box) - : BMessageFilter(B_PROGRAMMED_DELIVERY, B_ANY_SOURCE,B_KEY_DOWN), + +AutoTextControlFilter::AutoTextControlFilter(AutoTextControl* box) + : + BMessageFilter(B_PROGRAMMED_DELIVERY, B_ANY_SOURCE, B_KEY_DOWN), fBox(box), fCurrentMessage(NULL) { } -AutoTextControlFilter::~AutoTextControlFilter(void) +AutoTextControlFilter::~AutoTextControlFilter() { } filter_result -AutoTextControlFilter::Filter(BMessage *msg, BHandler **target) +AutoTextControlFilter::Filter(BMessage* msg, BHandler** target) { - int32 rawchar,mod; - msg->FindInt32("raw_char",&rawchar); - msg->FindInt32("modifiers",&mod); - - BView *view = dynamic_cast(*target); - if (!view || strcmp("_input_",view->Name()) != 0) + int32 rawchar, mod; + msg->FindInt32("raw_char", &rawchar); + msg->FindInt32("modifiers", &mod); + + BView* view = dynamic_cast(*target); + if (!view || strcmp("_input_", view->Name()) != 0) return B_DISPATCH_MESSAGE; - AutoTextControl *text = dynamic_cast(view->Parent()); + AutoTextControl* text = dynamic_cast(view->Parent()); if (!text || text != fBox) return B_DISPATCH_MESSAGE; - + fCurrentMessage = msg; - filter_result result = KeyFilter(rawchar,mod); + filter_result result = KeyFilter(rawchar, mod); fCurrentMessage = NULL; - + if (fBox->fCharLimit && result == B_DISPATCH_MESSAGE) { // See to it that we still allow shortcut keys if (mod & B_COMMAND_KEY) return B_DISPATCH_MESSAGE; - - // We don't use strlen() because it is not UTF-8 aware, which can affect - // how many characters can be typed. + + // We don't use strlen() because it is not UTF-8 aware, which can + // affect how many characters can be typed. if (isprint(rawchar) && (uint32)BString(text->Text()).CountChars() == text->fCharLimit) return B_SKIP_MESSAGE; } - + return result; } filter_result -AutoTextControlFilter::KeyFilter(const int32 &rawchar, const int32 &mod) +AutoTextControlFilter::KeyFilter(const int32& rawchar, const int32& mod) { if (fBox) fBox->Invoke(); - + return B_DISPATCH_MESSAGE; } diff --git a/sources/AutoTextControl.h b/sources/AutoTextControl.h new file mode 100644 index 0000000..63d5d2f --- /dev/null +++ b/sources/AutoTextControl.h @@ -0,0 +1,85 @@ +/* + AutoTextControl.h: A BTextControl which notifies on each keypress + Written by DarkWyrm , Copyright 2007 + Released under the MIT license. +*/ + +#ifndef AUTO_TEXT_CONTROL_H +#define AUTO_TEXT_CONTROL_H + +#include +#include + +class AutoTextControlFilter; + +/* + The AutoTextControl provides realtime updates to any changes made to it. + It also provides the ability to limit the text to a certain number of + characters. + + If, for some reason, you want to disable the updates-per-keypress, pass + a regular BMessageFilter to the SetFilter method. +*/ + +class AutoTextControl : public BTextControl +{ +public: + AutoTextControl(const BRect& frame, const char* name, + const char* label, const char* text, + BMessage* msg, + uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE); + AutoTextControl(BMessage* data); + virtual ~AutoTextControl(); + + static BArchivable* Instantiate(BMessage* data); + virtual status_t Archive(BMessage* data, bool deep = true) const; + + virtual status_t GetSupportedSuites(BMessage* msg); + virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, + BMessage* specifier, int32 form, + const char* property); + + + + virtual void AttachedToWindow(); + virtual void DetachedFromWindow(); + + void SetFilter(AutoTextControlFilter* filter); + AutoTextControlFilter* GetFilter() { return fFilter; } + + void SetCharacterLimit(const uint32& limit); + uint32 GetCharacterLimit(const uint32& limit); + +private: + friend AutoTextControlFilter; + + AutoTextControlFilter* fFilter; + uint32 fCharLimit; +}; + +/* + This class does all of the heavy lifting for AutoTextControl's realtime + updates. + + You can further customize input and updates by subclassing the + KeyFilter hook function. When doing so, the current key message can + be accessed by way of GetCurrentMessage(). However, it will return NULL + when called from any other method. +*/ +class AutoTextControlFilter : public BMessageFilter +{ +public: + AutoTextControlFilter(AutoTextControl* checkview); + ~AutoTextControlFilter(); + virtual filter_result Filter(BMessage* msg, BHandler** target); + virtual filter_result KeyFilter(const int32& key, const int32& mod); + + AutoTextControl* TextControl() const { return fBox; } + BMessage* GetCurrentMessage() { return fCurrentMessage; } +private: + AutoTextControl* fBox; + BMessage* fCurrentMessage; +}; + +#endif // AUTO_TEXT_CONTROL_H diff --git a/sources/Filer/CppSQLite3.cpp b/sources/CppSQLite3.cpp similarity index 100% rename from sources/Filer/CppSQLite3.cpp rename to sources/CppSQLite3.cpp diff --git a/sources/Filer/CppSQLite3.h b/sources/CppSQLite3.h similarity index 100% rename from sources/Filer/CppSQLite3.h rename to sources/CppSQLite3.h diff --git a/sources/Database.cpp b/sources/Database.cpp new file mode 100644 index 0000000..6f383ba --- /dev/null +++ b/sources/Database.cpp @@ -0,0 +1,134 @@ +/* + Database.cpp: Convenience functions for work with the SQLite3 database + Written by DarkWyrm , Copyright 2008 + Released under the MIT license. +*/ + +#include "CppSQLite3.h" +#include "Database.h" + +static const char* sIllegalCharacters[] = + { "!","@","#","$","%","^","&","*","(",")","-","+","=","{","}","[","]","\\", + "|",";",":","'","\"","<",">",",",".","/","?","`","~"," ", NULL + }; +static const char* sReplacementCharacters[] = + { "£21£","£40£","£23£","£24£","£25£","£5e£","£26£","£2a£","£28£","£29£", + "£2d£","£2b£","£3d£","£7b£","£7d£","£5b£","£5d£","£5c£","£7c£","£3b£", + "£3a£","£27£","£22£","£3c£","£3e£","£2c£","£2e£","£2f£","£3f£","£60£", + "£7e£","£20£", NULL + }; + +static const char* sIllegalWords[] = + { " select "," drop "," create "," delete "," where "," update "," order ", + " by "," and "," or "," in "," between "," aliases "," join "," union ", + " alter "," functions "," group "," into ", " view ", NULL }; +static const char* sReplacementWords[] = + { " ¥select "," ¥drop "," ¥create "," ¥delete "," ¥where "," ¥update ", + " ¥order "," ¥by "," ¥and "," ¥or "," ¥in "," ¥between "," ¥aliases ", + " ¥join "," ¥union "," ¥alter "," ¥functions "," ¥group "," ¥into ", + " ¥view ", NULL + }; + + +BString +EscapeIllegalCharacters(const char* instr) +{ + // Because the £ symbol isn't allowed in a category but is a valid database, + // characterwe'll use it as the escape character for illegal characters + + BString string(instr); + if (string.CountChars() < 1) + return string; + + string.RemoveAll("£"); + string.RemoveAll("¥"); + + int32 i = 0; + while (sIllegalCharacters[i]) + { + string.ReplaceAll(sIllegalCharacters[i], sReplacementCharacters[i]); + i++; + } + + // Just to make sure that reserved words aren't used, we'll prefix them with + // the ¥ character for the same reasons that we used £ with bad characters + i = 0; + while (sIllegalWords[i]) + { + string.ReplaceAll(sIllegalWords[i], sReplacementWords[i]); + i++; + } + return string; +} + + +BString +DeescapeIllegalCharacters(const char* instr) +{ + BString string(instr); + if (string.CountChars() < 1) + return string; + + int32 i = 0; + while (sIllegalCharacters[i]) + { + string.ReplaceAll(sReplacementCharacters[i], sIllegalCharacters[i]); + i++; + } + + // Just to make sure that reserved words aren't used, we'll prefix them with + // the ¥ character for the same reasons that we used £ with bad characters + i = 0; + while (sIllegalWords[i]) + { + string.ReplaceAll(sReplacementWords[i], sIllegalWords[i]); + i++; + } + return string; +} + + +void +DBCommand(CppSQLite3DB& db, const char* command, const char* functionname) +{ + if (!command) + printf("NULL database command in Database::DBCommand"); + if (!functionname) + printf("NULL function name in Database::DBCommand"); + + try + { + db.execDML(command); + } + catch(CppSQLite3Exception& e) + { + BString msg("Database Exception in "); + msg << functionname << ".\n\n" << e.errorMessage() + << "\n\nDatabase Exception Command: " << command << "\n"; + printf(msg.String()); + } +} + + +CppSQLite3Query +DBQuery(CppSQLite3DB& db, const char* query, const char* functionname) +{ + if (!query) + printf("NULL database command in Database::DBQuery"); + if (!functionname) + printf("NULL function name in Database::DBQuery"); + + try + { + return db.execQuery(query); + } + catch(CppSQLite3Exception& e) + { + BString msg("Database Exception in "); + msg << functionname << ".\n\n" << e.errorMessage() + << "\n\nDatabase Exception Query: " << query << "\n"; + printf(msg.String()); + } + // this will never be reached - just to shut up the compiler + return CppSQLite3Query(); +} diff --git a/sources/Database.h b/sources/Database.h new file mode 100644 index 0000000..3f96b08 --- /dev/null +++ b/sources/Database.h @@ -0,0 +1,20 @@ +/* + Database.h: Convenience functions for work with the SQLite3 database + Written by DarkWyrm , Copyright 2008 + Released under the MIT license. +*/ + +#ifndef DATABASE_H +#define DATABASE_H + +#include + +BString EscapeIllegalCharacters(const char* string); +BString DeescapeIllegalCharacters(const char* string); + +void DBCommand(CppSQLite3DB& db, const char* command, + const char* functionname); +CppSQLite3Query DBQuery(CppSQLite3DB& db, const char* query, + const char* functionname); + +#endif // DATABASE_H diff --git a/sources/DropZoneTab.cpp b/sources/DropZoneTab.cpp new file mode 100644 index 0000000..558ed52 --- /dev/null +++ b/sources/DropZoneTab.cpp @@ -0,0 +1,233 @@ +/* + * Copyright 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Humdinger, humdingerb@gmail.com + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "DropZoneTab.h" +#include "FilerDefs.h" +#include "main.h" +#include "ReplicantWindow.h" + + +#define REPLICATE 'repl' + +void +DropZone::_Init() +{ + fLabel1 = new BStringView("label1", " Filer "); + fLabel2 = new BStringView("label2", " Dropzone "); + + BFont font; + fLabel1->GetFont(&font); + font.SetFace(B_CONDENSED_FACE); + font.SetSize(font.Size() * 1.5); + fLabel1->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE + | B_FONT_FLAGS); + font.SetSize(font.Size() * 0.75); + fLabel2->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE + | B_FONT_FLAGS); + + fLabel1->SetAlignment(B_ALIGN_CENTER); + fLabel2->SetAlignment(B_ALIGN_CENTER); + + return; +} + + +DropZone::DropZone(bool replicatable) + : + BView("Filer dropzone", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), + fReplicated(false) +{ + SetViewColor(B_TRANSPARENT_COLOR); + + _Init(); + + if (replicatable) { + // Dragger + BRect rect(Bounds()); + rect.left = rect.right - 7; + rect.top = rect.bottom - 7; + BDragger* dragger = new BDragger(rect, this, + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + dragger->SetExplicitMinSize(BSize(7, 7)); + dragger->SetExplicitMaxSize(BSize(7, 7)); + dragger->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_BOTTOM)); + + // Layout + BLayoutBuilder::Group<>(this, B_VERTICAL, 0) + .AddGroup(B_VERTICAL, 3) + .AddGlue() + .AddStrut(1) + .Add(fLabel1) + .Add(fLabel2) + .AddGlue() + .End() + .Add(dragger, 0.01); + } else { + BLayoutBuilder::Group<>(this, B_VERTICAL, 0) + .AddGroup(B_VERTICAL, 3) + .AddGlue() + .AddStrut(1) + .Add(fLabel1) + .Add(fLabel2) + .AddGlue() + .End(); + } +} + + +DropZone::DropZone(BMessage* archive) + : + BView(archive), + fReplicated(true) +{ + _Init(); +} + + +DropZone::~DropZone() +{ +} + + +BArchivable* +DropZone::Instantiate(BMessage* data) +{ + if (!validate_instantiation(data, "Filer")) + return NULL; + + return new DropZone(data); +} + + +status_t +DropZone::Archive(BMessage* archive, bool deep) const +{ + BView::Archive(archive, deep); + + archive->AddString("add_on", kFilerSignature); + archive->AddString("class", "Filer"); + + archive->PrintToStream(); + + return B_OK; +} + + +void +DropZone::Draw(BRect rect) +{ + BRect bounds = Bounds(); + if (!fReplicated) { + SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + FillRect(bounds); + } + + SetDrawingMode(B_OP_ALPHA); + SetLowColor(0, 0, 0, 0); + SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), + B_DARKEN_2_TINT)); + + FillRect(bounds, B_SOLID_LOW); + StrokeRect(bounds); + FillRect(bounds.InsetBySelf(3, 3), stripePattern); + + BView::Draw(rect); +} + + +void +DropZone::MessageReceived(BMessage* msg) +{ + if (msg->WasDropped()) { + msg->what = B_REFS_RECEIVED; + be_roster->Launch(kFilerSignature, msg); + } + switch (msg->what) + { + case B_ABOUT_REQUESTED: + { + BAboutWindow* about = new BAboutWindow("Filer", kFilerSignature); + about->AddDescription( + "Filer is an automatic file organizer. It takes the " + "files it's opened with or that are dropped on it and moves, " + "renames, copies or does all sorts of other things with them " + "according to rules created by the user."); + about->AddCopyright(2008, "DarkWyrm"); + about->AddCopyright(2016, "Humdinger"); + about->Show(); + } + default: + { + BView::MessageReceived(msg); + break; + } + } +} + + +DropZoneTab::DropZoneTab() + : + BView("Dropzone", B_SUPPORTS_LAYOUT) +{ + BStringView* zoneLabel = new BStringView("zonelabel", + "Drag and drop the files to be processed below."); + zoneLabel->SetAlignment(B_ALIGN_CENTER); + fDropzone = new DropZone(false); + + fRepliButton = new BButton("replibutton", + "Replicate dropzone" B_UTF8_ELLIPSIS, new BMessage(REPLICATE)); + + static const float spacing = be_control_look->DefaultItemSpacing(); + BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING) + .SetInsets(spacing) + .Add(zoneLabel) + .Add(fDropzone) + .Add(fRepliButton); +} + + +DropZoneTab::~DropZoneTab() +{ +} + + +void +DropZoneTab::AttachedToWindow() +{ + fRepliButton->SetTarget(this); + + BView::AttachedToWindow(); +} + + +void +DropZoneTab::MessageReceived(BMessage* msg) +{ + switch (msg->what) + { + case REPLICATE: + { + ReplicantWindow* replicantWindow = new ReplicantWindow(Window()->Frame()); + replicantWindow->Show(); + break; + } + default: + { + BView::MessageReceived(msg); + break; + } + } +} diff --git a/sources/DropZoneTab.h b/sources/DropZoneTab.h new file mode 100644 index 0000000..8cadcb1 --- /dev/null +++ b/sources/DropZoneTab.h @@ -0,0 +1,55 @@ +/* + * Copyright 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Humdinger, humdingerb@gmail.com + */ + +#ifndef DROPZONETAB_H +#define DROPZONETAB_H + +#include +#include +#include + +const pattern stripePattern = {0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99}; + +class DropZone : public BView +{ +public: + DropZone(bool replicatable = true); + DropZone(BMessage* data); + ~DropZone(); + + static BArchivable* Instantiate(BMessage* archive); + virtual status_t Archive(BMessage* data, bool deep = true) const; + + virtual void Draw(BRect rect); + void MessageReceived(BMessage* msg); + + void _Init(); + +private: + bool fReplicated; + BStringView* fLabel1; + BStringView* fLabel2; +}; + + +class DropZoneTab : public BView +{ +public: + DropZoneTab(); + ~DropZoneTab(); + + virtual void AttachedToWindow(); + void MessageReceived(BMessage* msg); + + +private: + DropZone* fDropzone; + BButton* fRepliButton; +}; + +#endif // DROPZONETAB_H diff --git a/sources/Filer/FSUtils.cpp b/sources/FSUtils.cpp similarity index 70% rename from sources/Filer/FSUtils.cpp rename to sources/FSUtils.cpp index b2f85d4..b637750 100644 --- a/sources/Filer/FSUtils.cpp +++ b/sources/FSUtils.cpp @@ -3,86 +3,88 @@ Written by DarkWyrm , Copyright 2008 Released under the MIT license. */ -#include -#include + +#include #include -#include #include +#include +#include +#include #include -#include +#include +#include + +#include #include #include -#include -#include + #include -#include + #include "FSUtils.h" #define COPY_BUFFER_SIZE 1024000 -status_t CheckCopiable(BEntry *src,BEntry *dest) +status_t CheckCopiable(BEntry* src, BEntry* dest) { // Checks to see if we can copy the src to dest. - if(!src || !dest) + if (!src || !dest) return B_ERROR; - - if(!src->Exists()) + + if (!src->Exists()) return B_FILE_NOT_FOUND; // Ensure that when we want the destination directory, that is exactly // what we're working with. If we've been given an entry which is a file, // extract the destination directory. BEntry destdir; - if(dest->IsDirectory()) - destdir=*dest; + if (dest->IsDirectory()) + destdir = *dest; else dest->GetParent(&destdir); - + // check existence of target directory - if(!destdir.Exists()) + if (!destdir.Exists()) return B_NAME_NOT_FOUND; - + // check space entry_ref ref; off_t src_bytes; - dest->GetRef(&ref); BVolume dvolume(ref.device); src->GetSize(&src_bytes); - if(src_bytes>dvolume.FreeBytes()) + if (src_bytes > dvolume.FreeBytes()) return B_DEVICE_FULL; - + // check permissions - if(dvolume.IsReadOnly()) + if (dvolume.IsReadOnly()) return B_READ_ONLY; // check existing name BPath path; destdir.GetPath(&path); - char name[B_FILE_NAME_LENGTH]; src->GetName(name); - BString newpath=path.Path(); - newpath+=name; + BString newpath = path.Path(); + newpath += name; BFile file; - if(file.SetTo(newpath.String(),B_READ_WRITE | B_FAIL_IF_EXISTS)==B_FILE_EXISTS) - { + if (file.SetTo(newpath.String(), + B_READ_WRITE | B_FAIL_IF_EXISTS) == B_FILE_EXISTS) { // We have an existing file, so query the user what to do. status_t returncode; - newpath="The file "; - newpath+=name; - newpath+=" exists. Do you want to replace it?"; - - BAlert *alert=new BAlert("Error",newpath.String(),"Replace file", - "Skip file", "Stop"); - returncode=alert->Go(); - switch(returncode) + newpath = "The file "; + newpath += name; + newpath += " exists. Do you want to replace it?"; + + BAlert* alert = new BAlert("Error", newpath.String(), "Replace file", + "Skip file", "Stop"); + returncode = alert->Go(); + switch (returncode) { case 0: return FS_CLOBBER; @@ -95,157 +97,160 @@ status_t CheckCopiable(BEntry *src,BEntry *dest) return B_OK; } -status_t CopyFile(BEntry *srcentry, BEntry *destentry, bool clobber) + +status_t CopyFile(BEntry* srcentry, BEntry* destentry, bool clobber) { - if(!srcentry || !destentry) + if (!srcentry || !destentry) return B_ERROR; - + if (!destentry->IsDirectory()) return B_ERROR; - + entry_ref ref; srcentry->GetRef(&ref); - + BPath srcpath; srcentry->GetPath(&srcpath); - + BString srcstring(srcpath.Path()); - srcstring.CharacterEscape("'",'\\'); - + srcstring.CharacterEscape("'", '\\'); + BPath destpath; destentry->GetPath(&destpath); - + BString deststring(destpath.Path()); - deststring.CharacterEscape("'",'\\'); - + deststring.CharacterEscape("'", '\\'); + BString command("copyattr -r -d "); command << "'" << srcstring << "' '" << deststring << "/'"; int code = system(command.String()); - - if (!code) - { + + if (!code) { entry_ref ref; srcentry->GetRef(&ref); - + deststring << "/" << ref.name; return srcentry->SetTo(deststring.String()); } - + return code; } -status_t MoveFile(BEntry *srcentry,BEntry *destentry, bool clobber) + +status_t MoveFile(BEntry* srcentry, BEntry* destentry, bool clobber) { - if(!srcentry || !destentry) + if (!srcentry || !destentry) return B_ERROR; - + if (!destentry->IsDirectory()) return B_ERROR; - + BPath srcpath; srcentry->GetPath(&srcpath); - + BString srcstring(srcpath.Path()); - srcstring.CharacterEscape("'",'\\'); - + srcstring.CharacterEscape("'", '\\'); + BPath destpath; destentry->GetPath(&destpath); - + BString deststring(destpath.Path()); - deststring.CharacterEscape("'",'\\'); - + deststring.CharacterEscape("'", '\\'); + BString command("mv "); if (clobber) command << "-f "; command << "'" << srcstring << "' '" << deststring << "/'"; int code = system(command.String()); - if (!code) - { + if (!code) { entry_ref ref; srcentry->GetRef(&ref); - + deststring << "/" << ref.name; return srcentry->SetTo(deststring.String()); } - + return code; } -const char *GetValidName(BEntry *entry) + +const char* GetValidName(BEntry* entry) { // given a particular location, this will (1) check to see if said entry // exists and if it does, generates a filename which will work complete with // the full path. The entry is also set to this new, valid path - + BPath path; entry->GetPath(&path); - if(entry->Exists()) - { + if (entry->Exists()) { // separate into path and leaf char leafbase[B_FILE_NAME_LENGTH]; char newpath[B_PATH_NAME_LENGTH]; strcpy(leafbase, path.Leaf()); path.GetParent(&path); + + int32 attempt = 1; - int32 attempt=1; - - do - { - if(attempt>1) - sprintf(newpath, "%s/%s copy %ld", path.Path(),leafbase, attempt); - else + do { + if (attempt > 1) { + sprintf(newpath, "%s/%s copy %ld", path.Path(),leafbase, + attempt); + } else sprintf(newpath, "%s/%s copy", path.Path(),leafbase); entry->SetTo(newpath); attempt++; } while (entry->Exists()); - + return newpath; } - + return path.Path(); } + bool IsFilenameChar(char c) { // const char validstring[]="1234567890-_ ~.,+=!@#$%^&[]{}"; const char validstring[]="1234567890-_~.,+=!@#$%^&[]{}"; - if( (c>64 && c<91) || (c>96 && c<123)) + if ((c>64 && c < 91) || (c > 96 && c < 123)) return true; - int validlen=strlen(validstring); - for(int i=0;i96 && c1<123) - c1-=32; - if(c2>96 && c2<123) - c2-=32; + if (c1 > 96 && c1 < 123) + c1 -= 32; + if (c2 > 96 && c2 < 123) + c2 -= 32; - if(c1, Copyright 2008 + Released under the MIT license. +*/ + +#ifndef FSUTILS_H_ +#define FSUTILS_H_ + +#include + +#define FS_CLOBBER 'fscl' +#define FS_SKIP 'fssk' + +status_t CheckCopiable(BEntry* src, BEntry* dest); +status_t CopyFile(BEntry* src, BEntry* dest, bool clobber); +status_t MoveFile(BEntry* src, BEntry* dest, bool clobber); + +const char* GetValidName(BEntry* entry); +bool IsFilenameChar(char c); +int charcmp(char c1, char c2); +int charncmp(char c1, char c2); + +#endif // FSUTILS_H_ diff --git a/sources/Filer/Filer.iom b/sources/Filer.iom similarity index 100% rename from sources/Filer/Filer.iom rename to sources/Filer.iom diff --git a/sources/Filer/Filer.rdef b/sources/Filer.rdef similarity index 93% rename from sources/Filer/Filer.rdef rename to sources/Filer.rdef index 8116c3b..832f079 100644 --- a/sources/Filer/Filer.rdef +++ b/sources/Filer.rdef @@ -8,14 +8,14 @@ resource app_flags B_MULTIPLE_LAUNCH; resource app_version { major = 1, - middle = 0, + middle = 1, minor = 0, variety = 5, internal = 0, short_info = "Automatic file organizer", - long_info = "A tool to rename/copy/move and otherise process files" + long_info = "A tool to rename/copy/move and otherwise process files" }; resource vector_icon { diff --git a/sources/Filer/ActionView.h b/sources/Filer/ActionView.h deleted file mode 100644 index 5b5b411..0000000 --- a/sources/Filer/ActionView.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - ActionView.h: View for adjusting settings for an individual Filer action - Written by DarkWyrm , Copyright 2008 - Released under the MIT license. -*/ -#ifndef ACTIONVIEW_H -#define ACTIONVIEW_H - -#include -#include - -class AutoTextControl; - -#include - -class ActionView : public BView -{ -public: - ActionView(const BRect &frame,const char *name, - BMessage *test = NULL, - const int32 &resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, - const int32 &flags = B_WILL_DRAW); - ~ActionView(void); - void AttachedToWindow(void); - BRect GetPreferredSize(void); - void ResizeToPreferred(void); - void MessageReceived(BMessage *msg); - BMessage * GetAction(void) const; - -private: - void ShowActionMenu(void); - void SetAction(const char *name -); - - BButton *fActionButton; - - AutoTextControl *fValueBox; - - BMessage *fAction; - BMessage fActions; -}; - -#endif diff --git a/sources/Filer/AutoTextControl.h b/sources/Filer/AutoTextControl.h deleted file mode 100644 index a69df79..0000000 --- a/sources/Filer/AutoTextControl.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - AutoTextControl.h: A BTextControl which notifies on each keypress - Written by DarkWyrm , Copyright 2007 - Released under the MIT license. -*/ -#ifndef AUTO_TEXT_CONTROL_H -#define AUTO_TEXT_CONTROL_H - -#include -#include - -class AutoTextControlFilter; - -/* - The AutoTextControl provides realtime updates to any changes made to it. - It also provides the ability to limit the text to a certain number of - characters. - - If, for some reason, you want to disable the updates-per-keypress, pass - a regular BMessageFilter to the SetFilter method. -*/ - -class AutoTextControl : public BTextControl -{ -public: - AutoTextControl(const BRect &frame, const char *name, - const char *label, const char *text, - BMessage *msg, - uint32 resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, - uint32 flags = B_WILL_DRAW | B_NAVIGABLE); - - AutoTextControl(BMessage *data); - static BArchivable * Instantiate(BMessage *data); - virtual status_t Archive(BMessage *data, bool deep = true) const; - - virtual status_t GetSupportedSuites(BMessage *msg); - virtual BHandler * ResolveSpecifier(BMessage *msg, int32 index, - BMessage *specifier, int32 form, - const char *property); - - virtual ~AutoTextControl(void); - - virtual void AttachedToWindow(void); - virtual void DetachedFromWindow(void); - - void SetFilter(AutoTextControlFilter *filter); - AutoTextControlFilter * GetFilter(void) { return fFilter; } - - void SetCharacterLimit(const uint32 &limit); - uint32 GetCharacterLimit(const uint32 &limit); - -private: - friend AutoTextControlFilter; - - AutoTextControlFilter *fFilter; - uint32 fCharLimit; -}; - -/* - This class does all of the heavy lifting for AutoTextControl's realtime - updates. - - You can further customize input and updates by subclassing the - KeyFilter hook function. When doing so, the current key message can - be accessed by way of GetCurrentMessage(). However, it will return NULL - when called from any other method. -*/ -class AutoTextControlFilter : public BMessageFilter -{ -public: - AutoTextControlFilter(AutoTextControl *checkview); - ~AutoTextControlFilter(void); - virtual filter_result Filter(BMessage *msg, BHandler **target); - virtual filter_result KeyFilter(const int32 &key, const int32 &mod); - - AutoTextControl * TextControl(void) const { return fBox; } - BMessage * GetCurrentMessage(void) { return fCurrentMessage; } -private: - AutoTextControl *fBox; - BMessage *fCurrentMessage; -}; - -#endif diff --git a/sources/Filer/Database.cpp b/sources/Filer/Database.cpp deleted file mode 100644 index 3b0d07c..0000000 --- a/sources/Filer/Database.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - Database.cpp: Convenience functions for work with the SQLite3 database - Written by DarkWyrm , Copyright 2008 - Released under the MIT license. -*/ -#include "CppSQLite3.h" -#include "Database.h" - -static const char *sIllegalCharacters[] = - { "!","@","#","$","%","^","&","*","(",")","-","+","=","{","}","[","]","\\", - "|",";",":","'","\"","<",">",",",".","/","?","`","~"," ", NULL - }; -static const char *sReplacementCharacters[] = - { "£21£","£40£","£23£","£24£","£25£","£5e£","£26£","£2a£","£28£","£29£","£2d£", - "£2b£","£3d£","£7b£","£7d£","£5b£","£5d£","£5c£","£7c£","£3b£","£3a£","£27£", - "£22£","£3c£","£3e£","£2c£","£2e£","£2f£","£3f£","£60£","£7e£","£20£", NULL - }; - -static const char *sIllegalWords[]= - { " select "," drop "," create "," delete "," where "," update "," order "," by ", - " and "," or "," in "," between "," aliases "," join "," union "," alter ", - " functions "," group "," into ", " view ", NULL }; -static const char *sReplacementWords[]= - { " ¥select "," ¥drop "," ¥create "," ¥delete "," ¥where "," ¥update "," ¥order "," ¥by ", - " ¥and "," ¥or "," ¥in "," ¥between "," ¥aliases "," ¥join "," ¥union "," ¥alter ", - " ¥functions "," ¥group "," ¥into ", " ¥view ", NULL }; - -BString EscapeIllegalCharacters(const char *instr) -{ - // Because the £ symbol isn't allowed in a category but is a valid database character, - // we'll use it as the escape character for illegal characters - - BString string(instr); - if(string.CountChars()<1) - return string; - - string.RemoveAll("£"); - string.RemoveAll("¥"); - - int32 i=0; - while(sIllegalCharacters[i]) - { - string.ReplaceAll(sIllegalCharacters[i],sReplacementCharacters[i]); - i++; - } - - // Just to make sure that reserved words aren't used, we'll prefix them with the ¥ character - // for the same reasons that we used £ with bad characters - i=0; - while(sIllegalWords[i]) - { - string.ReplaceAll(sIllegalWords[i],sReplacementWords[i]); - i++; - } - return string; -} - -BString DeescapeIllegalCharacters(const char *instr) -{ - BString string(instr); - if(string.CountChars()<1) - return string; - - int32 i=0; - while(sIllegalCharacters[i]) - { - string.ReplaceAll(sReplacementCharacters[i],sIllegalCharacters[i]); - i++; - } - - // Just to make sure that reserved words aren't used, we'll prefix them with the ¥ character - // for the same reasons that we used £ with bad characters - i=0; - while(sIllegalWords[i]) - { - string.ReplaceAll(sReplacementWords[i],sIllegalWords[i]); - i++; - } - return string; -} - - -void DBCommand(CppSQLite3DB &db, const char *command, const char *functionname) -{ - if(!command) - printf("NULL database command in Database::DBCommand"); - if(!functionname) - printf("NULL function name in Database::DBCommand"); - - try - { - db.execDML(command); - } - catch(CppSQLite3Exception &e) - { - BString msg("Database Exception in "); - msg << functionname << ".\n\n" << e.errorMessage() - << "\n\nDatabase Exception Command: " << command << "\n"; - printf(msg.String()); - } -} - -CppSQLite3Query DBQuery(CppSQLite3DB &db, const char *query, const char *functionname) -{ - if(!query) - printf("NULL database command in Database::DBQuery"); - if(!functionname) - printf("NULL function name in Database::DBQuery"); - - try - { - return db.execQuery(query); - } - catch(CppSQLite3Exception &e) - { - BString msg("Database Exception in "); - msg << functionname << ".\n\n" << e.errorMessage() - << "\n\nDatabase Exception Query: " << query << "\n"; - printf(msg.String()); - } - // this will never be reached - just to shut up the compiler - return CppSQLite3Query(); -} diff --git a/sources/Filer/Database.h b/sources/Filer/Database.h deleted file mode 100644 index 46db23f..0000000 --- a/sources/Filer/Database.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - Database.h: Convenience functions for work with the SQLite3 database - Written by DarkWyrm , Copyright 2008 - Released under the MIT license. -*/ -#ifndef DATABASE_H -#define DATABASE_H - -#include - -BString EscapeIllegalCharacters(const char *string); -BString DeescapeIllegalCharacters(const char *string); - -void DBCommand(CppSQLite3DB &db, const char *command, - const char *functionname); -CppSQLite3Query DBQuery(CppSQLite3DB &db, const char *query, - const char *functionname); - -#endif diff --git a/sources/Filer/EscapeCancelFilter.h b/sources/Filer/EscapeCancelFilter.h deleted file mode 100644 index 3d6d145..0000000 --- a/sources/Filer/EscapeCancelFilter.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - EscapeCancelFilter.h: An easy way to quit with the Escape key - Written by DarkWyrm , Copyright 2007 - Released under the MIT license. -*/ -#ifndef ESCAPE_CANCEL_FILTER_H -#define ESCAPE_CANCEL_FILTER_H - -/* - This filter is most often useful in dialog windows where you would - like to allow the user to effectively hit the Cancel button just by - hitting the Escape key. Pass one of these to BWindow::AddCommonFilter - and that is all that is necessary. -*/ - -#include -#include - -class EscapeCancelFilter : public BMessageFilter -{ -public: - EscapeCancelFilter(void) - : BMessageFilter(B_PROGRAMMED_DELIVERY, - B_ANY_SOURCE,B_KEY_DOWN) - { - } - - ~EscapeCancelFilter(void) - { - } - - filter_result Filter(BMessage *msg, BHandler **target) - { - int32 rawchar,mod; - msg->FindInt32("raw_char",&rawchar); - msg->FindInt32("modifiers",&mod); - - if (rawchar == B_ESCAPE && (mod & (B_SHIFT_KEY | B_COMMAND_KEY | - B_OPTION_KEY | B_CONTROL_KEY)) == 0) { - BLooper *loop = (*target)->Looper(); - if (loop) { - BMessenger msgr(loop); - msgr.SendMessage(B_QUIT_REQUESTED); - return B_SKIP_MESSAGE; - } - } - return B_DISPATCH_MESSAGE; - } - -}; - - -#endif - diff --git a/sources/Filer/FSUtils.h b/sources/Filer/FSUtils.h deleted file mode 100644 index e405c1b..0000000 --- a/sources/Filer/FSUtils.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - FSUtils.h: Utility classes for basic filesystem operations - Written by DarkWyrm , Copyright 2008 - Released under the MIT license. -*/ -#ifndef FSUTILS_H_ -#define FSUTILS_H_ - -#include - -#define FS_CLOBBER 'fscl' -#define FS_SKIP 'fssk' - -status_t CheckCopiable(BEntry *src, BEntry *dest); -status_t CopyFile(BEntry *src,BEntry *dest, bool clobber); -status_t MoveFile(BEntry *src,BEntry *dest, bool clobber); -const char *GetValidName(BEntry *entry); -bool IsFilenameChar(char c); -int charcmp(char c1, char c2); -int charncmp(char c1, char c2); -#endif \ No newline at end of file diff --git a/sources/Filer/FilerRule.h b/sources/Filer/FilerRule.h deleted file mode 100644 index f982eba..0000000 --- a/sources/Filer/FilerRule.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - FilerRule.h: The main filing class for Filer. It holds a list of both test - conditions and one or more actions to be performed should the - conditions be met. - Written by DarkWyrm , Copyright 2008 - Released under the MIT license. -*/ -#ifndef FILER_RULE_H -#define FILER_RULE_H - -#include -#include -#include -#include -#include "ObjectList.h" - -typedef enum -{ - FILER_RULE_ALL = 0, - FILER_RULE_ANY -} filer_rule_mode; - - -class FilerRule : public BArchivable -{ -public: - FilerRule(void); - FilerRule(FilerRule &rule); - ~FilerRule(void); - - void SetRuleMode(const filer_rule_mode &mode); - filer_rule_mode GetRuleMode(void) const { return fMode; } - - const char * GetDescription(void) const; - void SetDescription(const char *desc); - - void AddTest(BMessage *item, const int32 &index = -1); - BMessage * RemoveTest(const int32 &index); - BMessage * TestAt(const int32 &index); - int32 CountTests(void) const; - - void AddAction(BMessage *action, const int32 &index = -1); - BMessage * RemoveAction(const int32 &index); - BMessage * ActionAt(const int32 &index); - int32 CountActions(void) const; - - void MakeEmpty(void); - virtual void PrintToStream(void); - FilerRule & operator=(FilerRule &from); - - int64 GetID(void) const { return fID; } - -private: - BObjectList *fTestList; - BObjectList *fActionList; - filer_rule_mode fMode; - BString fDescription; - int64 fID; -}; - -#endif diff --git a/sources/Filer/ObjectList.h b/sources/Filer/ObjectList.h deleted file mode 100644 index f2556ad..0000000 --- a/sources/Filer/ObjectList.h +++ /dev/null @@ -1,810 +0,0 @@ -/* -Open Tracker License - -Terms and Conditions - -Copyright (c) 1991-2000, Be Incorporated. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice applies to all licensees -and shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Be Incorporated shall not be -used in advertising or otherwise to promote the sale, use or other dealings in -this Software without prior written authorization from Be Incorporated. - -Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks -of Be Incorporated in the United States and other countries. Other brand product -names are registered trademarks or trademarks of their respective holders. -All rights reserved. -*/ - -/**************************************************************************** -** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ** -** ** -** DANGER, WILL ROBINSON! ** -** ** -** The interfaces contained here are part of BeOS's ** -** ** -** >> PRIVATE NOT FOR PUBLIC USE << ** -** ** -** implementation. ** -** ** -** These interfaces WILL CHANGE in future releases. ** -** If you use them, your app WILL BREAK at some future time. ** -** ** -** (And yes, this does mean that binaries built from OpenTracker will not ** -** be compatible with some future releases of the OS. When that happens, ** -** we will provide an updated version of this file to keep compatibility.) ** -** ** -** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ** -****************************************************************************/ - -// -// ObjectList is a wrapper around BList that adds type safety, -// optional object ownership, search, insert operations, etc. -// - -#ifndef __OBJECT_LIST__ -#define __OBJECT_LIST__ - -#ifndef _BE_H -#include -#endif - -#include - -template class BObjectList; - -template -struct UnaryPredicate { - - virtual int operator()(const T *) const - // virtual could be avoided here if FindBinaryInsertionIndex, - // etc. were member template functions - { return 0; } - -private: - static int _unary_predicate_glue(const void *item, void *context); - -friend class BObjectList; -}; - -template -int -UnaryPredicate::_unary_predicate_glue(const void *item, void *context) -{ - return ((UnaryPredicate *)context)->operator()((const T *)item); -} - - -class _PointerList_ : public BList { -public: - _PointerList_(const _PointerList_ &list); - _PointerList_(int32 itemsPerBlock = 20, bool owning = false); - ~_PointerList_(); - - typedef void *(* GenericEachFunction)(void *, void *); - typedef int (* GenericCompareFunction)(const void *, const void *); - typedef int (* GenericCompareFunctionWithState)(const void *, const void *, - void *); - typedef int (* UnaryPredicateGlue)(const void *, void *); - - void *EachElement(GenericEachFunction, void *); - void SortItems(GenericCompareFunction); - void SortItems(GenericCompareFunctionWithState, void *state); - void HSortItems(GenericCompareFunction); - void HSortItems(GenericCompareFunctionWithState, void *state); - - void *BinarySearch(const void *, GenericCompareFunction) const; - void *BinarySearch(const void *, GenericCompareFunctionWithState, void *state) const; - - int32 BinarySearchIndex(const void *, GenericCompareFunction) const; - int32 BinarySearchIndex(const void *, GenericCompareFunctionWithState, void *state) const; - int32 BinarySearchIndexByPredicate(const void *, UnaryPredicateGlue) const; - - bool Owning() const; - bool ReplaceItem(int32, void *); - -protected: - bool owning; - -}; - -template -class BObjectList : private _PointerList_ { -public: - - // iteration and sorting - typedef T *(* EachFunction)(T *, void *); - typedef const T *(* ConstEachFunction)(const T *, void *); - typedef int (* CompareFunction)(const T *, const T *); - typedef int (* CompareFunctionWithState)(const T *, const T *, void *state); - - BObjectList(int32 itemsPerBlock = 20, bool owning = false); - BObjectList(const BObjectList &list); - // clones list; if list is owning, makes copies of all - // the items - - virtual ~BObjectList(); - - BObjectList &operator=(const BObjectList &list); - // clones list; if list is owning, makes copies of all - // the items - - // adding and removing - // ToDo: - // change Add calls to return const item - bool AddItem(T *); - bool AddItem(T *, int32); - bool AddList(BObjectList *); - bool AddList(BObjectList *, int32); - - bool RemoveItem(T *, bool deleteIfOwning = true); - // if owning, deletes the removed item - T *RemoveItemAt(int32); - // returns the removed item - - void MakeEmpty(); - - // item access - T *ItemAt(int32) const; - - bool ReplaceItem(int32 index, T *); - // if list is owning, deletes the item at first - T *SwapWithItem(int32 index, T *newItem); - // same as ReplaceItem, except does not delete old item at , - // returns it instead - - T *FirstItem() const; - T *LastItem() const; - - // misc. getters - int32 IndexOf(const T *) const; - bool HasItem(const T *) const; - bool IsEmpty() const; - int32 CountItems() const; - - T *EachElement(EachFunction, void *); - const T *EachElement(ConstEachFunction, void *) const; - - void SwapItems(int32, int32); - - void SortItems(CompareFunction); - void SortItems(CompareFunctionWithState, void *state); - void HSortItems(CompareFunction); - void HSortItems(CompareFunctionWithState, void *state); - - // linear search, returns first item that matches predicate - const T *FindIf(const UnaryPredicate &) const; - T *FindIf(const UnaryPredicate &); - - // list must be sorted with CompareFunction for these to work - const T *BinarySearch(const T &, CompareFunction) const; - const T *BinarySearch(const T &, CompareFunctionWithState, void *state) const; - - // Binary insertion - list must be sorted with CompareFunction for - // these to work - - // simple insert - void BinaryInsert(T *, CompareFunction); - void BinaryInsert(T *, CompareFunctionWithState, void *state); - void BinaryInsert(T *, const UnaryPredicate &); - - // unique insert, returns false if item already in list - bool BinaryInsertUnique(T *, CompareFunction); - bool BinaryInsertUnique(T *, CompareFunctionWithState, void *state); - bool BinaryInsertUnique(T *, const UnaryPredicate &); - - // insert a copy of the item, returns new inserted item - T *BinaryInsertCopy(const T ©This, CompareFunction); - T *BinaryInsertCopy(const T ©This, CompareFunctionWithState, void *state); - - // insert a copy of the item if not in list already - // returns new inserted item or existing item in case of a conflict - T *BinaryInsertCopyUnique(const T ©This, CompareFunction); - T *BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState, void *state); - - - int32 FindBinaryInsertionIndex(const UnaryPredicate &, bool *alreadyInList = 0) const; - // returns either the index into which a new item should be inserted - // or index of an existing item that matches the predicate - - // deprecated API, will go away - BList *AsBList() - { return this; } - const BList *AsBList() const - { return this; } -private: - void SetItem(int32, T *); -}; - -template -Result -WhileEachListItem(BObjectList *list, Result (Item::*func)(Param1), Param1 p1) -{ - Result result = 0; - int32 count = list->CountItems(); - - for (int32 index = 0; index < count; index++) - if ((result = (list->ItemAt(index)->*func)(p1)) != 0) - break; - - return result; -} - -template -Result -WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1), Param1 p1) -{ - Result result = 0; - int32 count = list->CountItems(); - - for (int32 index = 0; index < count; index++) - if ((result = (*func)(list->ItemAt(index), p1)) != 0) - break; - - return result; -} - -template -Result -WhileEachListItem(BObjectList *list, Result (Item::*func)(Param1, Param2), - Param1 p1, Param2 p2) -{ - Result result = 0; - int32 count = list->CountItems(); - - for (int32 index = 0; index < count; index++) - if ((result = (list->ItemAt(index)->*func)(p1, p2)) != 0) - break; - - return result; -} - -template -Result -WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1, Param2), - Param1 p1, Param2 p2) -{ - Result result = 0; - int32 count = list->CountItems(); - - for (int32 index = 0; index < count; index++) - if ((result = (*func)(list->ItemAt(index), p1, p2)) != 0) - break; - - return result; -} - -template -Result -WhileEachListItem(BObjectList *list, Result (*func)(Item *, Param1, Param2, - Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4) -{ - Result result = 0; - int32 count = list->CountItems(); - - for (int32 index = 0; index < count; index++) - if ((result = (*func)(list->ItemAt(index), p1, p2, p3, p4)) != 0) - break; - - return result; -} - -template -void -EachListItemIgnoreResult(BObjectList *list, Result (Item::*func)()) -{ - int32 count = list->CountItems(); - for (int32 index = 0; index < count; index++) - (list->ItemAt(index)->*func)(); -} - -template -void -EachListItem(BObjectList *list, void (*func)(Item *, Param1), Param1 p1) -{ - int32 count = list->CountItems(); - for (int32 index = 0; index < count; index++) - (func)(list->ItemAt(index), p1); -} - -template -void -EachListItem(BObjectList *list, void (Item::*func)(Param1, Param2), - Param1 p1, Param2 p2) -{ - int32 count = list->CountItems(); - for (int32 index = 0; index < count; index++) - (list->ItemAt(index)->*func)(p1, p2); -} - -template -void -EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2), - Param1 p1, Param2 p2) -{ - int32 count = list->CountItems(); - for (int32 index = 0; index < count; index++) - (func)(list->ItemAt(index), p1, p2); -} - -template -void -EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2, - Param3), Param1 p1, Param2 p2, Param3 p3) -{ - int32 count = list->CountItems(); - for (int32 index = 0; index < count; index++) - (func)(list->ItemAt(index), p1, p2, p3); -} - - -template -void -EachListItem(BObjectList *list, void (*func)(Item *,Param1, Param2, - Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4) -{ - int32 count = list->CountItems(); - for (int32 index = 0; index < count; index++) - (func)(list->ItemAt(index), p1, p2, p3, p4); -} - -// inline code - -inline bool -_PointerList_::Owning() const -{ - return owning; -} - -template -BObjectList::BObjectList(int32 itemsPerBlock, bool owning) - : _PointerList_(itemsPerBlock, owning) -{ -} - -template -BObjectList::BObjectList(const BObjectList &list) - : _PointerList_(list) -{ - owning = list.owning; - if (owning) { - // make our own copies in an owning list - int32 count = list.CountItems(); - for (int32 index = 0; index < count; index++) { - T *item = list.ItemAt(index); - if (item) - item = new T(*item); - SetItem(index, item); - } - } -} - -template -BObjectList::~BObjectList() -{ - if (Owning()) - // have to nuke elements first - MakeEmpty(); - -} - -template -BObjectList & -BObjectList::operator=(const BObjectList &list) -{ - owning = list.owning; - BObjectList &result = (BObjectList &)_PointerList_::operator=(list); - if (owning) { - // make our own copies in an owning list - int32 count = list.CountItems(); - for (int32 index = 0; index < count; index++) { - T *item = list.ItemAt(index); - if (item) - item = new T(*item); - SetItem(index, item); - } - } - return result; -} - -template -bool -BObjectList::AddItem(T *item) -{ - // need to cast to void * to make T work for const pointers - return _PointerList_::AddItem((void *)item); -} - -template -bool -BObjectList::AddItem(T *item, int32 atIndex) -{ - return _PointerList_::AddItem((void *)item, atIndex); -} - -template -bool -BObjectList::AddList(BObjectList *newItems) -{ - return _PointerList_::AddList(newItems); -} - -template -bool -BObjectList::AddList(BObjectList *newItems, int32 atIndex) -{ - return _PointerList_::AddList(newItems, atIndex); -} - - -template -bool -BObjectList::RemoveItem(T *item, bool deleteIfOwning) -{ - bool result = _PointerList_::RemoveItem((void *)item); - - if (result && Owning() && deleteIfOwning) - delete item; - - return result; -} - -template -T * -BObjectList::RemoveItemAt(int32 index) -{ - return (T *)_PointerList_::RemoveItem(index); -} - -template -inline T * -BObjectList::ItemAt(int32 index) const -{ - return (T *)_PointerList_::ItemAt(index); -} - -template -bool -BObjectList::ReplaceItem(int32 index, T *item) -{ - if (owning) - delete ItemAt(index); - return _PointerList_::ReplaceItem(index, (void *)item); -} - -template -T * -BObjectList::SwapWithItem(int32 index, T *newItem) -{ - T *result = ItemAt(index); - _PointerList_::ReplaceItem(index, (void *)newItem); - return result; -} - -template -void -BObjectList::SetItem(int32 index, T *newItem) -{ - _PointerList_::ReplaceItem(index, (void *)newItem); -} - -template -int32 -BObjectList::IndexOf(const T *item) const -{ - return _PointerList_::IndexOf((void *)item); -} - -template -T * -BObjectList::FirstItem() const -{ - return (T *)_PointerList_::FirstItem(); -} - -template -T * -BObjectList::LastItem() const -{ - return (T *)_PointerList_::LastItem(); -} - -template -bool -BObjectList::HasItem(const T *item) const -{ - return _PointerList_::HasItem((void *)item); -} - -template -bool -BObjectList::IsEmpty() const -{ - return _PointerList_::IsEmpty(); -} - -template -int32 -BObjectList::CountItems() const -{ - return _PointerList_::CountItems(); -} - -template -void -BObjectList::MakeEmpty() -{ - if (owning) { - int32 count = CountItems(); - for (int32 index = 0; index < count; index++) - delete ItemAt(index); - } - _PointerList_::MakeEmpty(); -} - -template -T * -BObjectList::EachElement(EachFunction func, void *params) -{ - return (T *)_PointerList_::EachElement((GenericEachFunction)func, params); -} - - -template -const T * -BObjectList::EachElement(ConstEachFunction func, void *params) const -{ - return (const T *) - const_cast *>(this)->_PointerList_::EachElement( - (GenericEachFunction)func, params); -} - -template -const T * -BObjectList::FindIf(const UnaryPredicate &predicate) const -{ - int32 count = CountItems(); - for (int32 index = 0; index < count; index++) - if (predicate.operator()(ItemAt(index)) == 0) - return ItemAt(index); - return 0; -} - -template -T * -BObjectList::FindIf(const UnaryPredicate &predicate) -{ - int32 count = CountItems(); - for (int32 index = 0; index < count; index++) - if (predicate.operator()(ItemAt(index)) == 0) - return ItemAt(index); - return 0; -} - - -template -void -BObjectList::SwapItems(int32 one, int32 two) -{ - _PointerList_::SwapItems(one, two); -} - - -template -void -BObjectList::SortItems(CompareFunction function) -{ - _PointerList_::SortItems((GenericCompareFunction)function); -} - -template -void -BObjectList::SortItems(CompareFunctionWithState function, void *state) -{ - _PointerList_::SortItems((GenericCompareFunctionWithState)function, state); -} - -template -void -BObjectList::HSortItems(CompareFunction function) -{ - _PointerList_::HSortItems((GenericCompareFunction)function); -} - -template -void -BObjectList::HSortItems(CompareFunctionWithState function, void *state) -{ - _PointerList_::HSortItems((GenericCompareFunctionWithState)function, state); -} - -template -const T * -BObjectList::BinarySearch(const T &key, CompareFunction func) const -{ - return (const T *)_PointerList_::BinarySearch(&key, - (GenericCompareFunction)func); -} - -template -const T * -BObjectList::BinarySearch(const T &key, CompareFunctionWithState func, void *state) const -{ - return (const T *)_PointerList_::BinarySearch(&key, - (GenericCompareFunctionWithState)func, state); -} - -template -void -BObjectList::BinaryInsert(T *item, CompareFunction func) -{ - int32 index = _PointerList_::BinarySearchIndex(item, - (GenericCompareFunction)func); - if (index >= 0) - // already in list, add after existing - AddItem(item, index + 1); - else - AddItem(item, -index - 1); -} - -template -void -BObjectList::BinaryInsert(T *item, CompareFunctionWithState func, void *state) -{ - int32 index = _PointerList_::BinarySearchIndex(item, - (GenericCompareFunctionWithState)func, state); - if (index >= 0) - // already in list, add after existing - AddItem(item, index + 1); - else - AddItem(item, -index - 1); -} - -template -bool -BObjectList::BinaryInsertUnique(T *, CompareFunction func) -{ - int32 index = _PointerList_::BinarySearchIndex(item, - (GenericCompareFunction)func); - if (index >= 0) - return false; - - AddItem(item, -index - 1); - return true; -} - -template -bool -BObjectList::BinaryInsertUnique(T *, CompareFunctionWithState func, void *state) -{ - int32 index = _PointerList_::BinarySearchIndex(item, - (GenericCompareFunctionWithState)func, state); - if (index >= 0) - return false; - - AddItem(item, -index - 1); - return true; -} - - -template -T * -BObjectList::BinaryInsertCopy(const T ©This, CompareFunction func) -{ - int32 index = _PointerList_::BinarySearchIndex(©This, - (GenericCompareFunction)func); - - if (index >= 0) - index++; - else - index = -index - 1; - - T *newItem = new T(copyThis); - AddItem(newItem, index); - return newItem; -} - -template -T * -BObjectList::BinaryInsertCopy(const T ©This, CompareFunctionWithState func, void *state) -{ - int32 index = _PointerList_::BinarySearchIndex(©This, - (GenericCompareFunctionWithState)func, state); - - if (index >= 0) - index++; - else - index = -index - 1; - - T *newItem = new T(copyThis); - AddItem(newItem, index); - return newItem; -} - -template -T * -BObjectList::BinaryInsertCopyUnique(const T ©This, CompareFunction func) -{ - int32 index = _PointerList_::BinarySearchIndex(©This, - (GenericCompareFunction)func); - if (index >= 0) - return ItemAt(index); - - index = -index - 1; - T *newItem = new T(copyThis); - AddItem(newItem, index); - return newItem; -} - -template -T * -BObjectList::BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState func, - void *state) -{ - int32 index = _PointerList_::BinarySearchIndex(©This, - (GenericCompareFunctionWithState)func, state); - if (index >= 0) - return ItemAt(index); - - index = -index - 1; - T *newItem = new T(copyThis); - AddItem(newItem, index); - return newItem; -} - -template -int32 -BObjectList::FindBinaryInsertionIndex(const UnaryPredicate &pred, bool *alreadyInList) - const -{ - int32 index = _PointerList_::BinarySearchIndexByPredicate(&pred, - (UnaryPredicateGlue)&UnaryPredicate::_unary_predicate_glue); - - if (alreadyInList) - *alreadyInList = index >= 0; - - if (index < 0) - index = -index - 1; - - return index; -} - -template -void -BObjectList::BinaryInsert(T *item, const UnaryPredicate &pred) -{ - int32 index = FindBinaryInsertionIndex(pred); - AddItem(item, index); -} - -template -bool -BObjectList::BinaryInsertUnique(T *item, const UnaryPredicate &pred) -{ - bool alreadyInList; - int32 index = FindBinaryInsertionIndex(pred, &alreadyInList); - if (alreadyInList) - return false; - - AddItem(item, index); - return true; -} - - -#endif diff --git a/sources/Filer/PrefsWindow.cpp b/sources/Filer/PrefsWindow.cpp deleted file mode 100644 index b618537..0000000 --- a/sources/Filer/PrefsWindow.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/* - PrefsWindow.cpp: Window class to show and edit settings for the Filer - Released under the MIT license. - Written by DarkWyrm , Copyright 2008 - Contributed by: Humdinger , 2016 -*/ -#include -#include -#include -#include - -#include "FilerRule.h" -#include "PrefsWindow.h" -#include "RuleEditWindow.h" -#include "RuleItem.h" -#include "RuleRunner.h" - -enum -{ - M_SHOW_ADD_WINDOW = 'shaw', - M_SHOW_EDIT_WINDOW = 'shew', - M_REMOVE_RULE = 'shrr', - M_REVERT = 'rvrt', - M_RULE_SELECTED = 'rlsl', - M_MOVE_RULE_UP = 'mvup', - M_MOVE_RULE_DOWN = 'mvdn' -}; - - -PrefsWindow::PrefsWindow(void) - : BWindow(BRect(100,100,450,350),"Filer settings",B_TITLED_WINDOW, - B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE), - fChanges(false) -{ - fRuleList = new BObjectList(20,true); - - AddShortcut('a',B_COMMAND_KEY,new BMessage(M_SHOW_ADD_WINDOW)); - AddShortcut('e',B_COMMAND_KEY,new BMessage(M_SHOW_EDIT_WINDOW)); - - BView *top = new BView(Bounds(),"top",B_FOLLOW_ALL,B_WILL_DRAW); - top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - AddChild(top); - - BRect rect(Bounds().InsetByCopy(10,10)); - rect.right -= B_V_SCROLL_BAR_WIDTH; - - fRuleItemList = new BListView(rect,"rulelist",B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL); - fScrollView = new BScrollView("listscroll",fRuleItemList, - B_FOLLOW_ALL,0,true,true); - fScrollView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - top->AddChild(fScrollView); - fRuleItemList->SetSelectionMessage(new BMessage(M_RULE_SELECTED)); - fRuleItemList->SetInvocationMessage(new BMessage(M_SHOW_EDIT_WINDOW)); - fScrollView->ScrollBar(B_HORIZONTAL)->SetRange(0.0,0.0); - - fAddButton = new BButton(BRect(0,0,1,1),"addbutton","Add…", - new BMessage(M_SHOW_ADD_WINDOW), - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fAddButton->ResizeToPreferred(); - fAddButton->MoveTo(10,Bounds().bottom - 20 - (fAddButton->Bounds().IntegerHeight() * 2)); - top->AddChild(fAddButton); - - fScrollView->ResizeBy(0,(fAddButton->Bounds().IntegerHeight() * -2) - 20 - B_H_SCROLL_BAR_HEIGHT); - - fEditButton = new BButton(BRect(0,0,1,1),"editbutton","Edit…", - new BMessage(M_SHOW_EDIT_WINDOW), - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fEditButton->ResizeToPreferred(); - fEditButton->MoveTo((Bounds().Width() - fEditButton->Bounds().Width()) / 2.0, - fAddButton->Frame().top); - top->AddChild(fEditButton); - fEditButton->SetEnabled(false); - - - fRemoveButton = new BButton(BRect(0,0,1,1),"removebutton","Remove", - new BMessage(M_REMOVE_RULE), - B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); - fRemoveButton->ResizeToPreferred(); - fRemoveButton->MoveTo(Bounds().Width() - fRemoveButton->Bounds().Width() - 10, - fAddButton->Frame().top); - top->AddChild(fRemoveButton); - fRemoveButton->SetEnabled(false); - - - fMoveDownButton = new BButton(BRect(0,0,1,1),"movedownbutton","Move down", - new BMessage(M_MOVE_RULE_DOWN), - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fMoveDownButton->ResizeToPreferred(); - fMoveDownButton->MoveTo((Bounds().Width() / 2.0) + 10.0, - fAddButton->Frame().bottom + 10.0); - - - fMoveUpButton = new BButton(BRect(0,0,1,1),"moveupbutton","Move up", - new BMessage(M_MOVE_RULE_UP), - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fMoveUpButton->ResizeTo(fMoveDownButton->Bounds().Width(), fMoveDownButton->Bounds().Height()); - fMoveUpButton->MoveTo((Bounds().Width() / 2.0) - fMoveUpButton->Bounds().Width() - 10.0, - fAddButton->Frame().bottom + 10.0); - - top->AddChild(fMoveUpButton); - top->AddChild(fMoveDownButton); - - fMoveUpButton->SetEnabled(false); - fMoveDownButton->SetEnabled(false); - - - float minwidth = (fRemoveButton->Bounds().Width() * 3.0) + 40; - SetSizeLimits(minwidth, 30000, 200, 30000); - - LoadRules(fRuleList); - - for (int32 i = 0; i < fRuleList->CountItems(); i++) - fRuleItemList->AddItem(new RuleItem(fRuleList->ItemAt(i))); - - fRuleItemList->MakeFocus(); - if (fRuleItemList->CountItems() > 0) - fRuleItemList->Select(0L); - else - { - BAlert *alert = new BAlert("Filer","It appears that there aren't any rules for " - "organizing files. Would you like Filer to " - "add some basic ones for you?","No","Yes"); - if (alert->Go() == 1) - { - FilerRule *rule = new FilerRule(); - - // NOTE: If actions - rule->AddTest(MakeTest("Type","is","text/plain")); - rule->AddAction(MakeAction("Move it to…","/boot/home/Documents")); - rule->SetDescription("Store text files in my Documents folder"); - AddRule(rule); - - rule = new FilerRule(); - rule->AddTest(MakeTest("Type","is","application/pdf")); - rule->AddAction(MakeAction("Move it to…","/boot/home/Documents")); - rule->SetDescription("Store PDF files in my Documents folder"); - AddRule(rule); - - rule = new FilerRule(); - rule->AddTest(MakeTest("Type","starts with","image/")); - rule->AddAction(MakeAction("Move it to…","/boot/home/Pictures")); - rule->SetDescription("Store pictures in my Pictures folder"); - AddRule(rule); - - rule = new FilerRule(); - rule->AddTest(MakeTest("Type","starts with","video/")); - rule->AddAction(MakeAction("Move it to…","/boot/home/Videos")); - rule->SetDescription("Store movie files in my Videos folder"); - AddRule(rule); - - rule = new FilerRule(); - rule->AddTest(MakeTest("Name","ends with",".zip")); - rule->AddAction(MakeAction("Terminal command…","unzip %FULLPATH% -d /boot/home/Desktop")); - rule->SetDescription("Extract ZIP files to the Desktop"); - AddRule(rule); - -// rule = new FilerRule(); -// rule->AddTest(MakeTest("","","")); -// rule->AddAction(MakeAction("","")); -// rule->SetDescription(""); -// AddRule(rule); - } - SaveRules(fRuleList); - } -} - - -PrefsWindow::~PrefsWindow(void) -{ - delete fRuleList; -} - - -bool -PrefsWindow::QuitRequested(void) -{ - if (fChanges) - SaveRules(fRuleList); - MakeEmpty(); - be_app->PostMessage(B_QUIT_REQUESTED); - return true; -} - - -void -PrefsWindow::MessageReceived(BMessage *msg) -{ - switch(msg->what) - { - case M_SHOW_ADD_WINDOW: - { - BRect frame(Frame()); - frame.right = frame.left + 400; - frame.bottom = frame.top + 300; - frame.OffsetBy(20,20); - - RuleEditWindow *rulewin = new RuleEditWindow(frame,NULL); - rulewin->Show(); - break; - } - case M_SHOW_EDIT_WINDOW: - { - BRect frame(Frame()); - frame.right = frame.left + 400; - frame.bottom = frame.top + 300; - frame.OffsetBy(20,20); - - FilerRule *rule = fRuleList->ItemAt(fRuleItemList->CurrentSelection()); - - RuleEditWindow *rulewin = new RuleEditWindow(frame,rule); - rulewin->Show(); - break; - } - case M_ADD_RULE: - { - fChanges = true; - FilerRule *item; - if (msg->FindPointer("item",(void**)&item) == B_OK) - AddRule(item); - break; - } - case M_REMOVE_RULE: - { - fChanges = true; - if (fRuleItemList->CurrentSelection() >= 0) - RemoveRule((RuleItem*)fRuleItemList->ItemAt(fRuleItemList->CurrentSelection())); - break; - } - case M_UPDATE_RULE: - { - fChanges = true; - FilerRule *rule; - if (msg->FindPointer("item",(void**)&rule) == B_OK) - { - int64 id; - if (msg->FindInt64("id",&id) != B_OK) - debugger("Couldn't find update ID"); - - for (int32 i = 0; i < fRuleList->CountItems(); i++) - { - FilerRule *oldrule = fRuleList->ItemAt(i); - if (oldrule->GetID() == id) - { - *oldrule = *rule; - RuleItem *item = (RuleItem*)fRuleItemList->ItemAt(i); - item->SetText(rule->GetDescription()); - break; - } - } - - delete rule; - } - break; - } - case M_REVERT: - { - while (fRuleItemList->CountItems() > 0) - RemoveRule((RuleItem*)fRuleItemList->ItemAt(0L)); - fRuleList->MakeEmpty(); - fEditButton->SetEnabled(false); - fRemoveButton->SetEnabled(false); - - LoadRules(fRuleList); - break; - } - case M_RULE_SELECTED: - { - bool value = (fRuleItemList->CurrentSelection() >= 0); - - fEditButton->SetEnabled(value); - fRemoveButton->SetEnabled(value); - - if (fRuleItemList->CountItems() > 1) - { - fMoveUpButton->SetEnabled(value); - fMoveDownButton->SetEnabled(value); - } - break; - } - case M_MOVE_RULE_UP: - { - fChanges = true; - int32 selection = fRuleItemList->CurrentSelection(); - if (selection < 1) - break; - - fRuleItemList->SwapItems(selection, selection - 1); - fRuleList->SwapItems(selection, selection - 1); - break; - } - case M_MOVE_RULE_DOWN: - { - fChanges = true; - int32 selection = fRuleItemList->CurrentSelection(); - if (selection > fRuleItemList->CountItems() - 1) - break; - - fRuleItemList->SwapItems(selection, selection + 1); - fRuleList->SwapItems(selection, selection + 1); - break; - } - default: - BWindow::MessageReceived(msg); - break; - } -} - - -void -PrefsWindow::FrameResized(float width, float height) -{ - float x = fAddButton->Frame().right + ((fRemoveButton->Frame().left - - fAddButton->Frame().right) / 2.0); - fEditButton->MoveTo(x - (fEditButton->Bounds().Width() / 2.0), - fAddButton->Frame().top); -} - - -void -PrefsWindow::AddRule(FilerRule *rule) -{ - fRuleList->AddItem(rule); - fRuleItemList->AddItem(new RuleItem(rule)); - - if (fRuleItemList->CurrentSelection() < 0) - fRuleItemList->Select(0L); -} - - -void -PrefsWindow::RemoveRule(RuleItem *item) -{ - // Select a new rule (if there is one) before removing the old one. BListView simply drops - // the selection if the selected item is removed. What a pain in the neck. :/ - int32 itemindex = fRuleItemList->IndexOf(item); - int32 selection = fRuleItemList->CurrentSelection(); - if (itemindex == selection && fRuleItemList->CountItems() > 1) - { - if (selection == fRuleItemList->CountItems() - 1) - selection--; - else - selection++; - fRuleItemList->Select(selection); - } - - fRuleItemList->RemoveItem(item); - - FilerRule *rule = item->Rule(); - fRuleList->RemoveItem(rule); - delete item; - - if (fRuleItemList->CountItems() <= 0) - { - fEditButton->SetEnabled(false); - fRemoveButton->SetEnabled(false); - } - - if (fRuleItemList->CountItems() < 2) - { - fMoveUpButton->SetEnabled(false); - fMoveDownButton->SetEnabled(false); - } -} - - -void -PrefsWindow::MakeEmpty(void) -{ - for (int32 i = fRuleItemList->CountItems() - 1; i >= 0; i--) - { - RuleItem *item = (RuleItem*)fRuleItemList->RemoveItem(i); - delete item; - } -} diff --git a/sources/Filer/PrefsWindow.h b/sources/Filer/PrefsWindow.h deleted file mode 100644 index cf8b6c6..0000000 --- a/sources/Filer/PrefsWindow.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - PrefsWindow.h: Window class to show and edit settings for the Filer - Written by DarkWyrm , Copyright 2008 - Released under the MIT license. -*/ -#ifndef PREFS_WIN_H -#define PREFS_WIN_H - -#include -#include -#include -#include "ObjectList.h" - -class RuleItem; -class FilerRule; - -#define M_CLOSE_APP 'clar' - - -class PrefsWindow : public BWindow -{ -public: - PrefsWindow(void); - ~PrefsWindow(void); - bool QuitRequested(void); - void MessageReceived(BMessage *msg); - void FrameResized(float width, float height); - -private: - void AddRule(FilerRule *rule); - void RemoveRule(RuleItem *item); - void MakeEmpty(void); - - BObjectList *fRuleList; - - BListView *fRuleItemList; - - BButton *fAddButton, - *fEditButton, - *fRemoveButton, - *fMoveUpButton, - *fMoveDownButton; - - BScrollView *fScrollView; - bool fChanges; -}; - -#endif diff --git a/sources/Filer/RuleEditWindow.cpp b/sources/Filer/RuleEditWindow.cpp deleted file mode 100644 index 21084c3..0000000 --- a/sources/Filer/RuleEditWindow.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* - RuleEditWindow.cpp: Rule editor class (duh) - Released under the MIT license. - Written by DarkWyrm , Copyright 2008 - Contributed by: Humdinger , 2016 -*/ -#include "RuleEditWindow.h" - -#include -#include -#include -#include -#include -#include - - -#include "ActionView.h" -#include "AutoTextControl.h" -#include "EscapeCancelFilter.h" -#include "FilerRule.h" -#include "TestView.h" - -// Internal message defs -enum -{ - M_DESCRIPTION_CHANGED = 'dsch', - M_OK = 'mok ', - M_CANCEL = 'cncl', - - M_ADD_TEST = 'adts', - M_REMOVE_TEST = 'rmts', - - M_ADD_ACTION = 'adac', - M_REMOVE_ACTION = 'rmac', - - M_SHOW_HELP = 'shhl' -}; - - -RuleEditWindow::RuleEditWindow(BRect &rect, FilerRule *rule) - : BWindow(rect,"Edit rule",B_TITLED_WINDOW,B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE), - fOriginalID(-1) -{ - if (rule) - fOriginalID = rule->GetID(); - else - SetTitle("Add rule"); - - - AddCommonFilter(new EscapeCancelFilter); - - BView *top = new BView(Bounds(),"top",B_FOLLOW_ALL,B_WILL_DRAW); - top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - AddChild(top); - - // Description - fDescriptionBox = new AutoTextControl(BRect(0,0,1,1),"description","Description: ", - NULL,new BMessage(M_DESCRIPTION_CHANGED), - B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); - top->AddChild(fDescriptionBox); - - float width,height; - fDescriptionBox->GetPreferredSize(&width,&height); - fDescriptionBox->ResizeTo(Bounds().Width() - 20,height); - fDescriptionBox->MoveTo(10,10); - fDescriptionBox->SetDivider(be_plain_font->StringWidth("Description: ") + 5); - - if (rule) - fDescriptionBox->SetText(rule->GetDescription()); - - // Separator line - BRect rect(fDescriptionBox->Frame()); - rect.OffsetBy(0,rect.IntegerHeight() + 10); - rect.bottom = rect.top + 1.0; - BBox *box = new BBox(rect, NULL, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); - top->AddChild(box); - - // Set up the tests group and associated buttons - rect.OffsetBy(0,12.0); - rect.bottom = rect.top + 20.0; - fTestGroup = new BBox(rect,"whengroup", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); - fTestGroup->SetLabel("When"); - top->AddChild(fTestGroup); - - fAddTest = new BButton(BRect(0,0,1,1),"addtestbutton","Add",new BMessage(M_ADD_TEST), - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fAddTest->ResizeToPreferred(); - fAddTest->MoveTo(10.0, fTestGroup->Bounds().bottom - 10.0 - fAddTest->Bounds().Height()); - fTestGroup->AddChild(fAddTest); - - fRemoveTest = new BButton(BRect(0,0,1,1),"removetestbutton","Remove", - new BMessage(M_REMOVE_TEST),B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fRemoveTest->ResizeToPreferred(); - fRemoveTest->MoveTo(fAddTest->Frame().right + 10, fAddTest->Frame().top); - fTestGroup->AddChild(fRemoveTest); - fRemoveTest->SetEnabled(false); - - fTestGroup->ResizeBy(0,fAddTest->Bounds().Height() + 10.0); - - // Set up the actions group and associated buttons - - rect.OffsetTo(10,fTestGroup->Frame().bottom + 10.0); - fActionGroup = new BBox(rect,"dogroup", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); - fActionGroup->SetLabel("Do"); - top->AddChild(fActionGroup); - - fAddAction = new BButton(BRect(0,0,1,1),"addactionbutton","Add",new BMessage(M_ADD_ACTION), - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fAddAction->ResizeToPreferred(); - fAddAction->MoveTo(10.0, fActionGroup->Bounds().bottom - 10.0 - fAddAction->Bounds().Height()); - fActionGroup->AddChild(fAddAction); - - fRemoveAction = new BButton(BRect(0,0,1,1),"removeactionbutton","Remove", - new BMessage(M_REMOVE_ACTION),B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fRemoveAction->ResizeToPreferred(); - fRemoveAction->MoveTo(fAddAction->Frame().right + 10, fAddAction->Frame().top); - fActionGroup->AddChild(fRemoveAction); - fRemoveAction->SetEnabled(false); - - fActionGroup->ResizeBy(0,fAddAction->Bounds().Height() + 10.0); - - - - fOK = new BButton(BRect(0,0,1,1),"okbutton","OK",new BMessage(M_OK), - B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); - fOK->ResizeToPreferred(); - fOK->MoveTo(Bounds().right - fOK->Bounds().Width() - 10, - Bounds().bottom - fOK->Bounds().Height() - 10); - // calling AddChild later to ensure proper keyboard navigation - - fCancel = new BButton(BRect(0,0,1,1),"cancelbutton","Cancel",new BMessage(M_CANCEL), - B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); - fCancel->ResizeToPreferred(); - fCancel->MoveTo(fOK->Frame().left - fCancel->Bounds().Width() - 10, - fOK->Frame().top); - - fHelp = new BButton(BRect(0,0,1,1),"helpbutton","Help…",new BMessage(M_SHOW_HELP), - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fHelp->ResizeToPreferred(); - fHelp->MoveTo(10, fOK->Frame().top); - top->AddChild(fHelp); - - top->AddChild(fCancel); - top->AddChild(fOK); - fOK->MakeDefault(true); - - if (rule) - { - for (int32 i = 0; i < rule->CountTests(); i++) - AppendTest(rule->TestAt(i)); - - for (int32 i = 0; i < rule->CountActions(); i++) - AppendAction(rule->ActionAt(i)); - } - else - { - AppendTest(NULL); - AppendAction(NULL); - } - - ResizeTo(Bounds().Width(), fActionGroup->Frame().bottom + 15 + fOK->Bounds().Height()); - - fDescriptionBox->MakeFocus(); -} - - -RuleEditWindow::~RuleEditWindow(void) -{ -} - - -void -RuleEditWindow::MessageReceived(BMessage *msg) -{ - switch(msg->what) - { - case M_SHOW_HELP: - { - app_info info; - BPath path; - be_roster->GetActiveAppInfo(&info); - BEntry entry(&info.ref); - - entry.GetPath(&path); - path.GetParent(&path); - path.Append("documentation/Rule-Making Reference.html"); - - entry = path.Path(); - entry_ref ref; - entry.GetRef(&ref); - be_roster->Launch(&ref); - break; - } - case M_OK: - { - if (strlen(fDescriptionBox->Text()) < 1) - { - BAlert *alert = new BAlert("Filer","You need to add a description " - "if you want to add this rule to the list.", - "OK"); - alert->Go(); - fDescriptionBox->MakeFocus(true); - break; - } - - SendRuleMessage(); - PostMessage(B_QUIT_REQUESTED); - break; - } - case M_CANCEL: - { - PostMessage(B_QUIT_REQUESTED); - break; - } - case M_ADD_TEST: - { - AppendTest(NULL); - break; - } - case M_REMOVE_TEST: - { - RemoveTest(); - break; - } - case M_ADD_ACTION: - { - AppendAction(NULL); - break; - } - case M_REMOVE_ACTION: - { - RemoveAction(); - break; - } - default: - BWindow::MessageReceived(msg); - } -} - - -void -RuleEditWindow::AppendTest(BMessage *test) -{ - TestView *view = new TestView(BRect(0,0,1,1),"test",test,B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); - view->ResizeToPreferred(); - BRect r = view->GetPreferredSize(); - fTestGroup->ResizeBy(0,r.Height() + 10); - - if (fTestGroup->Bounds().Width() < r.Width() + 20) - ResizeBy(r.Width() + 20 - fTestGroup->Bounds().Width(),0); - - TestView *last = (TestView*)fTestList.ItemAt(fTestList.CountItems() - 1); - - if (last) - view->MoveTo(last->Frame().left,last->Frame().bottom + 10); - else - view->MoveTo(10,15); - - fTestGroup->AddChild(view); - fTestList.AddItem(view); - - fActionGroup->MoveBy(0,r.Height() + 10); - ResizeBy(0,r.Height() + 10); - - if (fTestList.CountItems() > 1 && !fRemoveTest->IsEnabled()) - fRemoveTest->SetEnabled(true); -} - - -void -RuleEditWindow::RemoveTest(void) -{ - TestView *view = (TestView*) fTestList.RemoveItem(fTestList.CountItems() - 1); - view->RemoveSelf(); - fTestGroup->ResizeBy(0,-view->Bounds().Height() - 10); - fActionGroup->MoveBy(0,-view->Bounds().Height() - 10); - ResizeBy(0,-view->Bounds().Height() - 10); - delete view; - - if (fTestList.CountItems() == 1) - fRemoveTest->SetEnabled(false); -} - - -void -RuleEditWindow::AppendAction(BMessage *action) -{ - ActionView *view = new ActionView(BRect(0,0,1,1),"action",action,B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); - BRect r = view->GetPreferredSize(); - view->ResizeTo(fActionGroup->Bounds().Width() - 20, r.Height()); - fActionGroup->ResizeBy(0,r.Height() + 10); - - if (fActionGroup->Bounds().Width() < r.Width() + 20) - ResizeBy(r.Width() + 20 - fActionGroup->Bounds().Width(),0); - - ActionView *last = (ActionView*)fActionList.ItemAt(fActionList.CountItems() - 1); - - if (last) - view->MoveTo(last->Frame().left,last->Frame().bottom + 10); - else - view->MoveTo(10,15); - - fActionGroup->AddChild(view); - fActionList.AddItem(view); - - ResizeBy(0,r.Height() + 10); - - if (fActionList.CountItems() > 1 && !fRemoveAction->IsEnabled()) - fRemoveAction->SetEnabled(true); -} - - -void -RuleEditWindow::RemoveAction(void) -{ - ActionView *view = (ActionView*) fActionList.RemoveItem(fActionList.CountItems() - 1); - view->RemoveSelf(); - fActionGroup->ResizeBy(0,-view->Bounds().Height() - 10); - ResizeBy(0,-view->Bounds().Height() - 10); - delete view; - - - if (fActionList.CountItems() == 1) - fRemoveAction->SetEnabled(false); -} - - -BRect -RuleEditWindow::GetPreferredSize(void) const -{ - // Base minimum size, padding included - BRect rect(0.0,0.0,320.0,220.0); - - // Figure preferred height - - rect.bottom += fDescriptionBox->Bounds().Height() + 10.0; - - // 2 pixels for separator line + 10 pixels padding above it - rect.bottom += 12.0; - - // Base minimum size for boxes (including inside padding) of 20 each and outside - // padding of 10 pixels above each box - rect.bottom += 40.0 + 20.0; - - rect.bottom += fOK->Bounds().Height() + 10.0; - - return rect; -} - - -void -RuleEditWindow::SendRuleMessage(void) -{ - FilerRule *rule = new FilerRule; - - rule->SetDescription(fDescriptionBox->Text()); - - for(int32 i = 0; i < fTestList.CountItems(); i++) - { - TestView *view = (TestView*)fTestList.ItemAt(i); - rule->AddTest(new BMessage(*view->GetTest())); - } - - for(int32 i = 0; i < fActionList.CountItems(); i++) - { - ActionView *view = (ActionView*)fActionList.ItemAt(i); - rule->AddAction(new BMessage(*view->GetAction())); - } - - BMessage msg; - msg.what = (fOriginalID >= 0) ? M_UPDATE_RULE : M_ADD_RULE; - msg.AddPointer("item",rule); - msg.AddInt64("id",fOriginalID); - - for (int32 i = 0; i < be_app->CountWindows(); i++) - { - BWindow *win = be_app->WindowAt(i); - if (strcmp(win->Title(),"Filer settings") == 0) - win->PostMessage(&msg); - } -} - diff --git a/sources/Filer/RuleEditWindow.h b/sources/Filer/RuleEditWindow.h deleted file mode 100644 index ab2cbd5..0000000 --- a/sources/Filer/RuleEditWindow.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - RuleEditWindow.h: Rule editor class (duh) - Written by DarkWyrm , Copyright 2008 - Released under the MIT license. -*/ -#ifndef RULE_EDIT_WINDNOW_H -#define RULE_EDIT_WINDNOW_H - -#include -#include -#include -#include "ObjectList.h" - -class AutoTextControl; -class FilerRule; -class TestView; - -// Message defs used by other classes -enum -{ - M_ADD_RULE = 'adrl', - M_UPDATE_RULE = 'uprl', - M_FORCE_QUIT = 'frcq' -}; - -class RuleEditWindow : public BWindow -{ -public: - RuleEditWindow(BRect &rect, FilerRule *rule); - ~RuleEditWindow(void); - void MessageReceived(BMessage *msg); - -// FilerRule * Rule(void); - - void AppendTest(BMessage *test); - void RemoveTest(void); - - void AppendAction(BMessage *action); - void RemoveAction(void); - -private: - BRect GetPreferredSize(void) const; - void SendRuleMessage(void); - - AutoTextControl *fDescriptionBox; - - BBox *fTestGroup, - *fActionGroup; - - BButton *fOK, - *fCancel, - *fAddTest, - *fRemoveTest, - *fAddAction, - *fRemoveAction, - *fHelp; - - int64 fOriginalID; - - BList fTestList, - fActionList; -}; - -#endif diff --git a/sources/Filer/RuleRunner.cpp b/sources/Filer/RuleRunner.cpp deleted file mode 100644 index 6bf9aea..0000000 --- a/sources/Filer/RuleRunner.cpp +++ /dev/null @@ -1,1306 +0,0 @@ -/* - RuleRunner.cpp: class to handle running test and actions for the rules - Released under the MIT license. - Written by DarkWyrm , Copyright 2008 - Contributed by: Humdinger , 2016 -*/ -#include -#include -#include -#include -#include -#include - -#include "CppSQLite3.h" -#include "Database.h" -#include "FSUtils.h" -#include "PatternProcessor.h" -#include "RuleRunner.h" - -#include -#include - -/* - FilerAction message fields: - "name" - the particular action, i.e. copy, move, trash, delete, etc. - "value" - string data associated with the action. Usually a file path - - FilerTest message fields: - "name" - the particular data being compared -- name, date, etc. This is set to - "Attribute" if it's an extended attribute - "mode" - the kind of comparison being used -- ==, != -- in plain English - "value" - the value to be compared to - - - These fields are either not present or NULL in non-attribute tests: - - "mimetype" - This is the MIME type associated with the attribute. - "typename" - This is the mime type's short description. - "attrtype" - The MIME description for the attribute type, like META:email for email - addresses. - "attrname" - The public name for the attribute to be compared. - - - To add another test to this file, you'll need to implement an IsXxxxMatch() function, - make sure it is called from within IsMatch(), and add the appropriate name to both - sTestTypes[] and either sStringTests[], sDateTests[], or sNumberTests[]. - - To add an action to this file, you'll need to implement an xxxxAction() function, - make sure it is called from within RunAction, and add the appropriate action name - to sActions[]; - - In both cases, please make sure that you keep the location within the static array - variables when adding or deleting entries -*/ - -// The various compare functions used by IsMatch to do the actual comparing -bool IsNameMatch(const BMessage &test, const entry_ref &ref); -bool IsTypeMatch(const BMessage &test, const entry_ref &ref); -bool IsSizeMatch(const BMessage &test, const entry_ref &ref); -bool IsLocationMatch(const BMessage &test, const entry_ref &ref); -bool IsModifiedMatch(const BMessage &test, const entry_ref &ref); -bool IsAttributeMatch(const BMessage &test, const entry_ref &ref); -bool StringCompare(const BString &from, const BString &to, const char *mode, - const bool &match_case); - -// The various action functions used by RunAction to do the heavy lifting -status_t MoveAction(const BMessage &action, entry_ref &ref); -status_t CopyAction(const BMessage &action, entry_ref &ref); -status_t RenameAction(const BMessage &action, entry_ref &ref); -status_t OpenAction(const BMessage &action, entry_ref &ref); -status_t ArchiveAction(const BMessage &action, entry_ref &ref); -status_t CommandAction(const BMessage &action, entry_ref &ref); -status_t TrashAction(const BMessage &action, entry_ref &ref); -status_t DeleteAction(const BMessage &action, entry_ref &ref); - - -// Internal variables for all the supported types of tests - -static const char *sTestTypes[] = -{ - "Type", - "Name", - "Size", - "Location", -// "Last Changed", - NULL -}; - -static const char *sStringTests[] = -{ - "Type", - "Name", - "Location", - NULL -}; - -static const char *sNumberTests[] = -{ - "Size", - NULL -}; - -static const char *sDateTests[] = -{ -// "Last Changed", - NULL -}; - - -static const char *sTestEditors[] = -{ - "type selector", - "textbox", - "textbox", - "textbox", -// "textbox", - NULL -}; - - -// Internal variables for all the supported types of compare operators - -static const char *sAnyModes[] = -{ - "is", - "is not", - - // for future expansion -// "matches pattern", -// "does not match pattern", - - NULL -}; - -static const char *sStringModes[] = -{ - "starts with", - "ends with", - "contains", - "does not contain", - NULL -}; - -static const char *sNumberModes[] = -{ - "is more than", - "is less than", - "is at least", - "is at most", - NULL -}; - -static const char *sDateModes[] = -{ - "is before", - "is after", - NULL -}; - - -// Internal variable for all the supported types of actions - -static const char *sActions[] = -{ - "Move it to…", - "Copy it to…", - "Rename it to…", - "Open it", - "Add it to the archive…", - "Move it to the Trash", - "Delete it", - "Terminal command…", - - // Future expansion -// "Shred it", -// "E-mail it to…", -// "Make a Deskbar link", - - NULL -}; - - -RuleRunner::RuleRunner(void) -{ -} - - -RuleRunner::~RuleRunner(void) -{ -} - - -void -RuleRunner::GetTestTypes(BMessage &msg) -{ - int32 i = 0; - while (sTestTypes[i]) - { - msg.AddString("tests",sTestTypes[i]); - i++; - } -} - - -status_t -RuleRunner::GetCompatibleModes(const char *testtype, BMessage &msg) -{ - if (!testtype) - return B_ERROR; - - return GetCompatibleModes(GetDataTypeForTest(testtype),msg); -} - - -status_t -RuleRunner::GetCompatibleModes(const int32 &type, BMessage &msg) -{ - int32 i = 0; - switch (type) - { - case TEST_TYPE_STRING: - { - while (sAnyModes[i]) - { - msg.AddString("modes",sAnyModes[i]); - i++; - } - - i = 0; - while (sStringModes[i]) - { - msg.AddString("modes",sStringModes[i]); - i++; - } - break; - } - case TEST_TYPE_NUMBER: - { - while (sAnyModes[i]) - { - msg.AddString("modes",sAnyModes[i]); - i++; - } - - i = 0; - while (sNumberModes[i]) - { - msg.AddString("modes",sNumberModes[i]); - i++; - } - break; - } - case TEST_TYPE_DATE: - { - while (sAnyModes[i]) - { - msg.AddString("modes",sAnyModes[i]); - i++; - } - - i = 0; - while (sDateModes[i]) - { - msg.AddString("modes",sDateModes[i]); - i++; - } - break; - } - case TEST_TYPE_ANY: - { - while (sAnyModes[i]) - { - msg.AddString("modes",sAnyModes[i]); - i++; - } - break; - } - default: - return B_BAD_VALUE; - } - return B_OK; -} - - -void -RuleRunner::GetModes(BMessage &msg) -{ - int32 i; - - i = 0; - while (sAnyModes[i]) - { - msg.AddString("modes",sAnyModes[i]); - i++; - } - - i = 0; - while (sStringModes[i]) - { - msg.AddString("modes",sStringModes[i]); - i++; - } - - i = 0; - while (sNumberModes[i]) - { - msg.AddString("modes",sNumberModes[i]); - i++; - } - - i = 0; - while (sDateModes[i]) - { - msg.AddString("modes",sDateModes[i]); - i++; - } -} - - -void -RuleRunner::GetActions(BMessage &msg) -{ - int32 i = 0; - while (sActions[i]) - { - msg.AddString("actions",sActions[i]); - i++; - } -} - - -BString -RuleRunner::GetEditorTypeForTest(const char *testname) -{ - int32 i = 0; - while (sTestTypes[i]) - { - if (strcmp(testname,sTestTypes[i]) == 0) - return BString(sTestEditors[i]); - i++; - } - return BString(""); -} - - -int32 -RuleRunner::GetDataTypeForTest(const char *testname) -{ - if (!testname) - return TEST_TYPE_NULL; - - int32 i; - - i = 0; - while (sStringTests[i]) - { - if (strcmp(testname,sStringTests[i]) == 0) - return TEST_TYPE_STRING; - i++; - } - - i = 0; - while (sNumberTests[i]) - { - if (strcmp(testname,sNumberTests[i]) == 0) - return TEST_TYPE_NUMBER; - i++; - } - - i = 0; - while (sDateTests[i]) - { - if (strcmp(testname,sDateTests[i]) == 0) - return TEST_TYPE_DATE; - i++; - } - - return TEST_TYPE_NULL; -} - - -int32 -RuleRunner::GetDataTypeForMode(const char *modename) -{ - if (!modename) - return TEST_TYPE_NULL; - - int32 i; - - i = 0; - while (sStringModes[i]) - { - if (strcmp(modename,sStringModes[i]) == 0) - return TEST_TYPE_STRING; - i++; - } - - i = 0; - while (sNumberModes[i]) - { - if (strcmp(modename,sNumberModes[i]) == 0) - return TEST_TYPE_NUMBER; - i++; - } - - i = 0; - while (sDateModes[i]) - { - if (strcmp(modename,sDateModes[i]) == 0) - return TEST_TYPE_DATE; - i++; - } - - i = 0; - while (sAnyModes[i]) - { - if (strcmp(modename,sAnyModes[i]) == 0) - return TEST_TYPE_ANY; - i++; - } - - return TEST_TYPE_NULL; -} - -bool -RuleRunner::IsMatch(const BMessage &test, const entry_ref &ref) -{ - BString testname; - if (test.FindString("name",&testname) != B_OK) - { - debugger("Couldn't find test name in RuleRunner::IsMatch"); - return false; - } - - if (testname.Compare("Name") == 0) - return IsNameMatch(test,ref); - else if (testname.Compare("Size") == 0) - return IsSizeMatch(test,ref); - else if (testname.Compare("Location") == 0) - return IsLocationMatch(test,ref); - else if (testname.Compare("Type") == 0) - return IsTypeMatch(test,ref); - else if (testname.Compare("Last Changed") == 0) - return IsModifiedMatch(test,ref); - else if (testname.Compare("Attribute") == 0) - return IsAttributeMatch(test,ref); - - return false; -} - - -status_t -RuleRunner::RunAction(const BMessage &action, entry_ref &ref) -{ - BString actionname; - if (action.FindString("name",&actionname) != B_OK) - { - debugger("Couldn't find action name in RuleRunner::RunAction"); - return B_ERROR; - } - - if (actionname.Compare("Move it to…") == 0) - return MoveAction(action,ref); - else if (actionname.Compare("Copy it to…") == 0) - return CopyAction(action,ref); - else if (actionname.Compare("Rename it to…") == 0) - return RenameAction(action,ref); - else if (actionname.Compare("Open it") == 0) - return OpenAction(action,ref); - else if (actionname.Compare("Add it to the archive…") == 0) - return ArchiveAction(action,ref); - else if (actionname.Compare("Terminal command…") == 0) - return CommandAction(action,ref); - else if (actionname.Compare("Move it to the Trash") == 0) - return TrashAction(action,ref); - else if (actionname.Compare("Delete it") == 0) - return DeleteAction(action,ref); - - return B_ERROR; -} - - -status_t -RuleRunner::RunRule(FilerRule *rule, entry_ref &ref) -{ - if (!rule) - return B_ERROR; - - bool pass; - - printf("Running rule '%s'\n",rule->GetDescription()); - - if (rule->GetRuleMode() == FILER_RULE_ANY) - { - pass = false; - for (int32 i = 0; i < rule->CountTests(); i++) - { - BMessage *test = rule->TestAt(i); - if (IsMatch(*test,ref)) - { - pass = true; - break; - } - } - } - else // And mode - { - pass = true; - for (int32 i = 0; i < rule->CountTests(); i++) - { - BMessage *test = rule->TestAt(i); - if (!IsMatch(*test,ref)) - { - pass = false; - break; - } - } - } - - if (pass) - { - entry_ref realref; - BEntry(&ref,true).GetRef(&realref); - - for (int32 i = 0; i < rule->CountActions(); i++) - { - BMessage *action = rule->ActionAt(i); - - // Note that this call passes the same ref object from one call to the - // next. This allows the user to chain actions together. The only thing - // required to do this is for the particular action to change the ref - // passed to it. - status_t status = RunAction(*action,realref); - if (status != B_OK) - return status; - } - } - - return B_OK; -} - - -bool -IsNameMatch(const BMessage &test, const entry_ref &ref) -{ - BString value; - if (test.FindString("value",&value) != B_OK) - { - debugger("Couldn't get value in IsNameMatch"); - return false; - } - - BString compare; - if (test.FindString("mode",&compare) != B_OK) - { - debugger("Couldn't get mode in IsNameMatch"); - return false; - } - - bool result = StringCompare(value,BString(ref.name),compare.String(),true); - - printf("\tName test: %s %s %s - %s\n",ref.name,compare.String(),value.String(), - result ? "MATCH" : "NO MATCH"); - - return result; -} - - -bool -IsTypeMatch(const BMessage &test, const entry_ref &ref) -{ - BString value; - if (test.FindString("value",&value) != B_OK) - { - debugger("Couldn't get value in IsTypeMatch"); - return false; - } - -//if (value == "image/") -// debugger(""); - - BString compare; - if (test.FindString("mode",&compare) != B_OK) - { - debugger("Couldn't get mode in IsTypeMatch"); - return false; - } - - BString string; - attr_info info; - BNode node(&ref); - if (node.InitCheck() != B_OK) - return false; - - if (node.GetAttrInfo("BEOS:TYPE",&info) != B_OK) - { - BPath path(&ref); - if (update_mime_info(path.Path(),0,1,0) != B_OK) - return false; - } - - if (node.ReadAttrString("BEOS:TYPE",&string) != B_OK) - return false; - - - bool result = StringCompare(value,string.String(),compare.String(),true); - - printf("\tType test: %s %s %s - %s\n",ref.name,compare.String(),value.String(), - result ? "MATCH" : "NO MATCH"); - - return result; -} - - -bool -IsSizeMatch(const BMessage &test, const entry_ref &ref) -{ - BString value; - if (test.FindString("value",&value) != B_OK) - { - debugger("Couldn't get value in IsTypeMatch"); - return false; - } - - BString compare; - if (test.FindString("mode",&compare) != B_OK) - { - debugger("Couldn't get mode in IsTypeMatch"); - return false; - } - - off_t fromsize = atoll(value.String()); - - BFile file(&ref,B_READ_ONLY); - if (file.InitCheck() != B_OK) - return false; - - off_t tosize; - file.GetSize(&tosize); - file.Unset(); - - bool result = false; - - if (strcmp(compare.String(),"is") == 0) - result = (fromsize == tosize); - else if (strcmp(compare.String(),"is not") == 0) - result = (fromsize != tosize); - else if (strcmp(compare.String(),"is more than") == 0) - result = (fromsize > tosize); - else if (strcmp(compare.String(),"is less than") == 0) - result = (fromsize < tosize); - else if (strcmp(compare.String(),"is at least") == 0) - result = (fromsize >= tosize); - else if (strcmp(compare.String(),"is at most") == 0) - result = (fromsize <= tosize); - - printf("\tSize test: %s %s %lld - %s\n",ref.name,compare.String(),tosize, - result ? "MATCH" : "NO MATCH"); - - return result; -} - - -bool -IsLocationMatch(const BMessage &test, const entry_ref &ref) -{ - BString value; - if (test.FindString("value",&value) != B_OK) - { - debugger("Couldn't get value in IsLocationMatch"); - return false; - } - - BString compare; - if (test.FindString("mode",&compare) != B_OK) - { - debugger("Couldn't get mode in IsLocationMatch"); - return false; - } - - // This is a little tricky -- we resolve symlinks in the location test - entry_ref realref; - BEntry(&ref).GetRef(&realref); - - BPath path(&realref); - BString filepath(path.Path()); - filepath.RemoveLast(path.Leaf()); - - if (value[value.CountChars() - 1] != '/') - value << "/"; - - bool result = StringCompare(value,filepath.String(),compare.String(),true); - - printf("\tLocation test: %s %s %s - %s\n",filepath.String(), - compare.String(),value.String(), - result ? "MATCH" : "NO MATCH"); - - return result; -} - - -bool -IsModifiedMatch(const BMessage &test, const entry_ref &ref) -{ - // TODO: Implement using Mr. Peeps! date-parsing code - return false; -} - - -bool -IsAttributeMatch(const BMessage &test, const entry_ref &ref) -{ - BString value; - if (test.FindString("value",&value) != B_OK) - { - debugger("Couldn't get value in IsTypeMatch"); - return false; - } - - BString compare; - if (test.FindString("mode",&compare) != B_OK) - { - debugger("Couldn't get mode in IsTypeMatch"); - return false; - } - - BString attribute; - if (test.FindString("attrtype",&attribute) != B_OK) - { - debugger("Couldn't get attribute in IsAttributeMatch"); - return false; - } - - BString string; - attr_info info; - BNode node(&ref); - if (node.InitCheck() != B_OK) - return false; - - if (node.GetAttrInfo(attribute.String(),&info) != B_OK) - return false; - - if (node.ReadAttrString(attribute.String(),&string) != B_OK) - return false; - - - bool result = StringCompare(value,string,compare.String(),true); - - - BString attrname; - if (test.FindString("attrname",&attrname) != B_OK) - attrname = attribute; - - printf("\tAttribute test: %s %s %s - %s\n",attrname.String(), - compare.String(),value.String(), - result ? "MATCH" : "NO MATCH"); - - return result; -} - - -bool -StringCompare(const BString &from, const BString &to, const char *mode, - const bool &match_case) -{ - if (!mode) - { - debugger("NULL mode in StringCompare"); - return false; - } - - if (strcmp(mode,"is") == 0) - if (match_case) - return from.Compare(to) == 0; - else - return from.ICompare(to) == 0; - else if (strcmp(mode,"is not") == 0) - if (match_case) - return from.Compare(to) != 0; - else - return from.ICompare(to) != 0; - else if (strcmp(mode,"contains") == 0) - if (match_case) - return to.FindFirst(from) >= 0; - else - return to.IFindFirst(from) >= 0; - else if (strcmp(mode,"does not contain") == 0) - if (match_case) - return to.FindFirst(from) < 0; - else - return to.IFindFirst(from) < 0; - else if (strcmp(mode,"starts with") == 0) - if (match_case) - return to.FindFirst(from) == 0; - else - return to.IFindFirst(from) == 0; - else if (strcmp(mode,"ends with") == 0) - { - int32 pos; - if (match_case) - pos = to.FindLast(from); - else - pos = to.IFindLast(from); - - return (to.CountChars() - from.CountChars() == pos); - } - - return false; -} - - -status_t -MoveAction(const BMessage &action, entry_ref &ref) -{ - BString value; - status_t status; - status = action.FindString("value",&value); - if (status != B_OK) - return status; - value = ProcessPatterns(value.String(),ref); - - BEntry entry(value.String(),true); - status = entry.InitCheck(); - if (status != B_OK || (entry.Exists() && !entry.IsDirectory())) - return B_ERROR; - - if (!entry.Exists()) - create_directory(value.String(),0777); - - BEntry source(&ref); - status = source.InitCheck(); - if (status != B_OK) - return B_ERROR; - - status = MoveFile(&source,&entry,false); - if (status == B_OK) - { - printf("\tMoved %s to %s\n",ref.name,value.String()); - source.GetRef(&ref); - } - else - { - printf("\tCouldn't move %s to %s. Stopping here.\n\t\tError Message: %s\n",ref.name, - value.String(),strerror(status)); - } - - return B_OK; -} - - -status_t -CopyAction(const BMessage &action, entry_ref &ref) -{ - BString value; - status_t status; - status = action.FindString("value",&value); - if (status != B_OK) - return status; - value = ProcessPatterns(value.String(),ref); - - BEntry entry(value.String(),true); - status = entry.InitCheck(); - if (status != B_OK || (entry.Exists() && !entry.IsDirectory())) - return B_ERROR; - - if (!entry.Exists()) - create_directory(value.String(),0777); - - BEntry source(&ref); - status = source.InitCheck(); - if (status != B_OK) - return B_ERROR; - - status = CopyFile(&source,&entry,false); - if (status == B_OK) - { - printf("\tCopied %s to %s\n",ref.name,value.String()); - source.GetRef(&ref); - } - else - { - printf("\tCouldn't copy %s to %s. Stopping here.\n\t\tError Message: %s\n",ref.name, - value.String(),strerror(status)); - } - - - return B_OK; -} - - -status_t -RenameAction(const BMessage &action, entry_ref &ref) -{ - BString value; - status_t status; - status = action.FindString("value",&value); - if (status != B_OK) - return status; - value = ProcessPatterns(value.String(),ref); - - BEntry entry(value.String(),true); - status = entry.InitCheck(); - if (status != B_OK || entry.Exists()) - return B_ERROR; - - BEntry source(&ref); - status = source.InitCheck(); - if (status != B_OK) - return B_ERROR; - - status = source.Rename(value.String()); - if (status == B_OK) - { - printf("\tRenamed %s to %s\n",ref.name,value.String()); - source.GetRef(&ref); - } - else - { - printf("\tCouldn't rename %s to %s. Stopping here.\n\t\tError Message: %s\n",ref.name, - value.String(),strerror(status)); - } - - if (status == B_OK) - source.GetRef(&ref); - - return B_OK; -} - - -status_t -OpenAction(const BMessage &action, entry_ref &ref) -{ - entry_ref app; - BString appName(""); - if (be_roster->FindApp(&ref,&app) == B_OK) - appName = app.name; - - status_t status = be_roster->Launch(&ref); - - if (status == B_OK) - printf("\tOpened %s in program %s\n",ref.name,appName.String()); - else - { - // R5 (and probably others) don't seem to want to open folders in Tracker -- - // FindApp() returns B_OK, but sets the entry_ref of the app to open it to - // the folder's ref, which is dumb. This works around this apparent stupidity. - BString typestr; - if (BNode(&ref).ReadAttrString("BEOS:TYPE",&typestr) == B_OK && - typestr.Compare("application/x-vnd.Be-directory") == 0) - { - BMessage *msg = new BMessage(B_REFS_RECEIVED); - msg->AddRef("refs",&ref); - be_roster->Launch("application/x-vnd.Be-TRAK",msg); - printf("\tOpened %s in program Tracker\n",ref.name); - return B_OK; - } - if (appName.CountChars() > 0) - printf("\tCouldn't open %s in program %s\n",ref.name,appName.String()); - else - printf("\tCouldn't open %s -- the system couldn't find a program to do it.\n",ref.name); - } - - return status; -} - - -status_t -ArchiveAction(const BMessage &action, entry_ref &ref) -{ - BString value; - status_t status; - status = action.FindString("value",&value); - if (status != B_OK) - return status; - value = ProcessPatterns(value.String(),ref); - - BPath path(&ref); - BString parentstr = path.Path(); - parentstr.ReplaceLast(path.Leaf(),""); - - BString command = ""; - command << "cd '" << parentstr << "'; zip -9 -u -r '" << value << "' '" - << path.Leaf() << "'"; - - int result = system(command.String()); - if (result) - printf("\tCouldn't create archive %s\n\t\tError code: %d\n", value.String(),result); - else - printf("\tAdded %s to Archive %s\n",ref.name,value.String()); - - return B_OK; -} - - -status_t -CommandAction(const BMessage &action, entry_ref &ref) -{ - BString value; - status_t status; - status = action.FindString("value",&value); - if (status != B_OK) - return status; - value = ProcessPatterns(value.String(),ref); - - int result = system(value.String()); - if (result) - { - printf("\tTerminal Command: %s\n\t\tPossible error: command returned %d\n", - value.String(),result); - } - else - printf("\tTerminal Command: %s\n",value.String()); - - return B_OK; -} - - -status_t -TrashAction(const BMessage &action, entry_ref &ref) -{ - BPath path; - find_directory(B_TRASH_DIRECTORY, &path); - - BEntry entry(path.Path(), true); - status_t status = entry.InitCheck(); - if (status != B_OK || !entry.Exists() || !entry.IsDirectory()) - return B_ERROR; - - BEntry source(&ref); - status = source.InitCheck(); - if (status != B_OK) - return B_ERROR; - - status = MoveFile(&source,&entry,false); - if (status == B_OK) - { - printf("\tMoved %s to the Trash\n",ref.name); - source.GetRef(&ref); - } - else - { - printf("\tCouldn't move %s to the Trash. Stopping here.\n\t\tError Message: %s\n", - ref.name,strerror(status)); - } - - return B_OK; -} - - -status_t -DeleteAction(const BMessage &action, entry_ref &ref) -{ - BEntry entry(&ref); - - status_t status = entry.Remove(); - if (status == B_OK) - printf("\tDeleted %s\n",BPath(ref.name).Path()); - else - { - printf("\tCouldn't delete %s. Stopping here.\n\t\tError Message: %s\n", - BPath(ref.name).Path(),strerror(status)); - } - - return entry.Remove(); -} - - -status_t -SaveRules(BObjectList *ruleList) -{ - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY, &path); - - status_t ret = path.Append("Filer"); - if (ret == B_OK) - ret = create_directory(path.Path(), 0777); - - if (ret == B_OK) - ret = path.Append("FilerRules"); - - if (ret == B_OK) { - BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); - ret = file.InitCheck(); - } - if (ret != B_OK) - return(ret); - - BEntry entry(path.Path()); - if (entry.Exists()) - entry.Remove(); - - CppSQLite3DB db; - db.open(path.Path()); - - // While we could use other means of obtaining table names, this table is also - // used for maintaining the order of the rules, which must be preserved - DBCommand(db,"create table RuleList (ruleid int primary key, name varchar);", - "PrefsWindow::SaveRules"); - - BString command; - - for (int32 i = 0; i < ruleList->CountItems(); i++) - { - FilerRule *rule = ruleList->ItemAt(i); - - // Test table: - // 0) Entry type (test vs action) - // 1) type - // 2) mode - // 3) value - // 4) attribute type (if Attribute test) - // 5) attribute type public name (short description) - // 6) attribute public name (if Attribute test) - - BString tablename(EscapeIllegalCharacters(rule->GetDescription())); - - command = "create table "; - command << tablename - << "(entrytype varchar, testtype varchar, testmode varchar, testvalue varchar, - attrtype varchar, attrtypename varchar, attrpublicname varchar);"; - DBCommand(db,command.String(), "PrefsWindow::SaveRules"); - - command = "insert into RuleList values("; - command << i << ",'" << tablename << "');"; - DBCommand(db,command.String(), "PrefsWindow::SaveRules"); - - for (int32 j = 0; j < rule->CountTests(); j++) - { - BMessage *test = rule->TestAt(j); - if (!test) - continue; - - BString name,mode,value,mimeType,typeName, attrType, attrName; - test->FindString("name",&name); - test->FindString("mode",&mode); - test->FindString("value",&value); - test->FindString("mimetype",&mimeType); - test->FindString("typename",&typeName); - test->FindString("attrtype",&attrType); - test->FindString("attrname",&attrName); - - command = "insert into "; - command << tablename << " values('test', '" << EscapeIllegalCharacters(name.String()) - << "', '" << EscapeIllegalCharacters(mode.String()) - << "', '" << EscapeIllegalCharacters(value.String()) - << "', '" << EscapeIllegalCharacters(mimeType.String()) - << "', '" << EscapeIllegalCharacters(typeName.String()) - << "', '" << EscapeIllegalCharacters(attrName.String()) - << "');"; - - DBCommand(db,command.String(),"PrefsWindow::SaveRules:save test"); - } - - for (int32 j = 0; j < rule->CountActions(); j++) - { - BMessage *action = rule->ActionAt(j); - if (!action) - continue; - - BString name,value; - action->FindString("name",&name); - action->FindString("value",&value); - - command = "insert into "; - command << tablename << " values('action', '" << EscapeIllegalCharacters(name.String()) - << "', '" - << "', '" << EscapeIllegalCharacters(value.String()) - << "', '', '', '');"; - DBCommand(db,command.String(),"PrefsWindow::SaveRules:save action"); - } - } - - - db.close(); - - return B_OK; -} - - -status_t -LoadRules(BObjectList *ruleList) -{ - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY, &path); - path.Append("Filer/FilerRules"); - - BEntry entry(path.Path()); - if (!entry.Exists()) - return B_OK; - - CppSQLite3DB db; - db.open(path.Path()); - - // Because this particular build of sqlite3 does not support multithreading - // because of lack of pthreads support, we need to do this in a slightly different order - - CppSQLite3Query query; - query = DBQuery(db,"select name from RuleList order by ruleid;","PrefsWindow::LoadRules"); - - BString command; - while (!query.eof()) - { - BString rulename = query.getStringField((int)0); - - FilerRule *rule = new FilerRule; - rule->SetDescription(DeescapeIllegalCharacters(rulename.String()).String()); - - ruleList->AddItem(rule); - - query.nextRow(); - } - - query.finalize(); - - for (int32 i = 0; i < ruleList->CountItems(); i++) - { - FilerRule *rule = ruleList->ItemAt(i); - - if (!rule) - continue; - - BString rulename(EscapeIllegalCharacters(rule->GetDescription())); - - // Now comes the fun(?) part: loading the tests and actions. Joy. :/ - command = "select * from "; - command << rulename << " where entrytype = 'test';"; - query = DBQuery(db,command.String(),"PrefsWindow::LoadRules"); - - while (!query.eof()) - { - BString classname = DeescapeIllegalCharacters(query.getStringField(1)); - BMessage *test = new BMessage; - - test->AddString("name",classname); - - if (classname.ICompare("Attribute") == 0) - { - test->AddString("mimetype",DeescapeIllegalCharacters(query.getStringField(4))); - test->AddString("typename",DeescapeIllegalCharacters(query.getStringField(5))); - test->AddString("attrname",DeescapeIllegalCharacters(query.getStringField(6))); - } - - test->AddString("mode",DeescapeIllegalCharacters(query.getStringField(2)).String()); - test->AddString("value",DeescapeIllegalCharacters(query.getStringField(3)).String()); - - rule->AddTest(test); - - query.nextRow(); - } - query.finalize(); - - command = "select * from "; - command << rulename << " where entrytype = 'action';"; - query = DBQuery(db,command.String(),"PrefsWindow::LoadRules"); - - while (!query.eof()) - { - BMessage *action = new BMessage; - - action->AddString("name",DeescapeIllegalCharacters(query.getStringField(1))); - action->AddString("value",DeescapeIllegalCharacters(query.getStringField(3))); - - rule->AddAction(action); - - query.nextRow(); - } - query.finalize(); - - } - - db.close(); - return B_OK; -} - -BMessage * -MakeTest(const char *name,const char *mode, const char *value, const char *mimeType, - const char *typeName, const char *attrType, const char *attrName) -{ - BMessage *msg = new BMessage; - msg->AddString("name",name); - msg->AddString("mode",mode); - msg->AddString("value",value); - - if (typeName || mimeType || attrType || attrName) - { - if(!(typeName && mimeType && attrType && attrName)) - debugger("The last 4 parameters must all be either NULL or non-NULL as a group"); - - msg->AddString("typename",typeName); - msg->AddString("mimetype",mimeType); - msg->AddString("attrtype",attrType); - msg->AddString("attrname",attrName); - } - return msg; -} - - -BMessage * -MakeAction(const char *name,const char *value) -{ - BMessage *msg = new BMessage; - msg->AddString("name",name); - msg->AddString("value",value); - - return msg; -} diff --git a/sources/Filer/RuleRunner.h b/sources/Filer/RuleRunner.h deleted file mode 100644 index fd18f75..0000000 --- a/sources/Filer/RuleRunner.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - RuleRunner.h: class to handle running test and actions for the rules - Released under the MIT license. - Written by DarkWyrm , Copyright 2008 - Contributed by: Humdinger , 2016 -*/ -#ifndef RULERUNNER_H -#define RULERUNNER_H - -#include "FilerRule.h" -#include "ObjectList.h" - -#include -#include - -enum -{ - TEST_TYPE_NULL = 0, - TEST_TYPE_STRING, - TEST_TYPE_NUMBER, - TEST_TYPE_DATE, - TEST_TYPE_ANY -}; - - -class RuleRunner -{ -public: - RuleRunner(void); - ~RuleRunner(void); - - static void GetTestTypes(BMessage &msg); - static status_t GetCompatibleModes(const char *testtype, BMessage &msg); - static status_t GetCompatibleModes(const int32 &type, BMessage &msg); - static void GetModes(BMessage &msg); - static void GetActions(BMessage &msg); - - static BString GetEditorTypeForTest(const char *testname); - - static int32 GetDataTypeForTest(const char *testname); - static int32 GetDataTypeForMode(const char *modename); - - bool IsMatch(const BMessage &test, const entry_ref &ref); - status_t RunAction(const BMessage &test, entry_ref &ref); - status_t RunRule(FilerRule *rule, entry_ref &ref); -}; - -status_t LoadRules(BObjectList *ruleList); -status_t SaveRules(BObjectList *ruleList); - - -// Some convenience functions. Deleting the returned BMessage is the -// responsibility of the caller -BMessage * MakeTest(const char *name,const char *mode, const char *value, - const char *mimeType = NULL, const char *typeName = NULL, - const char *attrType = NULL, const char *attrName = NULL); -BMessage * MakeAction(const char *name,const char *value); - -#endif diff --git a/sources/Filer/TestView.h b/sources/Filer/TestView.h deleted file mode 100644 index 80f4a30..0000000 --- a/sources/Filer/TestView.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - TestView.h: view to display and edit settings for Filer tests - Written by DarkWyrm , Copyright 2008 - Released under the MIT license. -*/ -#ifndef TESTVIEW_H -#define TESTVIEW_H - -#include -#include -#include -#include -#include -#include -#include - -class AutoTextControl; - -class TestView : public BView -{ -public: - TestView(const BRect &frame,const char *name, - BMessage *test = NULL, - const int32 &resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, - const int32 &flags = B_WILL_DRAW); - void AttachedToWindow(void); - BRect GetPreferredSize(void); - void ResizeToPreferred(void); - void MessageReceived(BMessage *msg); - BMessage * GetTest(void) const; - -private: - - void SetupTestMenu(void); - void ShowModeMenu(void); - bool SetTest(BMessage *msg); - void SetMode(const char *mode); - const char *GetValue(void); - - BMenu * AddMenuSorted(BMenu *parent,const char *name); - BMenu * GetMenu(BMenu *parent,const char *name); - - BButton *fTestButton, - *fModeButton; - - BMessage fArchivedTestMenu; - - AutoTextControl *fValueBox; - - BMessage *fTest; - BMessage fTestTypes; - -}; - -#endif diff --git a/sources/Filer/main.h b/sources/Filer/main.h deleted file mode 100644 index 4ae743d..0000000 --- a/sources/Filer/main.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - Filer - an automatic rule-based file organizer - - Written by DarkWyrm , Copyright 2008 - Released under the MIT license. -*/ -#ifndef MAIN_H -#define MAIN_H - -#include -#include -#include -#include "ObjectList.h" - -class FilerRule; -class PrefsWindow; - -class App : public BApplication -{ -public: - App(void); - ~App(void); - void MessageReceived(BMessage *msg); - void RefsReceived(BMessage *msg); - void ArgvReceived(int32 argc, char **argv); - void ReadyToRun(void); - void SetupTypeMenu(void); - - // Filing-related functions - void FileRef(entry_ref ref); - -private: - BObjectList *fRefList; - BObjectList *fRuleList; - PrefsWindow *fPrefsWin; - - bool fQuitRequested; -}; - -#endif diff --git a/sources/FilerDefs.h b/sources/FilerDefs.h new file mode 100644 index 0000000..b3bdd63 --- /dev/null +++ b/sources/FilerDefs.h @@ -0,0 +1,59 @@ +/* + * Copyright 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Humdinger, humdingerb@gmail.com + */ + +#ifndef FILERDEFS_H +#define FILERDEFS_H + +static const char *kFilerSignature = "application/x-vnd.dw-Filer"; +static const char *kAutoFilerSignature = "application/x-vnd.dw-AutoFiler"; +static const char kSettingsFolder[] = "Filer"; +static const char kSettingsFile[] = "Filer_settings"; + +#define MSG_DOCS 'docs' +#define MSG_HELP 'help' +#define MSG_TYPE_CHOSEN 'tych' +#define MSG_NEW_DESCRIPTION 'dsch' +#define MSG_OK 'okay' +#define MSG_CANCEL 'cncl' + +#define MSG_ADD_TEST 'adts' +#define MSG_REMOVE_TEST 'rmts' +#define MSG_ADD_ACTION 'adac' +#define MSG_REMOVE_ACTION 'rmac' +#define MSG_ADD_RULE 'adrl' +#define MSG_UPDATE_RULE 'uprl' +#define MSG_FORCE_QUIT 'frcq' + +#define MSG_SHOW_ADD_WINDOW 'shaw' +#define MSG_SHOW_EDIT_WINDOW 'shew' +#define MSG_REMOVE_RULE 'shrr' +#define MSG_REVERT 'rvrt' +#define MSG_RULE_SELECTED 'rlsl' +#define MSG_MOVE_RULE_UP 'mvup' +#define MSG_MOVE_RULE_DOWN 'mvdn' + +#define MSG_STARTSTOP_AUTOFILER 'ssaf' +#define MSG_UPDATE_LABEL 'upla' +#define MSG_SHOW_ADD_PANEL 'shap' +#define MSG_SHOW_EDIT_PANEL 'shep' +#define MSG_REMOVE_FOLDER 'rmfl' +#define MSG_FOLDER_SELECTED 'flsl' +#define MSG_FOLDER_CHOSEN 'flch' +#define MSG_REFRESH_FOLDERS 'flrf' + +#define MSG_ACTION_CHOSEN 'tsch' +#define MSG_SHOW_ACTION_MENU 'sham' +#define MSG_VALUE_CHANGED 'vlch' + +#define MSG_TEST_CHOSEN 'tsch' +#define MSG_MODE_CHOSEN 'mdch' +#define MSG_SHOW_TEST_MENU 'shtm' +#define MSG_SHOW_TYPE_MENU 'stym' +#define MSG_SHOW_MODE_MENU 'shmm' + +#endif // FILERDEFS_H diff --git a/sources/Filer/FilerRule.cpp b/sources/FilerRule.cpp similarity index 57% rename from sources/Filer/FilerRule.cpp rename to sources/FilerRule.cpp index 422aa5a..a8c50d4 100644 --- a/sources/Filer/FilerRule.cpp +++ b/sources/FilerRule.cpp @@ -5,37 +5,40 @@ Written by DarkWyrm , Copyright 2008 Released under the MIT license. */ + #include "FilerRule.h" static int64 sIDCounter = 0; -FilerRule::FilerRule(void) - : fTestList(NULL), +FilerRule::FilerRule() + : + fTestList(NULL), fActionList(NULL), fMode(FILER_RULE_ALL) { - fTestList = new BObjectList(20,true); - fActionList = new BObjectList(20,true); - + fTestList = new BObjectList(20, true); + fActionList = new BObjectList(20, true); + fID = sIDCounter++; } -FilerRule::FilerRule(FilerRule &rule) - : fTestList(NULL), +FilerRule::FilerRule(FilerRule& rule) + : + fTestList(NULL), fActionList(NULL), fMode(FILER_RULE_ALL) { - fTestList = new BObjectList(20,true); - fActionList = new BObjectList(20,true); - + fTestList = new BObjectList(20, true); + fActionList = new BObjectList(20, true); + fID = sIDCounter++; - + *this = rule; } -FilerRule::~FilerRule(void) +FilerRule::~FilerRule() { delete fTestList; delete fActionList; @@ -43,90 +46,90 @@ FilerRule::~FilerRule(void) void -FilerRule::SetRuleMode(const filer_rule_mode &mode) +FilerRule::SetRuleMode(const filer_rule_mode& mode) { fMode = mode; } -const char * -FilerRule::GetDescription(void) const +const char* +FilerRule::GetDescription() const { return fDescription.String(); } void -FilerRule::SetDescription(const char *desc) +FilerRule::SetDescription(const char* desc) { fDescription = desc; } void -FilerRule::AddTest(BMessage *item, const int32 &index) +FilerRule::AddTest(BMessage* item, const int32& index) { if (index < 0) fTestList->AddItem(item); else - fTestList->AddItem(item,index); + fTestList->AddItem(item, index); } -BMessage * -FilerRule::RemoveTest(const int32 &index) +BMessage* +FilerRule::RemoveTest(const int32& index) { return fTestList->RemoveItemAt(index); } -BMessage * -FilerRule::TestAt(const int32 &index) +BMessage* +FilerRule::TestAt(const int32& index) { return fTestList->ItemAt(index); } int32 -FilerRule::CountTests(void) const +FilerRule::CountTests() const { return fTestList->CountItems(); } void -FilerRule::AddAction(BMessage *item, const int32 &index) +FilerRule::AddAction(BMessage* item, const int32& index) { if (index < 0) fActionList->AddItem(item); else - fActionList->AddItem(item,index); + fActionList->AddItem(item, index); } -BMessage * -FilerRule::RemoveAction(const int32 &index) +BMessage* +FilerRule::RemoveAction(const int32& index) { return fActionList->RemoveItemAt(index); } -BMessage * -FilerRule::ActionAt(const int32 &index) +BMessage* +FilerRule::ActionAt(const int32& index) { return fActionList->ItemAt(index); } int32 -FilerRule::CountActions(void) const +FilerRule::CountActions() const { return fActionList->CountItems(); } void -FilerRule::MakeEmpty(void) +FilerRule::MakeEmpty() { fTestList->MakeEmpty(); fActionList->MakeEmpty(); @@ -134,39 +137,39 @@ FilerRule::MakeEmpty(void) void -FilerRule::PrintToStream(void) +FilerRule::PrintToStream() { - printf("Filer Rule '%s':\n",GetDescription()); + printf("Filer Rule '%s':\n", GetDescription()); for (int32 i = 0; i < fTestList->CountItems(); i++) fTestList->ItemAt(i)->PrintToStream(); - + for (int32 i = 0; i < fActionList->CountItems(); i++) fActionList->ItemAt(i)->PrintToStream(); } -FilerRule & -FilerRule::operator=(FilerRule &from) +FilerRule& +FilerRule::operator=(FilerRule& from) { MakeEmpty(); for (int32 i = 0; i < from.CountTests(); i++) { - BMessage *test = from.TestAt(i); + BMessage* test = from.TestAt(i); if (test) AddTest(new BMessage(*test)); } - + for (int32 i = 0; i < from.CountActions(); i++) { - BMessage *action = from.ActionAt(i); + BMessage* action = from.ActionAt(i); if (action) AddAction(new BMessage(*action)); } - + SetDescription(from.GetDescription()); SetRuleMode(from.GetRuleMode()); - + return *this; } diff --git a/sources/FilerRule.h b/sources/FilerRule.h new file mode 100644 index 0000000..7dd1a31 --- /dev/null +++ b/sources/FilerRule.h @@ -0,0 +1,63 @@ +/* + FilerRule.h: The main filing class for Filer. It holds a list of both test + conditions and one or more actions to be performed should the + conditions be met. + Written by DarkWyrm , Copyright 2008 + Released under the MIT license. +*/ + +#ifndef FILER_RULE_H +#define FILER_RULE_H + +#include +#include +#include +#include + +#include "ObjectList.h" + +typedef enum +{ + FILER_RULE_ALL = 0, + FILER_RULE_ANY +} filer_rule_mode; + + +class FilerRule : public BArchivable +{ +public: + FilerRule(); + FilerRule(FilerRule& rule); + ~FilerRule(); + + void SetRuleMode(const filer_rule_mode& mode); + filer_rule_mode GetRuleMode() const { return fMode; } + + const char* GetDescription() const; + void SetDescription(const char* desc); + + void AddTest(BMessage* item, const int32& index = -1); + BMessage* RemoveTest(const int32& index); + BMessage* TestAt(const int32& index); + int32 CountTests() const; + + void AddAction(BMessage* action, const int32& index = -1); + BMessage* RemoveAction(const int32& index); + BMessage* ActionAt(const int32& index); + int32 CountActions() const; + + void MakeEmpty(); + virtual void PrintToStream(); + FilerRule& operator=(FilerRule& from); + + int64 GetID() const { return fID; } + +private: + BObjectList* fTestList; + BObjectList* fActionList; + filer_rule_mode fMode; + BString fDescription; + int64 fID; +}; + +#endif // FILER_RULE_H diff --git a/sources/Filer/FilerTypes.h b/sources/FilerTypes.h similarity index 85% rename from sources/Filer/FilerTypes.h rename to sources/FilerTypes.h index 9828cbf..fd16a4e 100644 --- a/sources/Filer/FilerTypes.h +++ b/sources/FilerTypes.h @@ -8,4 +8,4 @@ typedef enum FILER_NULL_TYPE } filer_data_type; -#endif +#endif // FILER_TYPES_H diff --git a/sources/HelpTab.cpp b/sources/HelpTab.cpp new file mode 100644 index 0000000..d449e01 --- /dev/null +++ b/sources/HelpTab.cpp @@ -0,0 +1,190 @@ +/* + * Copyright 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Humdinger, humdingerb@gmail.com + */ + +#include +#include +#include +#include + +#include "FilerDefs.h" +#include "HelpTab.h" +#include "main.h" + +IconView::IconView() + : + BView("iconview", B_WILL_DRAW | B_SUPPORTS_LAYOUT), + fIcon(NULL) +{ + GetIcon(); +} + + +IconView::~IconView() +{ +} + + +void +IconView::Draw(BRect updateRect) +{ + if (fIcon == NULL) + return; + + SetDrawingMode(B_OP_ALPHA); + SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + DrawBitmapAsync(fIcon, BPoint(0, 0)); +} + + +void +IconView::AttachedToWindow() +{ + SetViewUIColor(B_PANEL_BACKGROUND_COLOR); + + BView::AttachedToWindow(); +} + + +BBitmap* +IconView::Icon() +{ + return fIcon; +} + + +BSize +IconView::MinSize() +{ + return BSize(64.0, 64.0); +} + + +BSize +IconView::MaxSize() +{ + return BSize(64.0, 64.0); +} + + +void +IconView::GetIcon() +{ + BResources* resources = BApplication::AppResources(); + + if (resources != NULL) { + size_t size; + const uint8* data + = (const uint8*)resources->LoadResource(B_VECTOR_ICON_TYPE, + "BEOS:ICON", &size); + fIcon = new BBitmap(BRect(0, 0, 64, 64), 0, B_RGBA32); + if (fIcon != NULL) { + if (data == NULL + || BIconUtils::GetVectorIcon(data, size, fIcon) + != B_OK) { + delete fIcon; + fIcon = NULL; + } + } + } +} + + +HelpTab::HelpTab() + : + BView("Help", B_SUPPORTS_LAYOUT) +{ + // Icon + fIconView = new IconView(); + + // About info + fName = new BStringView("name", "Filer"); + BFont font; + fName->GetFont(&font); + font.SetFace(B_BOLD_FACE); + font.SetSize(font.Size() * 2.0); + fName->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE + | B_FONT_FLAGS); + fName->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + + fVersion = new BStringView("version", "v1.1.0"); + fVersion->GetFont(&font); + font.SetFace(B_REGULAR_FACE); + font.SetSize(font.Size() * 0.9); + fVersion->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE + | B_FONT_FLAGS); + fVersion->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + + fCopyright1 = new BStringView("copy1", "Copyright 2008, DarkWyrm"); + fCopyright2 = new BStringView("copy2", "Copyright 2016, Humdinger"); + fCopyright1->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE + | B_FONT_FLAGS); + fCopyright2->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE + | B_FONT_FLAGS); + fCopyright1->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + fCopyright2->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + + fInfo = new BTextView("info"); + fInfo->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); + fInfo->MakeEditable(false); + fInfo->SetWordWrap(true); + fInfo->SetStylable(true); + fInfo->SetText("Filer is an automatic file organizer. It takes the " + "files it's opened with or that are dropped on it and moves, " + "renames, copies or does all sorts of other things with them " + "according to rules created by the user."); + + // work-around for misbehaving BTextView: the other GUI elements treat it + // as it were only one line high. + float minHeight, maxHeight, prefHeight; + fInfo->GetHeightForWidth(300.0, &minHeight, &maxHeight, &prefHeight); + fInfo->SetExplicitMinSize(BSize(30.0, minHeight)); + fInfo->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + fInfo->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP)); + + // Buttons + fHelpButton = new BButton("help", "Help on rules", + new BMessage(MSG_HELP)); + fHelpButton->SetTarget(be_app); + + fDocsButton = new BButton("docs", "User documentation", + new BMessage(MSG_DOCS)); + fDocsButton->SetTarget(be_app); + + // Laying it all out + static const float spacing = be_control_look->DefaultItemSpacing(); + BLayoutBuilder::Group<>(this, B_HORIZONTAL) + .SetInsets(B_USE_WINDOW_INSETS) + .AddGroup(B_VERTICAL, 0) + .SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP)) + .SetInsets(0, spacing / 2, 0, 0) + .Add(fIconView) + .End() + .AddGroup(B_VERTICAL, 0) + .Add(fName) + .Add(fVersion) + .Add(fCopyright1) + .Add(fCopyright2) + .AddStrut(spacing) + .Add(fInfo, 0) + .AddStrut(spacing) + .AddGroup(B_HORIZONTAL) + .AddGlue() + .Add(fHelpButton) + .Add(fDocsButton) + .AddGlue() + .End() + .AddGlue(100.0) + .End(); + + SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); +} + + +HelpTab::~HelpTab() +{ +} diff --git a/sources/HelpTab.h b/sources/HelpTab.h new file mode 100644 index 0000000..4f972f7 --- /dev/null +++ b/sources/HelpTab.h @@ -0,0 +1,53 @@ +/* + * Copyright 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Humdinger, humdingerb@gmail.com + */ + +#ifndef HELPTAB_H +#define HELPTAB_H + +#include +#include +#include +#include +#include + +class IconView : public BView { +public: + IconView(); + ~IconView(); + + void AttachedToWindow(); + virtual void Draw(BRect updateRect); + virtual BSize MinSize(); + virtual BSize MaxSize(); + +private: + void GetIcon(); + BBitmap* Icon(); + + BBitmap* fIcon; +}; + + +class HelpTab : public BView +{ +public: + HelpTab(); + ~HelpTab(); +private: + IconView* fIconView; + BStringView* fName; + BStringView* fVersion; + BStringView* fCopyright1; + BStringView* fCopyright2; + BTextView* fInfo; + + BButton* fHelpButton; + BButton* fDocsButton; +}; + +#endif // HELPTAB_H diff --git a/sources/MainWindow.cpp b/sources/MainWindow.cpp new file mode 100644 index 0000000..8cc0c5a --- /dev/null +++ b/sources/MainWindow.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Humdinger, humdingerb@gmail.com + */ + +#include +#include +#include +#include +#include + +#include "MainWindow.h" + + +MainWindow::MainWindow() + : + BWindow(BRect(), ("Filer"), + B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS) +{ + _BuildLayout(); + + LoadSettings(); + + MoveTo(fPosition.left, fPosition.top); + ResizeTo(fPosition.Width(), fPosition.Height()); + + if (fPosition == BRect(-1, -1, -1, -1)) { + CenterOnScreen(); + ResizeTo(350, 250); + } else { + // make sure window is on screen + BScreen screen(this); + if (!screen.Frame().InsetByCopy(10, 10).Intersects(Frame())) + CenterOnScreen(); + } + + fTabView->Select(fTabSelection); +} + + +MainWindow::~MainWindow() +{ +} + + +bool +MainWindow::QuitRequested() +{ + SaveSettings(); + + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + + +void +MainWindow::_BuildLayout() +{ + // The tabview + fTabView = new BTabView("tabview", B_WIDTH_FROM_WIDEST); + fTabView->SetBorder(B_NO_BORDER); + fTabView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); + + fDropZone = new DropZoneTab(); + fRules = new RuleTab(); + fAutoFiler = new AutoFilerTab(); + fHelp = new HelpTab(); + + fTabView->AddTab(fDropZone); + fTabView->AddTab(fRules); + fTabView->AddTab(fAutoFiler); + fTabView->AddTab(fHelp); + + // do the layouting + BLayoutBuilder::Group<>(this, B_VERTICAL, 0) + .AddGroup(B_VERTICAL) + .SetInsets(0, B_USE_DEFAULT_SPACING, 0, 0) + .Add(fTabView) + .End(); + + fTabView->SetViewColor(B_TRANSPARENT_COLOR); +} + + +void +MainWindow::MessageReceived(BMessage* msg) +{ +// msg->PrintToStream(); + switch (msg->what) + { + default: + { + BWindow::MessageReceived(msg); + break; + } + } +} + +void +MainWindow::LoadSettings() +{ + fPosition.Set(-1, -1, -1, -1); + fTabSelection = 0; + + BPath path; + BMessage msg; + + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) { + status_t ret = path.Append(kSettingsFolder); + if (ret == B_OK) { + path.Append(kSettingsFile); + BFile file(path.Path(), B_READ_ONLY); + + if ((file.InitCheck() == B_OK) && (msg.Unflatten(&file) == B_OK)) { + if (msg.FindRect("pos", &fPosition) != B_OK) + fPosition.Set(-1, -1, -1, -1); + if (msg.FindInt32("tab", &fTabSelection) != B_OK) + fTabSelection = 0; + } + } + } +} + + +void +MainWindow::SaveSettings() +{ + BRect pos = Frame(); + int32 tab = fTabView->Selection(); + if (pos == fPosition && tab == fTabSelection) + return; + + BPath path; + BMessage msg; + + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) < B_OK) + return; + status_t ret = path.Append(kSettingsFolder); + + if (ret == B_OK) + ret = create_directory(path.Path(), 0777); + + if (ret == B_OK) + path.Append(kSettingsFile); + + if (ret == B_OK) { + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); + ret = file.InitCheck(); + + if (ret == B_OK) { + msg.AddRect("pos", pos); + msg.AddInt32("tab", tab); + msg.Flatten(&file); + } + } +} diff --git a/sources/MainWindow.h b/sources/MainWindow.h new file mode 100644 index 0000000..c6049ce --- /dev/null +++ b/sources/MainWindow.h @@ -0,0 +1,53 @@ +/* + * Copyright 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Humdinger, humdingerb@gmail.com + */ + +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AutoFilerTab.h" +#include "DropZoneTab.h" +#include "FilerDefs.h" +#include "HelpTab.h" +#include "RuleTab.h" + +#include + + +class MainWindow : public BWindow { +public: + MainWindow(); + virtual ~MainWindow(); + + bool QuitRequested(); + void MessageReceived(BMessage* msg); + +private: + void _BuildLayout(); + void LoadSettings(); + void SaveSettings(); + + BRect fPosition; + int32 fTabSelection; + + BTabView* fTabView; + DropZoneTab* fDropZone; + RuleTab* fRules; + AutoFilerTab* fAutoFiler; + HelpTab* fHelp; +}; + +#endif // MAIN_WINDOW_H diff --git a/sources/Filer/Makefile b/sources/Makefile similarity index 92% rename from sources/Filer/Makefile rename to sources/Makefile index 5d3ae48..250f0ae 100644 --- a/sources/Filer/Makefile +++ b/sources/Makefile @@ -28,9 +28,10 @@ APP_MIME_SIG = application/x-vnd.dw-Filer # means this Makefile will not work correctly if two source files with the # same name (source.c or source.cpp) are included from different directories. # Also note that spaces in folder names do not work well with this Makefile. -SRCS = FilerRule.cpp FSUtils.cpp main.cpp PatternProcessor.cpp RuleRunner.cpp \ - ActionView.cpp AutoTextControl.cpp CppSQLite3.cpp Database.cpp \ - PrefsWindow.cpp RuleEditWindow.cpp RuleItem.cpp TestView.cpp +SRCS = AutoFilerTab.cpp FilerRule.cpp FSUtils.cpp main.cpp PatternProcessor.cpp \ + RuleRunner.cpp ActionView.cpp AutoTextControl.cpp CppSQLite3.cpp Database.cpp \ + DropZoneTab.cpp HelpTab.cpp MainWindow.cpp RefStorage.cpp ReplicantWindow.cpp \ + RuleEditWindow.cpp RuleItem.cpp RuleTab.cpp TypedRefFilter.cpp TestView.cpp # Specify the resource definition files to use. Full or relative paths can be # used. @@ -56,7 +57,7 @@ RSRCS = # - if your library does not follow the standard library naming scheme, # you need to specify the path to the library and it's name. # (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a") -LIBS = be translation $(STDCPPLIBS) sqlite3 +LIBS = be tracker translation $(STDCPPLIBS) sqlite3 # Specify additional paths to directories following the standard libXXX.so # or libXXX.a naming scheme. You can specify full paths or paths relative @@ -103,7 +104,7 @@ SYMBOLS := # Includes debug information, which allows the binary to be debugged easily. # If set to "TRUE", debug info will be created. -DEBUGGER := +DEBUGGER := # Specify any additional compiler flags to be used. COMPILER_FLAGS = -Woverloaded-virtual -funsigned-bitfields -Wwrite-strings diff --git a/sources/AutoFiler/Makefile b/sources/Makefile_AutoFiler similarity index 100% rename from sources/AutoFiler/Makefile rename to sources/Makefile_AutoFiler diff --git a/sources/AutoFiler/ObjectList.h b/sources/ObjectList.h similarity index 100% rename from sources/AutoFiler/ObjectList.h rename to sources/ObjectList.h diff --git a/sources/Filer/PatternProcessor.cpp b/sources/PatternProcessor.cpp similarity index 57% rename from sources/Filer/PatternProcessor.cpp rename to sources/PatternProcessor.cpp index 274dc24..1e89444 100644 --- a/sources/Filer/PatternProcessor.cpp +++ b/sources/PatternProcessor.cpp @@ -3,13 +3,16 @@ Written by DarkWyrm , Copyright 2008 Released under the MIT license. */ + #include "PatternProcessor.h" -#include -#include + #include #include #include + #include +#include +#include /* Patterns in Filer @@ -33,71 +36,62 @@ %TIME% - The current time %ATTR:xxxx% - An attribute of the file. Note that this needs to be the internal name of the attributes, such as META:email - - */ BString -ProcessPatterns(const char *instr, const entry_ref &ref) +ProcessPatterns(const char* instr, const entry_ref& ref) { if (!instr) return BString(); - + BString outstr(instr); - - + // Handle filename-based patterns - BString basename(ref.name), extension; - + int32 strpos = basename.FindFirst("."); - if (strpos >= 0) - { + if (strpos >= 0) { extension = basename.String() + strpos; basename.Truncate(strpos); } - - outstr.ReplaceAll("%FILENAME%",ref.name); - outstr.ReplaceAll("%BASENAME%",basename.String()); - outstr.ReplaceAll("%EXTENSION%",extension.String()); - + + outstr.ReplaceAll("%FILENAME%", ref.name); + outstr.ReplaceAll("%BASENAME%", basename.String()); + outstr.ReplaceAll("%EXTENSION%", extension.String()); + BString pathstr = BPath(&ref).Path(); - outstr.ReplaceAll("%FULLPATH%",pathstr.String()); - + outstr.ReplaceAll("%FULLPATH%", pathstr.String()); + pathstr.ReplaceLast(BPath(&ref).Leaf(),""); - outstr.ReplaceAll("%FOLDER%",pathstr.String()); - + outstr.ReplaceAll("%FOLDER%", pathstr.String()); + // Date-based patterns time_t currenttime = time(NULL); struct tm timedata = *localtime(¤ttime); - + char timestr[64]; - if (outstr.FindFirst("%DATE%") >= 0) - { - sprintf(timestr,"%.2d-%.2d-%d",timedata.tm_mday,timedata.tm_mon + 1, - timedata.tm_year + 1900); - outstr.ReplaceAll("%DATE%",timestr); + if (outstr.FindFirst("%DATE%") >= 0) { + sprintf(timestr,"%.2d-%.2d-%d",timedata.tm_mday, timedata.tm_mon + 1, + timedata.tm_year + 1900); + outstr.ReplaceAll("%DATE%", timestr); } - - if (outstr.FindFirst("%EURODATE%") >= 0) - { - sprintf(timestr,"%.2d-%.2d-%d",timedata.tm_mon + 1,timedata.tm_mday, - timedata.tm_year + 1900); - outstr.ReplaceAll("%EURODATE%",timestr); + + if (outstr.FindFirst("%EURODATE%") >= 0) { + sprintf(timestr,"%.2d-%.2d-%d",timedata.tm_mon + 1, timedata.tm_mday, + timedata.tm_year + 1900); + outstr.ReplaceAll("%EURODATE%", timestr); } - - if (outstr.FindFirst("%REVERSEDATE%") >= 0) - { - sprintf(timestr,"%d-%.2d-%.2d",timedata.tm_year + 1900,timedata.tm_mon + 1, - timedata.tm_mday); - outstr.ReplaceAll("%REVERSEDATE%",timestr); + + if (outstr.FindFirst("%REVERSEDATE%") >= 0) { + sprintf(timestr,"%d-%.2d-%.2d",timedata.tm_year + 1900, + timedata.tm_mon + 1, timedata.tm_mday); + outstr.ReplaceAll("%REVERSEDATE%", timestr); } - - if (outstr.FindFirst("%TIME%") >= 0) - { - sprintf(timestr,"%.2d:%.2d:%.2d",timedata.tm_hour,timedata.tm_min, - timedata.tm_sec); - outstr.ReplaceAll("%TIME%",timestr); + + if (outstr.FindFirst("%TIME%") >= 0) { + sprintf(timestr,"%.2d:%.2d:%.2d",timedata.tm_hour, timedata.tm_min, + timedata.tm_sec); + outstr.ReplaceAll("%TIME%", timestr); } // Attribute-based patterns @@ -105,48 +99,40 @@ ProcessPatterns(const char *instr, const entry_ref &ref) while (strpos >= 0) { int32 strendpos = outstr.FindFirst("%",strpos + 1); - if (strendpos >= 0) - { - BString string,attrname, attrpattern; + if (strendpos >= 0) { + BString string, attrname, attrpattern; attrname = outstr.String() + strpos; - + attrpattern = attrname; - + attrname.RemoveFirst("%ATTR:"); attrname.RemoveFirst("%"); - + attr_info info; BNode node(&ref); - if (node.InitCheck() != B_OK) - { + if (node.InitCheck() != B_OK) { outstr.RemoveAll(attrpattern.String()); strpos = outstr.FindFirst("%ATTR:"); continue; } - - if (node.GetAttrInfo(attrname.String(),&info) == B_OK) - { - if (info.type == B_STRING_TYPE) - { - node.ReadAttrString(attrname.String(),&string); - outstr.ReplaceAll(attrpattern.String(),string.String()); - } - else if (info.type == B_INT32_TYPE) - { + + if (node.GetAttrInfo(attrname.String(), &info) == B_OK) { + if (info.type == B_STRING_TYPE) { + node.ReadAttrString(attrname.String(), &string); + outstr.ReplaceAll(attrpattern.String(), string.String()); + } else if (info.type == B_INT32_TYPE) { int32 attrdata; - if (node.ReadAttr(attrname.String(),B_INT32_TYPE,0, - (void*)&attrdata,sizeof(int32)) == B_OK) - { + if (node.ReadAttr(attrname.String(), B_INT32_TYPE, 0, + (void*)&attrdata, sizeof(int32)) == B_OK) { string = ""; string << attrdata; - outstr.ReplaceAll(attrpattern.String(),string.String()); + outstr.ReplaceAll(attrpattern.String(), + string.String()); } } } } strpos = outstr.FindFirst("%ATTR:"); } - return outstr; } - diff --git a/sources/Filer/PatternProcessor.h b/sources/PatternProcessor.h similarity index 72% rename from sources/Filer/PatternProcessor.h rename to sources/PatternProcessor.h index e499f7b..a92582f 100644 --- a/sources/Filer/PatternProcessor.h +++ b/sources/PatternProcessor.h @@ -3,12 +3,13 @@ Written by DarkWyrm , Copyright 2008 Released under the MIT license. */ + #ifndef PATTERN_PROCESSOR_H #define PATTERN_PROCESSOR_H #include #include -BString ProcessPatterns(const char *instr, const entry_ref &ref); +BString ProcessPatterns(const char* instr, const entry_ref& ref); -#endif +#endif // PATTERN_PROCESSOR_H diff --git a/sources/AutoFiler/RefStorage.cpp b/sources/RefStorage.cpp similarity index 80% rename from sources/AutoFiler/RefStorage.cpp rename to sources/RefStorage.cpp index e1f3e06..3067da5 100644 --- a/sources/AutoFiler/RefStorage.cpp +++ b/sources/RefStorage.cpp @@ -3,6 +3,7 @@ Written by DarkWyrm , Copyright 2008 Contributed by: Humdinger , 2016 */ + #include #include #include @@ -16,18 +17,17 @@ BLocker gRefLock; const char gPrefsPath[] = "Filer/AutoFilerFolders"; -RefStorage::RefStorage(const entry_ref &fileref) +RefStorage::RefStorage(const entry_ref& fileref) { SetData(fileref); } void -RefStorage::SetData(const entry_ref &fileref) +RefStorage::SetData(const entry_ref& fileref) { BEntry entry(&fileref); - if (entry.Exists()) - { + if (entry.Exists()) { entry.GetRef(&ref); entry.GetNodeRef(&nref); } @@ -35,7 +35,7 @@ RefStorage::SetData(const entry_ref &fileref) status_t -LoadFolders(void) +LoadFolders() { BPath path; find_directory(B_USER_SETTINGS_DIRECTORY, &path); @@ -43,80 +43,79 @@ LoadFolders(void) if (!BEntry(path.Path()).Exists()) return B_OK; - + BAutolock autolock(&gRefLock); if (!autolock.IsLocked()) return B_BUSY; - + BMessage msg; - + BFile file(path.Path(), B_READ_ONLY); status_t status = file.InitCheck(); if (status != B_OK) return status; - + status = msg.Unflatten(&file); if (status != B_OK) return status; - + entry_ref tempRef; int32 i = 0; while (msg.FindRef("refs",i,&tempRef) == B_OK) { i++; - RefStorage *refholder = new RefStorage(tempRef); + RefStorage* refholder = new RefStorage(tempRef); if (refholder) gRefStructList.AddItem(refholder); } - + return status; } status_t -ReloadFolders(void) +ReloadFolders() { BAutolock autolock(&gRefLock); if (!autolock.IsLocked()) return B_BUSY; - + for (int32 i = 0; i < gRefStructList.CountItems(); i++) { - RefStorage *refholder = (RefStorage*)gRefStructList.ItemAt(i); + RefStorage* refholder = (RefStorage*)gRefStructList.ItemAt(i); delete refholder; } gRefStructList.MakeEmpty(); - + LoadFolders(); - + return B_OK; } + status_t -SaveFolders(void) +SaveFolders() { BAutolock autolock(&gRefLock); if (!autolock.IsLocked()) return B_BUSY; - + BMessage msg; - + for (int32 i = 0; i < gRefStructList.CountItems(); i++) { - RefStorage *refholder = (RefStorage*)gRefStructList.ItemAt(i); - - msg.AddRef("refs",&refholder->ref);; + RefStorage* refholder = (RefStorage*)gRefStructList.ItemAt(i); + msg.AddRef("refs", &refholder->ref);; } BPath path; find_directory(B_USER_SETTINGS_DIRECTORY, &path); path.Append(gPrefsPath); - + BFile file(path.Path(),B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); status_t status = file.InitCheck(); if (status != B_OK) return status; - + status = msg.Flatten(&file); return status; - } diff --git a/sources/AutoFiler/RefStorage.h b/sources/RefStorage.h similarity index 65% rename from sources/AutoFiler/RefStorage.h rename to sources/RefStorage.h index 6912405..16a1237 100644 --- a/sources/AutoFiler/RefStorage.h +++ b/sources/RefStorage.h @@ -19,15 +19,15 @@ enum class RefStorage { public: - RefStorage(const entry_ref &ref); - void SetData(const entry_ref &ref); - + RefStorage(const entry_ref& ref); + void SetData(const entry_ref& ref); + entry_ref ref; node_ref nref; }; -status_t LoadFolders(void); -status_t ReloadFolders(void); -status_t SaveFolders(void); +status_t LoadFolders(); +status_t ReloadFolders(); +status_t SaveFolders(); -#endif +#endif // REFSTORAGE_H diff --git a/sources/ReplicantWindow.cpp b/sources/ReplicantWindow.cpp new file mode 100644 index 0000000..0e62dc7 --- /dev/null +++ b/sources/ReplicantWindow.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Humdinger, humdingerb@gmail.com + */ + + +#include +#include + +#include "DropZoneTab.h" +#include "ReplicantWindow.h" + + +ReplicantWindow::ReplicantWindow(BRect frame) + : + BWindow(BRect(0, 0, 120, 100), ("Resize"), + B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS) +{ + frame.OffsetBy(290.0, 130.0); + MoveTo(frame.LeftTop()); + + DropZone* dropzone = new DropZone(true); + dropzone->SetExplicitMinSize(BSize(70.0, 64.0)); + dropzone->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + + static const float spacing = be_control_look->DefaultItemSpacing(); + BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING) + .SetInsets(spacing) + .Add(dropzone); +} + + +ReplicantWindow::~ReplicantWindow() +{ +} + + +//bool +//ReplicantWindow::QuitRequested() +//{ +// be_app->PostMessage(B_QUIT_REQUESTED); +// return true; +//} diff --git a/sources/ReplicantWindow.h b/sources/ReplicantWindow.h new file mode 100644 index 0000000..a633cef --- /dev/null +++ b/sources/ReplicantWindow.h @@ -0,0 +1,26 @@ +/* + * Copyright 2015. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Author: + * Humdinger, humdingerb@gmail.com + */ + +#ifndef REPLICANT_WINDOW_H +#define REPLICANT_WINDOW_H + +#include +#include + +#include + +class ReplicantWindow : public BWindow { +public: + ReplicantWindow(BRect frame); + virtual ~ReplicantWindow(); + +// bool QuitRequested(); + +}; + +#endif // REPLICANT_WINDOW_H diff --git a/sources/RuleEditWindow.cpp b/sources/RuleEditWindow.cpp new file mode 100644 index 0000000..de53fc6 --- /dev/null +++ b/sources/RuleEditWindow.cpp @@ -0,0 +1,349 @@ +/* + RuleEditWindow.cpp: Rule editor class (duh) + Released under the MIT license. + Written by DarkWyrm , Copyright 2008 + Contributed by: Humdinger , 2016 +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "ActionView.h" +#include "AutoTextControl.h" +#include "FilerDefs.h" +#include "FilerRule.h" +#include "main.h" +#include "RuleEditWindow.h" +#include "TestView.h" + + +RuleEditWindow::RuleEditWindow(BRect& rect, FilerRule* rule) + : + BWindow(rect, "Edit rule", B_TITLED_WINDOW, + B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE | B_CLOSE_ON_ESCAPE), + fOriginalID(-1) +{ + if (rule) + fOriginalID = rule->GetID(); + else + SetTitle("Add rule"); + + BView* top = new BView(Bounds(), "top", B_FOLLOW_ALL, B_WILL_DRAW); + top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(top); + + // Description + fDescriptionBox = new AutoTextControl(BRect(0, 0, 1, 1), "description", + "Description: ", NULL, new BMessage(MSG_NEW_DESCRIPTION), + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + top->AddChild(fDescriptionBox); + + float width, height; + fDescriptionBox->GetPreferredSize(&width, &height); + fDescriptionBox->ResizeTo(Bounds().Width() - 20, height); + fDescriptionBox->MoveTo(10, 10); + fDescriptionBox->SetDivider(be_plain_font->StringWidth("Description: ") + 5); + + if (rule) + fDescriptionBox->SetText(rule->GetDescription()); + + // Separator line + BRect rect(fDescriptionBox->Frame()); + rect.OffsetBy(0, rect.IntegerHeight() + 10); + rect.bottom = rect.top + 1.0; + BBox* box = new BBox(rect, NULL, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + top->AddChild(box); + + // Set up the tests group and associated buttons + rect.OffsetBy(0, 12.0); + rect.bottom = rect.top + 20.0; + fTestGroup = new BBox(rect, "whengroup", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fTestGroup->SetLabel("When"); + top->AddChild(fTestGroup); + + fAddTest = new BButton(BRect(0, 0, 1, 1),"addtestbutton", "Add", + new BMessage(MSG_ADD_ACTION), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); + fAddTest->ResizeToPreferred(); + fAddTest->MoveTo(10.0, fTestGroup->Bounds().bottom - 10.0 + - fAddTest->Bounds().Height()); + fTestGroup->AddChild(fAddTest); + + fRemoveTest = new BButton(BRect(0, 0, 1, 1),"removetestbutton", "Remove", + new BMessage(MSG_REMOVE_TEST), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); + fRemoveTest->ResizeToPreferred(); + fRemoveTest->MoveTo(fAddTest->Frame().right + 10, fAddTest->Frame().top); + fTestGroup->AddChild(fRemoveTest); + fRemoveTest->SetEnabled(false); + + fTestGroup->ResizeBy(0, fAddTest->Bounds().Height() + 10.0); + + // Set up the actions group and associated buttons + + rect.OffsetTo(10, fTestGroup->Frame().bottom + 10.0); + fActionGroup = new BBox(rect, "dogroup", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fActionGroup->SetLabel("Do"); + top->AddChild(fActionGroup); + + fAddAction = new BButton(BRect(0, 0, 1, 1), "addactionbutton", "Add", + new BMessage(MSG_ADD_ACTION), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); + fAddAction->ResizeToPreferred(); + fAddAction->MoveTo(10.0, fActionGroup->Bounds().bottom - 10.0 + - fAddAction->Bounds().Height()); + fActionGroup->AddChild(fAddAction); + + fRemoveAction = new BButton(BRect(0, 0, 1, 1), "removeactionbutton", "Remove", + new BMessage(MSG_REMOVE_ACTION), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); + fRemoveAction->ResizeToPreferred(); + fRemoveAction->MoveTo(fAddAction->Frame().right + 10, fAddAction->Frame().top); + fActionGroup->AddChild(fRemoveAction); + fRemoveAction->SetEnabled(false); + + fActionGroup->ResizeBy(0, fAddAction->Bounds().Height() + 10.0); + + + fOK = new BButton(BRect(0, 0, 1, 1), "okbutton", "OK", new BMessage(MSG_OK), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + fOK->ResizeToPreferred(); + fOK->MoveTo(Bounds().right - fOK->Bounds().Width() - 10, + Bounds().bottom - fOK->Bounds().Height() - 10); + // calling AddChild later to ensure proper keyboard navigation + + fCancel = new BButton(BRect(0, 0, 1 ,1), "cancelbutton", "Cancel", + new BMessage(MSG_CANCEL), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + fCancel->ResizeToPreferred(); + fCancel->MoveTo(fOK->Frame().left - fCancel->Bounds().Width() - 10, + fOK->Frame().top); + + fHelp = new BButton(BRect(0, 0, 1, 1), "helpbutton", "Help…", + new BMessage(MSG_HELP), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); + fHelp->ResizeToPreferred(); + fHelp->MoveTo(10, fOK->Frame().top); + fHelp->SetTarget(be_app); + top->AddChild(fHelp); + + top->AddChild(fCancel); + top->AddChild(fOK); + fOK->MakeDefault(true); + + if (rule) { + for (int32 i = 0; i < rule->CountTests(); i++) + AppendTest(rule->TestAt(i)); + + for (int32 i = 0; i < rule->CountActions(); i++) + AppendAction(rule->ActionAt(i)); + } else { + AppendTest(NULL); + AppendAction(NULL); + } + + ResizeTo(Bounds().Width(), fActionGroup->Frame().bottom + 15 + + fOK->Bounds().Height()); + + fDescriptionBox->MakeFocus(); +} + + +RuleEditWindow::~RuleEditWindow() +{ +} + + +void +RuleEditWindow::MessageReceived(BMessage* msg) +{ + switch (msg->what) + { + case MSG_OK: + { + if (strlen(fDescriptionBox->Text()) < 1) { + BAlert* alert = new BAlert("Filer", + "You need to add a description if you want to add this " + "rule to the list.", "OK"); + alert->Go(); + fDescriptionBox->MakeFocus(true); + break; + } + + SendRuleMessage(); + PostMessage(B_QUIT_REQUESTED); + break; + } + case MSG_CANCEL: + { + PostMessage(B_QUIT_REQUESTED); + break; + } + case MSG_ADD_TEST: + { + AppendTest(NULL); + break; + } + case MSG_REMOVE_TEST: + { + RemoveTest(); + break; + } + case MSG_ADD_ACTION: + { + AppendAction(NULL); + break; + } + case MSG_REMOVE_ACTION: + { + RemoveAction(); + break; + } + default: + BWindow::MessageReceived(msg); + } +} + + +void +RuleEditWindow::AppendTest(BMessage* test) +{ + TestView* view = new TestView(BRect(0, 0, 1, 1), "test", test, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + view->ResizeToPreferred(); + BRect rect = view->GetPreferredSize(); + fTestGroup->ResizeBy(0, rect.Height() + 10); + + if (fTestGroup->Bounds().Width() < rect.Width() + 20) + ResizeBy(rect.Width() + 20 - fTestGroup->Bounds().Width(),0); + + TestView* last = (TestView*)fTestList.ItemAt(fTestList.CountItems() - 1); + + if (last) + view->MoveTo(last->Frame().left, last->Frame().bottom + 10); + else + view->MoveTo(10, 15); + + fTestGroup->AddChild(view); + fTestList.AddItem(view); + + fActionGroup->MoveBy(0, rect.Height() + 10); + ResizeBy(0, rect.Height() + 10); + + if (fTestList.CountItems() > 1 && !fRemoveTest->IsEnabled()) + fRemoveTest->SetEnabled(true); +} + + +void +RuleEditWindow::RemoveTest() +{ + TestView* view = (TestView*)fTestList.RemoveItem(fTestList.CountItems() - 1); + view->RemoveSelf(); + fTestGroup->ResizeBy(0, -view->Bounds().Height() - 10); + fActionGroup->MoveBy(0, -view->Bounds().Height() - 10); + ResizeBy(0, -view->Bounds().Height() - 10); + delete view; + + if (fTestList.CountItems() == 1) + fRemoveTest->SetEnabled(false); +} + + +void +RuleEditWindow::AppendAction(BMessage* action) +{ + ActionView* view = new ActionView(BRect(0, 0, 1, 1), "action", action, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + BRect rect = view->GetPreferredSize(); + view->ResizeTo(fActionGroup->Bounds().Width() - 20, rect.Height()); + fActionGroup->ResizeBy(0, rect.Height() + 10); + + if (fActionGroup->Bounds().Width() < rect.Width() + 20) + ResizeBy(rect.Width() + 20 - fActionGroup->Bounds().Width(), 0); + + ActionView* last + = (ActionView*)fActionList.ItemAt(fActionList.CountItems() - 1); + + if (last) + view->MoveTo(last->Frame().left, last->Frame().bottom + 10); + else + view->MoveTo(10, 15); + + fActionGroup->AddChild(view); + fActionList.AddItem(view); + + ResizeBy(0, rect.Height() + 10); + + if (fActionList.CountItems() > 1 && !fRemoveAction->IsEnabled()) + fRemoveAction->SetEnabled(true); +} + + +void +RuleEditWindow::RemoveAction() +{ + ActionView* view + = (ActionView*)fActionList.RemoveItem(fActionList.CountItems() - 1); + view->RemoveSelf(); + fActionGroup->ResizeBy(0, -view->Bounds().Height() - 10); + ResizeBy(0, -view->Bounds().Height() - 10); + delete view; + + if (fActionList.CountItems() == 1) + fRemoveAction->SetEnabled(false); +} + + +BRect +RuleEditWindow::GetPreferredSize() const +{ + // Base minimum size, padding included + BRect rect(0.0, 0.0, 320.0, 220.0); + + // Figure preferred height + rect.bottom += fDescriptionBox->Bounds().Height() + 10.0; + + // 2 pixels for separator line + 10 pixels padding above it + rect.bottom += 12.0; + + // Base minimum size for boxes (including inside padding) of 20 each and + // outside padding of 10 pixels above each box + rect.bottom += 40.0 + 20.0; + + rect.bottom += fOK->Bounds().Height() + 10.0; + + return rect; +} + + +void +RuleEditWindow::SendRuleMessage() +{ + FilerRule* rule = new FilerRule; + + rule->SetDescription(fDescriptionBox->Text()); + + for (int32 i = 0; i < fTestList.CountItems(); i++) + { + TestView* view = (TestView*)fTestList.ItemAt(i); + rule->AddTest(new BMessage(*view->GetTest())); + } + + for (int32 i = 0; i < fActionList.CountItems(); i++) + { + ActionView* view = (ActionView*)fActionList.ItemAt(i); + rule->AddAction(new BMessage(*view->GetAction())); + } + + BMessage msg; + msg.what = (fOriginalID >= 0) ? MSG_UPDATE_RULE : MSG_ADD_RULE; + msg.AddPointer("item", rule); + msg.AddInt64("id", fOriginalID); + + for (int32 i = 0; i < be_app->CountWindows(); i++) + { + BWindow* win = be_app->WindowAt(i); + if (strcmp(win->Title(), "Filer settings") == 0) + win->PostMessage(&msg); + } +} diff --git a/sources/RuleEditWindow.h b/sources/RuleEditWindow.h new file mode 100644 index 0000000..ea35abc --- /dev/null +++ b/sources/RuleEditWindow.h @@ -0,0 +1,58 @@ +/* + RuleEditWindow.h: Rule editor class (duh) + Written by DarkWyrm , Copyright 2008 + Released under the MIT license. +*/ +#ifndef RULE_EDIT_WINDNOW_H +#define RULE_EDIT_WINDNOW_H + +#include +#include +#include + +#include "ObjectList.h" + +class AutoTextControl; +class FilerRule; +class TestView; + + +class RuleEditWindow : public BWindow +{ +public: + RuleEditWindow(BRect& rect, FilerRule* rule); + ~RuleEditWindow(); + + void MessageReceived(BMessage* msg); + +// FilerRule* Rule(); + + void AppendTest(BMessage* test); + void RemoveTest(); + + void AppendAction(BMessage* action); + void RemoveAction(); +private: + BRect GetPreferredSize() const; + void SendRuleMessage(); + + AutoTextControl* fDescriptionBox; + + BBox* fTestGroup; + BBox* fActionGroup; + + BButton* fOK; + BButton* fCancel; + BButton* fAddTest; + BButton* fRemoveTest; + BButton* fAddAction; + BButton* fRemoveAction; + BButton* fHelp; + + int64 fOriginalID; + + BList fTestList; + BList fActionList; +}; + +#endif // RULE_EDIT_WINDNOW_H diff --git a/sources/Filer/RuleItem.cpp b/sources/RuleItem.cpp similarity index 74% rename from sources/Filer/RuleItem.cpp rename to sources/RuleItem.cpp index 8cf95f8..f68547a 100644 --- a/sources/Filer/RuleItem.cpp +++ b/sources/RuleItem.cpp @@ -3,22 +3,24 @@ Written by DarkWyrm , Copyright 2008 Released under the MIT license. */ + #include "RuleItem.h" #include "FilerRule.h" -RuleItem::RuleItem(FilerRule *item) - : BStringItem("") +RuleItem::RuleItem(FilerRule* item) + : + BStringItem("") { SetRule(item); } - + void -RuleItem::SetRule(FilerRule *rule) +RuleItem::SetRule(FilerRule* rule) { fRule = rule; - + if (fRule) SetText(rule->GetDescription()); else @@ -26,9 +28,8 @@ RuleItem::SetRule(FilerRule *rule) } -FilerRule * -RuleItem::Rule(void) +FilerRule* +RuleItem::Rule() { return fRule; } - diff --git a/sources/Filer/RuleItem.h b/sources/RuleItem.h similarity index 72% rename from sources/Filer/RuleItem.h rename to sources/RuleItem.h index c5e4bd8..d61e1bf 100644 --- a/sources/Filer/RuleItem.h +++ b/sources/RuleItem.h @@ -3,24 +3,25 @@ Written by DarkWyrm , Copyright 2008 Released under the MIT license. */ + #ifndef RULEITEM_H #define RULEITEM_H -#include #include +#include class FilerRule; class RuleItem : public BStringItem { public: - RuleItem(FilerRule *item); - - void SetRule(FilerRule *rule); - FilerRule * Rule(void); - + RuleItem(FilerRule* item); + + void SetRule(FilerRule* rule); + FilerRule* Rule(); + private: - FilerRule *fRule; + FilerRule* fRule; }; -#endif +#endif // RULEITEM_H diff --git a/sources/RuleRunner.cpp b/sources/RuleRunner.cpp new file mode 100644 index 0000000..3f4f516 --- /dev/null +++ b/sources/RuleRunner.cpp @@ -0,0 +1,1273 @@ +/* + RuleRunner.cpp: class to handle running test and actions for the rules + Released under the MIT license. + Written by DarkWyrm , Copyright 2008 + Contributed by: Humdinger , 2016 +*/ + +#include +#include +#include +#include +#include +#include + +#include "CppSQLite3.h" +#include "Database.h" +#include "FSUtils.h" +#include "PatternProcessor.h" +#include "RuleRunner.h" + +#include +#include + +/* + FilerAction message fields: + "name" - the particular action, i.e. copy, move, trash, delete, etc. + "value" - string data associated with the action. Usually a file path + + FilerTest message fields: + "name" - the particular data being compared -- name, date, etc. + This is set to"Attribute" if it's an extended attribute + "mode" - the kind of comparison being used -- ==, != -- in plain English + "value" - the value to be compared to + + + These fields are either not present or NULL in non-attribute tests: + + "mimetype" - This is the MIME type associated with the attribute. + "typename" - This is the mime type's short description. + "attrtype" - The MIME description for the attribute type, like + META:email for email addresses. + "attrname" - The public name for the attribute to be compared. + + + To add another test to this file, you'll need to implement an + IsXxxxMatch(), function make sure it is called from within IsMatch(), + and add the appropriate name to both sTestTypes[] and either + sStringTests[], sDateTests[], or sNumberTests[]. + + To add an action to this file, you'll need to implement an xxxxAction() + function, make sure it is called from within RunAction, and add the + appropriate action name to sActions[]; + + In both cases, please make sure that you keep the location within the + static array variables when adding or deleting entries +*/ + +// The various compare functions used by IsMatch to do the actual comparing +bool IsNameMatch(const BMessage& test, const entry_ref& ref); +bool IsTypeMatch(const BMessage& test, const entry_ref& ref); +bool IsSizeMatch(const BMessage& test, const entry_ref& ref); +bool IsLocationMatch(const BMessage& test, const entry_ref& ref); +bool IsModifiedMatch(const BMessage& test, const entry_ref& ref); +bool IsAttributeMatch(const BMessage& test, const entry_ref& ref); +bool StringCompare(const BString& from, const BString& to, const char* mode, + const bool& match_case); + +// The various action functions used by RunAction to do the heavy lifting +status_t MoveAction(const BMessage& action, entry_ref& ref); +status_t CopyAction(const BMessage& action, entry_ref& ref); +status_t RenameAction(const BMessage& action, entry_ref& ref); +status_t OpenAction(const BMessage& action, entry_ref& ref); +status_t ArchiveAction(const BMessage& action, entry_ref& ref); +status_t CommandAction(const BMessage& action, entry_ref& ref); +status_t TrashAction(const BMessage& action, entry_ref& ref); +status_t DeleteAction(const BMessage& action, entry_ref& ref); + + +// Internal variables for all the supported types of tests + +static const char* sTestTypes[] = +{ + "Type", + "Name", + "Size", + "Location", +// "Last Changed", + NULL +}; + +static const char* sStringTests[] = +{ + "Type", + "Name", + "Location", + NULL +}; + +static const char* sNumberTests[] = +{ + "Size", + NULL +}; + +static const char* sDateTests[] = +{ +// "Last Changed", + NULL +}; + + +static const char* sTestEditors[] = +{ + "type selector", + "textbox", + "textbox", + "textbox", +// "textbox", + NULL +}; + + +// Internal variables for all the supported types of compare operators + +static const char* sAnyModes[] = +{ + "is", + "is not", + + // for future expansion +// "matches pattern", +// "does not match pattern", + + NULL +}; + +static const char* sStringModes[] = +{ + "starts with", + "ends with", + "contains", + "does not contain", + NULL +}; + +static const char* sNumberModes[] = +{ + "is more than", + "is less than", + "is at least", + "is at most", + NULL +}; + +static const char* sDateModes[] = +{ + "is before", + "is after", + NULL +}; + + +// Internal variable for all the supported types of actions + +static const char* sActions[] = +{ + "Move it to…", + "Copy it to…", + "Rename it to…", + "Open it", + "Add it to the archive…", + "Move it to the Trash", + "Delete it", + "Terminal command…", + + // Future expansion +// "Shred it", +// "E-mail it to…", +// "Make a Deskbar link", + + NULL +}; + + +RuleRunner::RuleRunner() +{ +} + + +RuleRunner::~RuleRunner() +{ +} + + +void +RuleRunner::GetTestTypes(BMessage& msg) +{ + int32 i = 0; + while (sTestTypes[i]) + { + msg.AddString("tests", sTestTypes[i]); + i++; + } +} + + +status_t +RuleRunner::GetCompatibleModes(const char* testtype, BMessage& msg) +{ + if (!testtype) + return B_ERROR; + + return GetCompatibleModes(GetDataTypeForTest(testtype), msg); +} + + +status_t +RuleRunner::GetCompatibleModes(const int32& type, BMessage& msg) +{ + int32 i = 0; + switch (type) + { + case TEST_TYPE_STRING: + { + while (sAnyModes[i]) + { + msg.AddString("modes", sAnyModes[i]); + i++; + } + + i = 0; + while (sStringModes[i]) + { + msg.AddString("modes", sStringModes[i]); + i++; + } + break; + } + case TEST_TYPE_NUMBER: + { + while (sAnyModes[i]) + { + msg.AddString("modes", sAnyModes[i]); + i++; + } + + i = 0; + while (sNumberModes[i]) + { + msg.AddString("modes", sNumberModes[i]); + i++; + } + break; + } + case TEST_TYPE_DATE: + { + while (sAnyModes[i]) + { + msg.AddString("modes", sAnyModes[i]); + i++; + } + + i = 0; + while (sDateModes[i]) + { + msg.AddString("modes", sDateModes[i]); + i++; + } + break; + } + case TEST_TYPE_ANY: + { + while (sAnyModes[i]) + { + msg.AddString("modes", sAnyModes[i]); + i++; + } + break; + } + default: + return B_BAD_VALUE; + } + return B_OK; +} + + +void +RuleRunner::GetModes(BMessage& msg) +{ + int32 i; + + i = 0; + while (sAnyModes[i]) + { + msg.AddString("modes", sAnyModes[i]); + i++; + } + + i = 0; + while (sStringModes[i]) + { + msg.AddString("modes", sStringModes[i]); + i++; + } + + i = 0; + while (sNumberModes[i]) + { + msg.AddString("modes", sNumberModes[i]); + i++; + } + + i = 0; + while (sDateModes[i]) + { + msg.AddString("modes", sDateModes[i]); + i++; + } +} + + +void +RuleRunner::GetActions(BMessage& msg) +{ + int32 i = 0; + while (sActions[i]) + { + msg.AddString("actions", sActions[i]); + i++; + } +} + + +BString +RuleRunner::GetEditorTypeForTest(const char* testname) +{ + int32 i = 0; + while (sTestTypes[i]) + { + if (strcmp(testname, sTestTypes[i]) == 0) + return BString(sTestEditors[i]); + i++; + } + return BString(""); +} + + +int32 +RuleRunner::GetDataTypeForTest(const char* testname) +{ + if (!testname) + return TEST_TYPE_NULL; + + int32 i; + + i = 0; + while (sStringTests[i]) + { + if (strcmp(testname, sStringTests[i]) == 0) + return TEST_TYPE_STRING; + i++; + } + + i = 0; + while (sNumberTests[i]) + { + if (strcmp(testname, sNumberTests[i]) == 0) + return TEST_TYPE_NUMBER; + i++; + } + + i = 0; + while (sDateTests[i]) + { + if (strcmp(testname, sDateTests[i]) == 0) + return TEST_TYPE_DATE; + i++; + } + + return TEST_TYPE_NULL; +} + + +int32 +RuleRunner::GetDataTypeForMode(const char* modename) +{ + if (!modename) + return TEST_TYPE_NULL; + + int32 i; + + i = 0; + while (sStringModes[i]) + { + if (strcmp(modename, sStringModes[i]) == 0) + return TEST_TYPE_STRING; + i++; + } + + i = 0; + while (sNumberModes[i]) + { + if (strcmp(modename, sNumberModes[i]) == 0) + return TEST_TYPE_NUMBER; + i++; + } + + i = 0; + while (sDateModes[i]) + { + if (strcmp(modename, sDateModes[i]) == 0) + return TEST_TYPE_DATE; + i++; + } + + i = 0; + while (sAnyModes[i]) + { + if (strcmp(modename, sAnyModes[i]) == 0) + return TEST_TYPE_ANY; + i++; + } + + return TEST_TYPE_NULL; +} + + +bool +RuleRunner::IsMatch(const BMessage& test, const entry_ref& ref) +{ + BString testname; + if (test.FindString("name", &testname) != B_OK) { + debugger("Couldn't find test name in RuleRunner::IsMatch"); + return false; + } + + if (testname.Compare("Name") == 0) + return IsNameMatch(test, ref); + else if (testname.Compare("Size") == 0) + return IsSizeMatch(test, ref); + else if (testname.Compare("Location") == 0) + return IsLocationMatch(test, ref); + else if (testname.Compare("Type") == 0) + return IsTypeMatch(test, ref); + else if (testname.Compare("Last Changed") == 0) + return IsModifiedMatch(test, ref); + else if (testname.Compare("Attribute") == 0) + return IsAttributeMatch(test, ref); + + return false; +} + + +status_t +RuleRunner::RunAction(const BMessage& action, entry_ref& ref) +{ + BString actionname; + if (action.FindString("name", &actionname) != B_OK) { + debugger("Couldn't find action name in RuleRunner::RunAction"); + return B_ERROR; + } + + if (actionname.Compare("Move it to…") == 0) + return MoveAction(action, ref); + else if (actionname.Compare("Copy it to…") == 0) + return CopyAction(action, ref); + else if (actionname.Compare("Rename it to…") == 0) + return RenameAction(action, ref); + else if (actionname.Compare("Open it") == 0) + return OpenAction(action, ref); + else if (actionname.Compare("Add it to the archive…") == 0) + return ArchiveAction(action, ref); + else if (actionname.Compare("Terminal command…") == 0) + return CommandAction(action, ref); + else if (actionname.Compare("Move it to the Trash") == 0) + return TrashAction(action, ref); + else if (actionname.Compare("Delete it") == 0) + return DeleteAction(action, ref); + + return B_ERROR; +} + + +status_t +RuleRunner::RunRule(FilerRule* rule, entry_ref& ref) +{ + if (!rule) + return B_ERROR; + + bool pass; + printf("Running rule '%s'\n",rule->GetDescription()); + + if (rule->GetRuleMode() == FILER_RULE_ANY) { + pass = false; + for (int32 i = 0; i < rule->CountTests(); i++) + { + BMessage* test = rule->TestAt(i); + if (IsMatch(*test, ref)) { + pass = true; + break; + } + } + } else { // And mode + pass = true; + for (int32 i = 0; i < rule->CountTests(); i++) + { + BMessage* test = rule->TestAt(i); + if (!IsMatch(*test, ref)) { + pass = false; + break; + } + } + } + + if (pass) { + entry_ref realref; + BEntry(&ref, true).GetRef(&realref); + + for (int32 i = 0; i < rule->CountActions(); i++) + { + BMessage* action = rule->ActionAt(i); + + // Note that this call passes the same ref object from one call to the + // next. This allows the user to chain actions together. The only thing + // required to do this is for the particular action to change the ref + // passed to it. + status_t status = RunAction(*action, realref); + if (status != B_OK) + return status; + } + } + return B_OK; +} + + +bool +IsNameMatch(const BMessage& test, const entry_ref& ref) +{ + BString value; + if (test.FindString("value", &value) != B_OK) { + debugger("Couldn't get value in IsNameMatch"); + return false; + } + + BString compare; + if (test.FindString("mode", &compare) != B_OK) { + debugger("Couldn't get mode in IsNameMatch"); + return false; + } + + bool result = StringCompare(value, BString(ref.name), compare.String(), + true); + printf("\tName test: %s %s %s - %s\n", ref.name, compare.String(), + value.String(), result ? "MATCH" : "NO MATCH"); + + return result; +} + + +bool +IsTypeMatch(const BMessage& test, const entry_ref& ref) +{ + BString value; + if (test.FindString("value", &value) != B_OK) { + debugger("Couldn't get value in IsTypeMatch"); + return false; + } + +// if (value == "image/") +// debugger(""); + + BString compare; + if (test.FindString("mode", &compare) != B_OK) { + debugger("Couldn't get mode in IsTypeMatch"); + return false; + } + + BString string; + attr_info info; + BNode node(&ref); + if (node.InitCheck() != B_OK) + return false; + + if (node.GetAttrInfo("BEOS:TYPE", &info) != B_OK) { + BPath path(&ref); + if (update_mime_info(path.Path(), 0, 1, 0) != B_OK) + return false; + } + + if (node.ReadAttrString("BEOS:TYPE", &string) != B_OK) + return false; + + bool result = StringCompare(value, string.String(), compare.String(), + true); + printf("\tType test: %s %s %s - %s\n", ref.name, compare.String(), + value.String(), result ? "MATCH" : "NO MATCH"); + + return result; +} + + +bool +IsSizeMatch(const BMessage& test, const entry_ref& ref) +{ + BString value; + if (test.FindString("value", &value) != B_OK) { + debugger("Couldn't get value in IsTypeMatch"); + return false; + } + + BString compare; + if (test.FindString("mode",&compare) != B_OK) { + debugger("Couldn't get mode in IsTypeMatch"); + return false; + } + + off_t fromsize = atoll(value.String()); + + BFile file(&ref, B_READ_ONLY); + if (file.InitCheck() != B_OK) + return false; + + off_t tosize; + file.GetSize(&tosize); + file.Unset(); + + bool result = false; + + if (strcmp(compare.String(), "is") == 0) + result = (fromsize == tosize); + else if (strcmp(compare.String(), "is not") == 0) + result = (fromsize != tosize); + else if (strcmp(compare.String(), "is more than") == 0) + result = (fromsize > tosize); + else if (strcmp(compare.String(), "is less than") == 0) + result = (fromsize < tosize); + else if (strcmp(compare.String(), "is at least") == 0) + result = (fromsize >= tosize); + else if (strcmp(compare.String(), "is at most") == 0) + result = (fromsize <= tosize); + + printf("\tSize test: %s %s %lld - %s\n", ref.name, compare.String(), + tosize, result ? "MATCH" : "NO MATCH"); + + return result; +} + + +bool +IsLocationMatch(const BMessage& test, const entry_ref& ref) +{ + BString value; + if (test.FindString("value", &value) != B_OK) { + debugger("Couldn't get value in IsLocationMatch"); + return false; + } + + BString compare; + if (test.FindString("mode", &compare) != B_OK) { + debugger("Couldn't get mode in IsLocationMatch"); + return false; + } + + // This is a little tricky -- we resolve symlinks in the location test + entry_ref realref; + BEntry(&ref).GetRef(&realref); + + BPath path(&realref); + BString filepath(path.Path()); + filepath.RemoveLast(path.Leaf()); + + if (value[value.CountChars() - 1] != '/') + value << "/"; + + bool result = StringCompare(value, filepath.String(), compare.String(), + true); + + printf("\tLocation test: %s %s %s - %s\n", filepath.String(), + compare.String(), value.String(), result ? "MATCH" : "NO MATCH"); + + return result; +} + + +bool +IsModifiedMatch(const BMessage& test, const entry_ref& ref) +{ + // TODO: Implement using Mr. Peeps! date-parsing code + return false; +} + + +bool +IsAttributeMatch(const BMessage& test, const entry_ref& ref) +{ + BString value; + if (test.FindString("value", &value) != B_OK) { + debugger("Couldn't get value in IsTypeMatch"); + return false; + } + + BString compare; + if (test.FindString("mode", &compare) != B_OK) { + debugger("Couldn't get mode in IsTypeMatch"); + return false; + } + + BString attribute; + if (test.FindString("attrtype", &attribute) != B_OK) { + debugger("Couldn't get attribute in IsAttributeMatch"); + return false; + } + + BString string; + attr_info info; + BNode node(&ref); + if (node.InitCheck() != B_OK) + return false; + + if (node.GetAttrInfo(attribute.String(), &info) != B_OK) + return false; + + if (node.ReadAttrString(attribute.String(), &string) != B_OK) + return false; + + bool result = StringCompare(value, string, compare.String(), true); + + BString attrname; + if (test.FindString("attrname", &attrname) != B_OK) + attrname = attribute; + + printf("\tAttribute test: %s %s %s - %s\n", attrname.String(), + compare.String(), value.String(), result ? "MATCH" : "NO MATCH"); + + return result; +} + + +bool +StringCompare(const BString& from, const BString& to, const char* mode, + const bool& match_case) +{ + if (!mode) { + debugger("NULL mode in StringCompare"); + return false; + } + + if (strcmp(mode, "is") == 0) + if (match_case) + return from.Compare(to) == 0; + else + return from.ICompare(to) == 0; + else if (strcmp(mode, "is not") == 0) + if (match_case) + return from.Compare(to) != 0; + else + return from.ICompare(to) != 0; + else if (strcmp(mode, "contains") == 0) + if (match_case) + return to.FindFirst(from) >= 0; + else + return to.IFindFirst(from) >= 0; + else if (strcmp(mode, "does not contain") == 0) + if (match_case) + return to.FindFirst(from) < 0; + else + return to.IFindFirst(from) < 0; + else if (strcmp(mode, "starts with") == 0) + if (match_case) + return to.FindFirst(from) == 0; + else + return to.IFindFirst(from) == 0; + else if (strcmp(mode, "ends with") == 0) { + int32 pos; + if (match_case) + pos = to.FindLast(from); + else + pos = to.IFindLast(from); + + return (to.CountChars() - from.CountChars() == pos); + } + + return false; +} + + +status_t +MoveAction(const BMessage& action, entry_ref& ref) +{ + BString value; + status_t status; + status = action.FindString("value", &value); + if (status != B_OK) + return status; + value = ProcessPatterns(value.String(), ref); + + BEntry entry(value.String(), true); + status = entry.InitCheck(); + if (status != B_OK || (entry.Exists() && !entry.IsDirectory())) + return B_ERROR; + + if (!entry.Exists()) + create_directory(value.String(), 0777); + + BEntry source(&ref); + status = source.InitCheck(); + if (status != B_OK) + return B_ERROR; + + status = MoveFile(&source, &entry, false); + if (status == B_OK) { + printf("\tMoved %s to %s\n", ref.name, value.String()); + source.GetRef(&ref); + } else { + printf("\tCouldn't move %s to %s. Stopping here.\n\t\t" + "Error Message: %s\n", ref.name, value.String(), strerror(status)); + } + + return B_OK; +} + + +status_t +CopyAction(const BMessage& action, entry_ref& ref) +{ + BString value; + status_t status; + status = action.FindString("value", &value); + if (status != B_OK) + return status; + value = ProcessPatterns(value.String(), ref); + + BEntry entry(value.String(), true); + status = entry.InitCheck(); + if (status != B_OK || (entry.Exists() && !entry.IsDirectory())) + return B_ERROR; + + if (!entry.Exists()) + create_directory(value.String(), 0777); + + BEntry source(&ref); + status = source.InitCheck(); + if (status != B_OK) + return B_ERROR; + + status = CopyFile(&source, &entry, false); + if (status == B_OK) { + printf("\tCopied %s to %s\n", ref.name, value.String()); + source.GetRef(&ref); + } else { + printf("\tCouldn't copy %s to %s. Stopping here.\n\t\t" + "Error Message: %s\n", ref.name, value.String(), strerror(status)); + } + + return B_OK; +} + + +status_t +RenameAction(const BMessage& action, entry_ref& ref) +{ + BString value; + status_t status; + status = action.FindString("value", &value); + if (status != B_OK) + return status; + value = ProcessPatterns(value.String(), ref); + + BEntry entry(value.String(), true); + status = entry.InitCheck(); + if (status != B_OK || entry.Exists()) + return B_ERROR; + + BEntry source(&ref); + status = source.InitCheck(); + if (status != B_OK) + return B_ERROR; + + status = source.Rename(value.String()); + if (status == B_OK) { + printf("\tRenamed %s to %s\n", ref.name, value.String()); + source.GetRef(&ref); + } else { + printf("\tCouldn't rename %s to %s. Stopping here.\n\t\t" + "Error Message: %s\n", ref.name, value.String(), strerror(status)); + } + + if (status == B_OK) + source.GetRef(&ref); + + return B_OK; +} + + +status_t +OpenAction(const BMessage& action, entry_ref& ref) +{ + entry_ref app; + BString appName(""); + if (be_roster->FindApp(&ref, &app) == B_OK) + appName = app.name; + + status_t status = be_roster->Launch(&ref); + + if (status == B_OK) + printf("\tOpened %s in program %s\n", ref.name, appName.String()); + else { + // R5 (and probably others) don't seem to want to open folders in + // Tracker -- FindApp() returns B_OK, but sets the entry_ref of the + // app to open it to the folder's ref, which is dumb. This works + // around this apparent stupidity. + BString typestr; + if (BNode(&ref).ReadAttrString("BEOS:TYPE", &typestr) == B_OK + && typestr.Compare("application/x-vnd.Be-directory") == 0) { + BMessage* msg = new BMessage(B_REFS_RECEIVED); + msg->AddRef("refs", &ref); + be_roster->Launch("application/x-vnd.Be-TRAK", msg); + printf("\tOpened %s in program Tracker\n", ref.name); + return B_OK; + } + if (appName.CountChars() > 0) { + printf("\tCouldn't open %s in program %s\n", + ref.name, appName.String()); + } else + printf("\tCouldn't open %s -- the system couldn't find a program " + "to do it.\n", ref.name); + } + return status; +} + + +status_t +ArchiveAction(const BMessage& action, entry_ref& ref) +{ + BString value; + status_t status; + status = action.FindString("value", &value); + if (status != B_OK) + return status; + value = ProcessPatterns(value.String(), ref); + + BPath path(&ref); + BString parentstr = path.Path(); + parentstr.ReplaceLast(path.Leaf(),""); + + BString command = ""; + command << "cd '" << parentstr << "'; zip -9 -u -r '" << value << "' '" + << path.Leaf() << "'"; + + int result = system(command.String()); + if (result) { + printf("\tCouldn't create archive %s\n\t\tError code: %d\n", + value.String(), result); + } else + printf("\tAdded %s to Archive %s\n", ref.name, value.String()); + + return B_OK; +} + + +status_t +CommandAction(const BMessage& action, entry_ref& ref) +{ + BString value; + status_t status; + status = action.FindString("value", &value); + if (status != B_OK) + return status; + value = ProcessPatterns(value.String(), ref); + + int result = system(value.String()); + if (result) { + printf("\tTerminal Command: %s\n\t\tPossible error: " + "command returned %d\n", value.String(), result); + } else + printf("\tTerminal Command: %s\n", value.String()); + + return B_OK; +} + + +status_t +TrashAction(const BMessage& action, entry_ref& ref) +{ + BPath path; + find_directory(B_TRASH_DIRECTORY, &path); + + BEntry entry(path.Path(), true); + status_t status = entry.InitCheck(); + if (status != B_OK || !entry.Exists() || !entry.IsDirectory()) + return B_ERROR; + + BEntry source(&ref); + status = source.InitCheck(); + if (status != B_OK) + return B_ERROR; + + status = MoveFile(&source, &entry, false); + if (status == B_OK) { + printf("\tMoved %s to the Trash\n", ref.name); + source.GetRef(&ref); + } else { + printf("\tCouldn't move %s to the Trash. Stopping here.\n\t\t" + "Error Message: %s\n", ref.name, strerror(status)); + } + return B_OK; +} + + +status_t +DeleteAction(const BMessage& action, entry_ref& ref) +{ + BEntry entry(&ref); + + status_t status = entry.Remove(); + if (status == B_OK) + printf("\tDeleted %s\n", BPath(ref.name).Path()); + else { + printf("\tCouldn't delete %s. Stopping here.\n\t\tError Message: %s\n", + BPath(ref.name).Path(), strerror(status)); + } + return entry.Remove(); +} + + +status_t +SaveRules(BObjectList* ruleList) +{ + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + + status_t ret = path.Append("Filer"); + if (ret == B_OK) + ret = create_directory(path.Path(), 0777); + + if (ret == B_OK) + ret = path.Append("FilerRules"); + + if (ret == B_OK) { + BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); + ret = file.InitCheck(); + } + if (ret != B_OK) + return(ret); + + BEntry entry(path.Path()); + if (entry.Exists()) + entry.Remove(); + + CppSQLite3DB db; + db.open(path.Path()); + + // While we could use other means of obtaining table names, this table is also + // used for maintaining the order of the rules, which must be preserved + DBCommand(db,"create table RuleList (ruleid int primary key, name varchar);", + "PrefsWindow::SaveRules"); + + BString command; + + for (int32 i = 0; i < ruleList->CountItems(); i++) + { + FilerRule* rule = ruleList->ItemAt(i); + + // Test table: + // 0) Entry type (test vs action) + // 1) type + // 2) mode + // 3) value + // 4) attribute type (if Attribute test) + // 5) attribute type public name (short description) + // 6) attribute public name (if Attribute test) + + BString tablename(EscapeIllegalCharacters(rule->GetDescription())); + + command = "create table "; + command << tablename + << "(entrytype varchar, testtype varchar, testmode varchar, + testvalue varchar, attrtype varchar, attrtypename varchar, + attrpublicname varchar);"; + DBCommand(db, command.String(), "PrefsWindow::SaveRules"); + + command = "insert into RuleList values("; + command << i << ",'" << tablename << "');"; + DBCommand(db, command.String(), "PrefsWindow::SaveRules"); + + for (int32 j = 0; j < rule->CountTests(); j++) + { + BMessage* test = rule->TestAt(j); + if (!test) + continue; + + BString name, mode, value, mimeType, typeName, attrType, attrName; + test->FindString("name", &name); + test->FindString("mode", &mode); + test->FindString("value", &value); + test->FindString("mimetype", &mimeType); + test->FindString("typename", &typeName); + test->FindString("attrtype", &attrType); + test->FindString("attrname", &attrName); + + command = "insert into "; + command << tablename << " values('test', '" + << EscapeIllegalCharacters(name.String()) + << "', '" << EscapeIllegalCharacters(mode.String()) + << "', '" << EscapeIllegalCharacters(value.String()) + << "', '" << EscapeIllegalCharacters(mimeType.String()) + << "', '" << EscapeIllegalCharacters(typeName.String()) + << "', '" << EscapeIllegalCharacters(attrName.String()) + << "');"; + + DBCommand(db, command.String(), "PrefsWindow::SaveRules:save test"); + } + + for (int32 j = 0; j < rule->CountActions(); j++) + { + BMessage* action = rule->ActionAt(j); + if (!action) + continue; + + BString name, value; + action->FindString("name", &name); + action->FindString("value", &value); + + command = "insert into "; + command << tablename << " values('action', '" + << EscapeIllegalCharacters(name.String()) + << "', '" + << "', '" << EscapeIllegalCharacters(value.String()) + << "', '', '', '');"; + DBCommand(db, command.String(), "PrefsWindow::SaveRules:save action"); + } + } + db.close(); + + return B_OK; +} + + +status_t +LoadRules(BObjectList* ruleList) +{ + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + path.Append("Filer/FilerRules"); + + BEntry entry(path.Path()); + if (!entry.Exists()) + return B_OK; + + CppSQLite3DB db; + db.open(path.Path()); + + // Because this particular build of sqlite3 does not support multithreading + // because of lack of pthreads support, we need to do this in a slightly + // different order + + CppSQLite3Query query; + query = DBQuery(db,"select name from RuleList order by ruleid;", + "PrefsWindow::LoadRules"); + + BString command; + while (!query.eof()) + { + BString rulename = query.getStringField((int)0); + + FilerRule* rule = new FilerRule; + rule->SetDescription(DeescapeIllegalCharacters(rulename.String()).String()); + + ruleList->AddItem(rule); + + query.nextRow(); + } + + query.finalize(); + + for (int32 i = 0; i < ruleList->CountItems(); i++) + { + FilerRule* rule = ruleList->ItemAt(i); + + if (!rule) + continue; + + BString rulename(EscapeIllegalCharacters(rule->GetDescription())); + + // Now comes the fun(?) part: loading the tests and actions. Joy. :/ + command = "select * from "; + command << rulename << " where entrytype = 'test';"; + query = DBQuery(db, command.String(), "PrefsWindow::LoadRules"); + + while (!query.eof()) + { + BString classname = DeescapeIllegalCharacters(query.getStringField(1)); + BMessage* test = new BMessage; + + test->AddString("name", classname); + + if (classname.ICompare("Attribute") == 0) { + test->AddString("mimetype", + DeescapeIllegalCharacters(query.getStringField(4))); + test->AddString("typename", + DeescapeIllegalCharacters(query.getStringField(5))); + test->AddString("attrname", + DeescapeIllegalCharacters(query.getStringField(6))); + } + + test->AddString("mode", + DeescapeIllegalCharacters(query.getStringField(2)).String()); + test->AddString("value", + DeescapeIllegalCharacters(query.getStringField(3)).String()); + + rule->AddTest(test); + + query.nextRow(); + } + query.finalize(); + + command = "select * from "; + command << rulename << " where entrytype = 'action';"; + query = DBQuery(db, command.String(), "PrefsWindow::LoadRules"); + + while (!query.eof()) + { + BMessage* action = new BMessage; + + action->AddString("name", + DeescapeIllegalCharacters(query.getStringField(1))); + action->AddString("value", + DeescapeIllegalCharacters(query.getStringField(3))); + + rule->AddAction(action); + + query.nextRow(); + } + query.finalize(); + } + db.close(); + return B_OK; +} + + +BMessage* +MakeTest(const char* name, const char* mode, const char* value, + const char* mimeType, const char* typeName, const char* attrType, + const char* attrName) +{ + BMessage* msg = new BMessage; + msg->AddString("name", name); + msg->AddString("mode", mode); + msg->AddString("value", value); + + if (typeName || mimeType || attrType || attrName) { + if (!(typeName && mimeType && attrType && attrName)) { + debugger("The last 4 parameters must all be either NULL " + "or non-NULL as a group"); + } + msg->AddString("typename", typeName); + msg->AddString("mimetype", mimeType); + msg->AddString("attrtype", attrType); + msg->AddString("attrname", attrName); + } + return msg; +} + + +BMessage* +MakeAction(const char* name, const char* value) +{ + BMessage* msg = new BMessage; + msg->AddString("name", name); + msg->AddString("value", value); + + return msg; +} diff --git a/sources/RuleRunner.h b/sources/RuleRunner.h new file mode 100644 index 0000000..493fc8d --- /dev/null +++ b/sources/RuleRunner.h @@ -0,0 +1,60 @@ +/* + RuleRunner.h: class to handle running test and actions for the rules + Released under the MIT license. + Written by DarkWyrm , Copyright 2008 + Contributed by: Humdinger , 2016 +*/ + +#ifndef RULERUNNER_H +#define RULERUNNER_H + +#include "FilerRule.h" +#include "ObjectList.h" + +#include +#include + +enum +{ + TEST_TYPE_NULL = 0, + TEST_TYPE_STRING, + TEST_TYPE_NUMBER, + TEST_TYPE_DATE, + TEST_TYPE_ANY +}; + + +class RuleRunner +{ +public: + RuleRunner(); + ~RuleRunner(); + + static void GetTestTypes(BMessage& msg); + static status_t GetCompatibleModes(const char* testtype, BMessage& msg); + static status_t GetCompatibleModes(const int32& type, BMessage& msg); + static void GetModes(BMessage& msg); + static void GetActions(BMessage& msg); + + static BString GetEditorTypeForTest(const char* testname); + + static int32 GetDataTypeForTest(const char* testname); + static int32 GetDataTypeForMode(const char* modename); + + bool IsMatch(const BMessage& test, const entry_ref& ref); + status_t RunAction(const BMessage& test, entry_ref& ref); + status_t RunRule(FilerRule* rule, entry_ref& ref); +}; + +status_t LoadRules(BObjectList *ruleList); +status_t SaveRules(BObjectList *ruleList); + + +// Some convenience functions. Deleting the returned BMessage is the +// responsibility of the caller +BMessage* MakeTest(const char* name, const char* mode, const char* value, + const char* mimeType = NULL, const char* typeName = NULL, + const char* attrType = NULL, const char* attrName = NULL); +BMessage* MakeAction(const char* name, const char* value); + +#endif // RULERUNNER_H diff --git a/sources/RuleTab.cpp b/sources/RuleTab.cpp new file mode 100644 index 0000000..ffa4b2f --- /dev/null +++ b/sources/RuleTab.cpp @@ -0,0 +1,359 @@ +/* + * Copyright 2008, 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm , Copyright 2008 + * Humdinger, humdingerb@gmail.com + */ +#include +#include +#include +#include +#include +#include +#include + +#include "FilerRule.h" +#include "FilerDefs.h" +#include "RuleEditWindow.h" +#include "RuleItem.h" +#include "RuleRunner.h" +#include "RuleTab.h" + + +RuleTab::RuleTab() + : + BView("Rules", B_SUPPORTS_LAYOUT) +{ + _BuildLayout(); + + fRuleList = new BObjectList(20, true); + LoadRules(fRuleList); + + for (int32 i = 0; i < fRuleList->CountItems(); i++) + fRuleItemList->AddItem(new RuleItem(fRuleList->ItemAt(i))); + + fRuleItemList->MakeFocus(); + if (fRuleItemList->CountItems() > 0) + fRuleItemList->Select(0L); + else { + BAlert* alert = new BAlert("Filer", + "It appears that there aren't any rules for " + "organizing files. Would you like Filer to " + "add some basic ones for you?", + "No", "Yes"); + + if (alert->Go() == 1) { + FilerRule* rule = new FilerRule(); + + // NOTE: If actions + rule->AddTest(MakeTest("Type", "is", "text/plain")); + rule->AddAction(MakeAction("Move it to…", "/boot/home/Documents")); + rule->SetDescription("Store text files in my Documents folder"); + AddRule(rule); + + rule = new FilerRule(); + rule->AddTest(MakeTest("Type", "is", "application/pdf")); + rule->AddAction(MakeAction("Move it to…", "/boot/home/Documents")); + rule->SetDescription("Store PDF files in my Documents folder"); + AddRule(rule); + + rule = new FilerRule(); + rule->AddTest(MakeTest("Type", "starts with", "image/")); + rule->AddAction(MakeAction("Move it to…", "/boot/home/Pictures")); + rule->SetDescription("Store pictures in my Pictures folder"); + AddRule(rule); + + rule = new FilerRule(); + rule->AddTest(MakeTest("Type", "starts with","video/")); + rule->AddAction(MakeAction("Move it to…", "/boot/home/Videos")); + rule->SetDescription("Store movie files in my Videos folder"); + AddRule(rule); + + rule = new FilerRule(); + rule->AddTest(MakeTest("Name", "ends with", ".zip")); + rule->AddAction(MakeAction("Terminal command…", + "unzip %FULLPATH% -d /boot/home/Desktop")); + rule->SetDescription("Extract ZIP files to the Desktop"); + AddRule(rule); + +// rule = new FilerRule(); +// rule->AddTest(MakeTest("","","")); +// rule->AddAction(MakeAction("","")); +// rule->SetDescription(""); +// AddRule(rule); + } + SaveRules(fRuleList); + } +} + + +RuleTab::~RuleTab() +{ + delete fRuleList; +} + + +void +RuleTab::_BuildLayout() +{ + fRuleItemList = new BListView("rulelist", B_SINGLE_SELECTION_LIST, + B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE); + fScrollView = new BScrollView("listscroll", fRuleItemList, + B_FRAME_EVENTS | B_WILL_DRAW, false, true); + + fRuleItemList->SetSelectionMessage(new BMessage(MSG_RULE_SELECTED)); + fRuleItemList->SetInvocationMessage(new BMessage(MSG_SHOW_EDIT_WINDOW)); +// fScrollView->ScrollBar(B_HORIZONTAL)->SetRange(0.0, 0.0); + + fAddButton = new BButton("addbutton", "Add" B_UTF8_ELLIPSIS, + new BMessage(MSG_SHOW_ADD_WINDOW)); + + fEditButton = new BButton("editbutton", "Edit" B_UTF8_ELLIPSIS, + new BMessage(MSG_SHOW_EDIT_WINDOW)); + fEditButton->SetEnabled(false); + + fRemoveButton = new BButton("removebutton", "Remove", + new BMessage(MSG_REMOVE_RULE)); + fRemoveButton->SetEnabled(false); + + fMoveUpButton = new BButton("moveupbutton", "Move up", + new BMessage(MSG_MOVE_RULE_UP)); + fMoveUpButton->SetEnabled(false); + + fMoveDownButton = new BButton("movedownbutton", "Move down", + new BMessage(MSG_MOVE_RULE_DOWN)); + fMoveDownButton->SetEnabled(false); + + static const float spacing = be_control_look->DefaultItemSpacing(); + BLayoutBuilder::Group<>(this, B_HORIZONTAL, B_USE_DEFAULT_SPACING) + .SetInsets(spacing) + .AddGroup(B_VERTICAL, 10.0f) + .Add(fScrollView) + .AddGroup(B_HORIZONTAL) + .AddGlue() + .Add(fAddButton) + .Add(fEditButton) + .Add(fRemoveButton) + .AddGlue() + .End() + .End() + .AddGroup(B_VERTICAL) + .Add(fMoveUpButton) + .Add(fMoveDownButton) + .AddGlue() + .End(); +} + + +void +RuleTab::AttachedToWindow() +{ + fAddButton->SetTarget(this); + fEditButton->SetTarget(this); + fRemoveButton->SetTarget(this); + fMoveUpButton->SetTarget(this); + fMoveDownButton->SetTarget(this); + fRuleItemList->SetTarget(this); + + if (fRuleItemList->CountItems() > 0) { + BMessenger messenger(this); + BMessage message(MSG_RULE_SELECTED); + messenger.SendMessage(&message); + } + BView::AttachedToWindow(); +} + + +void +RuleTab::DetachedFromWindow() +{ + if (fChanges) + SaveRules(fRuleList); + MakeEmpty(); +} + + +void +RuleTab::MessageReceived(BMessage* message) +{ +// message->PrintToStream(); + switch (message->what) + { + case MSG_SHOW_ADD_WINDOW: + { + printf("Show Add Window\n"); + BRect frame(Frame()); + ConvertToScreen(&frame); + frame.right = frame.left + 400; + frame.bottom = frame.top + 300; + frame.OffsetBy(60, 30); + + RuleEditWindow* rulewin = new RuleEditWindow(frame, NULL); + rulewin->Show(); + break; + } + case MSG_SHOW_EDIT_WINDOW: + { + BRect frame(Frame()); + ConvertToScreen(&frame); + frame.right = frame.left + 400; + frame.bottom = frame.top + 300; + frame.OffsetBy(60, 30); + + FilerRule* rule = fRuleList->ItemAt( + fRuleItemList->CurrentSelection()); + + RuleEditWindow* rulewin = new RuleEditWindow(frame, rule); + rulewin->Show(); + break; + } + case MSG_ADD_RULE: + { + fChanges = true; + FilerRule* item; + if (message->FindPointer("item", (void**)&item) == B_OK) + AddRule(item); + break; + } + case MSG_REMOVE_RULE: + { + fChanges = true; + if (fRuleItemList->CurrentSelection() >= 0) + RemoveRule((RuleItem*)fRuleItemList->ItemAt( + fRuleItemList->CurrentSelection())); + break; + } + case MSG_UPDATE_RULE: + { + fChanges = true; + FilerRule* rule; + if (message->FindPointer("item", (void**)&rule) == B_OK) + { + int64 id; + if (message->FindInt64("id",&id) != B_OK) + debugger("Couldn't find update ID"); + + for (int32 i = 0; i < fRuleList->CountItems(); i++) + { + FilerRule* oldrule = fRuleList->ItemAt(i); + if (oldrule->GetID() == id) + { + *oldrule = *rule; + RuleItem* item = (RuleItem*)fRuleItemList->ItemAt(i); + item->SetText(rule->GetDescription()); + break; + } + } + delete rule; + } + break; + } + case MSG_REVERT: + { + while (fRuleItemList->CountItems() > 0) + RemoveRule((RuleItem*)fRuleItemList->ItemAt(0L)); + fRuleList->MakeEmpty(); + fEditButton->SetEnabled(false); + fRemoveButton->SetEnabled(false); + + LoadRules(fRuleList); + break; + } + case MSG_RULE_SELECTED: + { + bool value = (fRuleItemList->CurrentSelection() >= 0); + + fEditButton->SetEnabled(value); + fRemoveButton->SetEnabled(value); + + if (fRuleItemList->CountItems() > 1) { + fMoveUpButton->SetEnabled(value); + fMoveDownButton->SetEnabled(value); + } + break; + } + case MSG_MOVE_RULE_UP: + { + fChanges = true; + int32 selection = fRuleItemList->CurrentSelection(); + if (selection < 1) + break; + + fRuleItemList->SwapItems(selection, selection - 1); + fRuleList->SwapItems(selection, selection - 1); + break; + } + case MSG_MOVE_RULE_DOWN: + { + fChanges = true; + int32 selection = fRuleItemList->CurrentSelection(); + if (selection > fRuleItemList->CountItems() - 1) + break; + + fRuleItemList->SwapItems(selection, selection + 1); + fRuleList->SwapItems(selection, selection + 1); + break; + } + default: + BView::MessageReceived(message); + break; + } +} + + +void +RuleTab::AddRule(FilerRule* rule) +{ + fRuleList->AddItem(rule); + fRuleItemList->AddItem(new RuleItem(rule)); + + if (fRuleItemList->CurrentSelection() < 0) + fRuleItemList->Select(0L); +} + + +void +RuleTab::RemoveRule(RuleItem* item) +{ + // Select a new rule (if there is one) before removing the old one. + // BListView simply drops the selection if the selected item is removed. + // What a pain in the neck. :/ + int32 itemindex = fRuleItemList->IndexOf(item); + int32 selection = fRuleItemList->CurrentSelection(); + if (itemindex == selection && fRuleItemList->CountItems() > 1) { + if (selection == fRuleItemList->CountItems() - 1) + selection--; + else + selection++; + fRuleItemList->Select(selection); + } + + fRuleItemList->RemoveItem(item); + + FilerRule* rule = item->Rule(); + fRuleList->RemoveItem(rule); + delete item; + + if (fRuleItemList->CountItems() <= 0) { + fEditButton->SetEnabled(false); + fRemoveButton->SetEnabled(false); + } + + if (fRuleItemList->CountItems() < 2) { + fMoveUpButton->SetEnabled(false); + fMoveDownButton->SetEnabled(false); + } +} + + +void +RuleTab::MakeEmpty() +{ + for (int32 i = fRuleItemList->CountItems() - 1; i >= 0; i--) + { + RuleItem* item = (RuleItem*)fRuleItemList->RemoveItem(i); + delete item; + } +} diff --git a/sources/RuleTab.h b/sources/RuleTab.h new file mode 100644 index 0000000..0a877e5 --- /dev/null +++ b/sources/RuleTab.h @@ -0,0 +1,52 @@ +/* + * Copyright 2008, 2016. All rights reserved. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm , Copyright 2008 + * Humdinger, humdingerb@gmail.com + */ +#ifndef RULETAB_H +#define RULETAB_H + +#include +#include +#include + +#include "ObjectList.h" + +class RuleItem; +class FilerRule; + +class RuleTab : public BView +{ +public: + RuleTab(); + ~RuleTab(); + + virtual void AttachedToWindow(); + virtual void DetachedFromWindow(); + void MessageReceived(BMessage* message); + +private: + void _BuildLayout(); + + void AddRule(FilerRule* rule); + void RemoveRule(RuleItem* item); + void MakeEmpty(); + + BObjectList*fRuleList; + + BButton* fAddButton; + BButton* fEditButton; + BButton* fRemoveButton; + BButton* fMoveUpButton; + BButton* fMoveDownButton; + + BListView* fRuleItemList; + BScrollView* fScrollView; + bool fChanges; +}; + + +#endif // RULETAB_H diff --git a/sources/Filer/TestView.cpp b/sources/TestView.cpp similarity index 52% rename from sources/Filer/TestView.cpp rename to sources/TestView.cpp index dc0767b..d8402ba 100644 --- a/sources/Filer/TestView.cpp +++ b/sources/TestView.cpp @@ -3,27 +3,16 @@ Written by DarkWyrm , Copyright 2008 Released under the MIT license. */ -#include "TestView.h" + #include -#include #include #include -#include "RuleRunner.h" +#include #include "AutoTextControl.h" - -enum -{ - M_TEST_CHOSEN = 'tsch', - M_MODE_CHOSEN = 'mdch', - M_VALUE_CHANGED = 'vlch', - - M_TYPE_CHOSEN = 'tych', - - M_SHOW_TEST_MENU = 'shtm', - M_SHOW_TYPE_MENU = 'stym', - M_SHOW_MODE_MENU = 'shmm' -}; +#include "FilerDefs.h" +#include "RuleRunner.h" +#include "TestView.h" extern BMessage gArchivedTypeMenu; @@ -39,9 +28,10 @@ extern BMessage gArchivedTypeMenu; #endif -TestView::TestView(const BRect &frame,const char *name, BMessage *test, - const int32 &resize,const int32 &flags) - : BView(frame,name,resize,flags), +TestView::TestView(const BRect& frame, const char* name, BMessage* test, + const int32& resize, const int32& flags) + : + BView(frame, name, resize, flags), fTest(NULL) { SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); @@ -50,103 +40,99 @@ TestView::TestView(const BRect &frame,const char *name, BMessage *test, RuleRunner::GetTestTypes(fTestTypes); int32 i = 0; BString teststr, widesttest, widestmode; - while (fTestTypes.FindString("tests",i,&teststr) == B_OK) + while (fTestTypes.FindString("tests", i, &teststr) == B_OK) { i++; if (teststr.CountChars() > widesttest.CountChars()) widesttest = teststr; } - + // This will hopefully accomodate some of the attribute strings teststr = "Netpositive Password"; if (teststr.CountChars() > widesttest.CountChars()) widesttest = teststr; - - fTestButton = new BButton(BRect(0,0,1,1),"testbutton",widesttest.String(), - new BMessage(M_SHOW_TEST_MENU)); + + fTestButton = new BButton(BRect(0, 0, 1, 1), "testbutton", + widesttest.String(), new BMessage(MSG_SHOW_TEST_MENU)); fTestButton->ResizeToPreferred(); AddChild(fTestButton); - + BRect rect = fTestButton->Frame(); - rect.OffsetBy(rect.Width() + 10.0,0.0); - + rect.OffsetBy(rect.Width() + 10.0, 0.0); + // Find the longest name in all the modes BMessage modes; RuleRunner::GetModes(modes); i = 0; - while (modes.FindString("modes",i,&teststr) == B_OK) + while (modes.FindString("modes", i, &teststr) == B_OK) { i++; if (teststr.CountChars() > widestmode.CountChars()) widestmode = teststr; } - - fModeButton = new BButton(rect,"modebutton",widestmode.String(), - new BMessage(M_SHOW_MODE_MENU)); + + fModeButton = new BButton(rect, "modebutton", widestmode.String(), + new BMessage(MSG_SHOW_MODE_MENU)); fModeButton->ResizeToPreferred(); AddChild(fModeButton); - + rect = fModeButton->Frame(); - rect.OffsetBy(rect.Width() + 5,0); + rect.OffsetBy(rect.Width() + 5, 0); rect.right = rect.left + StringWidth("application/x-vnd.dw-foo") + 5; - fValueBox = new AutoTextControl(rect,"valuebox",NULL,NULL, - new BMessage(M_VALUE_CHANGED), - B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fValueBox = new AutoTextControl(rect, "valuebox", NULL, NULL, + new BMessage(MSG_VALUE_CHANGED), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); AddChild(fValueBox); fValueBox->SetDivider(0); - if (fValueBox->Bounds().Height() < fModeButton->Bounds().Height()) - fValueBox->MoveBy(0.0,(fModeButton->Bounds().Height() - fValueBox->Bounds().Height()) / 2.0); - + if (fValueBox->Bounds().Height() < fModeButton->Bounds().Height()) { + fValueBox->MoveBy(0.0,(fModeButton->Bounds().Height() + - fValueBox->Bounds().Height()) / 2.0); + } SetupTestMenu(); - + bool usedefaults = false; - if (test) - { + if (test) { STRACE(("\nTestView::TestView: test parameter\n")); MSGTRACE(test); - + fTest = new BMessage(*test); BString str; - + if (!SetTest(fTest)) usedefaults = true; - - if (fTest->FindString("mode",&str) == B_OK) + + if (fTest->FindString("mode", &str) == B_OK) SetMode(str.String()); - else - { - fTest->FindString("name",&str); + else { + fTest->FindString("name" ,&str); modes.MakeEmpty(); - RuleRunner::GetCompatibleModes(str.String(),modes); - modes.FindString("modes",0,&str); + RuleRunner::GetCompatibleModes(str.String(), modes); + modes.FindString("modes", 0, &str); SetMode(str.String()); } - - if (fTest->FindString("value",&str) == B_OK) + + if (fTest->FindString("value", &str) == B_OK) fValueBox->SetText(str.String()); - } - else + } else usedefaults = true; - - if (usedefaults) - { + + if (usedefaults) { if (!fTest) fTest = new BMessage; - + BString str; - fTestTypes.FindString("tests",0,&str); - + fTestTypes.FindString("tests", 0, &str); + BMessage newtest; - newtest.AddString("name",str); - + newtest.AddString("name", str); + modes.MakeEmpty(); - RuleRunner::GetCompatibleModes(str.String(),modes); - modes.FindString("modes",0,&str); - - newtest.AddString("mode",str); - newtest.AddString("value",""); - + RuleRunner::GetCompatibleModes(str.String(), modes); + modes.FindString("modes", 0, &str); + + newtest.AddString("mode", str); + newtest.AddString("value", ""); + SetTest(&newtest); SetMode(str.String()); } @@ -154,7 +140,7 @@ TestView::TestView(const BRect &frame,const char *name, BMessage *test, void -TestView::AttachedToWindow(void) +TestView::AttachedToWindow() { fTestButton->SetTarget(this); fModeButton->SetTarget(this); @@ -163,18 +149,18 @@ TestView::AttachedToWindow(void) BRect -TestView::GetPreferredSize(void) +TestView::GetPreferredSize() { BRect rect(fValueBox->Frame()); rect.left = rect.top = 0.0; rect.bottom += 10.0; - + return rect; } void -TestView::ResizeToPreferred(void) +TestView::ResizeToPreferred() { BRect rect = GetPreferredSize(); ResizeTo(rect.Width(),rect.Height()); @@ -182,90 +168,92 @@ TestView::ResizeToPreferred(void) void -TestView::MessageReceived(BMessage *msg) +TestView::MessageReceived(BMessage* msg) { switch (msg->what) { - case M_TEST_CHOSEN: + case MSG_TEST_CHOSEN: { SetTest(msg); break; } - case M_MODE_CHOSEN: + case MSG_MODE_CHOSEN: { BString mode; if (msg->FindString("mode",&mode) != B_OK) break; - + SetMode(mode.String()); break; } - case M_VALUE_CHANGED: + case MSG_VALUE_CHANGED: { BString str; - if (fTest->FindString("value",&str) == B_OK) - fTest->ReplaceString("value",fValueBox->Text()); + if (fTest->FindString("value", &str) == B_OK) + fTest->ReplaceString("value", fValueBox->Text()); else - fTest->AddString("value",fValueBox->Text()); + fTest->AddString("value", fValueBox->Text()); break; } - case M_SHOW_TEST_MENU: + case MSG_SHOW_TEST_MENU: { - BPopUpMenu *menu = (BPopUpMenu*)BPopUpMenu::Instantiate(&fArchivedTestMenu); + BPopUpMenu* menu + = (BPopUpMenu*)BPopUpMenu::Instantiate(&fArchivedTestMenu); menu->SetTargetForItems(this); - + for (int32 i = 0; i < menu->CountItems(); i++) { - BMenuItem *item = menu->ItemAt(i); + BMenuItem* item = menu->ItemAt(i); if (item->Submenu()) item->Submenu()->SetTargetForItems(this); } - - BPoint pt; + + BPoint point; uint32 buttons; - GetMouse(&pt,&buttons); - ConvertToScreen(&pt); - pt.x -= 10.0; - if (pt.x < 0.0) - pt.x = 0.0; - - pt.y -= 10.0; - if (pt.y < 0.0) - pt.y = 0.0; - + GetMouse(&point, &buttons); + ConvertToScreen(&point); + point.x -= 10.0; + if (point.x < 0.0) + point.x = 0.0; + + point.y -= 10.0; + if (point.y < 0.0) + point.y = 0.0; + menu->SetAsyncAutoDestruct(true); - menu->Go(pt,true,true,true); + menu->Go(point, true, true, true); break; } - case M_SHOW_TYPE_MENU: + case MSG_SHOW_TYPE_MENU: { - BPopUpMenu *menu = (BPopUpMenu*)BPopUpMenu::Instantiate(&gArchivedTypeMenu); + BPopUpMenu* menu + = (BPopUpMenu*)BPopUpMenu::Instantiate(&gArchivedTypeMenu); menu->SetTargetForItems(this); - + for (int32 i = 0; i < menu->CountItems(); i++) { - BMenuItem *item = menu->ItemAt(i); + BMenuItem* item = menu->ItemAt(i); if (item->Submenu()) item->Submenu()->SetTargetForItems(this); } - - BPoint pt; + + BPoint point; uint32 buttons; - GetMouse(&pt,&buttons); - ConvertToScreen(&pt); - pt.x -= 10.0; - if (pt.x < 0.0) - pt.x = 0.0; - - pt.y -= 10.0; - if (pt.y < 0.0) - pt.y = 0.0; - + GetMouse(&point, &buttons); + ConvertToScreen(&point); + point.x -= 10.0; + if (point.x < 0.0) + point.x = 0.0; + + point.y -= 10.0; + if (point.y < 0.0) + point.y = 0.0; + menu->SetAsyncAutoDestruct(true); - menu->Go(pt,true,true,true); + menu->Go(point, true, true, true); break; } - case M_SHOW_MODE_MENU: + case MSG_SHOW_MODE_MENU: { ShowModeMenu(); break; @@ -280,31 +268,30 @@ TestView::MessageReceived(BMessage *msg) } -BMessage * -TestView::GetTest(void) const +BMessage* +TestView::GetTest() const { return fTest; } void -TestView::SetupTestMenu(void) +TestView::SetupTestMenu() { // These ones will always exist. Type is the default because it's probably // going to be the one most used - BMessage *msg; - BPopUpMenu *menu = new BPopUpMenu("Test"); - - + BMessage* msg; + BPopUpMenu* menu = new BPopUpMenu("Test"); + // Read in the types in the MIME database which have extra attributes // associated with them - + BMimeType mime; BMessage types, info, attr; BString string; - + BMimeType::GetInstalledTypes(&types); - + int32 index = 0; while (types.FindString("types",index,&string) == B_OK) { @@ -312,133 +299,132 @@ TestView::SetupTestMenu(void) mime.SetTo(string.String()); if (mime.GetAttrInfo(&info) != B_OK) continue; - + int32 infoindex = 0; BString attrName; BString attrPublicName; int32 attrType; - + char attrTypeName[B_MIME_TYPE_LENGTH]; mime.GetShortDescription(attrTypeName); - - while (info.FindString("attr:name",infoindex,&attrName) == B_OK) + + while (info.FindString("attr:name", infoindex, &attrName) == B_OK) { - // This is where we create tests based on a particular type's "special" attributes + // This is where we create tests based on a particular type's + // "special" attributes // Just string attributes are supported for now - if (info.FindInt32("attr:type",infoindex,&attrType) != B_OK || - attrType != B_STRING_TYPE || - info.FindString("attr:public_name",infoindex,&attrPublicName) != B_OK) - { - infoindex++; - continue; + if (info.FindInt32("attr:type", infoindex, &attrType) != B_OK + || attrType != B_STRING_TYPE + || info.FindString("attr:public_name", infoindex, + &attrPublicName) != B_OK) { + infoindex++; + continue; } - - BMenu *submenu = GetMenu(menu,attrTypeName); + + BMenu* submenu = GetMenu(menu, attrTypeName); if (!submenu) - submenu = AddMenuSorted(menu,attrTypeName); - - msg = new BMessage(M_TEST_CHOSEN); - msg->AddString("name","Attribute"); - msg->AddString("attrtype",attrName); - msg->AddString("attrname",attrPublicName); - msg->AddString("mimetype",string); - msg->AddString("typename",attrTypeName); - submenu->AddItem(new BMenuItem(attrPublicName.String(),msg)); - + submenu = AddMenuSorted(menu, attrTypeName); + + msg = new BMessage(MSG_TEST_CHOSEN); + msg->AddString("name", "Attribute"); + msg->AddString("attrtype", attrName); + msg->AddString("attrname", attrPublicName); + msg->AddString("mimetype", string); + msg->AddString("typename", attrTypeName); + submenu->AddItem(new BMenuItem(attrPublicName.String(), msg)); + infoindex++; } } - - menu->AddItem(new BSeparatorItem(),0); - - + + menu->AddItem(new BSeparatorItem(), 0); + // All this weirdness is to have the "standard" tests at the top and // the attribute tests at the bottom with a separator in between BString testtype; int32 i = 0; - while (fTestTypes.FindString("tests",i,&testtype) == B_OK) + while (fTestTypes.FindString("tests", i, &testtype) == B_OK) i++; - + i--; - + while (i >= 0) { - fTestTypes.FindString("tests",i,&testtype); - msg = new BMessage(M_TEST_CHOSEN); - msg->AddString("name",testtype); - menu->AddItem(new BMenuItem(testtype.String(),msg),0); + fTestTypes.FindString("tests", i, &testtype); + msg = new BMessage(MSG_TEST_CHOSEN); + msg->AddString("name", testtype); + menu->AddItem(new BMenuItem(testtype.String(), msg),0); i--; } - - + menu->Archive(&fArchivedTestMenu); delete menu; } void -TestView::ShowModeMenu(void) +TestView::ShowModeMenu() { - BPopUpMenu *menu = new BPopUpMenu("String"); - BMessage *msg, modes; + BPopUpMenu* menu = new BPopUpMenu("String"); + BMessage* msg, modes; - if (RuleRunner::GetCompatibleModes(fTestButton->Label(),modes) != B_OK) + if (RuleRunner::GetCompatibleModes(fTestButton->Label(), modes) != B_OK) return; BString modestr; int32 i = 0; - while (modes.FindString("modes",i,&modestr) == B_OK) + while (modes.FindString("modes", i, &modestr) == B_OK) { i++; - msg = new BMessage(M_MODE_CHOSEN); - msg->AddString("mode",modestr); + msg = new BMessage(MSG_MODE_CHOSEN); + msg->AddString("mode", modestr); menu->AddItem(new BMenuItem(modestr.String(), msg)); } - + menu->SetTargetForItems(this); - - BPoint pt; + + BPoint point; uint32 buttons; - GetMouse(&pt,&buttons); - ConvertToScreen(&pt); - pt.x -= 10.0; - if (pt.x < 0.0) - pt.x = 0.0; - - pt.y -= 10.0; - if (pt.y < 0.0) - pt.y = 0.0; - + GetMouse(&point, &buttons); + ConvertToScreen(&point); + point.x -= 10.0; + if (point.x < 0.0) + point.x = 0.0; + + point.y -= 10.0; + if (point.y < 0.0) + point.y = 0.0; + menu->SetAsyncAutoDestruct(true); - menu->Go(pt,true,true,true); + menu->Go(point, true, true, true); } -BMenu * -TestView::AddMenuSorted(BMenu *parent,const char *name) +BMenu* +TestView::AddMenuSorted(BMenu* parent, const char* name) { // XXX: TODO: This doesn't work for some reason -- the items aren't sorted :( - + if (!name) return NULL; - - BMenu *menu = new BMenu(name); - + + BMenu* menu = new BMenu(name); + for (int32 i = 0; i < parent->CountItems(); i++) { - BMenuItem *item = parent->ItemAt(i); - - if (strcmp(item->Label(),name) == -1) - { -// printf("INSERT: %s is after %s\n",name,item->Label()); - parent->AddItem(menu,i); + BMenuItem* item = parent->ItemAt(i); + + if (strcmp(item->Label(), name) == -1) { +// printf("INSERT: %s is after %s\n", name, item->Label()); + parent->AddItem(menu, i); return menu; } } - + // if (parent->CountItems()) -// printf("%s is after %s\n",name,parent->ItemAt(parent->CountItems() - 1)->Label()); +// printf("%s is after %s\n", name, parent->ItemAt(parent->CountItems() +// - 1)->Label()); // else // printf("%s is last\n",name); @@ -447,127 +433,122 @@ TestView::AddMenuSorted(BMenu *parent,const char *name) } -BMenu * -TestView::GetMenu(BMenu *parent, const char *name) +BMenu* +TestView::GetMenu(BMenu* parent, const char* name) { - // This is because FindMenu recursively searches a menu. We just want to check the - // top level of fTestMenu - + // This is because FindMenu recursively searches a menu. We just want to + // check the top level of fTestMenu + if (!name) return NULL; - - + for (int32 i = 0; i < parent->CountItems(); i++) { - BMenuItem *item = parent->ItemAt(i); - + BMenuItem* item = parent->ItemAt(i); + if (!item->Submenu()) continue; - - if (strcmp(item->Label(),name) == 0) + + if (strcmp(item->Label(), name) == 0) return item->Submenu(); } - + return NULL; } bool -TestView::SetTest(BMessage *msg) +TestView::SetTest(BMessage* msg) { STRACE(("\nTestView::SetTest\n")); if (!msg) return false; - + MSGTRACE(msg); - + // The easy way to update fTest is just copy the whole thing and update // the mode and value from the controls. This saves some conditionals when // dealing with attribute tests. The fields sent by the menu items (and passed - // to this function) are the exact same as what is needed by RuleRunner's test code + // to this function) are the exact same as what is needed by RuleRunner's test + // code. // There is one catch, however. The message passed here will NOT have the mode // or value, so we need to save them and copy them over - + BString str, mode, value; - - fTest->FindString("mode",&mode); - fTest->FindString("value",&value); + + fTest->FindString("mode", &mode); + fTest->FindString("value", &value); *fTest = *msg; - + fTest->what = 0; - - if (fTest->FindString("mode",&str) != B_OK) - fTest->AddString("mode",mode); - - if (fTest->FindString("value",&str) != B_OK) - fTest->AddString("value",value); - - + + if (fTest->FindString("mode" ,&str) != B_OK) + fTest->AddString("mode", mode); + + if (fTest->FindString("value", &str) != B_OK) + fTest->AddString("value", value); + BString label; - - fTest->FindString("name",&str); + + fTest->FindString("name", &str); int32 testtype; - if (str == "Attribute") - { - fTest->FindString("typename",&str); + if (str == "Attribute") { + fTest->FindString("typename", &str); label = str; - fTest->FindString("attrname",&str); + fTest->FindString("attrname", &str); label << " : " << str; testtype = TEST_TYPE_STRING; - + // Truncate the label because it is likely too long for the button - be_plain_font->TruncateString(&label,B_TRUNCATE_SMART, - fTestButton->Bounds().Width() - 10.0); - } - else - { + be_plain_font->TruncateString(&label, B_TRUNCATE_SMART, + fTestButton->Bounds().Width() - 10.0); + } else { label = str; testtype = RuleRunner::GetDataTypeForTest(label.String()); } - + fTestButton->SetLabel(label.String()); - + // Now that the test button has been updated, make sure that the mode currently // set is supported by the current test int32 modetype = RuleRunner::GetDataTypeForMode(fModeButton->Label()); - if (testtype != modetype && modetype != TEST_TYPE_ANY) - { + if (testtype != modetype && modetype != TEST_TYPE_ANY) { STRACE(("Modes not compatible, refreshing.\n")); // Not compatible, so reset the mode to something compatible BMessage modes; - RuleRunner::GetCompatibleModes(testtype,modes); - + RuleRunner::GetCompatibleModes(testtype, modes); + BString modestr; - modes.FindString("modes",0,&modestr); + modes.FindString("modes", 0, &modestr); SetMode(modestr.String()); } STRACE(("-------------------------\n")); - + return true; } void -TestView::SetMode(const char *mode) +TestView::SetMode(const char* mode) { if (!mode) return; - - // This function assumes that the string passed to it is valid for the test type + + // This function assumes that the string passed to it is valid + // for the test type BString str; - if (fTest->FindString("mode",&str) == B_OK) - fTest->ReplaceString("mode",mode); + if (fTest->FindString("mode", &str) == B_OK) + fTest->ReplaceString("mode", mode); else - fTest->AddString("mode",mode); + fTest->AddString("mode", mode); fModeButton->SetLabel(mode); } -const char * -TestView::GetValue(void) +const char* +TestView::GetValue() { // Exists for future expansion when different controls are associated with // different tests return fValueBox->Text(); } - diff --git a/sources/TestView.h b/sources/TestView.h new file mode 100644 index 0000000..4894313 --- /dev/null +++ b/sources/TestView.h @@ -0,0 +1,55 @@ +/* + TestView.h: view to display and edit settings for Filer tests + Written by DarkWyrm , Copyright 2008 + Released under the MIT license. +*/ +#ifndef TESTVIEW_H +#define TESTVIEW_H + +#include +#include +#include +#include +#include +#include +#include + +class AutoTextControl; + +class TestView : public BView +{ +public: + TestView(const BRect& frame, const char* name, + BMessage* test = NULL, + const int32& resize = B_FOLLOW_LEFT | B_FOLLOW_TOP, + const int32& flags = B_WILL_DRAW); + + void AttachedToWindow(); + BRect GetPreferredSize(); + void ResizeToPreferred(); + void MessageReceived(BMessage* msg); + BMessage* GetTest() const; + +private: + void SetupTestMenu(); + void ShowModeMenu(); + bool SetTest(BMessage* msg); + void SetMode(const char* mode); + const char* GetValue(); + + BMenu* AddMenuSorted(BMenu* parent, const char* name); + BMenu* GetMenu(BMenu* parent, const char* name); + + BButton* fTestButton; + BButton* fModeButton; + + BMessage fArchivedTestMenu; + + AutoTextControl* fValueBox; + + BMessage* fTest; + BMessage fTestTypes; + +}; + +#endif // TESTVIEW_H diff --git a/sources/TypedRefFilter.cpp b/sources/TypedRefFilter.cpp new file mode 100644 index 0000000..8405872 --- /dev/null +++ b/sources/TypedRefFilter.cpp @@ -0,0 +1,70 @@ +#include "TypedRefFilter.h" + +TypedRefFilter::TypedRefFilter() + : + BRefFilter() +{ +} + + +TypedRefFilter::TypedRefFilter(const char* file_type, const uint32& node_type) + : + BRefFilter(), + fFileType(file_type), + fNodeType(node_type) +{ +} + + +TypedRefFilter::~TypedRefFilter() +{ +} + + +const char* +TypedRefFilter::FileType() const +{ + return fFileType.String(); +} + + +void +TypedRefFilter::SetFileType(const char* type) +{ + fFileType = type; +} + + +uint32 +TypedRefFilter::NodeType() const +{ + return fNodeType; +} + + +void +TypedRefFilter::SetNodeType(const uint32& node_type) +{ + fNodeType = node_type; +} + + +bool +TypedRefFilter::Filter(const entry_ref* ref, BNode* node, struct stat_beos* st, + const char* filetype) +{ + // it does not match the entry filter, then we automatically kick back a false + if ( !( ((B_DIRECTORY_NODE & NodeType()) && S_ISDIR(st->st_mode)) + || ((B_FILE_NODE & NodeType()) && S_ISREG(st->st_mode)) + || ((B_SYMLINK_NODE & NodeType()) && S_ISLNK(st->st_mode)) ) ) + return false; + + // An empty file type means any file type + if (fFileType.Length() < 1) + return true; + + if (fFileType == filetype) + return true; + + return false; +} diff --git a/sources/TypedRefFilter.h b/sources/TypedRefFilter.h new file mode 100644 index 0000000..4722b47 --- /dev/null +++ b/sources/TypedRefFilter.h @@ -0,0 +1,34 @@ +#ifndef TYPED_REF_FILTER +#define TYPED_REF_FILTER + +#include +#include + +#include + +/* + This utility class is for filtering +*/ +class TypedRefFilter : public BRefFilter +{ +public: + TypedRefFilter(); + TypedRefFilter(const char* file_type, + const uint32& node_type + = B_FILE_NODE | B_DIRECTORY_NODE | B_SYMLINK_NODE); + virtual ~TypedRefFilter(); + + const char* FileType() const; + void SetFileType(const char* type); + + uint32 NodeType() const; + void SetNodeType(const uint32& node_type); + + virtual bool Filter(const entry_ref* ref, BNode* node, + struct stat_beos* st, const char* filetype); +private: + BString fFileType; + uint32 fNodeType; +}; + +#endif // TYPED_REF_FILTER diff --git a/sources/Filer/main.cpp b/sources/main.cpp similarity index 52% rename from sources/Filer/main.cpp rename to sources/main.cpp index 404fda3..51d72a2 100644 --- a/sources/Filer/main.cpp +++ b/sources/main.cpp @@ -5,33 +5,35 @@ Written by DarkWyrm , Copyright 2008 Contributed by: Humdinger , 2016 */ + #include #include #include #include #include +#include #include "main.h" +#include "FilerDefs.h" #include "FilerRule.h" -#include "PrefsWindow.h" +#include "MainWindow.h" #include "RuleRunner.h" // Created upon startup instead of when spawning a RuleEditWindow for // better performance BMessage gArchivedTypeMenu; -// Original def in TestView.cpp -#define M_TYPE_CHOSEN 'tych' -App::App(void) - : BApplication("application/x-vnd.dw-Filer"), +App::App() + : + BApplication(kFilerSignature), fRefList(NULL), fRuleList(NULL), - fPrefsWin(NULL), + fMainWin(NULL), fQuitRequested(false) { - fRefList = new BObjectList(20,true); - fRuleList = new BObjectList(20,true); + fRefList = new BObjectList(20, true); + fRuleList = new BObjectList(20, true); // SetupTypeMenu(); @@ -39,7 +41,7 @@ App::App(void) } -App::~App(void) +App::~App() { delete fRefList; delete fRuleList; @@ -47,10 +49,20 @@ App::~App(void) void -App::MessageReceived(BMessage *msg) +App::MessageReceived(BMessage* msg) { - switch(msg->what) + switch (msg->what) { + case MSG_HELP: + { + ShowHTML("documentation/Rule-Making Reference.html"); + break; + } + case MSG_DOCS: + { + ShowHTML("documentation/User Documentation.html"); + break; + } default: BApplication::MessageReceived(msg); break; @@ -59,7 +71,7 @@ App::MessageReceived(BMessage *msg) void -App::RefsReceived(BMessage *msg) +App::RefsReceived(BMessage* msg) { entry_ref tempRef; int32 i = 0; @@ -68,11 +80,10 @@ App::RefsReceived(BMessage *msg) BEntry entry(&tempRef); if (entry.Exists()) { - entry_ref *ref = new entry_ref(tempRef); + entry_ref* ref = new entry_ref(tempRef); entry.GetRef(ref); fRefList->AddItem(ref); - } - else + } else printf("Couldn't find file %s\n",tempRef.name); i++; } @@ -82,27 +93,25 @@ App::RefsReceived(BMessage *msg) printf("No files given could be processed. Exiting.\n"); fQuitRequested = true; } + ProcessFiles(); } void -App::ArgvReceived(int32 argc, char **argv) +App::ArgvReceived(int32 argc, char** argv) { for (int32 i = 1; i < argc; i++) { BEntry entry(argv[i]); - if (entry.Exists()) - { - entry_ref *ref = new entry_ref; + if (entry.Exists()) { + entry_ref* ref = new entry_ref; entry.GetRef(ref); fRefList->AddItem(ref); - } - else + } else printf("Couldn't find file %s\n",argv[i]); } - if (argc > 1 && fRefList->CountItems() == 0) - { + if (argc > 1 && fRefList->CountItems() == 0) { printf("No files given could be processed. Exiting.\n"); fQuitRequested = true; } @@ -110,25 +119,48 @@ App::ArgvReceived(int32 argc, char **argv) void -App::ReadyToRun(void) +App::ReadyToRun() { - if (fRefList->CountItems() > 0 || fQuitRequested) - { - for (int32 i = 0; i < fRefList->CountItems(); i++) - { - entry_ref ref = *fRefList->ItemAt(i); - FileRef(ref); - } + if (fRefList->CountItems() > 0 || fQuitRequested) { + ProcessFiles(); PostMessage(B_QUIT_REQUESTED); + } else { + fMainWin = new MainWindow(); + fMainWin->Show(); } - else +} + + +void +App::ProcessFiles() +{ + for (int32 i = 0; i < fRefList->CountItems(); i++) { - fPrefsWin = new PrefsWindow(); - fPrefsWin->Show(); + entry_ref ref = *fRefList->ItemAt(i); + FileRef(ref); } } +void +App::ShowHTML(const char* docfile) +{ + app_info info; + BPath path; + be_roster->GetActiveAppInfo(&info); + BEntry entry(&info.ref); + + entry.GetPath(&path); + path.GetParent(&path); + path.Append(docfile); + + entry = path.Path(); + entry_ref ref; + entry.GetRef(&ref); + be_roster->Launch(&ref); +} + + void App::FileRef(entry_ref ref) { @@ -136,60 +168,58 @@ App::FileRef(entry_ref ref) for (int32 i = 0; i < fRuleList->CountItems(); i++) { - FilerRule * rule = fRuleList->ItemAt(i); - runner.RunRule(rule,ref); + FilerRule* rule = fRuleList->ItemAt(i); + runner.RunRule(rule, ref); } } void -App::SetupTypeMenu(void) +App::SetupTypeMenu() { - BPopUpMenu *menu = new BPopUpMenu("Type"); - - + BPopUpMenu* menu = new BPopUpMenu("Type"); + // Read in the types in the MIME database which have extra attributes // associated with them - + BMimeType mime; BMessage supertypes, types, info, attr; BString supertype; - + BMimeType::GetInstalledSupertypes(&supertypes); - + int32 index = 0; - while (supertypes.FindString("super_types",index,&supertype) == B_OK) + while (supertypes.FindString("super_types", index, &supertype) == B_OK) { index++; - - BMenu *submenu = new BMenu(supertype.String()); + + BMenu* submenu = new BMenu(supertype.String()); menu->AddItem(submenu); - - BMimeType::GetInstalledTypes(supertype.String(),&types); - + + BMimeType::GetInstalledTypes(supertype.String(), &types); + BString string; int32 typeindex = 0; - - while (types.FindString("types",typeindex,&string) == B_OK) + + while (types.FindString("types", typeindex, &string) == B_OK) { typeindex++; - + mime.SetTo(string.String()); - + char attrTypeName[B_MIME_TYPE_LENGTH]; mime.GetShortDescription(attrTypeName); - + BString supertype = string.String(); supertype.Truncate(supertype.FindFirst("/")); - - BMenuItem *item = menu->FindItem(supertype.String()); - BMenu *submenu = item->Submenu(); - if (!submenu->FindItem(attrTypeName)) - { - BMessage *msg = new BMessage(M_TYPE_CHOSEN); - msg->AddString("type",string.String()); - msg->AddString("typename",attrTypeName); - submenu->AddItem(new BMenuItem(attrTypeName,msg)); + + BMenuItem* item = menu->FindItem(supertype.String()); + BMenu* submenu = item->Submenu(); + if (!submenu->FindItem(attrTypeName)) { + BMessage* msg = new BMessage(MSG_TYPE_CHOSEN); + msg->AddString("type", string.String()); + msg->AddString("typename", attrTypeName); + submenu->AddItem(new BMenuItem(attrTypeName, msg)); } } } @@ -202,7 +232,7 @@ App::SetupTypeMenu(void) int main() { - App *app = new App; + App* app = new App; app->Run(); delete app; return 0; diff --git a/sources/main.h b/sources/main.h new file mode 100644 index 0000000..f202b6e --- /dev/null +++ b/sources/main.h @@ -0,0 +1,45 @@ +/* + Filer - an automatic rule-based file organizer + + Written by DarkWyrm , Copyright 2008 + Released under the MIT license. +*/ + +#ifndef MAIN_H +#define MAIN_H + +#include +#include +#include + +#include "ObjectList.h" + +class FilerRule; +class MainWindow; + +class App : public BApplication +{ +public: + App(); + ~App(); + + void MessageReceived(BMessage* msg); + void RefsReceived(BMessage* msg); + void ArgvReceived(int32 argc, char** argv); + void ReadyToRun(); + + void SetupTypeMenu(); + void ShowHTML(const char* docfile); + void FileRef(entry_ref ref); + +private: + void ProcessFiles(); + + BObjectList* fRefList; + BObjectList* fRuleList; + MainWindow* fMainWin; + + bool fQuitRequested; +}; + +#endif // MAIN_H diff --git a/sources/Filer/sqlite3.h b/sources/sqlite3.h similarity index 100% rename from sources/Filer/sqlite3.h rename to sources/sqlite3.h