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) isDeleting(false)
{ {
glade->get_widget_derived("treeView1", treeView); glade->get_widget_derived("treeView1", treeView);
treeModel = Gtk::ListStore::create(modelColumns); treeView->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
treeView->set_model(treeModel);
treeView->connectModelSignals(treeModel);
treeView->appendLineNumberColumn("", 2 /* offset */, 50); treeView->appendLineNumberColumn("", 2 /* offset */, 50);
treeView->appendColumn("", modelColumns.infoColumn, 200); treeView->appendColumn("", modelColumns.infoColumn, 200);
treeView->signal_button_press_event().connect_notify(sigc::mem_fun(*this, treeView->signal_button_press_event().connect(sigc::mem_fun(*this,
&LiveModeWindow::onEntryClicked)); &LiveModeWindow::onEntryClicked),
false /* call this first */);
treeView->signal_row_activated().connect(sigc::mem_fun(*this, treeView->signal_row_activated().connect(sigc::mem_fun(*this,
&LiveModeWindow::onDoubleClick)); &LiveModeWindow::onDoubleClick));
treeView->signalTreeModelChanged().connect(sigc::mem_fun(*this, 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, treeView->signal_key_press_event().connect(sigc::mem_fun(*this,
&LiveModeWindow::onKeyPressed)); &LiveModeWindow::onKeyPressed));
treeModel = Gtk::ListStore::create(modelColumns);
treeView->set_model(treeModel);
treeView->connectModelSignals(treeModel);
glade->get_widget("cueLabel1", cueLabel); glade->get_widget("cueLabel1", cueLabel);
cueLabel->set_label(*getResourceUstring("cuePlayerLabel")); cueLabel->set_label(*getResourceUstring("cuePlayerLabel"));
cuePlayer.reset(new CuePlayer(this, 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. * Event handler for an entry being clicked in the list.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void bool
LiveModeWindow :: onEntryClicked(GdkEventButton * event) throw () LiveModeWindow :: onEntryClicked(GdkEventButton * event) throw ()
{ {
if (event->type == GDK_BUTTON_PRESS && event->button == 3) { if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
Gtk::TreePath currentPath; Ptr<Playable>::Ref playable = getFirstSelectedPlayable();
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);
if (foundValidRow) { if (selectedPaths->size() == 1) {
Gtk::TreeIter iter = treeModel->get_iter(currentPath); if (playable->getType() == Playable::AudioClipType) {
if (iter) { audioClipContextMenu->popup(event->button, event->time);
Ptr<Playable>::Ref playable = return true;
(*iter)[modelColumns.playableColumn];
if (playable) { } else if (playable->getType() == Playable::PlaylistType) {
switch (playable->getType()) { playlistContextMenu->popup(event->button, event->time);
case Playable::AudioClipType: return true;
audioClipContextMenu->popup(event->button,
event->time);
break;
case Playable::PlaylistType:
playlistContextMenu->popup(event->button,
event->time);
break;
default:
break;
}
}
} }
} 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 () LiveModeWindow :: onKeyPressed(GdkEventKey * event) throw ()
{ {
if (event->type == GDK_KEY_PRESS) { if (event->type == GDK_KEY_PRESS) {
Gtk::TreeModel::iterator iter = getSelected(); KeyboardShortcut::Action action = gLiveSupport->findAction(
"liveModeWindow",
if (iter) { Gdk::ModifierType(event->state),
KeyboardShortcut::Action action = gLiveSupport->findAction( event->keyval);
"liveModeWindow", switch (action) {
Gdk::ModifierType(event->state), case KeyboardShortcut::moveItemUp :
event->keyval); if (selectionIsSingle()) {
switch (action) {
case KeyboardShortcut::moveItemUp :
treeView->onUpMenuOption(); treeView->onUpMenuOption();
return true; return true;
}
break;
case KeyboardShortcut::moveItemDown : case KeyboardShortcut::moveItemDown :
if (selectionIsSingle()) {
treeView->onDownMenuOption(); treeView->onDownMenuOption();
return true; return true;
}
break;
case KeyboardShortcut::removeItem : case KeyboardShortcut::removeItem :
onRemoveItemButtonClicked(); onRemoveMenuOption();
return true; return true;
break;
case KeyboardShortcut::playAudio : case KeyboardShortcut::playAudio :
onOutputPlay(); onOutputPlay();
return true; return true;
break;
default : 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 * Event handler for the Edit Playlist menu item selected from the
* entry context menu. * entry context menu.
@ -374,18 +408,15 @@ LiveModeWindow :: onKeyPressed(GdkEventKey * event) throw ()
void void
LiveModeWindow :: onEditPlaylist(void) throw () LiveModeWindow :: onEditPlaylist(void) throw ()
{ {
Gtk::TreeModel::iterator iter = getSelected(); Ptr<Playable>::Ref playable = getNextSelectedPlayable();
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (iter) { if (playlist) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn]; try {
Ptr<Playlist>::Ref playlist = playable->getPlaylist(); gLiveSupport->openPlaylistForEditing(playlist->getId());
if (playlist) { } catch (XmlRpcException &e) {
try { gLiveSupport->displayMessageWindow(*getResourceUstring(
gLiveSupport->openPlaylistForEditing(playlist->getId()); "cannotEditPlaylistMsg" ));
} catch (XmlRpcException &e) {
gLiveSupport->displayMessageWindow(*getResourceUstring(
"cannotEditPlaylistMsg" ));
}
} }
} }
} }
@ -398,14 +429,8 @@ LiveModeWindow :: onEditPlaylist(void) throw ()
void void
LiveModeWindow :: onSchedulePlaylist(void) throw () LiveModeWindow :: onSchedulePlaylist(void) throw ()
{ {
Gtk::TreeModel::iterator iter = getSelected(); Ptr<Playable>::Ref playable = getNextSelectedPlayable();
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (!iter) {
return;
}
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (playlist) { if (playlist) {
schedulePlaylistWindow.reset(new SchedulePlaylistWindow(playlist)); schedulePlaylistWindow.reset(new SchedulePlaylistWindow(playlist));
@ -421,14 +446,8 @@ LiveModeWindow :: onSchedulePlaylist(void) throw ()
void void
LiveModeWindow :: onExportPlaylist(void) throw () LiveModeWindow :: onExportPlaylist(void) throw ()
{ {
Gtk::TreeModel::iterator iter = getSelected(); Ptr<Playable>::Ref playable = getNextSelectedPlayable();
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (!iter) {
return;
}
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
Ptr<Playlist>::Ref playlist = playable->getPlaylist();
if (playlist) { if (playlist) {
exportPlaylistWindow.reset(new ExportPlaylistWindow(playlist)); exportPlaylistWindow.reset(new ExportPlaylistWindow(playlist));
@ -445,10 +464,9 @@ LiveModeWindow :: onExportPlaylist(void) throw ()
void void
LiveModeWindow :: onAddToPlaylist(void) throw () LiveModeWindow :: onAddToPlaylist(void) throw ()
{ {
Gtk::TreeModel::iterator iter = getSelected(); Ptr<Playable>::Ref playable;
if (iter) { while ((playable = getNextSelectedPlayable())) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
try { try {
gLiveSupport->addToPlaylist(playable->getId()); gLiveSupport->addToPlaylist(playable->getId());
} catch (XmlRpcException &e) { } catch (XmlRpcException &e) {
@ -466,10 +484,9 @@ LiveModeWindow :: onAddToPlaylist(void) throw ()
void void
LiveModeWindow :: onUploadToHub(void) throw () LiveModeWindow :: onUploadToHub(void) throw ()
{ {
Gtk::TreeModel::iterator iter = getSelected(); Ptr<Playable>::Ref playable;
if (iter) { while ((playable = getNextSelectedPlayable())) {
Ptr<Playable>::Ref playable = (*iter)[modelColumns.playableColumn];
gLiveSupport->uploadToHub(playable); gLiveSupport->uploadToHub(playable);
} }
} }
@ -514,8 +531,8 @@ LiveModeWindow :: constructAudioClipContextMenu(void) throw ()
&LiveModeWindow::onAddToPlaylist))); &LiveModeWindow::onAddToPlaylist)));
contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("removeMenuItem"), *getResourceUstring("removeMenuItem"),
sigc::mem_fun(*treeView, sigc::mem_fun(*this,
&ZebraTreeView::onRemoveMenuOption))); &LiveModeWindow::onRemoveMenuOption)));
contextMenuList.push_back(Gtk::Menu_Helpers::SeparatorElem()); contextMenuList.push_back(Gtk::Menu_Helpers::SeparatorElem());
contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("uploadToHubMenuItem"), *getResourceUstring("uploadToHubMenuItem"),
@ -550,8 +567,8 @@ LiveModeWindow :: constructPlaylistContextMenu(void) throw ()
&LiveModeWindow::onAddToPlaylist))); &LiveModeWindow::onAddToPlaylist)));
contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("removeMenuItem"), *getResourceUstring("removeMenuItem"),
sigc::mem_fun(*treeView, sigc::mem_fun(*this,
&ZebraTreeView::onRemoveMenuOption))); &LiveModeWindow::onRemoveMenuOption)));
contextMenuList.push_back(Gtk::Menu_Helpers::SeparatorElem()); contextMenuList.push_back(Gtk::Menu_Helpers::SeparatorElem());
contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem(
*getResourceUstring("editPlaylistMenuItem"), *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 void
LiveModeWindow :: onRemoveItemButtonClicked(void) throw () LiveModeWindow :: onRemoveMenuOption(void) throw ()
{ {
isDeleting = true; 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; isDeleting = false;
onTreeModelChanged(); onTreeModelChanged();
} }

View File

@ -119,13 +119,24 @@ class LiveModeWindow : public GuiWindow,
*/ */
Gtk::CheckButton * autoPlayNext; 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. * Construct the right-click context menu for local audio clips.
* *
* @return the context menu created. * @return the context menu created.
*/ */
Ptr<Gtk::Menu>::Ref Ptr<Gtk::Menu>::Ref
constructAudioClipContextMenu(void) throw (); constructAudioClipContextMenu(void) throw ();
/** /**
* Construct the right-click context menu for local playlists. * Construct the right-click context menu for local playlists.
@ -133,17 +144,39 @@ class LiveModeWindow : public GuiWindow,
* @return the context menu created. * @return the context menu created.
*/ */
Ptr<Gtk::Menu>::Ref Ptr<Gtk::Menu>::Ref
constructPlaylistContextMenu(void) throw (); constructPlaylistContextMenu(void) throw ();
/** /**
* Find the selected row. * Return the topmost selected row.
* If more than one row is selected, it returns the first one. * Sets selectedPaths and selectedIter; does not increment it.
* *
* @return an iterator for the selected row; may be invalid * @return the first selected playable item.
* if nothing is selected.
*/ */
Gtk::TreeModel::iterator Ptr<Playable>::Ref
getSelected(void) throw (); 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: protected:
@ -220,15 +253,18 @@ class LiveModeWindow : public GuiWindow,
* This brings up the right-click context menu. * This brings up the right-click context menu.
* *
* @param event the button event recieved * @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 (); onEntryClicked(GdkEventButton * event) throw ();
/** /**
* Signal handler for the user double-clicking, or pressing Enter * Signal handler for the user double-clicking, or pressing Enter
* on one of the entries. * 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 void
onDoubleClick(const Gtk::TreeModel::Path & path, onDoubleClick(const Gtk::TreeModel::Path & path,
@ -285,10 +321,11 @@ class LiveModeWindow : public GuiWindow,
onUploadToHub(void) throw (); 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 virtual void
onRemoveItemButtonClicked(void) throw (); onRemoveMenuOption(void) throw ();
/** /**
* Signal handler for a change in the tree model. * Signal handler for a change in the tree model.

View File

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

View File

@ -94,13 +94,33 @@ class ScratchpadWindow : public GuiWindow,
*/ */
Ptr<SchedulePlaylistWindow>::Ref schedulePlaylistWindow; 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. * Used to iterate over the selected rows.
* Reset to the first row by onEntryClicked(). * Reset to the first row by onEntryClicked().
* Returns a 0 pointer if nothing is selected or we have reached * Returns a 0 pointer if nothing is selected or we have reached
* the end of the list of selected rows. * the end of the list of selected rows.
* *
* @return the next selected item. * @return the next selected playable item.
*/ */
Ptr<Playable>::Ref Ptr<Playable>::Ref
getNextSelectedPlayable(void) throw (); getNextSelectedPlayable(void) throw ();
@ -113,7 +133,7 @@ class ScratchpadWindow : public GuiWindow,
* @return true if a single row is selected, false if not. * @return true if a single row is selected, false if not.
*/ */
bool bool
isSelectionSingle(void) throw (); selectionIsSingle(void) throw ();
/** /**
* Remove an item from the Scratchpad. * Remove an item from the Scratchpad.
@ -184,18 +204,6 @@ class ScratchpadWindow : public GuiWindow,
*/ */
ZebraTreeView * treeView; 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. * The cue player widget controlling the audio buttons.
*/ */
@ -205,13 +213,13 @@ class ScratchpadWindow : public GuiWindow,
* The right-click context menu for audio clips, * The right-click context menu for audio clips,
* that comes up when right-clicking an entry in the entry list. * 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, * The right-click context menu for playlists,
* that comes up when right-clicking an entry in the entry list. * 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. * 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 * Signal handler for the user double-clicking, or pressing Enter
* on one of the entries. * 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 void
onDoubleClick(const Gtk::TreeModel::Path & path, onDoubleClick(const Gtk::TreeModel::Path & path,

View File

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

View File

@ -99,6 +99,17 @@ class SearchWindow : public GuiWindow,
*/ */
int remoteSearchResultsCount; 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. * The "search where" input field.
*/ */
@ -339,7 +350,7 @@ class SearchWindow : public GuiWindow,
displaySearchResults( displaySearchResults(
Ptr<SearchResultsType>::Ref searchResults, Ptr<SearchResultsType>::Ref searchResults,
Glib::RefPtr<Gtk::ListStore> treeModel) Glib::RefPtr<Gtk::ListStore> treeModel)
throw (); throw ();
/** /**
* Update the paging portion of the search results view. * Update the paging portion of the search results view.
@ -347,7 +358,7 @@ class SearchWindow : public GuiWindow,
* the Backward and Forward buttons. * the Backward and Forward buttons.
*/ */
void void
updatePagingToolbar(void) throw (); updatePagingToolbar(void) throw ();
/** /**
* Display a (usually error) message in the search results tree view. * Display a (usually error) message in the search results tree view.
@ -358,7 +369,7 @@ class SearchWindow : public GuiWindow,
void void
displayMessage(const Glib::ustring & messageKey, displayMessage(const Glib::ustring & messageKey,
Glib::RefPtr<Gtk::ListStore> treeModel) Glib::RefPtr<Gtk::ListStore> treeModel)
throw (); throw ();
/** /**
* Display an error message which occurred during a search. * Display an error message which occurred during a search.
@ -369,7 +380,7 @@ class SearchWindow : public GuiWindow,
void void
displayError(const XmlRpcException & error, displayError(const XmlRpcException & error,
Glib::RefPtr<Gtk::ListStore> treeModel) Glib::RefPtr<Gtk::ListStore> treeModel)
throw (); throw ();
/** /**
* Display an error message which occurred during a local search. * Display an error message which occurred during a local search.
@ -378,7 +389,7 @@ class SearchWindow : public GuiWindow,
*/ */
void void
displayLocalSearchError(const XmlRpcException & error) displayLocalSearchError(const XmlRpcException & error)
throw (); throw ();
/** /**
* Display an error message which occurred during a remote search. * Display an error message which occurred during a remote search.
@ -387,7 +398,27 @@ class SearchWindow : public GuiWindow,
*/ */
void void
displayRemoteSearchError(const XmlRpcException & error) 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: protected:
@ -505,15 +536,18 @@ class SearchWindow : public GuiWindow,
* Signal handler for the mouse clicked on one of the entries. * Signal handler for the mouse clicked on one of the entries.
* *
* @param event the button event received * @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 (); onEntryClicked(GdkEventButton * event) throw ();
/** /**
* Signal handler for the user double-clicking, or pressing Enter * Signal handler for the user double-clicking, or pressing Enter
* on one of the entries. * 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 void
onDoubleClick(const Gtk::TreeModel::Path & path, onDoubleClick(const Gtk::TreeModel::Path & path,