Remove the SelectionChangeSubscriber mechanism from the grid and implement some basic selection change notification through SelectionController.

Change SelectionListener interface so it receives the set of lines added and removed from selection, instead of just the complete new selection.
Update VisualTool<> to use SelectionListener to receive selection change notifications.

This change (temporarily, I hope) breaks feature selection in visual drag mode, when changing selection via the grid. This is caused by the grid selection change first clearing the entire selection, which sends a separate notification about selection clear. This causes the last visual feature to be deselected, and then the visual tool base reselects the active line, causing a new notification for selection to be sent. The active line happens to be the newly clicked line, and the selection notification enters during the externalChange guard being set, and is then ignored for feature update purposes. When control returns to the original SelectRow call in the grid, the line to be selected has already been selected and then nothing happens.
The best fix is to avoid two notifications being required to deselect all then reselect one line in the first place, so making the grid selection handling saner is the best fix.

Originally committed to SVN as r4602.
This commit is contained in:
Niels Martin Hansen 2010-06-26 04:38:02 +00:00
parent e60d476f4a
commit 70d41d31b2
7 changed files with 90 additions and 48 deletions

View file

@ -80,7 +80,6 @@ BaseGrid::BaseGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wx
holding = false; holding = false;
byFrame = false; byFrame = false;
lineHeight = 1; // non-zero to avoid div by 0 lineHeight = 1; // non-zero to avoid div by 0
selChangeSub = NULL;
// Set scrollbar // Set scrollbar
scrollBar = new wxScrollBar(this,GRID_SCROLLBAR,wxDefaultPosition,wxDefaultSize,wxSB_VERTICAL); scrollBar = new wxScrollBar(this,GRID_SCROLLBAR,wxDefaultPosition,wxDefaultSize,wxSB_VERTICAL);
@ -142,6 +141,10 @@ void BaseGrid::UpdateStyle() {
/// @brief Clears grid /// @brief Clears grid
/// ///
void BaseGrid::Clear () { void BaseGrid::Clear () {
Selection lines_removed;
GetSelectedSet(lines_removed);
AnnounceSelectedSetChanged(Selection(), lines_removed);
diagMap.clear(); diagMap.clear();
diagPtrMap.clear(); diagPtrMap.clear();
selMap.clear(); selMap.clear();
@ -209,7 +212,11 @@ void BaseGrid::MakeCellVisible(int row, int col,bool center) {
/// ///
void BaseGrid::SelectRow(int row, bool addToSelected, bool select) { void BaseGrid::SelectRow(int row, bool addToSelected, bool select) {
if (row < 0 || (size_t)row >= selMap.size()) return; if (row < 0 || (size_t)row >= selMap.size()) return;
if (!addToSelected) ClearSelection();
if (!addToSelected) {
// Sends change notifications for itself
ClearSelection();
}
if (select != !!selMap[row]) { if (select != !!selMap[row]) {
selMap[row] = select; selMap[row] = select;
@ -224,7 +231,14 @@ void BaseGrid::SelectRow(int row, bool addToSelected, bool select) {
RefreshRect(wxRect(0,(row+1-yPos)*lineHeight,w,lineHeight),false); RefreshRect(wxRect(0,(row+1-yPos)*lineHeight,w,lineHeight),false);
} }
if (selChangeSub) selChangeSub->OnSelectionChange(!addToSelected, row, select); Selection lines_added;
Selection lines_removed;
if (select)
lines_added.insert(diagPtrMap[row]);
else
lines_removed.insert(diagPtrMap[row]);
AnnounceSelectedSetChanged(lines_added, lines_removed);
} }
} }
@ -233,6 +247,9 @@ void BaseGrid::SelectRow(int row, bool addToSelected, bool select) {
/// @brief Selects visible lines /// @brief Selects visible lines
/// ///
void BaseGrid::SelectVisible() { void BaseGrid::SelectVisible() {
Selection lines_removed;
GetSelectedSet(lines_removed);
int rows = GetRows(); int rows = GetRows();
bool selectedOne = false; bool selectedOne = false;
for (int i=0;i<rows;i++) { for (int i=0;i<rows;i++) {
@ -247,6 +264,11 @@ void BaseGrid::SelectVisible() {
} }
} }
} }
Selection lines_added;
GetSelectedSet(lines_added);
AnnounceSelectedSetChanged(lines_added, lines_removed);
} }
@ -254,11 +276,16 @@ void BaseGrid::SelectVisible() {
/// @brief Unselects all cells /// @brief Unselects all cells
/// ///
void BaseGrid::ClearSelection() { void BaseGrid::ClearSelection() {
Selection lines_removed;
GetSelectedSet(lines_removed);
int rows = selMap.size(); int rows = selMap.size();
for (int i=0;i<rows;i++) { for (int i=0;i<rows;i++) {
selMap[i] = false; selMap[i] = false;
} }
Refresh(false); Refresh(false);
AnnounceSelectedSetChanged(Selection(), lines_removed);
} }
@ -309,8 +336,8 @@ int BaseGrid::GetLastSelRow() const {
/// @brief Gets all selected rows /// @brief Gets all selected rows
/// @param[out] cont /// @param[out] cont Is the selection contiguous, i.e. free from holes
/// @return /// @return Array with indices of selected lines
/// ///
wxArrayInt BaseGrid::GetSelection(bool *cont) const { wxArrayInt BaseGrid::GetSelection(bool *cont) const {
// Prepare // Prepare
@ -1180,3 +1207,16 @@ wxArrayInt BaseGrid::GetRangeArray(int n1,int n2) const {
} }
// SelectionController
void BaseGrid::GetSelectedSet(Selection &selection) const {
for (size_t i = 0; i < selMap.size(); ++i) {
if (selMap[i] != 0) {
selection.insert(GetDialogue((int)i));
}
}
}

View file

@ -60,11 +60,9 @@ class FrameMain;
/// DOCME /// DOCME
typedef std::list<AssEntry*>::iterator entryIter; typedef std::list<AssEntry*>::iterator entryIter;
class SelectionChangeSubscriber {
public:
virtual void OnSelectionChange(bool clear, int row, bool selected) = 0;
};
typedef SelectionController<AssDialogue> SubtitleSelectionController;
typedef SelectionListener<AssDialogue> SubtitleSelectionListener;
/// DOCME /// DOCME
@ -72,7 +70,7 @@ public:
/// @brief DOCME /// @brief DOCME
/// ///
/// DOCME /// DOCME
class BaseGrid : public wxWindow, public BaseSelectionController<AssEntry> { class BaseGrid : public wxWindow, public BaseSelectionController<AssDialogue> {
private: private:
/// DOCME /// DOCME
@ -99,8 +97,6 @@ private:
/// DOCME /// DOCME
wxBitmap *bmp; wxBitmap *bmp;
SelectionChangeSubscriber* selChangeSub;
void OnPaint(wxPaintEvent &event); void OnPaint(wxPaintEvent &event);
void OnSize(wxSizeEvent &event); void OnSize(wxSizeEvent &event);
void OnScroll(wxScrollEvent &event); void OnScroll(wxScrollEvent &event);
@ -133,10 +129,10 @@ protected:
public: public:
// SelectionController implementation // SelectionController implementation
virtual void SetActiveLine(AssEntry *new_line) { } virtual void SetActiveLine(AssDialogue *new_line) { }
virtual AssEntry * GetActiveLine() const { return 0; } virtual AssDialogue * GetActiveLine() const { return 0; }
virtual void SetSelectedSet(const Selection &new_selection) { } virtual void SetSelectedSet(const Selection &new_selection) { }
virtual void GetSelectedSet(Selection &selection) const { } virtual void GetSelectedSet(Selection &selection) const;
virtual void NextLine() { } virtual void NextLine() { }
virtual void PrevLine() { } virtual void PrevLine() { }
@ -181,10 +177,6 @@ public:
AssDialogue *GetDialogue(int n) const; AssDialogue *GetDialogue(int n) const;
void RegisterSelectionChange(SelectionChangeSubscriber* sel) {
selChangeSub = sel;
}
BaseGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxWANTS_CHARS, const wxString& name = wxPanelNameStr); BaseGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxWANTS_CHARS, const wxString& name = wxPanelNameStr);
~BaseGrid(); ~BaseGrid();

View file

@ -47,13 +47,21 @@ public:
/// Virtual destructor for safety /// Virtual destructor for safety
virtual ~SelectionListener() { } virtual ~SelectionListener() { }
/// @brief Called when the active subtitle line changes /// @brief Called when the active line changes
/// @param new_line The subtitle line that is now the active line /// @param new_line The line that is now the active line
///
/// In case new_line is 0, the active line was changed to none.
virtual void OnActiveLineChanged(ItemDataType *new_line) = 0; virtual void OnActiveLineChanged(ItemDataType *new_line) = 0;
/// @brief Called when the selected set changes /// @brief Called when the selected set changes
/// @param new_selection The subtitle line set that is now the selected set /// @param lines_added Lines added to the selection
virtual void OnSelectedSetChanged(const Selection &new_selection) = 0; /// @param lines_removed Lines removed from the selection
///
/// Conceptually, removal happens before addition, for the purpose of this change notification.
///
/// In case the two sets overlap, the intersection are lines that were previously selected
/// and remain selected.
virtual void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) = 0;
}; };
@ -165,11 +173,11 @@ protected:
} }
/// Call OnSelectedSetChangedon all listeners /// Call OnSelectedSetChangedon all listeners
void AnnounceSelectedSetChanged(const Selection &new_selection) void AnnounceSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed)
{ {
for (SelectionListenerSet::iterator listener = listeners.begin(); listener != listeners.end(); ++listener) for (SelectionListenerSet::iterator listener = listeners.begin(); listener != listeners.end(); ++listener)
{ {
(*listener)->OnSelectedSetChanged(new_selection); (*listener)->OnSelectedSetChanged(lines_added, lines_removed);
} }
} }

