implemented multiple selection for righ-click context menus

This commit is contained in:
fgerlits 2007-10-12 11:56:50 +00:00
parent dfc15d008e
commit 00c687fb9f
6 changed files with 499 additions and 387 deletions

View File

@ -87,15 +87,14 @@ LiveModeWindow :: LiveModeWindow (Gtk::ToggleButton * windowOpenerButton)
isDeleting(false)
{
glade->get_widget_derived("treeView1", treeView);
treeModel = Gtk::ListStore::create(modelColumns);
treeView->set_model(treeModel);
treeView->connectModelSignals(treeModel);
treeView->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
treeView->appendLineNumberColumn("", 2 /* offset */, 50);
treeView->appendColumn("", modelColumns.infoColumn, 200);
treeView->signal_button_press_event().connect_notify(sigc::mem_fun(*this,
&LiveModeWindow::onEntryClicked));
treeView->signal_button_press_event().connect(sigc::mem_fun(*this,
&LiveModeWindow::onEntryClicked),
false /* call this first */);
treeView->signal_row_activated().connect(sigc::mem_fun(*this,
&LiveModeWindow::onDoubleClick));
treeView->signalTreeModelChanged().connect(sigc::mem_fun(*this,
@ -104,6 +103,10 @@ LiveModeWindow :: LiveModeWindow (Gtk::ToggleButton * windowOpenerButton)
treeView->signal_key_press_event().connect(sigc::mem_fun(*this,
&LiveModeWindow::onKeyPressed));
treeModel = Gtk::ListStore::create(modelColumns);
treeView->set_model(treeModel);
treeView->connectModelSignals(treeModel);
glade->get_widget("cueLabel1", cueLabel);
cueLabel->set_label(*getResourceUstring("cuePlayerLabel"));
cuePlayer.reset(new CuePlayer(this,
@ -225,93 +228,77 @@ LiveModeWindow :: popTop(void) throw ()
}
/*------------------------------------------------------------------------------
* Find the selected row.
*----------------------------------------------------------------------------*/
Gtk::TreeModel::iterator
LiveModeWindow :: getSelected(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection> selection
= treeView->get_selection();
std::vector<Gtk::TreeModel::Path> selectedPaths
= selection->get_selected_rows();
Gtk::TreeModel::iterator it;
if (selectedPaths.size() > 0) {
it = treeModel->get_iter(selectedPaths.front());
}
return it;
}
/*------------------------------------------------------------------------------
* Signal handler for the output play button clicked.
*----------------------------------------------------------------------------*/
void
LiveModeWindow :: onOutputPlay(void) throw ()
{
Gtk::TreeModel::iterator iter = getSelected();
if (!iter) {
iter = treeModel->children().begin();
}
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
try {
gLiveSupport->playOutputAudio(playable);
gLiveSupport->setNowPlaying(playable);
treeView->removeItem(iter);
gLiveSupport->runMainLoop();
} catch (std::runtime_error &e) {
std::cerr << "cannot play on live mode output device: "
<< e.what() << std::endl;
}
}
}
/*------------------------------------------------------------------------------
* Event handler for an entry being clicked in the list.
*----------------------------------------------------------------------------*/
void
bool
LiveModeWindow :: onEntryClicked(GdkEventButton * event) throw ()
{
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
Gtk::TreePath currentPath;
Gtk::TreeViewColumn * column;
int cell_x,
cell_y;
bool foundValidRow = treeView->get_path_at_pos(
int(event->x), int(event->y),
currentPath, column,
cell_x, cell_y);
Ptr<Playable>::Ref playable = getFirstSelectedPlayable();
if (foundValidRow) {
Gtk::TreeIter iter = treeModel->get_iter(currentPath);
if (iter) {
Ptr<Playable>::Ref playable =
(*iter)[modelColumns.playableColumn];
if (selectedPaths->size() == 1) {
if (playable->getType() == Playable::AudioClipType) {
audioClipContextMenu->popup(event->button, event->time);
return true;
if (playable) {
switch (playable->getType()) {
case Playable::AudioClipType:
audioClipContextMenu->popup(event->button,
event->time);
break;
case Playable::PlaylistType:
playlistContextMenu->popup(event->button,
event->time);
break;
default:
break;
}
}
} else if (playable->getType() == Playable::PlaylistType) {
playlistContextMenu->popup(event->button, event->time);
return true;
}
} else if (selectedPaths->size() > 1) {
audioClipContextMenu->popup(event->button, event->time);
return true;
}
}
return false;
}
/*------------------------------------------------------------------------------
* Return the first selected playable item.
*----------------------------------------------------------------------------*/
Ptr<Playable>::Ref
LiveModeWindow :: getFirstSelectedPlayable(void) throw ()
{
Ptr<Playable>::Ref playable;
Glib::RefPtr<Gtk::TreeView::Selection>
selection = treeView->get_selection();
selectedPaths.reset(new std::vector<Gtk::TreePath>(
selection->get_selected_rows()));
if (selectedPaths->size() > 0) {
selectedIter = selectedPaths->begin();
Gtk::TreeRow row = *(treeModel->get_iter(*selectedIter));
playable = row[modelColumns.playableColumn];
}
return playable;
}
/*------------------------------------------------------------------------------
* Return the next selected playable item.
*----------------------------------------------------------------------------*/
Ptr<Playable>::Ref
LiveModeWindow :: getNextSelectedPlayable(void) throw ()
{
Ptr<Playable>::Ref playable;
if (selectedPaths) {
if (selectedIter != selectedPaths->end()) {
Gtk::TreeRow row = *(treeModel->get_iter(*selectedIter));
playable = row[modelColumns.playableColumn];
++selectedIter;
} else {
selectedPaths.reset();
}
}
return playable;
}
@ -334,32 +321,36 @@ bool
LiveModeWindow :: onKeyPressed(GdkEventKey * event) throw ()
{
if (event->type == GDK_KEY_PRESS) {
Gtk::TreeModel::iterator iter = getSelected();
if (iter) {
KeyboardShortcut::Action action = gLiveSupport->findAction(
"liveModeWindow",
Gdk::ModifierType(event->state),
event->keyval);
switch (action) {
case KeyboardShortcut::moveItemUp :
KeyboardShortcut::Action action = gLiveSupport->findAction(
"liveModeWindow",
Gdk::ModifierType(event->state),
event->keyval);
switch (action) {
case KeyboardShortcut::moveItemUp :
if (selectionIsSingle()) {
treeView->onUpMenuOption();
return true;
}
break;
case KeyboardShortcut::moveItemDown :
case KeyboardShortcut::moveItemDown :
if (selectionIsSingle()) {
treeView->onDownMenuOption();
return true;
case KeyboardShortcut::removeItem :
onRemoveItemButtonClicked();
return true;
case KeyboardShortcut::playAudio :
onOutputPlay();
return true;
default : break;
}
}
break;
case KeyboardShortcut::removeItem :
onRemoveMenuOption();
return true;
break;
case KeyboardShortcut::playAudio :
onOutputPlay();
return true;
break;
default : break;
}
}
@ -367,6 +358,49 @@ LiveModeWindow :: onKeyPressed(GdkEventKey * event) throw ()
}
/*------------------------------------------------------------------------------
* Check whether exactly one row is selected.
*----------------------------------------------------------------------------*/
bool
LiveModeWindow :: selectionIsSingle(void) throw ()
{
getFirstSelectedPlayable();
return (selectedPaths->size() == 1);
}
/*------------------------------------------------------------------------------
* Signal handler for the output play button clicked.
*----------------------------------------------------------------------------*/
void
LiveModeWindow :: onOutputPlay(void) throw ()
{
Ptr<Playable>::Ref playable = getFirstSelectedPlayable();
std::cerr << "got playable: ";
if (playable) {
std::cerr << *playable->getTitle() << std::endl;
} else {
std::cerr << "null" << std::endl;
}
if (playable) {
try {
gLiveSupport->playOutputAudio(playable);
gLiveSupport->setNowPlaying(playable);
Gtk::TreeIter iter = treeModel->get_iter(*selectedIter);
treeView->removeItem(iter);
gLiveSupport->runMainLoop();
} catch (std::runtime_error &e) {
std::cerr << "cannot play on live mode output device: "
<< e.what() << std::endl;
}
}
}
/*------------------------------------------------------------------------------
* Event handler for the Edit Playlist menu item selected from the
* entry context menu.
@ -374,18 +408,15 @@ LiveModeWindow :: onKeyPressed(GdkEventKey * event) throw ()
void
LiveModeWindow :: onEditPlaylist(void) throw ()
{
Gtk::TreeModel::iterator iter = getSelected();
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (playlist) {
try {
gLiveSupport->openPlaylistForEditing(playlist->getId());
} catch (XmlRpcException &e) {
gLiveSupport->displayMessageWindow(*getResourceUstring(
"cannotEditPlaylistMsg" ));
}
Ptr<Playable>::Ref playable = getNextSelectedPlayable();
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (playlist) {
try {
gLiveSupport->openPlaylistForEditing(playlist->getId());
} catch (XmlRpcException &e) {
gLiveSupport->displayMessageWindow(*getResourceUstring(
"cannotEditPlaylistMsg" ));
}
}
}
@ -398,15 +429,9 @@ LiveModeWindow :: onEditPlaylist(void) throw ()
void
LiveModeWindow :: onSchedulePlaylist(void) throw ()
{
Gtk::TreeModel::iterator iter = getSelected();
if (!iter) {
return;
}
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
Ptr<Playable>::Ref playable = getNextSelectedPlayable();
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (playlist) {
schedulePlaylistWindow.reset(new SchedulePlaylistWindow(playlist));
schedulePlaylistWindow->getWindow()->set_transient_for(*mainWindow);
@ -421,15 +446,9 @@ LiveModeWindow :: onSchedulePlaylist(void) throw ()
void
LiveModeWindow :: onExportPlaylist(void) throw ()
{
Gtk::TreeModel::iterator iter = getSelected();
if (!iter) {
return;
}
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
Ptr<Playable>::Ref playable = getNextSelectedPlayable();
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (playlist) {
exportPlaylistWindow.reset(new ExportPlaylistWindow(playlist));
exportPlaylistWindow->getWindow()->set_transient_for(*mainWindow);
@ -445,10 +464,9 @@ LiveModeWindow :: onExportPlaylist(void) throw ()
void
LiveModeWindow :: onAddToPlaylist(void) throw ()
{
Gtk::TreeModel::iterator iter = getSelected();
Ptr<Playable>::Ref playable;
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
while ((playable = getNextSelectedPlayable())) {
try {
gLiveSupport->addToPlaylist(playable->getId());
} catch (XmlRpcException &e) {
@ -466,10 +484,9 @@ LiveModeWindow :: onAddToPlaylist(void) throw ()
void
LiveModeWindow :: onUploadToHub(void) throw ()
{
Gtk::TreeModel::iterator iter = getSelected();
Ptr<Playable>::Ref playable;
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
while ((playable = getNextSelectedPlayable())) {
gLiveSupport->uploadToHub(playable);
}
}
@ -514,8 +531,8 @@ LiveModeWindow :: constructAudioClipContextMenu(void) throw ()
&LiveModeWindow::onAddToPlaylist)));
contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("removeMenuItem"),
sigc::mem_fun(*treeView,
&ZebraTreeView::onRemoveMenuOption)));
sigc::mem_fun(*this,
&LiveModeWindow::onRemoveMenuOption)));
contextMenuList.push_back(Gtk::Menu_Helpers::SeparatorElem());
contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("uploadToHubMenuItem"),
@ -550,8 +567,8 @@ LiveModeWindow :: constructPlaylistContextMenu(void) throw ()
&LiveModeWindow::onAddToPlaylist)));
contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("removeMenuItem"),
sigc::mem_fun(*treeView,
&ZebraTreeView::onRemoveMenuOption)));
sigc::mem_fun(*this,
&LiveModeWindow::onRemoveMenuOption)));
contextMenuList.push_back(Gtk::Menu_Helpers::SeparatorElem());
contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("editPlaylistMenuItem"),
@ -577,13 +594,39 @@ LiveModeWindow :: constructPlaylistContextMenu(void) throw ()
/*------------------------------------------------------------------------------
* Event handler for the Remove menu button getting clicked.
* Event handler for the Remove menu item selected from the context menu.
*----------------------------------------------------------------------------*/
void
LiveModeWindow :: onRemoveItemButtonClicked(void) throw ()
LiveModeWindow :: onRemoveMenuOption(void) throw ()
{
isDeleting = true;
treeView->onRemoveMenuOption();
Glib::RefPtr<Gtk::TreeView::Selection> selection
= treeView->get_selection();
std::vector<Gtk::TreePath> selectedPaths
= selection->get_selected_rows();
std::vector<Gtk::TreeModel::iterator> selectedIters;
for (std::vector<Gtk::TreePath>::iterator pathIt = selectedPaths.begin();
pathIt != selectedPaths.end();
++pathIt) {
selectedIters.push_back(treeModel->get_iter(*pathIt));
}
Gtk::TreeModel::iterator newSelection;
for (std::vector<Gtk::TreeModel::iterator>::iterator
iterIt = selectedIters.begin();
iterIt != selectedIters.end();
++iterIt) {
newSelection = *iterIt;
++newSelection;
treeModel->erase(*iterIt);
}
if (newSelection) {
selection->select(newSelection);
}
isDeleting = false;
onTreeModelChanged();
}

View File

@ -119,13 +119,24 @@ class LiveModeWindow : public GuiWindow,
*/
Gtk::CheckButton * autoPlayNext;
/**
* The list of selected rows, as path references (row numbers).
* Reset by onEntryClicked().
*/
Ptr<std::vector<Gtk::TreePath> >::Ref selectedPaths;
/**
* One of the selected rows, set to the first one by onEntryClicked().
* Incremented by getNextSelectedPlayable().
*/
std::vector<Gtk::TreePath>::const_iterator selectedIter;
/**
* Construct the right-click context menu for local audio clips.
*
* @return the context menu created.
*/
Ptr<Gtk::Menu>::Ref
constructAudioClipContextMenu(void) throw ();
constructAudioClipContextMenu(void) throw ();
/**
* Construct the right-click context menu for local playlists.
@ -133,17 +144,39 @@ class LiveModeWindow : public GuiWindow,
* @return the context menu created.
*/
Ptr<Gtk::Menu>::Ref
constructPlaylistContextMenu(void) throw ();
constructPlaylistContextMenu(void) throw ();
/**
* Find the selected row.
* If more than one row is selected, it returns the first one.
* Return the topmost selected row.
* Sets selectedPaths and selectedIter; does not increment it.
*
* @return an iterator for the selected row; may be invalid
* if nothing is selected.
* @return the first selected playable item.
*/
Gtk::TreeModel::iterator
getSelected(void) throw ();
Ptr<Playable>::Ref
getFirstSelectedPlayable(void) throw ();
/**
* Used to iterate over the selected rows.
* Can only be called after onEntryClicked() has set the selectedPaths
* and selectedIter variables.
* Returns a 0 pointer if nothing is selected or we have reached the
* end of the list of selected rows.
* Increments selectedIter after reading it.
*
* @return the next selected playable item.
*/
Ptr<Playable>::Ref
getNextSelectedPlayable(void) throw ();
/**
* Check whether exactly one row is selected.
*
* This is an auxilliary function used by onKeyPressed().
*
* @return true if a single row is selected, false if not.
*/
bool
selectionIsSingle(void) throw ();
protected:
@ -220,15 +253,18 @@ class LiveModeWindow : public GuiWindow,
* This brings up the right-click context menu.
*
* @param event the button event recieved
* @return true if the event has been handled (a popup displayed),
* false otherwise
*/
void
bool
onEntryClicked(GdkEventButton * event) throw ();
/**
* Signal handler for the user double-clicking, or pressing Enter
* on one of the entries.
*
* @param event the button event recieved
* @param path the TreePath of the row clicked on (ignored).
* @param column the TreeViewColumn clicked on (ignored).
*/
void
onDoubleClick(const Gtk::TreeModel::Path & path,
@ -285,10 +321,11 @@ class LiveModeWindow : public GuiWindow,
onUploadToHub(void) throw ();
/**
* Signal handler for the remove item button clicked.
* Signal handler for the "remove" menu item selected from
* the entry context menu.
*/
virtual void
onRemoveItemButtonClicked(void) throw ();
onRemoveMenuOption(void) throw ();
/**
* Signal handler for a change in the tree model.

View File

@ -114,67 +114,67 @@ ScratchpadWindow :: ScratchpadWindow (
modelColumns));
// create the right-click entry context menu for audio clips
audioClipMenu.reset(new Gtk::Menu());
audioClipMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
audioClipContextMenu.reset(new Gtk::Menu());
audioClipContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("cueMenuItem"),
sigc::mem_fun(*cuePlayer,
&CuePlayer::onPlayItem)));
audioClipMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
audioClipContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("addToLiveModeMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onAddToLiveMode)));
audioClipMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
audioClipContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("addToPlaylistMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onAddToPlaylist)));
audioClipMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
audioClipContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("removeMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onRemoveMenuOption)));
audioClipMenu->items().push_back(Gtk::Menu_Helpers::SeparatorElem());
audioClipMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
audioClipContextMenu->items().push_back(Gtk::Menu_Helpers::SeparatorElem());
audioClipContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("uploadToHubMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onUploadToHub)));
audioClipMenu->accelerate(*mainWindow);
audioClipContextMenu->accelerate(*mainWindow);
// create the right-click entry context menu for playlists
playlistMenu.reset(new Gtk::Menu());
playlistMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
playlistContextMenu.reset(new Gtk::Menu());
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("cueMenuItem"),
sigc::mem_fun(*cuePlayer,
&CuePlayer::onPlayItem)));
playlistMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("addToLiveModeMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onAddToLiveMode)));
playlistMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("addToPlaylistMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onAddToPlaylist)));
playlistMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("removeMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onRemoveMenuOption)));
playlistMenu->items().push_back(Gtk::Menu_Helpers::SeparatorElem());
playlistMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::SeparatorElem());
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("editPlaylistMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onEditPlaylist)));
playlistMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("schedulePlaylistMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onSchedulePlaylist)));
playlistMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("exportPlaylistMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onExportPlaylist)));
playlistMenu->items().push_back(Gtk::Menu_Helpers::SeparatorElem());
playlistMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::SeparatorElem());
playlistContextMenu->items().push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("uploadToHubMenuItem"),
sigc::mem_fun(*this,
&ScratchpadWindow::onUploadToHub)));
playlistMenu->accelerate(*mainWindow);
playlistContextMenu->accelerate(*mainWindow);
// set the user preferences key
userPreferencesKey.reset(new const Glib::ustring(userPreferencesKeyName));
@ -188,32 +188,21 @@ bool
ScratchpadWindow :: onEntryClicked (GdkEventButton * event) throw ()
{
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
Glib::RefPtr<Gtk::TreeView::Selection>
selection = treeView->get_selection();
selectedPaths.reset(new std::vector<Gtk::TreePath>(
selection->get_selected_rows()));
Ptr<Playable>::Ref playable = getFirstSelectedPlayable();
if (selectedPaths->size() > 0) {
selectedIter = selectedPaths->begin();
if (selectedPaths->size() == 1) {
Gtk::TreeRow row = *(treeModel->get_iter(*selectedIter));
Ptr<Playable>::Ref
playable = row[modelColumns.playableColumn];
if (selectedPaths->size() == 1) {
if (playable->getType() == Playable::AudioClipType) {
audioClipContextMenu->popup(event->button, event->time);
return true;
if (playable->getType() == Playable::AudioClipType) {
audioClipMenu->popup(event->button, event->time);
return true;
} else if (playable->getType() == Playable::PlaylistType) {
playlistMenu->popup(event->button, event->time);
return true;
}
} else { // selectedPaths.size() > 1
audioClipMenu->popup(event->button, event->time);
} else if (playable->getType() == Playable::PlaylistType) {
playlistContextMenu->popup(event->button, event->time);
return true;
}
} else if (selectedPaths->size() > 1) {
audioClipContextMenu->popup(event->button, event->time);
return true;
}
}
@ -221,6 +210,29 @@ ScratchpadWindow :: onEntryClicked (GdkEventButton * event) throw ()
}
/*------------------------------------------------------------------------------
* Return the first selected playable item.
*----------------------------------------------------------------------------*/
Ptr<Playable>::Ref
ScratchpadWindow :: getFirstSelectedPlayable(void) throw ()
{
Ptr<Playable>::Ref playable;
Glib::RefPtr<Gtk::TreeView::Selection>
selection = treeView->get_selection();
selectedPaths.reset(new std::vector<Gtk::TreePath>(
selection->get_selected_rows()));
if (selectedPaths->size() > 0) {
selectedIter = selectedPaths->begin();
Gtk::TreeRow row = *(treeModel->get_iter(*selectedIter));
playable = row[modelColumns.playableColumn];
}
return playable;
}
/*------------------------------------------------------------------------------
* Return the next selected playable item.
*----------------------------------------------------------------------------*/
@ -369,7 +381,7 @@ ScratchpadWindow :: onUploadToHub(void) throw ()
/*------------------------------------------------------------------------------
* Event handler for the Remove menu item selected from the entry conext menu
* Event handler for the Remove menu item selected from the context menu.
*----------------------------------------------------------------------------*/
void
ScratchpadWindow :: onRemoveMenuOption(void) throw ()
@ -410,13 +422,9 @@ ScratchpadWindow :: onDoubleClick(const Gtk::TreeModel::Path & path,
const Gtk::TreeViewColumn * column)
throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
selection = treeView->get_selection();
selectedPaths.reset(new std::vector<Gtk::TreePath>(
selection->get_selected_rows()));
Ptr<Playable>::Ref playable = getFirstSelectedPlayable();
if (selectedPaths->size() > 0) {
selectedIter = selectedPaths->begin();
if (playable) {
onAddToLiveMode();
}
}
@ -435,14 +443,14 @@ ScratchpadWindow :: onKeyPressed(GdkEventKey * event) throw ()
event->keyval);
switch (action) {
case KeyboardShortcut::moveItemUp :
if (isSelectionSingle()) {
if (selectionIsSingle()) {
treeView->onUpMenuOption();
return true;
}
break;
case KeyboardShortcut::moveItemDown :
if (isSelectionSingle()) {
if (selectionIsSingle()) {
treeView->onDownMenuOption();
return true;
}
@ -451,6 +459,7 @@ ScratchpadWindow :: onKeyPressed(GdkEventKey * event) throw ()
case KeyboardShortcut::removeItem :
onRemoveMenuOption();
return true;
break;
default : break;
}
@ -464,14 +473,11 @@ ScratchpadWindow :: onKeyPressed(GdkEventKey * event) throw ()
* Check whether exactly one row is selected.
*----------------------------------------------------------------------------*/
bool
ScratchpadWindow :: isSelectionSingle(void) throw ()
ScratchpadWindow :: selectionIsSingle(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
selection = treeView->get_selection();
std::vector<Gtk::TreePath>
selectedRows = selection->get_selected_rows();
getFirstSelectedPlayable();
return (selectedRows.size() == 1);
return (selectedPaths->size() == 1);
}

View File

@ -94,13 +94,33 @@ class ScratchpadWindow : public GuiWindow,
*/
Ptr<SchedulePlaylistWindow>::Ref schedulePlaylistWindow;
/**
* The list of selected rows, as path references (row numbers).
* Reset by onEntryClicked().
*/
Ptr<std::vector<Gtk::TreePath> >::Ref selectedPaths;
/**
* One of the selected rows, set to the first one by onEntryClicked().
* Incremented by getNextSelectedPlayable().
*/
std::vector<Gtk::TreePath>::const_iterator selectedIter;
/**
* Return the topmost selected row.
* Sets selectedPaths and selectedIter; does not increment it.
*
* @return the first selected playable item.
*/
Ptr<Playable>::Ref
getFirstSelectedPlayable(void) throw ();
/**
* Used to iterate over the selected rows.
* Reset to the first row by onEntryClicked().
* Returns a 0 pointer if nothing is selected or we have reached
* the end of the list of selected rows.
*
* @return the next selected item.
* @return the next selected playable item.
*/
Ptr<Playable>::Ref
getNextSelectedPlayable(void) throw ();
@ -113,7 +133,7 @@ class ScratchpadWindow : public GuiWindow,
* @return true if a single row is selected, false if not.
*/
bool
isSelectionSingle(void) throw ();
selectionIsSingle(void) throw ();
/**
* Remove an item from the Scratchpad.
@ -184,18 +204,6 @@ class ScratchpadWindow : public GuiWindow,
*/
ZebraTreeView * treeView;
/**
* The list of selected rows, as path references (row numbers).
* Reset by onEntryClicked();
*/
Ptr<std::vector<Gtk::TreePath> >::Ref
selectedPaths;
/**
* One of the selected rows, set to the first one by onEntryClicked().
*/
std::vector<Gtk::TreePath>::const_iterator
selectedIter;
/**
* The cue player widget controlling the audio buttons.
*/
@ -205,13 +213,13 @@ class ScratchpadWindow : public GuiWindow,
* The right-click context menu for audio clips,
* that comes up when right-clicking an entry in the entry list.
*/
Ptr<Gtk::Menu>::Ref audioClipMenu;
Ptr<Gtk::Menu>::Ref audioClipContextMenu;
/**
* The right-click context menu for playlists,
* that comes up when right-clicking an entry in the entry list.
*/
Ptr<Gtk::Menu>::Ref playlistMenu;
Ptr<Gtk::Menu>::Ref playlistContextMenu;
/**
* Signal handler for the mouse clicked on one of the entries.
@ -228,7 +236,8 @@ class ScratchpadWindow : public GuiWindow,
* Signal handler for the user double-clicking, or pressing Enter
* on one of the entries.
*
* @param event the button event recieved
* @param path the TreePath of the row clicked on (ignored).
* @param column the TreeViewColumn clicked on (ignored).
*/
void
onDoubleClick(const Gtk::TreeModel::Path & path,

View File

@ -210,6 +210,7 @@ SearchWindow :: constructSearchResultsView(void) throw ()
remoteSearchResults = Gtk::ListStore::create(modelColumns);
glade->get_widget_derived("searchResultsTreeView1", searchResultsTreeView);
searchResultsTreeView->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
searchResultsTreeView->set_model(localSearchResults);
searchResultsTreeView->connectModelSignals(localSearchResults);
searchResultsTreeView->connectModelSignals(remoteSearchResults);
@ -230,9 +231,10 @@ SearchWindow :: constructSearchResultsView(void) throw ()
*getResourceUstring("lengthColumnLabel"),
modelColumns.lengthColumn, 55);
searchResultsTreeView->signal_button_press_event().connect_notify(
searchResultsTreeView->signal_button_press_event().connect(
sigc::mem_fun(*this,
&SearchWindow::onEntryClicked));
&SearchWindow::onEntryClicked),
false /* call this first */);
searchResultsTreeView->signal_row_activated().connect(sigc::mem_fun(*this,
&SearchWindow::onDoubleClick));
@ -589,49 +591,78 @@ SearchWindow :: displayRemoteSearchError(const XmlRpcException & error)
/*------------------------------------------------------------------------------
* Event handler for an entry being clicked in the list
*----------------------------------------------------------------------------*/
void
bool
SearchWindow :: onEntryClicked (GdkEventButton * event) throw ()
{
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
Gtk::TreePath currentPath;
Gtk::TreeViewColumn * column;
int cell_x,
cell_y;
bool foundValidRow = searchResultsTreeView->get_path_at_pos(
int(event->x), int(event->y),
currentPath, column,
cell_x, cell_y);
Ptr<Playable>::Ref playable = getFirstSelectedPlayable();
if (foundValidRow) {
Gtk::TreeIter iter = searchResultsTreeView->get_model()
->get_iter(currentPath);
if (iter) {
Ptr<Playable>::Ref playable =
(*iter)[modelColumns.playableColumn];
if (selectedPaths->size() == 1) {
if (playable->getType() == Playable::AudioClipType) {
audioClipContextMenu->popup(event->button, event->time);
return true;
if (playable) {
if (searchIsLocal()) {
switch (playable->getType()) {
case Playable::AudioClipType:
audioClipContextMenu->popup(event->button,
event->time);
break;
case Playable::PlaylistType:
playlistContextMenu->popup(event->button,
event->time);
break;
default:
break;
}
} else {
remoteContextMenu->popup(event->button, event->time);
}
}
} else if (playable->getType() == Playable::PlaylistType) {
playlistContextMenu->popup(event->button, event->time);
return true;
}
} else if (selectedPaths->size() > 1) {
audioClipContextMenu->popup(event->button, event->time);
return true;
}
}
return false;
}
/*------------------------------------------------------------------------------
* Return the first selected playable item.
*----------------------------------------------------------------------------*/
Ptr<Playable>::Ref
SearchWindow :: getFirstSelectedPlayable(void) throw ()
{
Ptr<Playable>::Ref playable;
Glib::RefPtr<Gtk::TreeView::Selection>
selection = searchResultsTreeView->get_selection();
selectedPaths.reset(new std::vector<Gtk::TreePath>(
selection->get_selected_rows()));
if (selectedPaths->size() > 0) {
selectedIter = selectedPaths->begin();
Glib::RefPtr<Gtk::TreeModel>
treeModel = searchResultsTreeView->get_model();
Gtk::TreeRow row = *(treeModel->get_iter(*selectedIter));
playable = row[modelColumns.playableColumn];
}
return playable;
}
/*------------------------------------------------------------------------------
* Return the next selected playable item.
*----------------------------------------------------------------------------*/
Ptr<Playable>::Ref
SearchWindow :: getNextSelectedPlayable(void) throw ()
{
Ptr<Playable>::Ref playable;
if (selectedPaths) {
if (selectedIter != selectedPaths->end()) {
Glib::RefPtr<Gtk::TreeModel>
treeModel = searchResultsTreeView->get_model();
Gtk::TreeRow row = *(treeModel->get_iter(*selectedIter));
playable = row[modelColumns.playableColumn];
++selectedIter;
} else {
selectedPaths.reset();
}
}
return playable;
}
@ -641,22 +672,16 @@ SearchWindow :: onEntryClicked (GdkEventButton * event) throw ()
void
SearchWindow :: onAddToScratchpad(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
refSelection = searchResultsTreeView->get_selection();
Gtk::TreeModel::iterator
iter = refSelection->get_selected();
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
if (playable) {
try {
gLiveSupport->addToScratchpad(playable);
} catch (XmlRpcException &e) {
Ptr<Glib::ustring>::Ref errorMessage(new Glib::ustring(
"error in SearchWindow::onAddToScratchpad(): "));
errorMessage->append(e.what());
gLiveSupport->displayMessageWindow(*errorMessage);
}
Ptr<Playable>::Ref playable;
while ((playable = getNextSelectedPlayable())) {
try {
gLiveSupport->addToScratchpad(playable);
} catch (XmlRpcException &e) {
Ptr<Glib::ustring>::Ref errorMessage(new Glib::ustring(
"error in SearchWindow::onAddToScratchpad(): "));
errorMessage->append(e.what());
gLiveSupport->displayMessageWindow(*errorMessage);
}
}
}
@ -669,20 +694,16 @@ SearchWindow :: onAddToScratchpad(void) throw ()
void
SearchWindow :: onAddToPlaylist(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
refSelection = searchResultsTreeView->get_selection();
Gtk::TreeModel::iterator
iter = refSelection->get_selected();
Ptr<Playable>::Ref playable;
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
while ((playable = getNextSelectedPlayable())) {
try {
gLiveSupport->addToPlaylist(playable->getId());
} catch (XmlRpcException &e) {
Ptr<Glib::ustring>::Ref errorMessage(new Glib::ustring(
"error in SearchWindow::onAddToPlaylist(): "));
errorMessage->append(e.what());
gLiveSupport->displayMessageWindow(*errorMessage);
Ptr<Glib::ustring>::Ref errorMessage(new Glib::ustring(
"error in SearchWindow::onAddToPlaylist(): "));
errorMessage->append(e.what());
gLiveSupport->displayMessageWindow(*errorMessage);
}
}
}
@ -694,24 +715,18 @@ SearchWindow :: onAddToPlaylist(void) throw ()
void
SearchWindow :: onAddToLiveMode(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
refSelection = searchResultsTreeView->get_selection();
Gtk::TreeModel::iterator
iter = refSelection->get_selected();
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
if (playable) {
try {
gLiveSupport->addToScratchpad(playable);
playable = gLiveSupport->getPlayable(playable->getId());
gLiveSupport->addToLiveMode(playable);
} catch (XmlRpcException &e) {
Ptr<Glib::ustring>::Ref errorMessage(new Glib::ustring(
"error in SearchWindow::onAddToLiveMode(): "));
errorMessage->append(e.what());
gLiveSupport->displayMessageWindow(*errorMessage);
}
Ptr<Playable>::Ref playable;
while ((playable = getNextSelectedPlayable())) {
try {
gLiveSupport->addToScratchpad(playable);
playable = gLiveSupport->getPlayable(playable->getId());
gLiveSupport->addToLiveMode(playable);
} catch (XmlRpcException &e) {
Ptr<Glib::ustring>::Ref errorMessage(new Glib::ustring(
"error in SearchWindow::onAddToLiveMode(): "));
errorMessage->append(e.what());
gLiveSupport->displayMessageWindow(*errorMessage);
}
}
}
@ -724,21 +739,15 @@ SearchWindow :: onAddToLiveMode(void) throw ()
void
SearchWindow :: onEditPlaylist(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
refSelection = searchResultsTreeView->get_selection();
Gtk::TreeModel::iterator
iter = refSelection->get_selected();
Ptr<Playable>::Ref playable = getNextSelectedPlayable();
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (playlist) {
try {
gLiveSupport->openPlaylistForEditing(playlist->getId());
} catch (XmlRpcException &e) {
gLiveSupport->displayMessageWindow(*getResourceUstring(
"cannotEditPlaylistMsg" ));
}
if (playlist) {
try {
gLiveSupport->openPlaylistForEditing(playlist->getId());
} catch (XmlRpcException &e) {
gLiveSupport->displayMessageWindow(*getResourceUstring(
"cannotEditPlaylistMsg" ));
}
}
}
@ -751,16 +760,7 @@ SearchWindow :: onEditPlaylist(void) throw ()
void
SearchWindow :: onSchedulePlaylist(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
refSelection = searchResultsTreeView->get_selection();
Gtk::TreeModel::iterator
iter = refSelection->get_selected();
if (!iter) {
return;
}
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
Ptr<Playable>::Ref playable = getNextSelectedPlayable();
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (playlist) {
@ -777,17 +777,8 @@ SearchWindow :: onSchedulePlaylist(void) throw ()
void
SearchWindow :: onExportPlaylist(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
refSelection = searchResultsTreeView->get_selection();
Gtk::TreeModel::iterator
iter = refSelection->get_selected();
if (!iter) {
return;
}
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
Ptr<Playable>::Ref playable = getNextSelectedPlayable();
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (playlist) {
exportPlaylistWindow.reset(new ExportPlaylistWindow(playlist));
@ -803,16 +794,10 @@ SearchWindow :: onExportPlaylist(void) throw ()
void
SearchWindow :: onUploadToHub(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
refSelection = searchResultsTreeView->get_selection();
Gtk::TreeModel::iterator
iter = refSelection->get_selected();
Ptr<Playable>::Ref playable;
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
if (playable) {
uploadToHub(playable);
}
while ((playable = getNextSelectedPlayable())) {
uploadToHub(playable);
}
}
@ -844,27 +829,21 @@ SearchWindow :: uploadToHub(Ptr<Playable>::Ref playable) throw ()
void
SearchWindow :: onDownloadFromHub(void) throw ()
{
Glib::RefPtr<Gtk::TreeView::Selection>
refSelection = searchResultsTreeView->get_selection();
Gtk::TreeModel::iterator
iter = refSelection->get_selected();
Ptr<Playable>::Ref playable;
if (iter) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
if (playable) {
if (!gLiveSupport->existsPlayable(playable->getId())) {
try {
searchInput->set_current_page(3);
transportList->addDownload(playable);
} catch (XmlRpcException &e) {
gLiveSupport->displayMessageWindow(*formatMessage(
"downloadFromHubErrorMsg", e.what() ));
return;
}
} else {
onAddToScratchpad();
while ((playable = getNextSelectedPlayable())) {
if (!gLiveSupport->existsPlayable(playable->getId())) {
try {
searchInput->set_current_page(3);
transportList->addDownload(playable);
} catch (XmlRpcException &e) {
gLiveSupport->displayMessageWindow(*formatMessage(
"downloadFromHubErrorMsg", e.what() ));
return;
}
} else {
onAddToScratchpad();
}
}
}
@ -878,10 +857,14 @@ SearchWindow :: onDoubleClick(const Gtk::TreeModel::Path & path,
const Gtk::TreeViewColumn * column)
throw ()
{
if (searchIsLocal()) {
onAddToScratchpad();
} else {
onDownloadFromHub();
Ptr<Playable>::Ref playable = getFirstSelectedPlayable();
if (playable) {
if (searchIsLocal()) {
onAddToScratchpad();
} else {
onDownloadFromHub();
}
}
}

View File

@ -99,6 +99,17 @@ class SearchWindow : public GuiWindow,
*/
int remoteSearchResultsCount;
/**
* The list of selected rows, as path references (row numbers).
* Reset by onEntryClicked().
*/
Ptr<std::vector<Gtk::TreePath> >::Ref selectedPaths;
/**
* One of the selected rows, set to the first one by onEntryClicked().
* Incremented by getNextSelectedPlayable().
*/
std::vector<Gtk::TreePath>::const_iterator selectedIter;
/**
* The "search where" input field.
*/
@ -339,7 +350,7 @@ class SearchWindow : public GuiWindow,
displaySearchResults(
Ptr<SearchResultsType>::Ref searchResults,
Glib::RefPtr<Gtk::ListStore> treeModel)
throw ();
throw ();
/**
* Update the paging portion of the search results view.
@ -347,7 +358,7 @@ class SearchWindow : public GuiWindow,
* the Backward and Forward buttons.
*/
void
updatePagingToolbar(void) throw ();
updatePagingToolbar(void) throw ();
/**
* Display a (usually error) message in the search results tree view.
@ -358,7 +369,7 @@ class SearchWindow : public GuiWindow,
void
displayMessage(const Glib::ustring & messageKey,
Glib::RefPtr<Gtk::ListStore> treeModel)
throw ();
throw ();
/**
* Display an error message which occurred during a search.
@ -369,7 +380,7 @@ class SearchWindow : public GuiWindow,
void
displayError(const XmlRpcException & error,
Glib::RefPtr<Gtk::ListStore> treeModel)
throw ();
throw ();
/**
* Display an error message which occurred during a local search.
@ -378,7 +389,7 @@ class SearchWindow : public GuiWindow,
*/
void
displayLocalSearchError(const XmlRpcException & error)
throw ();
throw ();
/**
* Display an error message which occurred during a remote search.
@ -387,7 +398,27 @@ class SearchWindow : public GuiWindow,
*/
void
displayRemoteSearchError(const XmlRpcException & error)
throw ();
throw ();
/**
* Return the topmost selected row.
* Sets selectedPaths and selectedIter; does not increment it.
*
* @return the first selected playable item.
*/
Ptr<Playable>::Ref
getFirstSelectedPlayable(void) throw ();
/**
* Used to iterate over the selected rows.
* Reset to the first row by onEntryClicked().
* Returns a 0 pointer if nothing is selected or we have reached
* the end of the list of selected rows.
*
* @return the next selected playable item.
*/
Ptr<Playable>::Ref
getNextSelectedPlayable(void) throw ();
protected:
@ -505,15 +536,18 @@ class SearchWindow : public GuiWindow,
* Signal handler for the mouse clicked on one of the entries.
*
* @param event the button event received
* @return true if the event has been handled (a popup displayed),
* false otherwise
*/
void
bool
onEntryClicked(GdkEventButton * event) throw ();
/**
* Signal handler for the user double-clicking, or pressing Enter
* on one of the entries.
*
* @param event the button event recieved
* @param path the TreePath of the row clicked on (ignored).
* @param column the TreeViewColumn clicked on (ignored).
*/
void
onDoubleClick(const Gtk::TreeModel::Path & path,