patches from lincoln to speed up the regionlist and provide region removal (causes dangling shared ptrs to regions, fix to come

git-svn-id: svn://localhost/ardour2/branches/3.0@8845 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2011-02-14 21:49:43 +00:00
parent 7ac5d03cb8
commit 7a5b6a5031
16 changed files with 468 additions and 362 deletions

View file

@ -560,6 +560,8 @@
</menu>
<separator/>
<menuitem action='addExternalAudioToRegionList'/>
<separator/>
<menuitem action='removeUnusedRegions'/>
</popup>
<popup name='PopupRegionMenu' action='PopupRegionMenu'>

View file

@ -269,7 +269,7 @@ AudioRegionView::~AudioRegionView ()
delete *i;
}
for (list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator i = feature_lines.begin(); i != feature_lines.end(); ++i) {
for (list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator i = feature_lines.begin(); i != feature_lines.end(); ++i) {
delete ((*i).second);
}
@ -408,7 +408,7 @@ AudioRegionView::region_resized (const PropertyChange& what_changed)
/* hide transient lines that extend beyond the region end */
list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
if ((*l).first > _region->length()- 1){
@ -444,11 +444,19 @@ AudioRegionView::reset_width_dependent_items (double pixel_width)
AnalysisFeatureList analysis_features = _region->transients();
AnalysisFeatureList::const_iterator i;
list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
(*l).second->property_x1() = trackview.editor().frame_to_pixel (*i);
(*l).second->property_x2() = trackview.editor().frame_to_pixel (*i);
float x_pos = trackview.editor().frame_to_pixel (*i);
ArdourCanvas::Points points;
points.push_back(Gnome::Art::Point(x_pos, 2.0)); // first x-coord needs to be a non-normal value
points.push_back(Gnome::Art::Point(x_pos, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
(*l).first = *i;
(*l).second->property_points() = points;
}
reset_fade_shapes ();
@ -526,13 +534,22 @@ AudioRegionView::set_height (gdouble height)
reset_fade_shapes ();
/* Update hights for any active feature lines */
list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
(*l).second->property_y2() = _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1;
float pos_x = trackview.editor().frame_to_pixel((*l).first);
ArdourCanvas::Points points;
points.push_back(Gnome::Art::Point(pos_x, 2.0)); // first x-coord needs to be a non-normal value
points.push_back(Gnome::Art::Point(pos_x, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
(*l).second->property_points() = points;
}
if (fade_position_line) {
if (height < NAME_HIGHLIGHT_THRESH) {
fade_position_line->property_y2() = _height - 1;
}
@ -1430,31 +1447,55 @@ AudioRegionView::transients_changed ()
AnalysisFeatureList analysis_features = _region->transients();
while (feature_lines.size() < analysis_features.size()) {
ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*group);
l->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();
feature_lines.push_back (make_pair(0, l));
ArdourCanvas::Line* canvas_item = new ArdourCanvas::Line(*group);
ArdourCanvas::Points points;
points.push_back(Gnome::Art::Point(-1.0, 2.0)); // first x-coord needs to be a non-normal value
points.push_back(Gnome::Art::Point(1.0, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
canvas_item->property_points() = points;
canvas_item->property_width_pixels() = 1;
canvas_item->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
canvas_item->property_first_arrowhead() = TRUE;
canvas_item->property_last_arrowhead() = TRUE;
canvas_item->property_arrow_shape_a() = 11.0;
canvas_item->property_arrow_shape_b() = 0.0;
canvas_item->property_arrow_shape_c() = 4.0;
canvas_item->raise_to_top ();
canvas_item->show ();
canvas_item->set_data ("regionview", this);
canvas_item->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_feature_line_event), canvas_item, this));
feature_lines.push_back (make_pair(0, canvas_item));
}
while (feature_lines.size() > analysis_features.size()) {
ArdourCanvas::SimpleLine *line = feature_lines.back().second;
ArdourCanvas::Line* line = feature_lines.back().second;
feature_lines.pop_back ();
delete line;
}
AnalysisFeatureList::const_iterator i;
list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
(*l).first = *i;
(*l).second->property_x1() = trackview.editor().frame_to_pixel (*i);
(*l).second->property_x2() = trackview.editor().frame_to_pixel (*i);
(*l).second->property_y1() = 2;
(*l).second->property_y2() = _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1;
(*l).second->set_data("regionview", this);
(*l).second->show ();
(*l).second->raise_to_top ();
(*l).second->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_feature_line_event), (*l).second, this));
ArdourCanvas::Points points;
float *pos = new float;
*pos = trackview.editor().frame_to_pixel (*i);
points.push_back(Gnome::Art::Point(*pos, 2.0)); // first x-coord needs to be a non-normal value
points.push_back(Gnome::Art::Point(*pos, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
(*l).second->property_points() = points;
(*l).second->set_data ("position", pos);
(*l).first = *i;
}
}
@ -1462,11 +1503,15 @@ void
AudioRegionView::update_transient(float /*old_pos*/, float new_pos)
{
/* Find frame at old pos, calulate new frame then update region transients*/
list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
/* Simple line x1 has been updated in drag so we compare to new_pos */
if (rint(new_pos) == rint((*l).second->property_x1())) {
/* Line has been updated in drag so we compare to new_pos */
float* pos = (float*) (*l).second->get_data ("position");
if (rint(new_pos) == rint(*pos)) {
framepos_t old_frame = (*l).first;
framepos_t new_frame = trackview.editor().pixel_to_frame (new_pos);
@ -1482,11 +1527,14 @@ void
AudioRegionView::remove_transient(float pos)
{
/* Find frame at old pos, calulate new frame then update region transients*/
list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> >::iterator l;
list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
/* Simple line x1 has been updated in drag so we compare to new_pos */
if (rint(pos) == rint((*l).second->property_x1())) {
/* Line has been updated in drag so we compare to new_pos */
float *line_pos = (float*) (*l).second->get_data ("position");
if (rint(pos) == rint(*line_pos)) {
_region->remove_transient ((*l).first);
break;
}

View file

@ -136,7 +136,7 @@ class AudioRegionView : public RegionView
std::vector<ArdourCanvas::WaveView *> waves;
std::vector<ArdourCanvas::WaveView *> tmp_waves; ///< see ::create_waves()
std::list<std::pair<framepos_t, ArdourCanvas::SimpleLine*> > feature_lines;
std::list<std::pair<framepos_t, ArdourCanvas::Line*> > feature_lines;
ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position
ArdourCanvas::SimpleLine* zero_line;

View file

@ -1386,6 +1386,9 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
bool canvas_markerview_start_handle_event(GdkEvent* event, ArdourCanvas::Item*,MarkerView*);
bool canvas_markerview_end_handle_event(GdkEvent* event, ArdourCanvas::Item*,MarkerView*);
PBD::Signal0<void> EditorFreeze;
PBD::Signal0<void> EditorThaw;
private:
friend class DragManager;
friend class EditorRouteGroups;

View file

@ -631,10 +631,13 @@ Editor::register_actions ()
act = ActionManager::register_action (rl_actions, X_("rlAudition"), _("Audition"), sigc::mem_fun(*this, &Editor::audition_region_from_region_list));
ActionManager::region_list_selection_sensitive_actions.push_back (act);
act = ActionManager::register_action (rl_actions, X_("rlHide"), _("Hide"), sigc::mem_fun(*this, &Editor::hide_region_from_region_list));
ActionManager::region_list_selection_sensitive_actions.push_back (act);
act = ActionManager::register_action (rl_actions, X_("rlShow"), _("Show"), sigc::mem_fun(*this, &Editor::show_region_in_region_list));
ActionManager::region_list_selection_sensitive_actions.push_back (act);
ActionManager::register_toggle_action (rl_actions, X_("rlShowAll"), _("Show All"), sigc::mem_fun(*_regions, &EditorRegions::toggle_full));
ActionManager::register_toggle_action (rl_actions, X_("rlShowAuto"), _("Show Automatic Regions"), sigc::mem_fun (*_regions, &EditorRegions::toggle_show_auto_regions));
@ -664,6 +667,7 @@ Editor::register_actions ()
ActionManager::register_radio_action (rl_actions, sort_type_group, X_("SortBySourceFilesystem"), _("By Source Filesystem"),
sigc::bind (sigc::mem_fun (*_regions, &EditorRegions::reset_sort_type), BySourceFileFS, false));
ActionManager::register_action (rl_actions, X_("removeUnusedRegions"), _("Delete Unused"), sigc::mem_fun(*_regions, &EditorRegions::delete_unused_regions));
/* the next two are duplicate items with different names for use in two different contexts */
@ -747,6 +751,7 @@ Editor::toggle_ruler_visibility (RulerType rt)
}
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Rulers"), action);
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
update_ruler_visibility ();

View file

@ -2900,7 +2900,7 @@ FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
{
Drag::start_grab (event);
_line = reinterpret_cast<SimpleLine*> (_item);
_line = reinterpret_cast<Line*> (_item);
assert (_line);
/* need to get x coordinate in terms of parent (AudioRegionView) origin. */
@ -2913,7 +2913,7 @@ FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
/* store grab start in parent frame */
_region_view_grab_x = cx;
_before = _line->property_x1();
_before = *(float*) _item->get_data ("position");
_arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
@ -2938,17 +2938,30 @@ FeatureLineDrag::motion (GdkEvent*, bool)
cx = 0;
}
_line->property_x1() = cx;
_line->property_x2() = cx;
ArdourCanvas::Points points;
_before = _line->property_x1();
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
_line->get_bounds(x1, y2, x2, y2);
points.push_back(Gnome::Art::Point(cx, 2.0)); // first x-coord needs to be a non-normal value
points.push_back(Gnome::Art::Point(cx, y2 - y1));
_line->property_points() = points;
float *pos = new float;
*pos = cx;
_line->set_data ("position", pos);
_before = cx;
}
void
FeatureLineDrag::finished (GdkEvent*, bool)
{
_arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
_arv->update_transient(_before, _line->property_x1());
_arv->update_transient(_before, _before);
}
void
@ -3049,6 +3062,7 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
}
_editor->commit_reversible_command ();
} else {
if (!getenv("ARDOUR_SAE")) {
_editor->selection->clear_tracks();

View file

@ -731,13 +731,13 @@ public:
private:
ArdourCanvas::SimpleLine* _line;
ArdourCanvas::Line* _line;
AudioRegionView* _arv;
double _region_view_grab_x;
double _cumulative_x_drag;
uint32_t _before;
float _before;
uint32_t _max_x;
};

View file

@ -1714,8 +1714,8 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
break;
case FeatureLineItem:
{
ArdourCanvas::SimpleLine *line = dynamic_cast<ArdourCanvas::SimpleLine *> (item);
line->property_color_rgba() = 0xFF0000FF;
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
line->property_fill_color_rgba() = 0xFF0000FF;
}
break;
case SelectionItem:
@ -1874,8 +1874,8 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
break;
case FeatureLineItem:
{
ArdourCanvas::SimpleLine *line = dynamic_cast<ArdourCanvas::SimpleLine *> (item);
line->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();;
ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
line->property_fill_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();;
}
break;
@ -2477,7 +2477,7 @@ Editor::mouse_brush_insert_region (RegionView* rv, framepos_t pos)
double speed = rtv->track()->speed();
playlist->clear_changes ();
boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region()));
boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region(), true));
playlist->add_region (new_region, (framepos_t) (pos * speed));
_session->add_command (new StatefulDiffCommand (playlist));

