diff --git a/src/apps/terminal/Changelog b/src/apps/terminal/Changelog index 9a418f248e..d8e87cd209 100644 --- a/src/apps/terminal/Changelog +++ b/src/apps/terminal/Changelog @@ -13,10 +13,7 @@ Stuff already done thats better than R5: Terminal window supports scrolling TODO: -Make a Jamfile -Make Find work Fix titling (-t works already, its the Terminal 1, 2, 3, etc...) Fix the Colour menu Move Fonts and font sizes to the "Right Place" Kill the Preferences Panel -Move to .rdef source resources diff --git a/src/apps/terminal/Constants.h b/src/apps/terminal/Constants.h deleted file mode 100644 index 7dc5c94565..0000000000 --- a/src/apps/terminal/Constants.h +++ /dev/null @@ -1,42 +0,0 @@ -/*Terminal: constants*/ -#ifndef CONSTANTS_H -#define CONSTANTS_H - -#include -#include - -#define APP_SIGNATURE "application/x-vnd.obos.terminal" - -const float TEXT_INSET = 3.0; - -// Application messages - -const uint32 OPEN_TERMINAL ='OTRM'; - -// Messages for menu commands - -// Terminal -const uint32 TERMINAL_SWITCH_TERMINAL ='TSWT'; -const uint32 TERMINAL_START_NEW_TERMINAL='TSNT'; -const uint32 TERMINAL_LOG_TO_FILE ='TLTF'; -// Edit -const uint32 EDIT_WRITE_SELECTION ='EWSL'; -const uint32 EDIT_CLEAR_ALL ='ECLA'; -const uint32 EDIT_FIND ='EFND'; -const uint32 EDIT_FIND_BACKWARD ='EFBK'; -const uint32 EDIT_FIND_FORWARD ='EFFD'; -// Settings -const uint32 SETTINGS_WINDOW_SIZE ='SWSZ'; -const uint32 SETTINGS_FONT ='SFNT'; -const uint32 SETTINGS_FONT_SIZE ='SFSZ'; -const uint32 SETTINGS_FONT_ENCODING ='SFEN'; -const uint32 SETTINGS_TAB_WIDTH ='STBW'; -const uint32 SETTINGS_COLOR ='SCLR'; -const uint32 SETTINGS_SAVE_AS_DEFAULT ='SSAD'; -const uint32 SETTINGS_SAVE_AS_SETTINGS ='SSAS'; - -// Edit menu toggle -const uint32 ENABLE_ITEMS ='EDON'; -const uint32 DISABLE_ITEMS ='EDOF'; - -#endif // CONSTANTS_H diff --git a/src/apps/terminal/FindDlg.cpp b/src/apps/terminal/FindDlg.cpp index 106a31937f..0262025c36 100644 --- a/src/apps/terminal/FindDlg.cpp +++ b/src/apps/terminal/FindDlg.cpp @@ -31,12 +31,16 @@ #include #include #include +#include +#include #include +#include #include #include #include #include +#include "TermWindow.h" #include "FindDlg.h" #include "TermApp.h" #include "MenuUtil.h" @@ -44,34 +48,90 @@ // message define -const uint32 FPANEL_HIDE = 'Fhid'; +const uint32 MSG_FIND_HIDE = 'Fhid'; ////////////////////////////////////////////////////////////////////////////// // FindDlg // Constructer ////////////////////////////////////////////////////////////////////////////// FindDlg::FindDlg (BRect frame, TermWindow *win) - : BWindow(frame, "Find", - B_FLOATING_WINDOW, B_NOT_RESIZABLE|B_NOT_ZOOMABLE) + : BWindow(frame, "Find", + B_FLOATING_WINDOW, B_NOT_RESIZABLE|B_NOT_ZOOMABLE) { - PrefHandler title; - LoadLocaleFile (&title); + fWindow = win; + SetTitle("Find"); - fWindow = win; - this->SetTitle (title.getString ("Find")); + AddShortcut ((ulong)'W', (ulong)B_COMMAND_KEY, new BMessage (MSG_FIND_HIDE)); - AddShortcut ((ulong)'Q', (ulong)B_COMMAND_KEY, new BMessage (FPANEL_HIDE)); - AddShortcut ((ulong)'W', (ulong)B_COMMAND_KEY, new BMessage (FPANEL_HIDE)); + //Build up view + fFindView = new BView(Bounds(), "FindView", B_FOLLOW_ALL, B_WILL_DRAW); + fFindView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(fFindView); - BRect r (10, 10, 120, 20); - - BTextControl *text_ctl = new BTextControl (r, "text", NULL, NULL, NULL); - AddChild (text_ctl); + font_height height; + fFindView->GetFontHeight(&height); + float lineHeight = height.ascent + height.descent + height.leading; - r.Set (100, 40, 130, 60); - BButton *button = new BButton (r, NULL, "Find", new BMessage (MSG_FIND_START)); - AddChild (button); - + //These labels are from the bottom up + float buttonsTop = frame.Height() - 19 - lineHeight; + float matchwordBottom = buttonsTop - 4; + float matchwordTop = matchwordBottom - lineHeight - 8; + float matchcaseBottom = matchwordTop - 4; + float matchcaseTop = matchcaseBottom - lineHeight - 8; + float forwardsearchBottom = matchcaseTop - 4; + float forwardsearchTop = forwardsearchBottom - lineHeight - 8; + + //These things are calculated from the top + float textRadioTop = 12; + float textRadioBottom = textRadioTop + 2 + lineHeight + 2 + 1; + float textRadioRight = fFindView->StringWidth("Use Text: ") + 30; + float selectionRadioTop = textRadioBottom + 4; + float selectionRadioBottom = selectionRadioTop + lineHeight + 8; + + //Divider + float dividerHeight = (selectionRadioBottom + forwardsearchTop) / 2; + + //Button Coordinates + float searchbuttonLeft = (frame.Width() - fFindView->StringWidth("Find") - 60) / 2; + float searchbuttonRight = searchbuttonLeft + fFindView->StringWidth("Find") + 60; + + //Build the Views + fTextRadio = new BRadioButton(BRect(14, textRadioTop, textRadioRight, textRadioBottom), + "fTextRadio", "Use Text: ", NULL); + fFindView->AddChild(fTextRadio); + fTextRadio->SetValue(1); //enable first option + + fFindLabel = new BTextControl(BRect(textRadioRight + 4, textRadioTop, frame.Width() - 14, textRadioBottom), + "fFindLabel", "", "", NULL); + fFindLabel->SetDivider(0); + fFindView->AddChild(fFindLabel); + fFindLabel->MakeFocus(true); + + fSelectionRadio = new BRadioButton(BRect(14, selectionRadioTop, frame.Width() - 14, selectionRadioBottom), + "fSelectionRadio", "Use Selection", NULL); + fFindView->AddChild(fSelectionRadio); + + fSeparator = new BBox(BRect(6, dividerHeight, frame.Width() - 6, dividerHeight + 1)); + fFindView->AddChild(fSeparator); + + fForwardSearchBox = new BCheckBox(BRect(14, forwardsearchTop, frame.Width() - 14, forwardsearchBottom), + "fForwardSearchBox", "Search Forward", NULL); + fFindView->AddChild(fForwardSearchBox); + + fMatchCaseBox = new BCheckBox(BRect(14, matchcaseTop, frame.Width() - 14, matchcaseBottom), + "fMatchCaseBox", "Match Case", NULL); + fFindView->AddChild(fMatchCaseBox); + + fMatchWordBox = new BCheckBox(BRect(14, matchwordTop, frame.Width() - 14, matchwordBottom), + "fMatchWordBox", "Match Word", NULL); + fFindView->AddChild(fMatchWordBox); + + fFindButton = new BButton(BRect(searchbuttonLeft, buttonsTop, searchbuttonRight, frame.Height() - 14), + "fFindButton", "Find", new BMessage(MSG_FIND)); + fFindButton->MakeDefault(true); + fFindView->AddChild(fFindButton); + + Show(); } FindDlg::~FindDlg (void) @@ -80,8 +140,47 @@ FindDlg::~FindDlg (void) } void -FindDlg::Quit (void) +FindDlg::MessageReceived (BMessage *msg) { - BWindow::Quit (); + switch (msg->what) { + case B_QUIT_REQUESTED: + Quit(); + break; + case MSG_FIND: + SendFindMessage(); + break; + case MSG_FIND_HIDE: + Quit(); + break; + default: + BWindow::MessageReceived(msg); + break; + } } +void +FindDlg::Quit (void) +{ + fWindow->PostMessage(MSG_FIND_CLOSED); + BWindow::Quit (); +} + +void +FindDlg::SendFindMessage (void) +{ + BMessage message(MSG_FIND); + + if (fTextRadio->Value() == B_CONTROL_ON) { + message.AddString("findstring", fFindLabel->Text()); + message.AddBool("findselection", false); + } else + message.AddBool("findselection", true); + + //Add the other parameters + message.AddBool("usetext", fTextRadio->Value() == B_CONTROL_ON); + message.AddBool("forwardsearch", fForwardSearchBox->Value() == B_CONTROL_ON); + message.AddBool("matchcase", fMatchCaseBox->Value() == B_CONTROL_ON); + message.AddBool("matchword", fMatchWordBox->Value() == B_CONTROL_ON); + + fWindow->PostMessage(&message); +} diff --git a/src/apps/terminal/FindDlg.h b/src/apps/terminal/FindDlg.h index cf5e86b17c..2a380a88ae 100644 --- a/src/apps/terminal/FindDlg.h +++ b/src/apps/terminal/FindDlg.h @@ -33,29 +33,42 @@ #include #include -#include "CurPos.h" - +const ulong MSG_FIND = 'msgf'; const ulong MSG_FIND_START = 'msac'; +const ulong MSG_FIND_CLOSED = 'mfcl'; class BRect; class BBitmap; class BMessage; class TermWindow; +class BTextControl; +class BRadioButton; +class BCheckBox; class FindDlg : public BWindow { public: - FindDlg(BRect frame, TermWindow *win); - ~FindDlg (); + FindDlg (BRect frame, TermWindow *win); + ~FindDlg (); - void Find (CurPos *start, CurPos *end); +private: + virtual void Quit (void); + void MessageReceived (BMessage *msg); - private: - virtual void Quit (void); - - BString *fFindString; - TermWindow *fWindow; + void SendFindMessage (void); + BView *fFindView; + BTextControl *fFindLabel; + BRadioButton *fTextRadio; + BRadioButton *fSelectionRadio; + BBox *fSeparator; + BCheckBox *fForwardSearchBox; + BCheckBox *fMatchCaseBox; + BCheckBox *fMatchWordBox; + BButton *fFindButton; + + BString *fFindString; + TermWindow *fWindow; }; diff --git a/src/apps/terminal/Jamfile b/src/apps/terminal/Jamfile index fa44238f1c..bb41d17902 100644 --- a/src/apps/terminal/Jamfile +++ b/src/apps/terminal/Jamfile @@ -3,10 +3,13 @@ SubDir HAIKU_TOP src apps terminal ; SetSubDirSupportedPlatformsBeOSCompatible ; AddSubDirSupportedPlatforms libbe_test ; +UseHeaders [ FDirName $(HAIKU_TOP) src kits tracker ] ; + Application Terminal : AppearPrefView.cpp CodeConv.cpp CurPos.cpp + FindDlg.cpp MenuUtil.cpp Terminal.cpp PrefDlg.cpp diff --git a/src/apps/terminal/TermBuffer.cpp b/src/apps/terminal/TermBuffer.cpp index 0bba29bf4b..dd0d5142cf 100644 --- a/src/apps/terminal/TermBuffer.cpp +++ b/src/apps/terminal/TermBuffer.cpp @@ -103,6 +103,9 @@ TermBuffer::TermBuffer(int rows, int cols) mRowSize = rows; mRowOffset = 0; + + mSelStart.Set(-1,-1); + mSelEnd.Set(-1,-1); buffer_size = gTermPref->getInt32(PREF_HISTORY_SIZE); if (buffer_size < 1000) @@ -544,3 +547,14 @@ TermBuffer::GetStringFromRegion(BString &str) } } +//Returns the complete internal buffer as a BString +void +TermBuffer::ToString(BString &str) +{ + for (int y = 0; y < mRowSize; y++) { + for (int x = 0; x < mNowColSize; x++) { + GetCharFromRegion(x, y, str); + } + } + AvoidWaste(str); +} \ No newline at end of file diff --git a/src/apps/terminal/TermBuffer.h b/src/apps/terminal/TermBuffer.h index 211d9f4ddf..be76d8f131 100644 --- a/src/apps/terminal/TermBuffer.h +++ b/src/apps/terminal/TermBuffer.h @@ -95,15 +95,26 @@ public: // void ClearAll (void); - // Set / Unset Selection + // + // Selection Methods + // void Select (const CurPos &start, const CurPos &end); void DeSelect (void); + + const CurPos &GetSelectionStart (void) { return mSelStart; }; + const CurPos &GetSelectionEnd (void) { return mSelEnd; }; int CheckSelectedRegion (const CurPos &pos); + + // + // Other methods + // bool FindWord (const CurPos &pos, CurPos *start, CurPos *end); void GetCharFromRegion (int x, int y, BString &str); void AvoidWaste (BString &str); + + void ToString (BString &str); int32 GetArraySize (void); diff --git a/src/apps/terminal/TermConst.h b/src/apps/terminal/TermConst.h index 1a30813b5a..c581887213 100644 --- a/src/apps/terminal/TermConst.h +++ b/src/apps/terminal/TermConst.h @@ -63,7 +63,8 @@ const uint32 MENU_ENCODING = 'Menc'; const uint32 MENU_PAGE_SETUP = 'Mpst'; const uint32 MENU_PRINT = 'Mpnt'; const uint32 MENU_FIND_STRING = 'Mfnd'; -const uint32 MENU_FIND_AGAIN = 'Mfag'; +const uint32 MENU_FIND_FORWARD = 'Mffw'; +const uint32 MENU_FIND_BACKWARD = 'Mfbw'; const uint32 MENU_SHOW_COLOR = 'Mcol'; const uint32 M_GET_DEVICE_NUM = 'Mgdn'; diff --git a/src/apps/terminal/TermView.cpp b/src/apps/terminal/TermView.cpp index 196e250a33..36d09ec2d0 100644 --- a/src/apps/terminal/TermView.cpp +++ b/src/apps/terminal/TermView.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "TermView.h" #include "TermWindow.h" @@ -2248,6 +2249,99 @@ TermView::GetFontInfo(int *width, int *height) *height = fFontHeight; } +// Find a string, and select it if found +bool +TermView::Find (const BString &str, bool forwardSearch, bool matchCase, bool matchWord) +{ + BString buffer; + CurPos selectionstart, selectionend; + int offset = 0; + int initialresult = -1; + int result = B_ERROR; + + //Get the buffer contents + fTextBuffer->ToString(buffer); + + selectionstart = fTextBuffer->GetSelectionStart(); + selectionend = fTextBuffer->GetSelectionEnd(); + + if (selectionstart.x >= 0 || selectionstart.y >= 0) { + if (forwardSearch) + //Set the offset to the end of the selection + offset = (selectionend.y) * fTermColumns + selectionend.x; + else + offset = (selectionstart.y) * fTermColumns + selectionstart.x; + } + +restart: + //Actual search + if (forwardSearch) { + if (matchCase) { + result = buffer.FindFirst(str, offset); + } else { + result = buffer.IFindFirst(str, offset); + } + } else { + if (matchCase) { + result = buffer.FindLast(str, offset); + } else { + result = buffer.IFindLast(str, offset); + } + } + if (result == B_ERROR) { //Wrap search like Be's Terminal + if (forwardSearch) { + if (matchCase) { + result = buffer.FindFirst(str, 0); + } else { + result = buffer.IFindFirst(str, 0); + } + } else { + if (matchCase) { + result = buffer.FindLast(str, buffer.Length()); + } else { + result = buffer.IFindLast(str, buffer.Length()); + } + } + } + + if (result < 0) + return false; + + if (matchWord) { + if (isalnum(buffer.ByteAt(result - 1)) || isalnum(buffer.ByteAt(result + str.Length()))) { + if (initialresult == -1) //Set the initial offset to the first result to aid word matching + initialresult = result; + else if (initialresult == result) //We went round the buffer, nothing found + return false; + if (forwardSearch) + offset = result + str.Length(); + else + offset = result; + goto restart; + } + } + + //Select the found text + selectionstart.y = result / fTermColumns; + selectionstart.x = result % fTermColumns; + //Length -1 since it seems to count the \0 as well + selectionend.y = (result + str.Length() - 1) / fTermColumns; + selectionend.x = (result + str.Length() - 1) % fTermColumns; + //Update the contents of the view + DeSelect(); + Select(selectionstart, selectionend); + + return true; +} + +//! Get the selected text and copy to str +void +TermView::GetSelection(BString &str) +{ + str.SetTo(""); + fTextBuffer->GetStringFromRegion(str); +} + // Send DrawRect data to Draw Engine thread. inline void TermView::SendDataToDrawEngine(int x1, int y1, int x2, int y2) diff --git a/src/apps/terminal/TermView.h b/src/apps/terminal/TermView.h index a6c07c4d5c..7a0d818a75 100644 --- a/src/apps/terminal/TermView.h +++ b/src/apps/terminal/TermView.h @@ -184,6 +184,9 @@ public: void ScrollScreenDraw (void); void GetFrameSize (float *width, float *height); void GetFontInfo (int *, int*); + bool Find (const BString &str, bool forwardSearch, bool matchCase, bool matchWord); + void GetSelection (BString &str); + /* * PRIVATE MEMBER. diff --git a/src/apps/terminal/TermWindow.cpp b/src/apps/terminal/TermWindow.cpp index c2e126578f..80a93d8040 100644 --- a/src/apps/terminal/TermWindow.cpp +++ b/src/apps/terminal/TermWindow.cpp @@ -27,6 +27,7 @@ #include "CodeConv.h" #include "ColorWindow.h" #include "MenuUtil.h" +#include "FindDlg.h" #include "PrefDlg.h" #include "PrefView.h" #include "PrefHandler.h" @@ -173,6 +174,10 @@ TermWindow::InitWindow(void) fTermParse->InitTermParse(fTermView, fCodeConv); // Set Coding. + + // Init find parameters + fMatchCase = false; + fMatchWord = false; // Initialize MessageRunner. fWindowUpdate = new BMessageRunner(BMessenger(this), @@ -219,13 +224,16 @@ TermWindow::SetupMenu(void) fEditmenu->AddSeparatorItem (); fEditmenu->AddItem (new BMenuItem ("Select All", new BMessage (B_SELECT_ALL), 'A')); fEditmenu->AddItem (new BMenuItem ("Clear All", new BMessage (MENU_CLEAR_ALL), 'L')); + fEditmenu->AddSeparatorItem (); + fEditmenu->AddItem (new BMenuItem ("Find", new BMessage (MENU_FIND_STRING),'F')); + fFindBackwardMenuItem = new BMenuItem ("Find Backward", new BMessage (MENU_FIND_BACKWARD), '['); + fEditmenu->AddItem (fFindBackwardMenuItem); + fFindBackwardMenuItem->SetEnabled(false); + fFindForwardMenuItem = new BMenuItem ("Find Forward", new BMessage (MENU_FIND_FORWARD), ']'); + fEditmenu->AddItem (fFindForwardMenuItem); + fFindForwardMenuItem->SetEnabled(false); + -/* - // TODO: Implement Finding - fEditmenu->AddSeparatorItem (); - fEditmenu->AddItem (new BMenuItem ("Find", new BMessage (MENU_FIND_STRING),'F')); - fEditmenu->AddItem (new BMenuItem ("Find Again", new BMessage (MENU_FIND_AGAIN), ']')); -*/ fMenubar->AddItem (fEditmenu); // Make Help Menu. @@ -277,6 +285,7 @@ TermWindow::MessageReceived(BMessage *message) BRect r; BFont halfFont; BFont fullFont; + bool findselection, forwardsearch, findresult; switch (message->what) { case MENU_SWITCH_TERM: { @@ -303,6 +312,77 @@ TermWindow::MessageReceived(BMessage *message) fPrefWindow = NULL; break; } + case MENU_FIND_STRING: { + if (!fFindPanel) { + BRect r = Frame(); + r.left += 20; + r.top += 20; + r.right = r.left + 260; + r.bottom = r.top + 190; + fFindPanel = new FindDlg(r, this); + } + else + fFindPanel->Activate(); + break; + } + case MSG_FIND: { + fFindPanel->PostMessage(B_QUIT_REQUESTED); + message->FindBool("findselection", &findselection); + if (!findselection) + message->FindString("findstring", &fFindString); + else + fTermView->GetSelection(fFindString); + + if (fFindString.Length() == 0) { + BAlert *alert = new BAlert("find failed", "No search string.", "Okay", NULL, + NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); + alert->Go(); + fFindBackwardMenuItem->SetEnabled(false); + fFindForwardMenuItem->SetEnabled(false); + break; + } + + message->FindBool("forwardsearch", &forwardsearch); + message->FindBool("matchcase", &fMatchCase); + message->FindBool("matchword", &fMatchWord); + findresult = fTermView->Find(fFindString, forwardsearch, fMatchCase, fMatchWord); + + if (!findresult) { + BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL, + NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); + alert->Go(); + fFindBackwardMenuItem->SetEnabled(false); + fFindForwardMenuItem->SetEnabled(false); + break; + } + + //Enable the menu items Find Forward and Find Backward + fFindBackwardMenuItem->SetEnabled(true); + fFindForwardMenuItem->SetEnabled(true); + break; + } + case MENU_FIND_FORWARD: { + findresult = fTermView->Find(fFindString, true, fMatchCase, fMatchWord); + if (!findresult) { + BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL, + NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); + alert->Go(); + } + break; + } + case MENU_FIND_BACKWARD: { + findresult = fTermView->Find(fFindString, false, fMatchCase, fMatchWord); + if (!findresult) { + BAlert *alert = new BAlert("find failed", "Not Found.", "Okay", NULL, + NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); + alert->Go(); + } + break; + } + case MSG_FIND_CLOSED: { + fFindPanel = NULL; + break; + } case MENU_FILE_QUIT: { be_app->PostMessage(B_QUIT_REQUESTED); break; @@ -522,8 +602,10 @@ TermWindow::Quit(void) { delete fTermParse; delete fCodeConv; - if(fPrefWindow) fPrefWindow->PostMessage (B_QUIT_REQUESTED); - be_app->PostMessage (B_QUIT_REQUESTED, be_app); + if (fPrefWindow) fPrefWindow->PostMessage (B_QUIT_REQUESTED); + if (fFindPanel) fFindPanel->PostMessage(B_QUIT_REQUESTED); + + be_app->PostMessage (B_QUIT_REQUESTED, be_app); BWindow::Quit (); } diff --git a/src/apps/terminal/TermWindow.h b/src/apps/terminal/TermWindow.h index 6d5201717b..7a32c8276d 100644 --- a/src/apps/terminal/TermWindow.h +++ b/src/apps/terminal/TermWindow.h @@ -87,6 +87,12 @@ private: BMenuItem *item; BRect fSavedFrame; window_look fSavedLook; + //Saved search parameters + BString fFindString; + BMenuItem *fFindForwardMenuItem; + BMenuItem *fFindBackwardMenuItem; + bool fMatchCase; + bool fMatchWord; }; #endif // TERMWIN_H