View file

@ -92,7 +92,7 @@ VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, VideoState const& vide
{ {
if (VideoContext::Get()->IsLoaded()) { if (VideoContext::Get()->IsLoaded()) {
frame_n = VideoContext::Get()->GetFrameN(); frame_n = VideoContext::Get()->GetFrameN();
VideoContext::Get()->grid->RegisterSelectionChange(this); VideoContext::Get()->grid->AddSelectionListener(this);
} }
PopulateFeatureList(); PopulateFeatureList();
@ -100,7 +100,7 @@ VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, VideoState const& vide
template<class FeatureType> template<class FeatureType>
VisualTool<FeatureType>::~VisualTool() { VisualTool<FeatureType>::~VisualTool() {
VideoContext::Get()->grid->RegisterSelectionChange(NULL); VideoContext::Get()->grid->RemoveSelectionListener(this);
} }
template<class FeatureType> template<class FeatureType>

View file

@ -79,7 +79,7 @@ public:
/// @brief DOCME /// @brief DOCME
/// DOCME /// DOCME
template<class FeatureType> template<class FeatureType>
class VisualTool : public IVisualTool, public SelectionChangeSubscriber { class VisualTool : public IVisualTool, protected SubtitleSelectionListener {
private: private:
agi::OptionValue* realtime; /// Realtime updating option agi::OptionValue* realtime; /// Realtime updating option
int dragStartX; /// Starting x coordinate of the current drag, if any int dragStartX; /// Starting x coordinate of the current drag, if any
@ -187,6 +187,12 @@ protected:
typedef typename std::vector<FeatureType>::iterator feature_iterator; typedef typename std::vector<FeatureType>::iterator feature_iterator;
typedef typename std::vector<FeatureType>::const_iterator feature_const_iterator; typedef typename std::vector<FeatureType>::const_iterator feature_const_iterator;
protected:
// SubtitleSelectionListener implementation
// (overridden by deriving classes too)
virtual void OnActiveLineChanged(AssDialogue *new_line) { }
virtual void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) { }
public: public:
/// @brief Handler for all mouse events /// @brief Handler for all mouse events
/// @param event Shockingly enough, the mouse event /// @param event Shockingly enough, the mouse event
@ -202,9 +208,6 @@ public:
/// @brief Called by stuff when there's stuff /// @brief Called by stuff when there's stuff
void Refresh(); void Refresh();
/// Called by the grid when the selection changes
virtual void OnSelectionChange(bool, int, bool) { }
/// @brief Constructor /// @brief Constructor
/// @param parent The VideoDisplay to use for coordinate conversion /// @param parent The VideoDisplay to use for coordinate conversion
/// @param video Video and mouse information passing blob /// @param video Video and mouse information passing blob

View file

@ -121,27 +121,24 @@ void VisualToolDrag::DoRefresh() {
UpdateToggleButtons(); UpdateToggleButtons();
} }
void VisualToolDrag::OnSelectionChange(bool clear, int row, bool selected) { void VisualToolDrag::OnSelectedSetChanged(const Selection &added, const Selection &removed) {
if (!externalChange) return; if (!externalChange) return;
externalChange = false; externalChange = false;
if (clear) {
ClearSelection(false); // Remove all deselected lines
} for (size_t i = 0; i < features.size(); i++) {
if (selected) { if (removed.find(features[i].line) != removed.end()) {
for (size_t i = 0; i < features.size(); i++) { RemoveSelection(i);
if (features[i].lineN == row && features[i].type == DRAG_START) {
AddSelection(i);
break;
}
} }
} }
else {
for (size_t i = 0; i < features.size(); i++) { // And add all newly selected lines
if (features[i].lineN == row) { for (size_t i = 0; i < features.size(); i++) {
RemoveSelection(i); if (added.find(features[i].line) != added.end() && features[i].type == DRAG_START) {
} AddSelection(i);
} }
} }
externalChange = true; externalChange = true;
} }

View file

@ -82,11 +82,13 @@ private:
void UpdateToggleButtons(); void UpdateToggleButtons();
void DoRefresh(); void DoRefresh();
protected:
// Overriding SubtitleSelectionListener inherited from base VisualTool<>
virtual void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
public: public:
VisualToolDrag(VideoDisplay *parent, VideoState const& video, wxToolBar *toolbar); VisualToolDrag(VideoDisplay *parent, VideoState const& video, wxToolBar *toolbar);
void OnSelectionChange(bool clear, int row, bool selected);
void Draw(); void Draw();
bool Update(); bool Update();
void OnSubTool(wxCommandEvent &event); void OnSubTool(wxCommandEvent &event);