Commit fcc72286 authored by twanvl's avatar twanvl

find/replace kind of working

parent 1922307e
......@@ -94,6 +94,29 @@ class TextToggleReminderAction : public ValueAction {
Char old; ///< Old value of the <kw- tag
};
// ----------------------------------------------------------------------------- : Replace all
/// A TextValueAction without the start and end stuff
class SimpleTextValueAction : public ValueAction {
public:
SimpleTextValueAction(const TextValueP& value, const Defaultable<String>& new_value);
virtual void perform(bool to_undo);
bool merge(const SimpleTextValueAction& action);
private:
Defaultable<String> new_value;
};
/// An action from "Replace All"; just a bunch of value actions performed in sequence
class ReplaceAllAction : public Action {
public:
~ReplaceAllAction();
virtual String getName(bool to_undo) const;
virtual void perform(bool to_undo);
vector<SimpleTextValueAction> actions;
};
// ----------------------------------------------------------------------------- : Event
/// Notification that a script caused a value to change
......
......@@ -12,6 +12,7 @@
#include <data/field.hpp>
#include <data/stylesheet.hpp>
#include <data/settings.hpp>
#include <util/find_replace.hpp>
#include <wx/caret.h>
DECLARE_TYPEOF_COLLECTION(ValueViewerP);
......@@ -133,6 +134,22 @@ void DataEditor::onInit() {
current_viewer = nullptr;
current_editor = nullptr;
}
// ----------------------------------------------------------------------------- : Search / replace
bool DataEditor::search(FindInfo& find, bool from_start) {
bool include = from_start;
for (size_t i = 0 ; i < by_tab_index.size() ; ++i) {
ValueViewer& viewer = *by_tab_index[find.forward() ? i : by_tab_index.size() - i - 1];
if (&viewer == current_viewer) include = true;
if (include) {
ValueEditor* editor = viewer.getEditor();
if (editor && editor->search(find, from_start || &viewer != current_viewer)) {
return true; // done
}
}
}
return false; // not done
}
// ----------------------------------------------------------------------------- : Clipboard & Formatting
......
......@@ -66,7 +66,7 @@ class DataEditor : public CardViewer {
/** If from_start == false: searches only from the current selection onward (or backward)
* If from_start == true: searches everything
*
* Returns true when more searching is needed.
* Returns true if we are done and searching should be ended.
*/
bool search(FindInfo& find, bool from_start);
......
......@@ -69,11 +69,12 @@ class CardListBase : public ItemList, public SetView {
virtual void onAction(const Action&, bool undone);
// --------------------------------------------------- : The cards
public:
/// Return the card at the given position in the sorted card list
inline CardP getCard(long pos) const { return static_pointer_cast<Card>(getItem(pos)); }
protected:
/// Get a list of all cards
virtual void getItems(vector<VoidP>& out) const;
/// Return the card at the given position in the sorted card list
inline CardP getCard(long pos) const { return static_pointer_cast<Card>(getItem(pos)); }
/// Rebuild the card list (clear all vectors and fill them again)
void rebuild();
......
......@@ -17,6 +17,8 @@
#include <data/card.hpp>
#include <data/action/set.hpp>
#include <data/settings.hpp>
#include <util/find_replace.hpp>
#include <util/tagged_string.hpp>
#include <util/window_id.hpp>
#include <wx/splitter.h>
......@@ -266,6 +268,61 @@ void CardsPanel::doPaste() { CUT_COPY_PASTE(doPaste, ;) }
// ----------------------------------------------------------------------------- : Searching
class CardsPanel::SearchFindInfo : public FindInfo {
public:
SearchFindInfo(CardsPanel& panel, wxFindReplaceData& what) : FindInfo(what), panel(panel) {}
virtual bool handle(const CardP& card, const TextValueP& value, size_t pos) {
// Select the card
panel.card_list->setCard(card);
return true;
}
private:
CardsPanel& panel;
};
class CardsPanel::ReplaceFindInfo : public FindInfo {
public:
ReplaceFindInfo(CardsPanel& panel, wxFindReplaceData& what) : FindInfo(what), panel(panel) {}
virtual bool handle(const CardP& card, const TextValueP& value, size_t pos) {
// Select the card
panel.card_list->setCard(card);
// Replace
panel.editor->insert(escape(what.GetReplaceString()), _("Replace"));
return true;
}
private:
CardsPanel& panel;
};
bool CardsPanel::doFind(wxFindReplaceData& what) {
SearchFindInfo find(*this, what);
return search(find, false);
}
bool CardsPanel::doReplace(wxFindReplaceData& what) {
ReplaceFindInfo find(*this, what);
return search(find, false);
}
bool CardsPanel::doReplaceAll(wxFindReplaceData& what) {
return false; // TODO
}
bool CardsPanel::search(FindInfo& find, bool from_start) {
bool include = from_start;
CardP current = card_list->getCard();
for (size_t i = 0 ; i < set->cards.size() ; ++i) {
CardP card = card_list->getCard( (long) (find.forward() ? i : set->cards.size() - i - 1) );
if (card == current) include = true;
if (include) {
editor->setCard(card);
if (editor->search(find, from_start || card != current)) {
return true; // done
}
}
}
editor->setCard(current);
return false;
}
// ----------------------------------------------------------------------------- : Selection
CardP CardsPanel::selectedCard() const {
......
......@@ -18,6 +18,7 @@ class DataEditor;
class TextCtrl;
class IconMenu;
class HoverButton;
class FindInfo;
// ----------------------------------------------------------------------------- : CardsPanel
......@@ -39,7 +40,6 @@ class CardsPanel : public SetWindowPanel {
// --------------------------------------------------- : Actions
virtual bool wantsToHandle(const Action&, bool undone) const;
public:
// --------------------------------------------------- : Clipboard
virtual bool canCut() const;
......@@ -50,39 +50,19 @@ class CardsPanel : public SetWindowPanel {
virtual void doPaste();
// --------------------------------------------------- : Searching (find/replace)
#if 0
virtual bool canFind() const;
virtual bool canReplace() const;
virtual bool doFind(wxFindReplaceData& what);
virtual bool doReplace(wxFindReplaceData& what);
virtual bool canFind() const { return true; }
virtual bool canReplace() const { return true; }
virtual bool doFind (wxFindReplaceData&);
virtual bool doReplace (wxFindReplaceData&);
virtual bool doReplaceAll(wxFindReplaceData&);
private:
// Functions that handle finding
typedef void (CardsPanel::*FindHandler)(const CardP&, const TextValueP&, const size_t, const size_t, wxFindReplaceData&);
/// Execute a find (or replace), and start with the currently selected card and value
/** if findSame==true then find will also find the currently highlighted word
* Returns true if found
*/
bool find(FindReplaceData& what, const FindHandler& handler, bool findSame = false);
/// find handler : select found value
void handleFind(const CardP& card, const TextValueP& value, size_t start, size_t end, FindReplaceData& what);
/// replace handler : replace found value, move selection to end
void handleReplace(const CardP& card, const TextValueP& value, size_t start, size_t end, FindReplaceData& what);
/// Find in all cards
/** NOTE: this function is essentially the same as findInCard */
bool findInCards(const CardP& firstCard, const ValueP& firstValue, int firstChar, FindReplaceData& what, const FindHandler& handler);
/// Find in a card, if firstValue is specified start searching there
/** NOTE: this function is essentially the same as findInCards */
bool findInCard(const CardP& card, const ValueP& firstValue, int firstChar, FindReplaceData& what, const FindHandler& handler);
/// Find the current search string in the specified value
/** if searchDir = up searches from the end and only before firstChar, unless firstChar == -1 */
bool findInValue(const CardP& crd_, virtual const ValueP& value, int firstChar, FindReplaceData& what, const FindHandler& handler);
#endif
/// Do a search or replace action for the given FindInfo in all cards
bool search(FindInfo& find, bool from_start);
class SearchFindInfo;
class ReplaceFindInfo;
friend class CardsPanel::SearchFindInfo;
friend class CardsPanel::ReplaceFindInfo;
public:
// --------------------------------------------------- : Selection
......
......@@ -61,8 +61,9 @@ class SetWindowPanel : public wxPanel, public SetView {
// --------------------------------------------------- : Searching (find/replace)
virtual bool canFind() const { return false; } ///< Is finding possible?
virtual bool canReplace() const { return false; } ///< Is replacing possible?
virtual bool doFind(wxFindReplaceData&) { return false; } ///< Find the next math
virtual bool doReplace(wxFindReplaceData&) { return false; } ///< Replace the next match
virtual bool doFind (wxFindReplaceData&) { return false; } ///< Find the next math
virtual bool doReplace (wxFindReplaceData&) { return false; } ///< Replace the next match
virtual bool doReplaceAll(wxFindReplaceData&) { return false; } ///< Replace all matches
// --------------------------------------------------- : Selection
virtual CardP selectedCard() const { return CardP(); } ///< Return the currently selected card, or CardP()
......
......@@ -43,6 +43,7 @@ SetWindow::SetWindow(Window* parent, const SetP& set)
: wxFrame(parent, wxID_ANY, _TITLE_("magic set editor"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
, current_panel(nullptr)
, find_dialog(nullptr)
, find_data(wxFR_DOWN)
, number_of_recent_sets(0)
{
SetIcon(load_resource_icon(_("app")));
......@@ -537,7 +538,7 @@ void SetWindow::onReplace (wxFindDialogEvent&) {
current_panel->doReplace(find_data);
}
void SetWindow::onReplaceAll(wxFindDialogEvent&) {
// todo
current_panel->doReplaceAll(find_data);
}
void SetWindow::onEditPreferences(wxCommandEvent&) {
......@@ -627,10 +628,10 @@ BEGIN_EVENT_TABLE(SetWindow, wxFrame)
EVT_GALLERY_SELECT (ID_FIELD_LIST, SetWindow::onChildMenu) // for StatsPanel, because it is not a EVT_TOOL
EVT_UPDATE_UI (wxID_ANY, SetWindow::onUpdateUI)
// EVT_FIND (wxID_ANY, SetWindow::onFind)
// EVT_FIND_NEXT (wxID_ANY, SetWindow::onFindNext)
// EVT_FIND_REPLACE (wxID_ANY, SetWindow::onReplace)
// EVT_FIND_REPLACE_ALL(wxID_ANY, SetWindow::onReplaceAll)
EVT_FIND (wxID_ANY, SetWindow::onFind)
EVT_FIND_NEXT (wxID_ANY, SetWindow::onFindNext)
EVT_FIND_REPLACE (wxID_ANY, SetWindow::onReplace)
EVT_FIND_REPLACE_ALL(wxID_ANY, SetWindow::onReplaceAll)
EVT_CLOSE ( SetWindow::onClose)
EVT_IDLE ( SetWindow::onIdle)
EVT_CARD_SELECT (wxID_ANY, SetWindow::onCardSelect)
......
......@@ -106,9 +106,9 @@ class ValueEditor {
* excluding the sellection itself.
* If from_start == true: searches everything
*
* Returns true when more searching is needed.
* Returns true if we are done and searching should be ended.
*/
bool search(FindInfo& find, bool from_start);
virtual bool search(FindInfo& find, bool from_start) { return false; }
// --------------------------------------------------- : Other
......
......@@ -11,6 +11,7 @@
#include <gui/util.hpp>
#include <data/action/value.hpp>
#include <util/tagged_string.hpp>
#include <util/find_replace.hpp>
#include <util/window_id.hpp>
#include <wx/clipbrd.h>
#include <wx/caret.h>
......@@ -195,7 +196,8 @@ bool TextValueEditor::onChar(wxKeyEvent& ev) {
}
break;
default:
if (ev.GetKeyCode() >= _(' ') /*&& ev.GetKeyCode() == (int)ev.GetRawKeyCode()*/) {
// if (ev.GetKeyCode() >= _(' ') /*&& ev.GetKeyCode() == (int)ev.GetRawKeyCode()*/) {
if (ev.GetKeyCode() >= _(' ') && ev.GetKeyCode() == (int)ev.GetRawKeyCode()) {
// TODO: Find a more correct way to determine normal characters,
// this might not work for internationalized input.
// It might also not be portable!
......@@ -656,6 +658,60 @@ size_t TextValueEditor::move(size_t pos, size_t start, size_t end, Movement dir)
else return start;
}
// ----------------------------------------------------------------------------- : Search / replace
bool is_word_end(const String& s, size_t pos) {
if (pos == 0 || pos >= s.size()) return true;
Char c = s.GetChar(pos);
return isSpace(c) || isPunct(c);
}
// is find.findString() at postion pos of s
bool TextValueEditor::matchSubstr(const String& s, size_t pos, FindInfo& find) {
if (find.wholeWord()) {
if (!is_word_end(s, pos - 1) || !is_word_end(s, pos + find.findString().size())) return false;
}
if (find.caseSensitive()) {
if (!is_substr(s, pos, find.findString())) return false;
} else {
if (!is_substr(s, pos, find.findString().Lower())) return false;
}
// handle
if (find.select()) {
editor().select(this);
editor().SetFocus();
selection_start_i = untagged_to_index(value().value(), pos, true);
selection_end_i = untagged_to_index(value().value(), pos + find.findString().size(), true);
fixSelection(TYPE_INDEX);
}
if (find.handle(viewer.getCard(), valueP(), pos)) {
return true;
} else {
// TODO: string might have changed when doing replace all
return false;
}
}
bool TextValueEditor::search(FindInfo& find, bool from_start) {
String v = untag(value().value());
if (!find.caseSensitive()) v.LowerCase();
if (find.forward()) {
size_t start = min(v.size(), max(selection_start, selection_end));
size_t end = max(0, (int)v.size() - (int)find.findString().size());
for (size_t i = start ; i <= end ; ++i) {
if (matchSubstr(v, i, find)) return true;
}
} else {
size_t start = 0;
int end = (int)min(selection_start, selection_end) - (int)find.findString().size();
if (end < 0) return false;
for (size_t i = end ; i >= start ; --i) {
if (matchSubstr(v, i, find)) return true;
}
}
return false;
}
// ----------------------------------------------------------------------------- : Native look / scrollbar
void TextValueEditor::determineSize(bool force_fit) {
......
......@@ -15,24 +15,6 @@
#include <render/value/text.hpp>
class TextValueEditorScrollBar;
class wxFindReplaceData;
DECLARE_POINTER_TYPE(Card);
// ----------------------------------------------------------------------------- : Search/replace
/// Information for search/replace
class FindInfo {
public:
FindInfo(wxFindReplaceData& what) : what(what) {}
virtual ~FindInfo() {}
/// Handle that a match was found.
/** Should return whether more searching is needed.
*/
virtual bool handle(const CardP& card, const TextValueP& value, size_t start, size_t end) = 0;
wxFindReplaceData& what; ///< What to search for, the direction to search in
};
// ----------------------------------------------------------------------------- : TextValueEditor
......@@ -94,6 +76,13 @@ class TextValueEditor : public TextValueViewer, public ValueEditor {
virtual void insert(const String& text, const String& action_name);
// --------------------------------------------------- : Search/replace
virtual bool search(FindInfo& find, bool from_start);
private:
bool matchSubstr(const String& s, size_t pos, FindInfo& find);
public:
// --------------------------------------------------- : Other
virtual wxCursor cursor() const;
......
......@@ -1919,6 +1919,9 @@
<File
RelativePath=".\util\defaultable.hpp">
</File>
<File
RelativePath=".\util\find_replace.hpp">
</File>
<File
RelativePath=".\util\index_map.hpp">
</File>
......@@ -2930,10 +2933,10 @@
RelativePath="..\conversion-todo.txt">
</File>
<File
RelativePath="..\data\en.mse-locale\locale">
RelativePath="..\data\nl.mse-locale\locale">
</File>
<File
RelativePath="..\data\nl.mse-locale\locale">
RelativePath="..\data\en.mse-locale\locale">
</File>
<File
RelativePath=".\main.cpp">
......
......@@ -68,7 +68,8 @@ Rotation DataViewer::getRotation() const {
// ----------------------------------------------------------------------------- : Setting data
void DataViewer::setCard(const CardP& card) {
if (!card) return; // TODO: clear vie?
if (!card) return; // TODO: clear viewer?
if (this->card == card) return; // already set
assert(set);
this->card = card;
stylesheet = set->stylesheetFor(card);
......
......@@ -317,7 +317,7 @@ void TextViewer::prepareLines(RotatedDC& dc, const String& text, const TextStyle
vector<CharInfo> chars;
scale = 1;
double min_scale = elements.minScale();
double scale_step = max(0.1,elements.scaleStep());
double scale_step = max(0.05,elements.scaleStep());
while (true) {
double next_scale = scale - scale_step;
bool last = next_scale < min_scale;
......
......@@ -61,7 +61,7 @@ void handle_error(const String& e, bool allow_duplicate = true, bool now = true)
// TODO: thread safety
if (!allow_duplicate) {
FOR_EACH(pe, previous_errors) {
if (e == pe) return;
if (e == pe) return;
}
previous_errors.push_back(e);
}
......
......@@ -78,6 +78,7 @@ inline bool isDigit(Char c) { return IF_UNICODE( iswdigit(c) , isdigit(c) ); }
inline bool isAlnum(Char c) { return IF_UNICODE( iswalnum(c) , isalnum(c) ); }
inline bool isUpper(Char c) { return IF_UNICODE( iswupper(c) , isupper(c) ); }
inline bool isLower(Char c) { return IF_UNICODE( iswlower(c) , islower(c) ); }
inline bool isPunct(Char c) { return IF_UNICODE( iswpunct(c) , ispunct(c) ); }
// Character conversions
inline Char toUpper(Char c) { return IF_UNICODE( towupper(c) , toupper(c) ); }
inline Char toLower(Char c) { return IF_UNICODE( towlower(c) , tolower(c) ); }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment