![]() |
Mixxx
|
00001 /*************************************************************************** 00002 dlgprefmidibindings.cpp - description 00003 ------------------- 00004 begin : Sat Jun 21 2008 00005 copyright : (C) 2008 by Tom Care 00006 email : psyc0de@gmail.com 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 #include <QtGui> 00018 #include <QDebug> 00019 #include "midi/midiinputmappingtablemodel.h" 00020 #include "midi/midioutputmappingtablemodel.h" 00021 #include "midi/midichanneldelegate.h" 00022 #include "midi/midistatusdelegate.h" 00023 #include "midi/midinodelegate.h" 00024 #include "midi/midioptiondelegate.h" 00025 #include "controlgroupdelegate.h" 00026 #include "controlvaluedelegate.h" 00027 #include "dlgprefmidibindings.h" 00028 #include "midi/mididevice.h" 00029 #include "midi/mididevicemanager.h" 00030 #include "configobject.h" 00031 #include "midi/midimapping.h" 00032 00033 #ifdef __MIDISCRIPT__ 00034 #include "midi/midiscriptengine.h" 00035 #endif 00036 00037 00038 DlgPrefMidiBindings::DlgPrefMidiBindings(QWidget *parent, MidiDevice* midiDevice, 00039 MidiDeviceManager* midiDeviceManager, 00040 ConfigObject<ConfigValue> *pConfig) 00041 : QWidget(parent), Ui::DlgPrefMidiBindingsDlg() 00042 { 00043 setupUi(this); 00044 m_pConfig = pConfig; 00045 m_pMidiDevice = midiDevice; 00046 m_pMidiDeviceManager = midiDeviceManager; 00047 00048 m_pDlgMidiLearning = NULL; 00049 00050 m_bDirty = false; 00051 00052 labelDeviceName->setText(m_pMidiDevice->getName()); 00053 00054 //Tell the input mapping table widget which data model it should be viewing 00055 //(note that m_pInputMappingTableView is defined in the .ui file!) 00056 m_pInputMappingTableView->setModel((QAbstractItemModel*)m_pMidiDevice->getMidiMapping()->getMidiInputMappingTableModel()); 00057 00058 m_pInputMappingTableView->setSelectionBehavior(QAbstractItemView::SelectRows); 00059 m_pInputMappingTableView->setSelectionMode(QAbstractItemView::ContiguousSelection); //The model won't like ExtendedSelection, probably. 00060 m_pInputMappingTableView->verticalHeader()->hide(); 00061 00062 //Set up "delete" as a shortcut key to remove a row for the MIDI input table. 00063 m_deleteMIDIInputRowAction = new QAction(m_pInputMappingTableView); 00064 /*m_deleteMIDIInputRowAction->setShortcut(QKeySequence::Delete); 00065 m_deleteMIDIInputRowAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); 00066 connect(m_deleteMIDIInputRowAction, SIGNAL(triggered()), this, SLOT(slotRemoveInputBinding())); 00067 */ 00068 //The above shortcut doesn't work yet, not quite sure why. -- Albert Feb 1 / 2009 00069 00070 //Set up the cool item delegates for the input mapping table 00071 m_pMidiChannelDelegate = new MidiChannelDelegate(m_pInputMappingTableView); 00072 m_pMidiStatusDelegate = new MidiStatusDelegate(m_pInputMappingTableView); 00073 m_pMidiNoDelegate = new MidiNoDelegate(m_pInputMappingTableView); 00074 m_pMidiOptionDelegate = new MidiOptionDelegate(m_pInputMappingTableView); 00075 m_pControlGroupDelegate = new ControlGroupDelegate(m_pInputMappingTableView); 00076 m_pControlValueDelegate = new ControlValueDelegate(m_pInputMappingTableView); 00077 m_pInputMappingTableView->setItemDelegateForColumn(MIDIINPUTTABLEINDEX_MIDISTATUS, m_pMidiStatusDelegate); 00078 m_pInputMappingTableView->setItemDelegateForColumn(MIDIINPUTTABLEINDEX_MIDICHANNEL, m_pMidiChannelDelegate); 00079 m_pInputMappingTableView->setItemDelegateForColumn(MIDIINPUTTABLEINDEX_MIDINO, m_pMidiNoDelegate); 00080 m_pInputMappingTableView->setItemDelegateForColumn(MIDIINPUTTABLEINDEX_CONTROLOBJECTGROUP, m_pControlGroupDelegate); 00081 m_pInputMappingTableView->setItemDelegateForColumn(MIDIINPUTTABLEINDEX_CONTROLOBJECTVALUE, m_pControlValueDelegate); 00082 m_pInputMappingTableView->setItemDelegateForColumn(MIDIINPUTTABLEINDEX_MIDIOPTION, m_pMidiOptionDelegate); 00083 00084 //Tell the output mapping table widget which data model it should be viewing 00085 //(note that m_pOutputMappingTableView is defined in the .ui file!) 00086 m_pOutputMappingTableView->setModel((QAbstractItemModel*)m_pMidiDevice->getMidiMapping()->getMidiOutputMappingTableModel()); 00087 m_pOutputMappingTableView->setSelectionBehavior(QAbstractItemView::SelectRows); 00088 m_pOutputMappingTableView->setSelectionMode(QAbstractItemView::ContiguousSelection); 00089 m_pOutputMappingTableView->verticalHeader()->hide(); 00090 00091 //Set up the cool item delegates for the output mapping table 00092 m_pOutputMappingTableView->setItemDelegateForColumn(MIDIOUTPUTTABLEINDEX_MIDISTATUS, m_pMidiStatusDelegate); 00093 m_pOutputMappingTableView->setItemDelegateForColumn(MIDIOUTPUTTABLEINDEX_MIDICHANNEL, m_pMidiChannelDelegate); 00094 m_pOutputMappingTableView->setItemDelegateForColumn(MIDIOUTPUTTABLEINDEX_MIDINO, m_pMidiNoDelegate); 00095 //TODO: We need different delegates for the output table's CO group/value columns because we only list real input 00096 // controls, and for output we'd want to list a different set with stuff like "VUMeter" and other output controls. 00097 //m_pOutputMappingTableView->setItemDelegateForColumn(MIDIOUTPUTTABLEINDEX_CONTROLOBJECTGROUP, m_pControlGroupDelegate); 00098 //m_pOutputMappingTableView->setItemDelegateForColumn(MIDIOUTPUTTABLEINDEX_CONTROLOBJECTVALUE, m_pControlValueDelegate); 00099 00100 // Connect buttons to slots 00101 connect(btnExportXML, SIGNAL(clicked()), this, SLOT(slotExportXML())); 00102 00103 //Input bindings 00104 connect(btnMidiLearnWizard, SIGNAL(clicked()), this, SLOT(slotShowMidiLearnDialog())); 00105 connect(btnMidiLearnWizard, SIGNAL(clicked()), this, SLOT(slotDirty())); 00106 connect(btnClearAllInputBindings, SIGNAL(clicked()), this, SLOT(slotClearAllInputBindings())); 00107 connect(btnClearAllInputBindings, SIGNAL(clicked()), this, SLOT(slotDirty())); 00108 connect(btnRemoveInputBinding, SIGNAL(clicked()), this, SLOT(slotRemoveInputBinding())); 00109 connect(btnRemoveInputBinding, SIGNAL(clicked()), this, SLOT(slotDirty())); 00110 connect(btnAddInputBinding, SIGNAL(clicked()), this, SLOT(slotAddInputBinding())); 00111 connect(btnAddInputBinding, SIGNAL(clicked()), this, SLOT(slotDirty())); 00112 00113 //Output bindings 00114 connect(btnClearAllOutputBindings, SIGNAL(clicked()), this, SLOT(slotClearAllOutputBindings())); 00115 connect(btnClearAllOutputBindings, SIGNAL(clicked()), this, SLOT(slotDirty())); 00116 connect(btnRemoveOutputBinding, SIGNAL(clicked()), this, SLOT(slotRemoveOutputBinding())); 00117 connect(btnRemoveOutputBinding, SIGNAL(clicked()), this, SLOT(slotDirty())); 00118 connect(btnAddOutputBinding, SIGNAL(clicked()), this, SLOT(slotAddOutputBinding())); 00119 connect(btnAddOutputBinding, SIGNAL(clicked()), this, SLOT(slotDirty())); 00120 00121 connect(comboBoxPreset, SIGNAL(activated(const QString&)), this, SLOT(slotLoadMidiMapping(const QString&))); 00122 connect(comboBoxPreset, SIGNAL(activated(const QString&)), this, SLOT(slotDirty())); 00123 00124 connect(m_pInputMappingTableView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(slotDirty())); 00125 connect(m_pOutputMappingTableView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(slotDirty())); 00126 00127 //Load the list of presets into the presets combobox. 00128 enumeratePresets(); 00129 00130 //Initialize the output device combobox 00131 enumerateOutputDevices(); 00132 00133 } 00134 00135 DlgPrefMidiBindings::~DlgPrefMidiBindings() { 00136 delete m_deleteMIDIInputRowAction; 00137 } 00138 00139 void DlgPrefMidiBindings::slotDirty () 00140 { 00141 m_bDirty = true; 00142 } 00143 00144 void DlgPrefMidiBindings::enumerateOutputDevices() 00145 { 00146 comboBoxOutputDevice->clear(); 00147 00148 comboBoxOutputDevice->addItem(tr("None")); 00149 00150 //For each MIDI output device, insert an item into the output device combobox. 00151 QList<MidiDevice*> deviceList = m_pMidiDeviceManager->getDeviceList(true, false); 00152 QListIterator<MidiDevice*> it(deviceList); 00153 00154 while (it.hasNext()) 00155 { 00156 MidiDevice* currentDevice = it.next(); 00157 QString curDeviceName = currentDevice->getName(); 00158 //qDebug() << "curDeviceName: " << curDeviceName; 00159 comboBoxOutputDevice->addItem(curDeviceName); 00160 } 00161 00162 //Assume autopairing was done and let's just show the output device combobox with the name 00163 //of the input device selected for now... 00164 QString currentOutputMidiDeviceName = m_pMidiDevice->getName(); 00165 comboBoxOutputDevice->setCurrentIndex(comboBoxOutputDevice->findText(currentOutputMidiDeviceName)); 00166 00167 } 00168 00169 void DlgPrefMidiBindings::enumeratePresets() 00170 { 00171 QList<QString> presetsList; 00172 comboBoxPreset->clear(); 00173 00174 //Insert a dummy "..." item at the top to try to make it less confusing. 00175 //(For example, we don't want "Akai MPD24" showing up as the default item 00176 // when a user has their controller plugged in) 00177 comboBoxPreset->addItem("..."); 00178 00179 // paths to search for midi presets 00180 QList<QString> midiDirPaths; 00181 midiDirPaths.append(LPRESETS_PATH); 00182 midiDirPaths.append(m_pConfig->getConfigPath().append("midi/")); 00183 00184 QListIterator<QString> itpth(midiDirPaths); 00185 while (itpth.hasNext()) { 00186 QDirIterator it(itpth.next()); 00187 while (it.hasNext()) 00188 { 00189 it.next(); //Advance iterator. We get the filename from the next line. (It's a bit weird.) 00190 QString curMapping = it.fileName(); 00191 if (curMapping.endsWith(MIDI_MAPPING_EXTENSION)) //blah, thanks for nothing Qt 00192 { 00193 curMapping.chop(QString(MIDI_MAPPING_EXTENSION).length()); //chop off the .midi.xml 00194 presetsList.append(curMapping); 00195 } 00196 } 00197 } 00198 //Sort in alphabetical order 00199 qSort(presetsList); 00200 comboBoxPreset->addItems(presetsList); 00201 } 00202 00203 00204 00205 /* slotUpdate() 00206 * Called when the dialog is displayed. 00207 */ 00208 void DlgPrefMidiBindings::slotUpdate() { 00209 00210 //Check if the device that this dialog is for is already enabled... 00211 if (m_pMidiDevice->isOpen()) 00212 { 00213 chkEnabledDevice->setCheckState(Qt::Checked); //Check the "Enabled" box 00214 toolBox->setEnabled(true); //Enable MIDI in/out toolbox. 00215 groupBoxPresets->setEnabled(true); //Enable presets group box. 00216 } 00217 else { 00218 chkEnabledDevice->setCheckState(Qt::Unchecked); //Uncheck the "Enabled" box 00219 toolBox->setEnabled(false); //Disable MIDI in/out toolbox. 00220 groupBoxPresets->setEnabled(false); //Disable presets group box. 00221 } 00222 00223 //Connect the "Enabled" checkbox after the checkbox state is set 00224 connect(chkEnabledDevice, SIGNAL(stateChanged(int)), this, SLOT(slotDeviceState(int))); 00225 connect(chkEnabledDevice, SIGNAL(stateChanged(int)), this, SLOT(slotDirty())); 00226 } 00227 00228 /* slotApply() 00229 * Called when the OK button is pressed. 00230 */ 00231 void DlgPrefMidiBindings::slotApply() { 00232 /* User has pressed OK, so enable or disable the device, write the 00233 * controls to the DOM, and reload the MIDI bindings. FIXED: only 00234 * do this if the user has changed the preferences. 00235 */ 00236 if (m_bDirty) 00237 { 00238 m_pMidiDevice->disableMidiLearn(); 00239 if (chkEnabledDevice->isChecked()) { 00240 //Enable the device. 00241 enableDevice(); 00242 00243 //Disable processing of MIDI messages received from the device in order to 00244 //prevent a race condition while we modify the MIDI mapping. 00245 m_pMidiDevice->setReceiveInhibit(true); 00246 m_pMidiDevice->getMidiMapping()->applyPreset(); 00247 m_pMidiDevice->setReceiveInhibit(false); 00248 00249 //FIXME: We need some logic like this to make changing the output device work. 00250 // See MidiDeviceManager::associateInputAndOutputDevices() for more info... 00251 /* 00252 if (comboBoxOutputDevice->currentText() != tr("None")) 00253 m_pMidiDeviceManager->associateInputAndOutputDevices(m_pMidiDevice, comboBoxOutputDevice->currentText()); 00254 */ 00255 } 00256 else disableDevice(); 00257 } 00258 m_bDirty = false; 00259 } 00260 00261 void DlgPrefMidiBindings::slotShowMidiLearnDialog() { 00262 // If the user has checked the "Enabled" checkbox but they haven't hit OK to 00263 // apply it yet, prompt them to apply the settings before we open the MIDI 00264 // learning dialog. If we don't apply the settings first and open the 00265 // device, MIDI learn won't react to MIDI messages. 00266 if (chkEnabledDevice->isChecked() && !m_pMidiDevice->isOpen()) { 00267 QMessageBox::StandardButton result = QMessageBox::question( 00268 this, 00269 tr("Apply MIDI device settings?"), 00270 tr("Your settings must be applied before starting the MIDI learning wizard.\n" 00271 "Apply settings and continue?"), 00272 QMessageBox::Ok | QMessageBox::Cancel, // Buttons to be displayed 00273 QMessageBox::Ok); // Default button 00274 // Stop if the user has not pressed the Ok button, 00275 // which could be the Cancel or the Close Button. 00276 if (result != QMessageBox::Ok) return; 00277 } 00278 slotApply(); 00279 00280 // Note that DlgMidiLearning is set to delete itself on close using the 00281 // Qt::WA_DeleteOnClose attribute (so this "new" doesn't leak memory) 00282 m_pDlgMidiLearning = new DlgMidiLearning( 00283 this, m_pMidiDevice->getMidiMapping()); 00284 m_pDlgMidiLearning->show(); 00285 } 00286 00287 /* slotImportXML() 00288 * Prompts the user for an XML preset and loads it. 00289 */ 00290 void DlgPrefMidiBindings::slotLoadMidiMapping(const QString &name) { 00291 00292 if (name == "...") 00293 return; 00294 00295 //Ask for confirmation if the MIDI tables aren't empty... 00296 MidiMapping* mapping = m_pMidiDevice->getMidiMapping(); 00297 if (mapping->numInputMidiMessages() > 0 || 00298 mapping->numOutputMixxxControls() > 0) 00299 { 00300 QMessageBox::StandardButton result = QMessageBox::question( 00301 this, 00302 tr("Overwrite existing mapping?"), 00303 tr("Are you sure you'd like to load the %1 mapping?\n" 00304 "This will overwrite your existing MIDI mapping.").arg(name), 00305 QMessageBox::Yes | QMessageBox::No); 00306 00307 if (result == QMessageBox::No) { 00308 //Select the "..." item again in the combobox. 00309 comboBoxPreset->setCurrentIndex(0); 00310 return; 00311 } 00312 } 00313 00314 QString filename = LPRESETS_PATH + name + MIDI_MAPPING_EXTENSION; 00315 QFile ftest(filename); 00316 if ( !ftest.exists() ) filename = m_pConfig->getConfigPath().append("midi/") + name + MIDI_MAPPING_EXTENSION; 00317 00318 if (!filename.isNull()) m_pMidiDevice->getMidiMapping()->loadPreset(filename, true); // It's applied on prefs close 00319 m_pInputMappingTableView->update(); 00320 00321 //Select the "..." item again in the combobox. 00322 comboBoxPreset->setCurrentIndex(0); 00323 } 00324 00325 /* slotExportXML() 00326 * Prompts the user for an XML preset and saves it. 00327 */ 00328 void DlgPrefMidiBindings::slotExportXML() { 00329 QString fileName = QFileDialog::getSaveFileName(this, 00330 tr("Export Mixxx MIDI Bindings"), m_pConfig->getConfigPath().append("midi/"), 00331 tr("Preset Files (*.midi.xml)")); 00332 if (!fileName.isNull()) m_pMidiDevice->getMidiMapping()->savePreset(fileName); 00333 } 00334 00335 void DlgPrefMidiBindings::slotDeviceState(int state) { 00336 if (state == Qt::Checked) { 00337 toolBox->setEnabled(true); //Enable MIDI in/out toolbox. 00338 groupBoxPresets->setEnabled(true); //Enable presets group box. 00339 emit deviceStateChanged(this,true); // Set tree item text to bold 00340 } 00341 else { 00342 toolBox->setEnabled(false); //Disable MIDI in/out toolbox. 00343 groupBoxPresets->setEnabled(false); //Disable presets group box. 00344 emit deviceStateChanged(this,false); // Set tree item text to not bold 00345 } 00346 } 00347 00348 void DlgPrefMidiBindings::enableDevice() 00349 { 00350 if (m_pMidiDevice->isOpen()) { 00351 m_pMidiDevice->close(); 00352 } 00353 m_pMidiDevice->open(); 00354 m_pConfig->set(ConfigKey("[Midi]", m_pMidiDevice->getName().replace(" ", "_")), 1); 00355 00356 //TODO: Should probably check if open() actually succeeded. 00357 } 00358 00359 void DlgPrefMidiBindings::disableDevice() 00360 { 00361 m_pMidiDevice->close(); 00362 m_pConfig->set(ConfigKey("[Midi]", m_pMidiDevice->getName().replace(" ", "_")), 0); 00363 00364 //TODO: Should probably check if close() actually succeeded. 00365 } 00366 00367 void DlgPrefMidiBindings::slotAddInputBinding() 00368 { 00369 bool ok = true; 00370 QString controlGroup = QInputDialog::getItem(this, tr("Select Control Group"), tr("Select Control Group"), 00371 ControlGroupDelegate::getControlGroups(), 0, false, &ok); 00372 if (!ok) return; 00373 00374 QStringList controlValues; 00375 if (controlGroup == CONTROLGROUP_CHANNEL1_STRING || 00376 controlGroup == CONTROLGROUP_CHANNEL2_STRING || 00377 controlGroup == CONTROLGROUP_SAMPLER1_STRING || 00378 controlGroup == CONTROLGROUP_SAMPLER2_STRING || 00379 controlGroup == CONTROLGROUP_SAMPLER3_STRING || 00380 controlGroup == CONTROLGROUP_SAMPLER4_STRING) { 00381 controlValues = ControlValueDelegate::getChannelControlValues(); 00382 } 00383 else if (controlGroup == CONTROLGROUP_MASTER_STRING) 00384 { 00385 controlValues = ControlValueDelegate::getMasterControlValues(); 00386 } 00387 else if (controlGroup == CONTROLGROUP_PLAYLIST_STRING) 00388 { 00389 controlValues = ControlValueDelegate::getPlaylistControlValues(); 00390 } 00391 else if (controlGroup == CONTROLGROUP_FLANGER_STRING) 00392 { 00393 controlValues = ControlValueDelegate::getFlangerControlValues(); 00394 } 00395 else if (controlGroup == CONTROLGROUP_MICROPHONE_STRING) 00396 { 00397 controlValues = ControlValueDelegate::getMicrophoneControlValues(); 00398 } 00399 else 00400 { 00401 qDebug() << "Unhandled ControlGroup in " << __FILE__; 00402 } 00403 00404 00405 QString controlValue = QInputDialog::getItem(this, tr("Select Control"), tr("Select Control"), 00406 controlValues, 0, false, &ok); 00407 if (!ok) return; 00408 00409 00410 MixxxControl mixxxControl(controlGroup, controlValue); 00411 MidiMessage message; 00412 00413 while (m_pMidiDevice->getMidiMapping()->isMidiMessageMapped(message)) 00414 { 00415 message.setMidiNo(message.getMidiNo() + 1); 00416 if (message.getMidiNo() >= 127) //If the table is full, then overwrite something... 00417 break; 00418 } 00419 m_pMidiDevice->getMidiMapping()->setInputMidiMapping(message, mixxxControl); 00420 } 00421 00422 void DlgPrefMidiBindings::slotRemoveInputBinding() 00423 { 00424 QModelIndexList selectedIndices = m_pInputMappingTableView->selectionModel()->selectedRows(); 00425 if (selectedIndices.size() > 0) 00426 { 00427 MidiInputMappingTableModel* tableModel = dynamic_cast<MidiInputMappingTableModel*>(m_pInputMappingTableView->model()); 00428 if (tableModel) { 00429 00430 QModelIndex curIndex; 00431 //The model indices are sorted so that we remove the rows from the table 00432 //in ascending order. This is necessary because if row A is above row B in 00433 //the table, and you remove row A, the model index for row B will change. 00434 //Sorting the indices first means we don't have to worry about this. 00435 qSort(selectedIndices); 00436 00437 //Going through the model indices in descending order (see above comment for explanation). 00438 QListIterator<QModelIndex> it(selectedIndices); 00439 it.toBack(); 00440 while (it.hasPrevious()) 00441 { 00442 curIndex = it.previous(); 00443 tableModel->removeRow(curIndex.row()); 00444 } 00445 } 00446 } 00447 } 00448 00449 void DlgPrefMidiBindings::slotClearAllInputBindings() { 00450 if (QMessageBox::warning(this, tr("Clear Input Bindings"), 00451 tr("Are you sure you want to clear all bindings?"), 00452 QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Ok) 00453 return; 00454 00455 //Remove all the rows from the data model (ie. the MIDI mapping). 00456 MidiInputMappingTableModel* tableModel = dynamic_cast<MidiInputMappingTableModel*>(m_pInputMappingTableView->model()); 00457 if (tableModel) { 00458 tableModel->removeRows(0, tableModel->rowCount()); 00459 } 00460 } 00461 00462 00463 void DlgPrefMidiBindings::slotAddOutputBinding() { 00464 qDebug() << "STUB: DlgPrefMidiBindings::slotAddOutputBinding()"; 00465 00466 m_pMidiDevice->getMidiMapping()->setOutputMidiMapping(MixxxControl(), MidiMessage()); 00467 } 00468 00469 void DlgPrefMidiBindings::slotRemoveOutputBinding() 00470 { 00471 QModelIndexList selectedIndices = m_pOutputMappingTableView->selectionModel()->selectedRows(); 00472 if (selectedIndices.size() > 0) 00473 { 00474 MidiOutputMappingTableModel* tableModel = 00475 dynamic_cast<MidiOutputMappingTableModel*>(m_pOutputMappingTableView->model()); 00476 if (tableModel) { 00477 QModelIndex curIndex; 00478 //The model indices are sorted so that we remove the rows from the table 00479 //in ascending order. This is necessary because if row A is above row B in 00480 //the table, and you remove row A, the model index for row B will change. 00481 //Sorting the indices first means we don't have to worry about this. 00482 //qSort(selectedIndices); 00483 00484 //Going through the model indices in descending order (see above comment for explanation). 00485 QListIterator<QModelIndex> it(selectedIndices); 00486 it.toBack(); 00487 while (it.hasPrevious()) 00488 { 00489 curIndex = it.previous(); 00490 qDebug() << "Dlg: removing row" << curIndex.row(); 00491 tableModel->removeRow(curIndex.row()); 00492 } 00493 } 00494 } 00495 } 00496 00497 void DlgPrefMidiBindings::slotClearAllOutputBindings() { 00498 if (QMessageBox::warning(this, tr("Clear Output Bindings"), 00499 tr("Are you sure you want to clear all output bindings?"), 00500 QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Ok) 00501 return; 00502 00503 //Remove all the rows from the data model (ie. the MIDI mapping). 00504 MidiOutputMappingTableModel* tableModel = dynamic_cast<MidiOutputMappingTableModel*>(m_pOutputMappingTableView->model()); 00505 if (tableModel) { 00506 tableModel->removeRows(0, tableModel->rowCount()); 00507 } 00508 }