View file

@ -120,6 +120,8 @@ Editor::redo (uint32_t n)
void
Editor::split_regions_at (framepos_t where, RegionSelection& regions)
{
bool frozen = false;
list <boost::shared_ptr<Playlist > > used_playlists;
if (regions.empty()) {
@ -142,6 +144,9 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions)
}
} else {
snap_to (where);
frozen = true;
EditorFreeze(); /* Emit Signal */
}
for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
@ -191,6 +196,10 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions)
}
commit_reversible_command ();
if (frozen){
EditorThaw(); /* Emit Signal */
}
}
boost::shared_ptr<Region>
@ -5851,6 +5860,7 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
plist.add (ARDOUR::Properties::layer, 0);
boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
pl->add_region (nr, r->position() + pos);
if (select_new) {
@ -5924,16 +5934,18 @@ Editor::remove_transient(ArdourCanvas::Item* item)
return;
}
ArdourCanvas::SimpleLine* _line = reinterpret_cast<ArdourCanvas::SimpleLine*> (item);
ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
assert (_line);
AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
_arv->remove_transient(_line->property_x1());
_arv->remove_transient (*(float*) _line->get_data ("position"));
}
void
Editor::snap_regions_to_grid ()
{
list <boost::shared_ptr<Playlist > > used_playlists;
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
@ -5943,17 +5955,36 @@ Editor::snap_regions_to_grid ()
_session->begin_reversible_command (_("snap regions to grid"));
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
if (!pl->frozen()) {
/* we haven't seen this playlist before */
/* remember used playlists so we can thaw them later */
used_playlists.push_back(pl);
pl->freeze();
}
framepos_t start_frame = (*r)->region()->first_frame ();
snap_to (start_frame);
(*r)->region()->set_position (start_frame, this);
}
while (used_playlists.size() > 0) {
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
(*i)->thaw();
used_playlists.pop_front();
}
_session->commit_reversible_command ();
}
void
Editor::close_region_gaps ()
{
list <boost::shared_ptr<Playlist > > used_playlists;
RegionSelection rs = get_regions_from_selection_and_entered ();
if (!_session || rs.empty()) {
@ -6015,6 +6046,16 @@ Editor::close_region_gaps ()
for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
if (!pl->frozen()) {
/* we haven't seen this playlist before */
/* remember used playlists so we can thaw them later */
used_playlists.push_back(pl);
pl->freeze();
}
framepos_t position = (*r)->region()->position();
if (idx == 0 || position < last_region->position()){
@ -6031,6 +6072,12 @@ Editor::close_region_gaps ()
idx++;
}
while (used_playlists.size() > 0) {
list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
(*i)->thaw();
used_playlists.pop_front();
}
_session->commit_reversible_command ();
}

View file

@ -34,6 +34,7 @@
#include "ardour/silentfilesource.h"
#include "ardour/profile.h"
#include "gtkmm2ext/choice.h"
#include "gtkmm2ext/treeutils.h"
#include "editor.h"
@ -72,6 +73,7 @@ EditorRegions::EditorRegions (Editor* e)
_display.set_size_request (100, -1);
_display.set_name ("RegionListDisplay");
_display.set_rules_hint (true);
/* Try to prevent single mouse presses from initiating edits.
This relies on a hack in gtktreeview.c:gtk_treeview_button_press()
*/
@ -117,24 +119,28 @@ EditorRegions::EditorRegions (Editor* e)
CellRendererToggle* locked_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (7));
locked_cell->property_activatable() = true;
locked_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::locked_changed));
TreeViewColumn* locked_col = _display.get_column (7);
locked_col->add_attribute (locked_cell->property_visible(), _columns.property_toggles_visible);
CellRendererToggle* glued_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (8));
glued_cell->property_activatable() = true;
glued_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::glued_changed));
TreeViewColumn* glued_col = _display.get_column (8);
glued_col->add_attribute (glued_cell->property_visible(), _columns.property_toggles_visible);
CellRendererToggle* muted_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (9));
muted_cell->property_activatable() = true;
muted_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::muted_changed));
TreeViewColumn* muted_col = _display.get_column (9);
muted_col->add_attribute (muted_cell->property_visible(), _columns.property_toggles_visible);
CellRendererToggle* opaque_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (10));
opaque_cell->property_activatable() = true;
opaque_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRegions::opaque_changed));
TreeViewColumn* opaque_col = _display.get_column (10);
opaque_col->add_attribute (opaque_cell->property_visible(), _columns.property_toggles_visible);
@ -171,6 +177,9 @@ EditorRegions::EditorRegions (Editor* e)
ARDOUR_UI::instance()->secondary_clock.mode_changed.connect (sigc::mem_fun(*this, &EditorRegions::update_all_rows));
ARDOUR::Region::RegionPropertyChanged.connect (region_property_connection, MISSING_INVALIDATOR, ui_bind (&EditorRegions::region_changed, this, _1, _2), gui_context());
ARDOUR::RegionFactory::CheckNewRegion.connect (check_new_region_connection, MISSING_INVALIDATOR, ui_bind (&EditorRegions::add_region, this, _1), gui_context());
e->EditorFreeze.connect (editor_freeze_connection, MISSING_INVALIDATOR, ui_bind (&EditorRegions::freeze_tree_model, this), gui_context());
e->EditorThaw.connect (editor_thaw_connection, MISSING_INVALIDATOR, ui_bind (&EditorRegions::thaw_tree_model, this), gui_context());
}
bool
@ -237,14 +246,6 @@ EditorRegions::set_session (ARDOUR::Session* s)
redisplay ();
}
void
EditorRegions::add_regions (vector<boost::shared_ptr<Region> >& regions)
{
for (vector<boost::shared_ptr<Region> >::iterator x = regions.begin(); x != regions.end(); ++x) {
add_region (*x);
}
}
void
EditorRegions::add_region (boost::shared_ptr<Region> region)
{
@ -262,6 +263,7 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
}
if (region->hidden()) {
TreeModel::iterator iter = _model->get_iter ("0");
TreeModel::Row parent;
TreeModel::Row child;
@ -282,6 +284,7 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
parent = *iter;
}
}
row = *(_model->append (parent.children()));
} else if (region->whole_file()) {
@ -357,31 +360,29 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
}
}
if (region->automatic()) {
region_row_map.insert(pair<boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::RowReference>(region, TreeRowReference(_model, TreePath (row))) );
parent_regions_sources_map.insert(pair<string, Gtk::TreeModel::RowReference>(region->source_string(), TreeRowReference(_model, TreePath (row))) );
return;
}
} else {
/* find parent node, add as new child */
// find parent node, add as new child
TreeModel::iterator i;
TreeModel::Children rows = _model->children();
bool found_parent = false;
for (i = rows.begin(); i != rows.end(); ++i) {
boost::shared_ptr<Region> r = (*i)[_columns.region];
boost::unordered_map<string, Gtk::TreeModel::RowReference>::iterator it;
if (r && r->whole_file()) {
it = parent_regions_sources_map.find (region->source_string());
if (region->source_equivalent (r)) {
found_parent = true;
}
}
if (it != parent_regions_sources_map.end()){
TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
TreeModel::iterator ii;
TreeModel::Children subrows = (*i).children();
TreeModel::Children subrows = (*j).children();
/* XXXX: should we be accounting for all regions? */
/*
for (ii = subrows.begin(); ii != subrows.end(); ++ii) {
boost::shared_ptr<Region> rr = (*ii)[_columns.region];
@ -389,14 +390,11 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
return;
}
}
*/
if (found_parent) {
row = *(_model->append ((*i).children()));
break;
row = *(_model->insert (subrows.end()));
}
}
if (!found_parent) {
else {
row = *(_model->append());
}
@ -405,9 +403,37 @@ EditorRegions::add_region (boost::shared_ptr<Region> region)
row[_columns.region] = region;
region_row_map.insert(pair<boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::RowReference>(region, TreeRowReference(_model, TreePath (row))) );
populate_row(region, (*row));
}
void
EditorRegions::delete_unused_regions ()
{
vector<string> choices;
string prompt;
if (!_session) {
return;
}
prompt = _("Do you really want to remove unused regions?"
"\n(This is destructive and cannot be undone)");
choices.push_back (_("No, do nothing."));
choices.push_back (_("Yes, remove."));
Gtkmm2ext::Choice prompter (_("Remove unused regions"), prompt, choices);
if (prompter.run () == 1) {
_no_redisplay = true;
_session->cleanup_regions ();
_no_redisplay = false;
redisplay ();
}
}
void
EditorRegions::region_changed (boost::shared_ptr<Region> r, const PropertyChange& what_changed)
{
@ -424,6 +450,8 @@ EditorRegions::region_changed (boost::shared_ptr<Region> r, const PropertyChange
our_interests.add (ARDOUR::Properties::fade_in);
our_interests.add (ARDOUR::Properties::fade_out);
if (what_changed.contains (our_interests)) {
if (last_row != 0) {
TreeModel::iterator j = _model->get_iter (last_row.get_path());
@ -440,85 +468,30 @@ EditorRegions::region_changed (boost::shared_ptr<Region> r, const PropertyChange
}
}
if (what_changed.contains (our_interests)) {
RegionRowMap::iterator it;
it = region_row_map.find (r);
if (it != region_row_map.end()){
TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
boost::shared_ptr<Region> c = (*j)[_columns.region];
if (c == r) {
populate_row (r, (*j));
if (what_changed.contains (ARDOUR::Properties::hidden)) {
redisplay ();
}
return;
}
}
/* find the region in our model and update its row */
TreeModel::Children rows = _model->children ();
TreeModel::iterator i = rows.begin ();
while (i != rows.end ()) {
TreeModel::Children children = (*i)->children ();
TreeModel::iterator found = children.end ();
boost::shared_ptr<Region> c = (*i)[_columns.region];
if (c == r) {
/* check this row */
last_row = TreeRowReference (_model, TreePath (i));
found = i;
} else {
/* check its children */
found = children.begin ();
while (found != children.end()) {
boost::shared_ptr<Region> c = (*found)[_columns.region];
if (c == r) {
last_row = TreeRowReference(_model, TreePath (found));
break;
}
++found;
}
}
if (found != children.end()) {
boost::shared_ptr<AudioRegion> audioregion = boost::dynamic_pointer_cast<AudioRegion>(r);
uint32_t used = _editor->get_regionview_count_from_region_list (r);
if (what_changed.contains (ARDOUR::Properties::name)) {
populate_row_name (r, *found);
}
if (what_changed.contains (ARDOUR::Properties::position)) {
populate_row_position (r, *found, used);
populate_row_end (r, *found, used);
}
if (what_changed.contains (ARDOUR::Properties::length)) {
populate_row_end (r, *found, used);
populate_row_length (r, *found);
}
if (what_changed.contains (ARDOUR::Properties::start)) {
populate_row_length (r, *found);
}
if (what_changed.contains (ARDOUR::Properties::locked)) {
populate_row_locked (r, *found, used);
}
if (what_changed.contains (ARDOUR::Properties::position_lock_style)) {
populate_row_glued (r, *found, used);
}
if (what_changed.contains (ARDOUR::Properties::muted)) {
populate_row_muted (r, *found, used);
}
if (what_changed.contains (ARDOUR::Properties::opaque)) {
populate_row_opaque (r, *found, used);
}
if (what_changed.contains (ARDOUR::Properties::fade_in)) {
populate_row_fade_in (r, *found, used, audioregion);
}
if (what_changed.contains (ARDOUR::Properties::fade_out)) {
populate_row_fade_out (r, *found, used, audioregion);
}
break;
}
++i;
}
}
if (what_changed.contains (ARDOUR::Properties::hidden)) {
@ -576,66 +549,18 @@ EditorRegions::selection_changed ()
void
EditorRegions::set_selected (RegionSelection& regions)
{
TreeModel::Children rows = _model->children();
for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
for (RegionSelection::iterator iter = regions.begin(); iter != regions.end(); ++iter) {
boost::shared_ptr<Region> r ((*i)->region());
TreeModel::iterator i;
RegionRowMap::iterator it;
boost::shared_ptr<Region> r ((*iter)->region());
it = region_row_map.find (r);
for (i = rows.begin(); i != rows.end(); ++i) {
boost::shared_ptr<Region> compared_region = (*i)[_columns.region];
if (r == compared_region) {
_display.get_selection()->select(*i);
break;
if (it != region_row_map.end()){
TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
_display.get_selection()->select(*j);
}
if (!(*i).children().empty()) {
if (set_selected_in_subrow(r, (*i), 2)) {
break;
}
}
}
}
}
bool
EditorRegions::set_selected_in_subrow (boost::shared_ptr<Region> region, TreeModel::Row const &parent_row, int level)
{
TreeModel::iterator i;
TreeModel::Children subrows = (*parent_row).children();
for (i = subrows.begin(); i != subrows.end(); ++i) {
boost::shared_ptr<Region> compared_region = (*i)[_columns.region];
if (region == compared_region) {
_display.get_selection()->select(*i);
return true;
}
if (!(*i).children().empty()) {
if (set_selected_in_subrow (region, (*i), level + 1)) {
return true;
}
}
}
return false;
}
void
EditorRegions::insert_into_tmp_regionlist(boost::shared_ptr<Region> region)
{
/* keep all whole files at the beginning */
if (region->whole_file()) {
tmp_region_list.push_front (region);
} else {
tmp_region_list.push_back (region);
}
}
@ -655,23 +580,36 @@ EditorRegions::redisplay ()
_display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
_model->clear ();
_model->set_sort_column (-2, SORT_ASCENDING); //Disable sorting to gain performance
region_row_map.clear();
parent_regions_sources_map.clear();
/* now add everything we have, via a temporary list used to help with sorting */
tmp_region_list.clear();
const RegionFactory::RegionMap& regions (RegionFactory::regions());
for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
insert_into_tmp_regionlist (i->second);
if ( i->second->whole_file()) {
/* add automatic regions first so that children can find their parents as we add them */
add_region (i->second);
continue;
}
tmp_region_list.push_front (i->second);
}
for (list<boost::shared_ptr<Region> >::iterator r = tmp_region_list.begin(); r != tmp_region_list.end(); ++r) {
add_region (*r);
}
tmp_region_list.clear();
_model->set_sort_column (0, SORT_ASCENDING); // renabale sorting
_display.set_model (_model);
tmp_region_list.clear();
if (tree_expanded) {
_display.expand_all();
}
@ -684,59 +622,15 @@ EditorRegions::update_row (boost::shared_ptr<Region> region)
return;
}
TreeModel::iterator i;
TreeModel::Children rows = _model->children();
RegionRowMap::iterator it;
return;
it = region_row_map.find (region);
for (i = rows.begin(); i != rows.end(); ++i) {
if (it != region_row_map.end()){
// cerr << "Level 1: Compare " << region->name() << " with parent " << (*i)[_columns.name] << "\n";
boost::shared_ptr<Region> compared_region = (*i)[_columns.region];
if (region == compared_region) {
// cerr << "Matched\n";
populate_row(region, (*i));
return;
TreeModel::iterator j = _model->get_iter ((*it).second.get_path());
populate_row(region, (*j));
}
if (!(*i).children().empty()) {
if (update_subrows(region, (*i), 2)) {
return;
}
}
}
// cerr << "Returning - No match\n";
}
bool
EditorRegions::update_subrows (boost::shared_ptr<Region> region, TreeModel::Row const &parent_row, int level)
{
TreeModel::iterator i;
TreeModel::Children subrows = (*parent_row).children();
for (i = subrows.begin(); i != subrows.end(); ++i) {
// cerr << "Level " << level << ": Compare " << region->name() << " with child " << (*i)[_columns.name] << "\n";
boost::shared_ptr<Region> compared_region = (*i)[_columns.region];
if (region == compared_region) {
populate_row(region, (*i));
// cerr << "Matched\n";
return true;
}
if (!(*i).children().empty()) {
if (update_subrows (region, (*i), level + 1)) {
return true;
}
}
}
return false;
}
void
@ -746,39 +640,16 @@ EditorRegions::update_all_rows ()
return;
}
TreeModel::iterator i;
TreeModel::Children rows = _model->children();
RegionRowMap::iterator i;
for (i = rows.begin(); i != rows.end(); ++i) {
for (i = region_row_map.begin(); i != region_row_map.end(); ++i) {
boost::shared_ptr<Region> region = (*i)[_columns.region];
TreeModel::iterator j = _model->get_iter ((*i).second.get_path());
boost::shared_ptr<Region> region = (*j)[_columns.region];
if (!region->automatic()) {
populate_row(region, (*i));
}
if (!(*i).children().empty()) {
update_all_subrows ((*i), 2);
}
}
}
void
EditorRegions::update_all_subrows (TreeModel::Row const &parent_row, int level)
{
TreeModel::iterator i;
TreeModel::Children subrows = (*parent_row).children();
for (i = subrows.begin(); i != subrows.end(); ++i) {
boost::shared_ptr<Region> region = (*i)[_columns.region];
if (!region->automatic()) {
populate_row(region, (*i));
}
if (!(*i).children().empty()) {
update_all_subrows ((*i), level + 1);
populate_row(region, (*j));
}
}
}
@ -827,7 +698,9 @@ void
EditorRegions::populate_row (boost::shared_ptr<Region> region, TreeModel::Row const &row)
{
boost::shared_ptr<AudioRegion> audioregion = boost::dynamic_pointer_cast<AudioRegion>(region);
uint32_t used = _session->playlists->region_use_count (region);
//uint32_t used = _session->playlists->region_use_count (region);
/* Presently a region is only used once so let's save on the sequential scan to determine use count */
uint32_t used = 1;
populate_row_position (region, row, used);
populate_row_end (region, row, used);
@ -1448,6 +1321,25 @@ EditorRegions::get_single_selection ()
return (*iter)[_columns.region];
}
void
EditorRegions::freeze_tree_model (){
_display.set_model (Glib::RefPtr<Gtk::TreeStore>(0));
_model->set_sort_column (-2, SORT_ASCENDING); //Disable sorting to gain performance
}
void
EditorRegions::thaw_tree_model (){
_model->set_sort_column (0, SORT_ASCENDING); // renabale sorting
_display.set_model (_model);
if (toggle_full_action()->get_active()) {
_display.expand_all();
}
}
void
EditorRegions::locked_changed (std::string const & path)
{
@ -1526,28 +1418,35 @@ EditorRegions::set_state (const XMLNode & node)
}
XMLProperty const * p = node.property (X_("sort-type"));
if (p) {
Editing::RegionListSortType const t = static_cast<Editing::RegionListSortType> (string_2_enum (p->value(), _sort_type));
if (_sort_type != t) {
changed = true;
}
reset_sort_type (t, true);
RefPtr<RadioAction> ract = sort_type_action (t);
ract->set_active ();
}
p = node.property (X_("sort-ascending"));
if (p) {
bool const yn = string_is_affirmative (p->value ());
SortType old_sort_type;
int old_sort_column;
_model->get_sort_column_id (old_sort_column, old_sort_type);
if (old_sort_type != (yn ? SORT_ASCENDING : SORT_DESCENDING)) {
changed = true;
}
reset_sort_direction (yn);
RefPtr<Action> act;
if (yn) {
act = ActionManager::get_action (X_("RegionList"), X_("SortAscending"));
} else {
@ -1560,9 +1459,11 @@ EditorRegions::set_state (const XMLNode & node)
p = node.property (X_("show-all"));
if (p) {
bool const yn = string_is_affirmative (p->value ());
if (expanded != yn) {
changed = true;
}
set_full (yn);
toggle_full_action()->set_active (yn);
}
@ -1570,6 +1471,7 @@ EditorRegions::set_state (const XMLNode & node)
p = node.property (X_("show-automatic-regions"));
if (p) {
bool const yn = string_is_affirmative (p->value ());
if (yn != _show_automatic_regions) {
_show_automatic_regions = yn;
toggle_show_auto_regions_action()->set_active (yn);
@ -1642,6 +1544,12 @@ EditorRegions::show_action () const
return ActionManager::get_action (X_("RegionList"), X_("rlShow"));
}
RefPtr<Action>
EditorRegions::delete_unused_regions_action () const
{
return ActionManager::get_action (X_("RegionList"), X_("removeUnusedRegions"));
}
RefPtr<ToggleAction>
EditorRegions::toggle_full_action () const
{

View file

@ -20,6 +20,7 @@
#define __gtk_ardour_editor_regions_h__
#include "editor_component.h"
#include <boost/unordered_map.hpp>
class EditorRegions : public EditorComponent, public ARDOUR::SessionHandlePtr
{
@ -67,6 +68,8 @@ public:
_display.get_selection()->unselect_all ();
}
void delete_unused_regions();
XMLNode& get_state () const;
void set_state (const XMLNode &);
@ -115,12 +118,13 @@ private:
Gtk::TreeModel::RowReference last_row;
void freeze_tree_model ();
void thaw_tree_model ();
void region_changed (boost::shared_ptr<ARDOUR::Region>, PBD::PropertyChange const &);
void selection_changed ();
sigc::connection _change_connection;
bool set_selected_in_subrow (boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::Row const &, int);
bool selection_filter (const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path, bool yn);
Gtk::Widget* old_focus;
@ -135,10 +139,12 @@ private:
bool key_press (GdkEventKey *);
bool button_press (GdkEventButton *);
bool focus_in (GdkEventFocus*);
bool focus_out (GdkEventFocus*);
bool enter_notify (GdkEventCrossing*);
bool leave_notify (GdkEventCrossing*);
void show_context_menu (int button, int time);
int sorter (Gtk::TreeModel::iterator, Gtk::TreeModel::iterator);
@ -146,7 +152,7 @@ private:
void format_position (ARDOUR::framepos_t pos, char* buf, size_t bufsize);
void add_region (boost::shared_ptr<ARDOUR::Region>);
void add_regions (std::vector<boost::shared_ptr<ARDOUR::Region> > & );
void populate_row (boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::Row const &);
void populate_row_used (boost::shared_ptr<ARDOUR::Region> region, Gtk::TreeModel::Row const& row, uint32_t used);
void populate_row_position (boost::shared_ptr<ARDOUR::Region> region, Gtk::TreeModel::Row const& row, uint32_t used);
@ -163,9 +169,8 @@ private:
void populate_row_source (boost::shared_ptr<ARDOUR::Region> region, Gtk::TreeModel::Row const& row);
void update_row (boost::shared_ptr<ARDOUR::Region>);
bool update_subrows (boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::Row const &, int);
void update_all_rows ();
void update_all_subrows (Gtk::TreeModel::Row const &, int);
void insert_into_tmp_regionlist (boost::shared_ptr<ARDOUR::Region>);
void drag_data_received (
@ -177,22 +182,39 @@ private:
Glib::RefPtr<Gtk::Action> hide_action () const;
Glib::RefPtr<Gtk::Action> show_action () const;
Glib::RefPtr<Gtk::Action> delete_unused_regions_action() const;
Glib::RefPtr<Gtk::ToggleAction> toggle_full_action () const;
Glib::RefPtr<Gtk::ToggleAction> toggle_show_auto_regions_action () const;
Gtk::Menu* _menu;
Gtk::ScrolledWindow _scroller;
Gtk::Frame _frame;
Gtkmm2ext::DnDTreeView<boost::shared_ptr<ARDOUR::Region> > _display;
Glib::RefPtr<Gtk::TreeStore> _model;
bool _show_automatic_regions;
Editing::RegionListSortType _sort_type;
bool _no_redisplay;
std::list<boost::shared_ptr<ARDOUR::Region> > tmp_region_list;
PBD::ScopedConnection region_property_connection;
PBD::ScopedConnection check_new_region_connection;
bool ignore_region_list_selection_change;
bool ignore_selected_region_change;
bool _no_redisplay;
Editing::RegionListSortType _sort_type;
std::list<boost::shared_ptr<ARDOUR::Region> > tmp_region_list;
typedef boost::unordered_map<boost::shared_ptr<ARDOUR::Region>, Gtk::TreeModel::RowReference> RegionRowMap;
typedef boost::unordered_map<std::string, Gtk::TreeModel::RowReference > RegionSourceMap;
RegionRowMap region_row_map;
RegionSourceMap parent_regions_sources_map;
PBD::ScopedConnection region_property_connection;
PBD::ScopedConnection check_new_region_connection;
PBD::ScopedConnection editor_freeze_connection;
PBD::ScopedConnection editor_thaw_connection;
bool expanded;
};

View file

@ -139,23 +139,24 @@ class Region
framepos_t first_frame () const { return _position; }
framepos_t last_frame () const { return _position + _length - 1; }
bool hidden () const { return _hidden; }
bool muted () const { return _muted; }
bool hidden() const { return _hidden; }
bool muted() const { return _muted; }
bool opaque () const { return _opaque; }
bool locked () const { return _locked; }
bool position_locked () const { return _position_locked; }
bool valid_transients () const { return _valid_transients; }
bool automatic () const { return _automatic; }
bool whole_file () const { return _whole_file; }
bool captured () const { return !(_import || _external); }
bool can_move () const { return !_position_locked; }
bool sync_marked () const { return _sync_marked; }
bool external () const { return _external; }
bool import () const { return _import; }
bool locked() const { return _locked; }
bool position_locked() const { return _position_locked; }
bool valid_transients() const { return _valid_transients; }
bool automatic() const { return _automatic; }
bool whole_file() const { return _whole_file; }
bool captured() const { return !(_import || _external); }
bool can_move() const { return !_position_locked; }
bool sync_marked() const { return _sync_marked; }
bool external() const { return _external; }
bool import() const { return _import; }
Trimmable::CanTrim can_trim () const;
Trimmable::CanTrim can_trim() const;
PositionLockStyle position_lock_style () const { return _position_lock_style; }
void set_position_lock_style (PositionLockStyle ps);
void recompute_position_from_lock_style ();
@ -176,6 +177,9 @@ class Region
bool source_equivalent (boost::shared_ptr<const Region>) const;
bool uses_source (boost::shared_ptr<const Source>) const;
std::string source_string () const;
/* EDITING OPERATIONS */
void set_length (framecnt_t, void *src);

View file

@ -512,6 +512,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void add_source (boost::shared_ptr<Source>);
void remove_source (boost::weak_ptr<Source>);
void cleanup_regions();
int cleanup_sources (CleanupReport&);
int cleanup_trash_sources (CleanupReport&);

View file

@ -423,6 +423,7 @@ Region::set_name (const std::string& str)
if (_name != str) {
SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
assert(_name == str);
send_change (Properties::name);
}
@ -490,6 +491,7 @@ Region::first_edit ()
_first_edit = EditChangesNothing;
send_change (Properties::name);
RegionFactory::CheckNewRegion (shared_from_this());
}
}
@ -559,6 +561,7 @@ Region::set_position_lock_style (PositionLockStyle ps)
}
send_change (Properties::position_lock_style);
}
}
@ -643,7 +646,6 @@ Region::set_position_on_top (framepos_t pos, void* /*src*/)
/* do this even if the position is the same. this helps out
a GUI that has moved its representation already.
*/
send_change (Properties::position);
}
@ -1023,6 +1025,7 @@ Region::set_sync_position (framepos_t absolute_pos)
if (!property_changes_suspended()) {
maybe_uncopy ();
}
send_change (Properties::sync_position);
}
}
@ -1035,6 +1038,7 @@ Region::clear_sync_position ()
if (!property_changes_suspended()) {
maybe_uncopy ();
}
send_change (Properties::sync_position);
}
}
@ -1428,6 +1432,29 @@ Region::source_equivalent (boost::shared_ptr<const Region> other) const
return true;
}
std::string
Region::source_string () const
{
//string res = itos(_sources.size());
char buf[64];
stringstream res;
res << _sources.size() << ":";
SourceList::const_iterator i;
for (i = _sources.begin(); i != _sources.end(); ++i) {
res << (*i)->id() << ":";
}
for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
res << (*i)->id() << ":";
}
return res.str();
}
bool
Region::uses_source (boost::shared_ptr<const Source> source) const
{

View file

@ -2575,6 +2575,32 @@ Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
return r.get_value_or (1);
}
void
Session::cleanup_regions ()
{
const RegionFactory::RegionMap& regions (RegionFactory::regions());
for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
boost::shared_ptr<AudioRegion> audio_region = boost::dynamic_pointer_cast<AudioRegion>( i->second);
if (!audio_region) {
continue;
}
uint32_t used = playlists->region_use_count (audio_region);
if (used == 0 && !audio_region->automatic()){
RegionFactory::map_remove(i->second);
}
}
/* dump the history list */
_history.clear ();
save_state ("");
}
int
Session::cleanup_sources (CleanupReport& rep)
{

View file

@ -147,7 +147,7 @@ UI::load_rcfile (string path, bool themechange)
return -1;
}
if (access (path.c_str(), R_OK)) {
if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
error << "UI: couldn't find rc file \""
<< path
<< '"'
@ -156,11 +156,10 @@ UI::load_rcfile (string path, bool themechange)
}
RC rc (path.c_str());
//this is buggy in gtkmm for some reason, so use C
//RC::reset_styles (Gtk::Settings::get_default());
gtk_rc_reset_styles (gtk_settings_get_default());
//vector<string> files;
//files.push_back(path.c_str());
//RC::set_default_files(files);
//RC::reparse_all (Gtk::Settings::get_default(), true);
theme_changed.emit();
if (themechange) {