\section{What's New?}\label{whatsnew}
+{\bf Version 1.01, June 14th 2003}
+
+\begin{itemize}\itemsep=10pt
+\item Added Find facility.
+\end{itemize}
+
{\bf Version 1.0, June 11th 2003}
\begin{itemize}\itemsep=10pt
\twocolitem{\hrule}{\htmlonly{\hrule}}
\twocolitem{{\bf Delete Option}}{Deletes the selected option.}
\twocolitem{{\bf Rename Option}}{Shows a dialog for renaming the selected option.}
+\twocolitem{\hrule}{\htmlonly{\hrule}}
+\twocolitem{{\bf Find...}}{Shows the Find dialog, allowing you to search for text
+within name, description and notes for each item.}
\end{twocollist}
\section{View menu}
\ctgiftversiononly [1] {}
%\ctgiftversiononly [1] {#1}
\ctcustomversiononly [1] {#1}
-\ctversion [0] {1.0}
+\ctversion [0] {1.01}
\ctname [0] {wxWindows Configuration Tool}
\ctshortname [0] {Configuration Tool}
\cttitle [0] {\ctname \ctversion}
m_trayIconIsShown = FALSE;
m_useEnvironmentVariable = TRUE;
m_frameworkDir = wxEmptyString;
+ m_matchWholeWord = FALSE;
+ m_matchCase = FALSE;
}
// Copy constructor
m_useEnvironmentVariable = settings.m_useEnvironmentVariable;
m_frameworkDir = settings.m_frameworkDir;
+ m_matchWholeWord = settings.m_matchWholeWord;
+ m_matchCase = settings.m_matchCase;
}
// Do some initialisation within stApp::OnInit
config.Read(wxT("Misc/ShowWelcomeDialog"), (bool*) & m_showWelcomeDialog);
config.Read(wxT("Misc/Ran"), & m_noUses);
config.Read(wxT("Misc/ShowTrayIcon"), (bool*) & m_showTrayIcon);
+ config.Read(wxT("Misc/MatchWholeWord"), (bool*) & m_matchWholeWord);
+ config.Read(wxT("Misc/MatchCase"), (bool*) & m_matchCase);
m_noUses ++;
config.Write(wxT("Misc/ShowWelcomeDialog"), (long) m_showWelcomeDialog);
config.Write(wxT("Misc/Ran"), m_noUses);
config.Write(wxT("Misc/ShowTrayIcon"), (long) m_showTrayIcon);
+ config.Write(wxT("Misc/MatchWholeWord"), (long) m_matchWholeWord);
+ config.Write(wxT("Misc/MatchCase"), (long) m_matchCase);
config.Write(wxT("Windows/ShowToolBar"), m_showToolBar);
config.Write(wxT("Windows/WindowX"), (long) m_frameSize.x);
int m_mainSashSize;
bool m_showTrayIcon;
bool m_trayIconIsShown;
+
+ // Search settings
+ bool m_matchCase;
+ bool m_matchWholeWord;
};
#endif
return path;
}
+/// Finds the next item in the tree
+ctConfigItem* ctConfigToolDoc::FindNextItem(ctConfigItem* item, bool wrap)
+{
+ if (!item)
+ return GetTopItem();
+
+ // First, try to find the first child
+ if (item->GetChildCount() > 0)
+ {
+ return item->GetChild(0);
+ }
+ else
+ {
+ ctConfigItem* p = item;
+ while (p)
+ {
+ ctConfigItem* toFind = FindNextSibling(p);
+ if (toFind)
+ return toFind;
+ p = p->GetParent();
+ }
+ }
+
+ // Finally, wrap around to the root.
+ if (wrap)
+ return GetTopItem();
+ else
+ return NULL;
+}
+
+/// Finds the next sibling in the tree
+ctConfigItem* ctConfigToolDoc::FindNextSibling(ctConfigItem* item)
+{
+ if (item->GetParent())
+ {
+ wxNode* node = item->GetParent()->GetChildren().Member(item);
+ if (node && node->GetNext())
+ {
+ ctConfigItem* nextItem = (ctConfigItem*) node->GetNext()->GetData();
+ return nextItem;
+ }
+ }
+ return NULL;
+}
+
/*
* Implements a document editing command.
return TRUE;
}
+
/// Helper function
void GenerateConfigureCommand(ctConfigItem* item, wxString& str);
+
+ /// Finds the next item in the tree
+ ctConfigItem* FindNextItem(ctConfigItem* item, bool wrap);
+
+ /// Finds the next sibling in the tree
+ ctConfigItem* FindNextSibling(ctConfigItem* item);
protected:
ctConfigItem* m_topItem;
EVT_MENU(ctID_SAVE_CONFIGURE_COMMAND, ctConfigToolView::OnSaveConfigureCommand)
EVT_UPDATE_UI(ctID_SAVE_SETUP_FILE, ctConfigToolView::OnUpdateSaveSetupFile)
EVT_UPDATE_UI(ctID_SAVE_CONFIGURE_COMMAND, ctConfigToolView::OnUpdateSaveConfigureCommand)
+
+ EVT_MENU(wxID_FIND, ctConfigToolView::OnFind)
+ EVT_UPDATE_UI(wxID_FIND, ctConfigToolView::OnUpdateFind)
+
END_EVENT_TABLE()
ctConfigToolView::ctConfigToolView()
{
event.Enable(TRUE);
}
+
+/// Find text
+void ctConfigToolView::OnFind(wxCommandEvent& event)
+{
+ ctFindReplaceDialog* dialog = wxGetApp().GetMainFrame()->GetFindDialog();
+ if (dialog)
+ {
+ dialog->Raise();
+ }
+
+ if (!dialog)
+ {
+ int style = wxFR_NOUPDOWN;
+ wxString caption(wxT("Find text in settings"));
+ int flags = wxFR_DOWN;
+ if (wxGetApp().GetSettings().m_matchCase)
+ flags|=wxFR_MATCHCASE;
+ if (wxGetApp().GetSettings().m_matchWholeWord)
+ flags|=wxFR_WHOLEWORD;
+
+ ctFindReplaceDialog::sm_findData.SetFlags(flags);
+
+ dialog = new ctFindReplaceDialog(wxGetApp().GetMainFrame(), caption, style);
+ dialog->Show(TRUE);
+ }
+}
+
+/// Update find text
+void ctConfigToolView::OnUpdateFind(wxUpdateUIEvent& event)
+{
+ event.Enable(TRUE);
+}
+
+//----------------------------------------------------------------------------
+// ctFindReplaceDialog
+//----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(ctFindReplaceDialog, wxFindReplaceDialog)
+ EVT_FIND(-1, ctFindReplaceDialog::OnFind)
+ EVT_FIND_NEXT(-1, ctFindReplaceDialog::OnFind)
+ EVT_FIND_CLOSE(-1, ctFindReplaceDialog::OnClose)
+END_EVENT_TABLE()
+
+wxFindReplaceData ctFindReplaceDialog::sm_findData;
+wxString ctFindReplaceDialog::sm_currentItem = wxEmptyString;
+
+ctFindReplaceDialog::ctFindReplaceDialog( wxWindow *parent, const wxString& title,
+ long style):
+ wxFindReplaceDialog( parent, & sm_findData, title, style )
+{
+ sm_currentItem = wxEmptyString;
+
+ if (parent)
+ ((ctMainFrame*) parent)->SetFindDialog(this);
+}
+
+void ctFindReplaceDialog::OnFind(wxFindDialogEvent& event)
+{
+ wxString textToFind = event.GetFindString();
+ bool matchCase = ((event.GetFlags() & wxFR_MATCHCASE) != 0);
+ bool wholeWord = ((event.GetFlags() & wxFR_WHOLEWORD) != 0);
+
+ wxGetApp().GetSettings().m_matchCase = matchCase;
+ wxGetApp().GetSettings().m_matchWholeWord = wholeWord;
+
+ if (!DoFind(textToFind, matchCase, wholeWord))
+ {
+ wxMessageBox(wxT("No more matches."), wxT("Search"), wxOK|wxICON_INFORMATION, this);
+ }
+}
+
+bool ctFindReplaceDialog::DoFind(const wxString& textToFind, bool matchCase, bool wholeWord, bool wrap)
+{
+ ctConfigToolDoc* doc = wxGetApp().GetMainFrame()->GetDocument();
+ if (!doc)
+ return FALSE;
+ ctConfigToolView* view = (ctConfigToolView*) doc->GetFirstView();
+
+ ctConfigItem* currentItem = NULL;
+ ctConfigItem* focusItem = view->GetSelection();
+ if (!focusItem)
+ {
+ focusItem = doc->GetTopItem();
+ if (!focusItem)
+ return FALSE;
+ }
+
+ if (!sm_currentItem.IsEmpty())
+ {
+ currentItem = doc->GetTopItem()->FindItem(sm_currentItem);
+ }
+
+ // If we were at this item last time, skip the first one.
+ bool skipFirstItem = (currentItem == focusItem);
+ currentItem = FindNextItem(doc, currentItem, textToFind, matchCase, wholeWord, wrap,
+ skipFirstItem);
+
+ if (currentItem)
+ {
+ sm_currentItem = currentItem->GetName();
+ wxGetApp().GetMainFrame()->GetConfigTreeCtrl()->SelectItem(currentItem->GetTreeItemId());
+ return TRUE;
+ }
+ else
+ {
+ sm_currentItem = wxEmptyString;
+ }
+
+ return FALSE;
+}
+
+ctConfigItem* ctFindReplaceDialog::FindNextItem(ctConfigToolDoc* doc,
+ ctConfigItem* item,
+ const wxString& text,
+ bool matchCase,
+ bool matchWordOnly,
+ bool wrap,
+ bool skipFirst)
+{
+ ctConfigItem* firstInDoc = NULL;
+
+ wxString text2(text);
+ if (!matchCase)
+ text2.MakeLower();
+
+ ctConfigItem* found = NULL;
+ ctConfigItem* next = item;
+
+ int i = 0;
+ do
+ {
+ // If starting the search from beginning, we can now
+ // set the value of 'item' in the 2nd iteration without immediately
+ // dropping out of the while loop because card == next
+ if (!item && (i > 0))
+ item = firstInDoc;
+
+ // We might want to start from this item if skipFirst is false.
+ if ((i == 0) && !skipFirst && next)
+ {
+ }
+ else
+ next = doc->FindNextItem(next, wrap);
+
+ // Save to be used in iteration 2
+ if ((i == 0) && !item)
+ firstInDoc = next;
+
+ if (next)
+ {
+ wxString str(next->GetName());
+ wxString description(next->GetPropertyString(wxT("description")));
+ wxString notes(next->GetPropertyString(wxT("notes")));
+ if (!matchCase)
+ {
+ str.MakeLower();
+ description.MakeLower();
+ notes.MakeLower();
+ }
+ if (ctMatchString(str, text2, matchWordOnly) ||
+ ctMatchString(description, text2, matchWordOnly) ||
+ ctMatchString(notes, text2, matchWordOnly))
+ {
+ found = next;
+ }
+ }
+ else
+ break; // Didn't find an item at all
+
+ i ++;
+ }
+ while (!found && item != next);
+
+ if (item == found && !firstInDoc)
+ return NULL;
+ else
+ return found;
+}
+
+void ctFindReplaceDialog::OnClose(wxFindDialogEvent& event)
+{
+ bool matchCase = ((event.GetFlags() & wxFR_MATCHCASE) != 0);
+ bool wholeWord = ((event.GetFlags() & wxFR_WHOLEWORD) != 0);
+ wxGetApp().GetSettings().m_matchCase = matchCase;
+ wxGetApp().GetSettings().m_matchWholeWord = wholeWord;
+
+ this->Destroy();
+ ((ctMainFrame*) GetParent())->SetFindDialog(NULL);
+}
#include "wx/docview.h"
#include "wx/treectrl.h"
+#include "wx/fdrepdlg.h"
#include "configitem.h"
class ctConfigTreeCtrl;
/// Save configure command file update handler
void OnUpdateSaveConfigureCommand(wxUpdateUIEvent& event);
+ // Find
+
+ /// Find text
+ void OnFind(wxCommandEvent& event);
+
+ /// Update find text
+ void OnUpdateFind(wxUpdateUIEvent& event);
+
DECLARE_EVENT_TABLE()
protected:
int m_op;
};
+/*
+ * ctFindReplaceDialog
+ */
+
+class ctFindReplaceDialog: public wxFindReplaceDialog
+{
+public:
+ // constructors and destructors
+ ctFindReplaceDialog( wxWindow* parent, const wxString& title,
+ long style = 0 );
+
+ void OnFind(wxFindDialogEvent& event);
+ void OnClose(wxFindDialogEvent& event);
+
+ // If wrap is TRUE, go back to the beginning if at the end of the
+ // document.
+ bool DoFind(const wxString& textToFind, bool matchCase, bool wholeWord, bool wrap = TRUE);
+
+ ctConfigItem* FindNextItem(ctConfigToolDoc* doc,
+ ctConfigItem* item,
+ const wxString& text,
+ bool matchCase,
+ bool matchWordOnly,
+ bool wrap,
+ bool skipFirst);
+ static wxFindReplaceData sm_findData;
+ static wxString sm_currentItem; // card name
+
+private:
+ DECLARE_EVENT_TABLE()
+};
+
#endif
// _CT_CONFIGTOOLVIEW_H_
EVT_UPDATE_UI(ctID_SAVE_SETUP_FILE, ctMainFrame::OnUpdateDisable)
EVT_UPDATE_UI(ctID_SAVE_CONFIGURE_COMMAND, ctMainFrame::OnUpdateDisable)
+
+ EVT_UPDATE_UI(wxID_FIND, ctMainFrame::OnUpdateDisable)
END_EVENT_TABLE()
// Define my frame constructor
m_configurePage = NULL;
m_setupPage = NULL;
m_mainNotebook = NULL;
+ m_findDialog = NULL;
m_treeSplitterWindow = new wxSplitterWindow(this, -1, wxDefaultPosition, wxSize(400, 300),
wxSP_3DSASH|wxSP_3DBORDER);
}
}
+ if (m_findDialog)
+ {
+ m_findDialog->Destroy();
+ m_findDialog = NULL;
+ }
+
Show(FALSE);
if (IsMaximized())
editMenu->AppendSeparator();
editMenu->Append(ctID_DELETE_ITEM, _("&Delete Option"), _("Delete a configuration option"));
editMenu->Append(ctID_RENAME_ITEM, _("&Rename Option"), _("Rename a configuration option"));
+ editMenu->AppendSeparator();
+ editMenu->Append(wxID_FIND, _("&Find...\tCtrl+F"), _("Search for a string in the settings document"));
// Save for the command processor.
m_editMenu = editMenu;
class ctConfigTreeCtrl;
class ctPropertyEditor;
class ctOutputWindow;
+class ctFindReplaceDialog;
/*!
* \brief The main window of the application.
/// Returns the main notebook containing editor and text tabs
wxNotebook* GetMainNotebook() const { return m_mainNotebook; }
+ /// Sets the find dialog for future closing
+ void SetFindDialog(ctFindReplaceDialog* findDialog) { m_findDialog = findDialog; }
+
+ /// Gets the find dialog
+ ctFindReplaceDialog* GetFindDialog() const { return m_findDialog ; }
+
DECLARE_EVENT_TABLE()
protected:
wxNotebook* m_mainNotebook;
ctOutputWindow* m_setupPage;
ctOutputWindow* m_configurePage;
+
+ ctFindReplaceDialog* m_findDialog;
};
/*!
}
else if (page->GetId() == ID_LOCATION_SETTINGS_DIALOG)
{
- helpTopic = wxT("Location dialog");
+ helpTopic = wxT("Location settings dialog");
}
if (!helpTopic.IsEmpty())
//// Build settings
// Version
-#define ctVERSION_NUMBER 1.0
+#define ctVERSION_NUMBER 1.01
// Whether to have a splash screen
#define ctUSE_SPLASH_SCREEN 0
}
return s;
}
+
+// Match 'matchText' against 'matchAgainst', optionally constraining to
+// whole-word only.
+bool ctMatchString(const wxString& matchAgainst, const wxString& matchText, bool wholeWordOnly)
+{
+ // Fast operation if not matching against whole words only
+ if (!wholeWordOnly)
+ return (matchAgainst.Find(matchText) != -1);
+
+ wxString left(matchAgainst);
+ bool success = FALSE;
+ int pos = 0;
+ int matchTextLen = (int) matchText.Length();
+ while (!success && !matchAgainst.IsEmpty())
+ {
+ pos = left.Find(matchText);
+ if (pos == -1)
+ return FALSE;
+
+ bool firstCharOK = FALSE;
+ bool lastCharOK = FALSE;
+ if (pos == 0 || !wxIsalnum(left[(size_t) (pos-1)]))
+ firstCharOK = TRUE;
+
+ if (((pos + matchTextLen) == (int) left.Length()) || !wxIsalnum(left[(size_t) (pos + matchTextLen)]))
+ lastCharOK = TRUE;
+
+ if (firstCharOK && lastCharOK)
+ success = TRUE;
+
+ left = left.Mid(pos+1);
+ }
+ return success;
+}
// Convert characters to HTML equivalents
wxString ctEscapeHTMLCharacters(const wxString& str);
+// Match 'matchText' against 'matchAgainst', optionally constraining to
+// whole-word only.
+bool ctMatchString(const wxString& matchAgainst, const wxString& matchText, bool wholeWordOnly);
+
+
#endif
// _AP_UTILS_H_