stationlistmodel.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2008-2010  Lukas Sommer < SommerLuk at gmail dot com >
00003 
00004     This program is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU General Public License as
00006     published by the Free Software Foundation; either version 2 of
00007     the License or (at your option) version 3 or any later version
00008     accepted by the membership of KDE e.V. (or its successor approved
00009     by the membership of KDE e.V.), which shall act as a proxy
00010     defined in Section 14 of version 3 of the license.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 */
00020 
00021 #include "stationlistmodel.h"
00022 
00023 #include "folderpropertiesdialog.h"
00024 #include "includekio.h"
00025 #include "stationlistwidget.h"
00026 #include "settings_general.h"
00027 #include <QAbstractItemModel>
00028 #include <QApplication>
00029 #include <QClipboard>
00030 #include <QFile>
00031 #include <QItemSelection>
00032 #include <QMimeData>
00033 #include <QXmlStreamReader>
00034 #include <KLocale>
00035 #include <KProgressDialog>
00036 #include <KStandardDirs>
00037 #include <KTemporaryFile>
00038 #define AND  &&
00039 #define OR  ||
00040 #define NOT  !
00041 #define EQUAL  ==
00042 
00043 stationlistModel::stationlistModel(stationlistWidget *parent,
00044                                    QWidget *mainWidget) : QAbstractItemModel(parent)
00045 {
00046   // variables
00047   QXmlStreamReader stationlistReader;
00048   QFile stationlistFile;
00049   stationlistItem *actualFolder;
00050   stationlistItem *temp_item;
00051   QString temp_string;
00052   QModelIndexList expandedRows;
00053 
00054   // general setup
00055   m_mainWidget = mainWidget;
00056   view = parent;
00057   m_listOfStreamsOfWhichTheUserWantsThatTheyRip = 0;
00058   // setup data model
00059   rootItem = new stationlistItem("");
00060   stationlistFile.setFileName(helper_stationlistXmlFilepath());
00061   if (stationlistFile.open(QIODevice::ReadOnly)) {
00062     stationlistReader.setDevice(&stationlistFile);
00063     actualFolder = rootItem;
00064     while (!stationlistReader.atEnd()) {
00065       stationlistReader.readNext();
00066       if (stationlistReader.name() == "folder") {
00067         if (stationlistReader.isStartElement()) {
00068           temp_item = new stationlistItem(stationlistReader.attributes().value("name").toString());
00069           actualFolder->appendChild(temp_item);
00070           actualFolder = temp_item;
00071           if (stationlistReader.attributes().value("expanded").toString() == "true") {
00072             expandedRows.append(modelindexOfItem(temp_item, 0));
00073           };
00074         } else if (stationlistReader.isEndElement()) {
00075           actualFolder = actualFolder->parent();
00076           if (!actualFolder) { // should never happen for properly written xml lists
00077             actualFolder = rootItem;
00078           };
00079         };
00080       } else if (stationlistReader.name() == "stream" && stationlistReader.isStartElement()) {
00081         temp_item = helper_createStreamItem(new radioStation(this,
00082                                                        m_mainWidget,
00083                                                        stationlistReader.readElementText()));
00084         actualFolder->appendChild(temp_item);
00085       };
00086     };
00087   };
00088 
00089   // initialize attributes
00090   recalculate_numberOfActiveStreams_and_bandwidth(); // now possible (after making stationlist)
00091 
00092   connect(this, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
00093           this, SLOT(recalculate_numberOfActiveStreams_and_bandwidth()));
00094   connect(this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
00095           this, SLOT(recalculate_numberOfActiveStreams_and_bandwidth()));
00096   view->setModel(this);
00097   foreach (const QModelIndex &m_index, expandedRows) {
00098     view->expand(m_index);
00099   };
00100   helper_writeStationList();  /* We do this because when radioStation can't
00101   open the file, it creates a new one. Probaby this won't happen, but we have to make sure
00102   that the list in the general config file is actual. (We must du this _after_ setting this
00103   object as model of the view because helper_writeStationList() relays on an existing view. */
00104   connect(view->selectionModel(),
00105           SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
00106           this,
00107           SLOT(recalculateSelectedStreams()));
00108 }
00109 
00110 stationlistModel::~stationlistModel()
00111 {
00112   delete rootItem;
00113 }
00114 
00115 void stationlistModel::helper_connectSignalsAndSlots(radioStation *m_stream)
00116 {
00117     connect(m_stream, SIGNAL(streamNameChanged(void *, PropertyValue)),
00118             this, SLOT(reloadStreamName(void *)));
00119     connect(m_stream, SIGNAL(uriChanged(void *, PropertyValue)),
00120             this, SLOT(reloadUri(void *)));
00121     connect(m_stream, SIGNAL(statusChanged(void *, PropertyValue)),
00122             this, SLOT(reloadStatus(void *)));
00123     connect(m_stream, SIGNAL(errorChanged(void *, PropertyValue)),
00124             this, SLOT(reloadStatus(void *)));
00125     connect(m_stream, SIGNAL(songChanged(void *, PropertyValue)),
00126             this, SLOT(reloadSong(void *)));
00127     connect(m_stream, SIGNAL(dataSizeChanged(void *, PropertyValue)),
00128             this, SLOT(reloadDataSize(void *)));
00129     connect(m_stream, SIGNAL(bitrateChanged(void *, PropertyValue)),
00130             this, SLOT(reloadBitrate(void *)));
00131     connect(m_stream, SIGNAL(bitrateChanged(void *, PropertyValue)),
00132             this, SLOT(recalculate_numberOfActiveStreams_and_bandwidth()));
00133     connect(m_stream, SIGNAL(metaIntervalChanged(void *, PropertyValue)),
00134             this, SLOT(reloadMetaInterval(void *)));
00135     connect(m_stream, SIGNAL(metaInterval_milliSecondsChanged(void *, PropertyValue)),
00136             this, SLOT(reloadMetaInterval_milliSeconds(void *)));
00137     connect(m_stream, SIGNAL(serverNameChanged(void *, PropertyValue)),
00138             this, SLOT(reloadServerName(void *)));
00139     connect(m_stream, SIGNAL(relayPortChanged(void *, PropertyValue)),
00140             this, SLOT(reloadRelayPort(void *)));
00141     connect(m_stream, SIGNAL(running()),
00142             this, SLOT(recalculate_numberOfActiveStreams_and_bandwidth()));
00143     connect(m_stream, SIGNAL(not_running()),
00144             this, SLOT(recalculate_numberOfActiveStreams_and_bandwidth()));
00145 }
00146 
00147 inline QString stationlistModel::helper_stationlistXmlFilepath()
00148 {
00149   return KStandardDirs::locateLocal("appdata", "stationlist.xml");
00150 }
00151 
00152 int stationlistModel::rowCount (const QModelIndex & parent) const
00153 {
00154   // variables
00155   stationlistItem *parentItem = item(parent);
00156 
00157   // code
00158   if (parent.column() > 0) {
00159     return 0;
00160   };
00161   return parentItem->childCount();
00162 }
00163 
00164 int stationlistModel::columnCount (const QModelIndex &) const
00165 {
00166   return 10;
00167 }
00168 
00169 QVariant stationlistModel::columnInfo(const columnInfoType type,
00170                                       const int column,
00171                                       const radioStation *stream,
00172                                       const quint64 value) const
00173 {
00174   QVariant temp;
00175 
00176   switch (type) {  // make sure that row is valid to prevent a memory access failure
00177     case columnHeaderTitle:
00178     case columnHeaderToolTip:
00179     case columnHeaderWhatsThis:
00180     case columnWidth:
00181     case setColumnWidth:
00182     case columnVisibility:
00183     case setColumnVisibility:
00184       break;  // These functions are known to not make use of the row.
00185     default:  // Else we break as a precaution we break up here.
00186       if (stream == 0) {
00187         return QVariant();
00188       };
00189   }
00190   /* IF data is requested that is NOT depending on the "row"
00191   *  THEN no check is needed.
00192   *  ELSE (=when data is depending on the "row") we check if it is a valid row.
00193   *  If not, we return a QVariant(). This is important, because the rest of this
00194   *  function body assumes that "row" is valid and uses it for QList::at(row) - and
00195   *  when "row" is invalid, this function leeds to a crash.
00196   *
00197   *  I use the "switch" systax because this looks clearer than an "if" construct.
00198   *  And I test for the cases where the row is NOT important - this way (when one
00199   *  day the enum gets more items that depend on the row - and we forget to change
00200   *  it here) at least we don't get a crash.
00201   *
00202   *  We don't test if "column" is valid, because the rest of the function is a
00203   *  switch-case, and when there nothing matches, an invalid QVariant is returned. */
00204 
00205   switch (column) {
00206 
00207     case 0:
00208     {
00209       switch (type) {
00210         case columnHeaderTitle:
00211           return i18nc("@title:column", "stream name");
00212         case columnHeaderToolTip:
00213         case columnHeaderWhatsThis:
00214           return QVariant();
00215         case columnWidth:
00216           return settings_general::columnWidth_streamName();
00217         case setColumnWidth:
00218           settings_general::setColumnWidth_streamName(value);
00219           settings_general::self()->writeConfig();
00220           return QVariant();
00221         case columnVisibility:
00222           return settings_general::columnVisibility_streamName();
00223         case setColumnVisibility:
00224           settings_general::setColumnVisibility_streamName(value);
00225           settings_general::self()->writeConfig();
00226           return QVariant();
00227         case columnData:
00228           temp.setValue<PropertyValue>(stream->streamName());
00229           return temp;
00230       };
00231       break;
00232     }
00233 
00234     case 1:
00235     {
00236       switch (type) {
00237         case columnHeaderTitle:
00238           return i18nc("@title:column", "URL");
00239         case columnHeaderToolTip:
00240         case columnHeaderWhatsThis:
00241           return QVariant();
00242         case columnWidth:
00243           return settings_general::columnWidth_uri();
00244         case setColumnWidth:
00245           settings_general::setColumnWidth_uri(value);
00246           settings_general::self()->writeConfig();
00247           return QVariant();
00248         case columnVisibility:
00249           return settings_general::columnVisibility_uri();
00250         case setColumnVisibility:
00251           settings_general::setColumnVisibility_uri(value);
00252           settings_general::self()->writeConfig();
00253           return QVariant();
00254         case columnData:
00255           temp.setValue<PropertyValue>(stream->uri());
00256           return temp;
00257       };
00258       break;
00259     }
00260 
00261     case 2:
00262     {
00263       switch (type) {
00264         case columnHeaderTitle:
00265           return i18nc("@title:column", "status");
00266         case columnHeaderToolTip:
00267         case columnHeaderWhatsThis:
00268           return QVariant();
00269         case columnWidth:
00270           return settings_general::columnWidth_statusAndError();
00271         case setColumnWidth:
00272           settings_general::setColumnWidth_statusAndError(value);
00273           settings_general::self()->writeConfig();
00274           return QVariant();
00275         case columnVisibility:
00276           return settings_general::columnVisibility_statusAndError();
00277         case setColumnVisibility:
00278           settings_general::setColumnVisibility_statusAndError(value);
00279           settings_general::self()->writeConfig();
00280           return QVariant();
00281         case columnData:
00282           PropertyValue my_statusAndError;
00283           if (stream->error().formatedValue.isEmpty()) {
00284             my_statusAndError.formatedValue = stream->status().formatedValue;
00285             my_statusAndError.toolTip = stream->status().toolTip;
00286             my_statusAndError.whatsThis = stream->status().whatsThis;
00287           } else {
00288             my_statusAndError.toolTip = stream->error().toolTip;
00289             my_statusAndError.whatsThis = stream->error().whatsThis;
00290             if (stream->status().formatedValue.isEmpty()) {
00291               my_statusAndError.formatedValue = stream->error().formatedValue;
00292             } else {
00293               my_statusAndError.formatedValue = QString(i18nc(
00294                 "@item:intable This produces the status message from the actual status (%1) and "
00295                   "the error message (%3). Both of them are guaranteed to be not empty. %2 is "
00296                   "replaced by an en-dash (Unicode U+2013). Use it or replace it by something "
00297                   "what looks nicer in your language.",
00298                 "%1 %2 %3",
00299                 stream->status().formatedValue,
00300                 QString(QChar(0x2013)),
00301                 stream->error().formatedValue));
00302             };
00303           };
00304           my_statusAndError.internalValue = stream->status().internalValue;
00305           if ((!(stream->error().type == PropertyValue::unset)) ||
00306               (stream->status().type == PropertyValue::error)) {
00307             my_statusAndError.type = PropertyValue::error;
00308           } else if (my_statusAndError.formatedValue.isEmpty()) {
00309             my_statusAndError.type = PropertyValue::unset;
00310           } else {
00311             my_statusAndError.type = PropertyValue::value;
00312           };
00313           temp.setValue<PropertyValue>(my_statusAndError);
00314           return temp;
00315       };
00316       break;
00317     }
00318 
00319     case 3:
00320     {
00321       switch (type) {
00322         case columnHeaderTitle:
00323           return  i18nc("@title:column header of the column with the name of the actual track",
00324                         "track");
00325         case columnHeaderToolTip:
00326         case columnHeaderWhatsThis:
00327           return  QVariant();
00328         case columnWidth:
00329           return settings_general::columnWidth_song();
00330         case setColumnWidth:
00331           settings_general::setColumnWidth_song(value);
00332           settings_general::self()->writeConfig();
00333           return QVariant();
00334         case columnVisibility:
00335           return settings_general::columnVisibility_song();
00336         case setColumnVisibility:
00337           settings_general::setColumnVisibility_song(value);
00338           settings_general::self()->writeConfig();
00339           return QVariant();
00340         case columnData:
00341           temp.setValue<PropertyValue>(stream->song());
00342           return temp;
00343       };
00344       break;
00345     }
00346 
00347     case 4:
00348     {
00349       switch (type) {
00350         case columnHeaderTitle:
00351           return  i18nc("@title:column", "track size");
00352         case columnHeaderToolTip:
00353         case columnHeaderWhatsThis:
00354           return  QVariant();
00355         case columnWidth:
00356           return settings_general::columnWidth_dataSize();
00357         case setColumnWidth:
00358           settings_general::setColumnWidth_dataSize(value);
00359           settings_general::self()->writeConfig();
00360           return QVariant();
00361         case columnVisibility:
00362           return settings_general::columnVisibility_dataSize();
00363         case setColumnVisibility:
00364           settings_general::setColumnVisibility_dataSize(value);
00365           settings_general::self()->writeConfig();
00366           return QVariant();
00367         case columnData:
00368           temp.setValue<PropertyValue>(stream->dataSize());
00369           return temp;
00370       };
00371       break;
00372     }
00373 
00374     case 5:
00375     {
00376       switch (type) {
00377         case columnHeaderTitle:
00378           return  i18nc("@title:column", "bit rate");
00379         case columnHeaderToolTip:
00380         case columnHeaderWhatsThis:
00381           return  QVariant();
00382         case columnWidth:
00383           return settings_general::columnWidth_bitrate();
00384         case setColumnWidth:
00385           settings_general::setColumnWidth_bitrate(value);
00386           settings_general::self()->writeConfig();
00387           return QVariant();
00388         case columnVisibility:
00389           return settings_general::columnVisibility_bitrate();
00390         case setColumnVisibility:
00391           settings_general::setColumnVisibility_bitrate(value);
00392           settings_general::self()->writeConfig();
00393           return QVariant();
00394         case columnData:
00395           temp.setValue<PropertyValue>(stream->bitrate());
00396           return temp;
00397       };
00398       break;
00399     }
00400 
00401     case 6:
00402     {
00403       switch (type) {
00404         case columnHeaderTitle:
00405           return  i18nc("@title:column The unit is KiB instead of kB. See "
00406                           "http://en.wikipedia.org/wiki/Binary_prefix for details.",
00407                         "meta data interval (KiB)");
00408         case columnHeaderToolTip:
00409           return  i18nc("@info:tooltip", "interval of meta data in bytes");
00410         case columnHeaderWhatsThis:
00411           return  QVariant();
00412         case columnWidth:
00413           return settings_general::columnWidth_metaInterval();
00414         case setColumnWidth:
00415           settings_general::setColumnWidth_metaInterval(value);
00416           settings_general::self()->writeConfig();
00417           return QVariant();
00418         case columnVisibility:
00419           return settings_general::columnVisibility_metaInterval();
00420         case setColumnVisibility:
00421           settings_general::setColumnVisibility_metaInterval(value);
00422           settings_general::self()->writeConfig();
00423           return QVariant();
00424         case columnData:
00425           temp.setValue<PropertyValue>(stream->metaInterval());
00426           return temp;
00427       };
00428       break;
00429     }
00430 
00431     case 7:
00432     {
00433       switch (type) {
00434         case columnHeaderTitle:
00435           return  i18nc("@title:column unit is millisecond", "meta data interval (ms)");
00436         case columnHeaderToolTip:
00437           return  i18nc("@info:tooltip", "interval of meta data in milliseconds");
00438         case columnHeaderWhatsThis:
00439           return  QVariant();
00440         case columnWidth:
00441           return settings_general::columnWidth_metaInterval_milliSeconds();
00442         case setColumnWidth:
00443           settings_general::setColumnWidth_metaInterval_milliSeconds(value);
00444           settings_general::self()->writeConfig();
00445           return QVariant();
00446         case columnVisibility:
00447           return settings_general::columnVisibility_metaInterval_milliSeconds();
00448         case setColumnVisibility:
00449           settings_general::setColumnVisibility_metaInterval_milliSeconds(value);
00450           settings_general::self()->writeConfig();
00451           return QVariant();
00452         case columnData:
00453           temp.setValue<PropertyValue>(stream->metaInterval_milliSeconds());
00454           return temp;
00455       };
00456       break;
00457     }
00458 
00459     case 8:
00460     {
00461       switch (type) {
00462         case columnHeaderTitle:
00463           return  i18nc("@title:column", "server name");
00464         case columnHeaderToolTip:
00465         case columnHeaderWhatsThis:
00466           return  QVariant();
00467         case columnWidth:
00468           return settings_general::columnWidth_serverName();
00469         case setColumnWidth:
00470           settings_general::setColumnWidth_serverName(value);
00471           settings_general::self()->writeConfig();
00472           return QVariant();
00473         case columnVisibility:
00474           return settings_general::columnVisibility_serverName();
00475         case setColumnVisibility:
00476           settings_general::setColumnVisibility_serverName(value);
00477           settings_general::self()->writeConfig();
00478           return QVariant();
00479         case columnData:
00480           temp.setValue<PropertyValue>(stream->serverName());
00481           return temp;
00482       };
00483       break;
00484     }
00485 
00486     case 9:
00487     {
00488       switch (type) {
00489         case columnHeaderTitle:
00490           return  i18nc("@title:column 'relay port' means 'the port that the relay server uses'",
00491                         "relay port");
00492         case columnHeaderToolTip:
00493           return  i18nc("@info:tooltip", "port of the relay server");
00494         case columnHeaderWhatsThis:
00495           return  QVariant();
00496         case columnWidth:
00497           return settings_general::columnWidth_relayPort();
00498         case setColumnWidth:
00499           settings_general::setColumnWidth_relayPort(value);
00500           settings_general::self()->writeConfig();
00501           return QVariant();
00502         case columnVisibility:
00503           return settings_general::columnVisibility_relayPort();
00504         case setColumnVisibility:
00505           settings_general::setColumnVisibility_relayPort(value);
00506           settings_general::self()->writeConfig();
00507           return QVariant();
00508         case columnData:
00509           temp.setValue<PropertyValue>(stream->relayPort());
00510           return temp;
00511       };
00512       break;
00513     }
00514 
00515   /* No "default:"! This way we get a compiler warning when one day
00516   *  the enum type has more items and we forget to implement this here. */
00517 
00518   };
00519   return QVariant();  // Return an invalid QVariant if the given "column" was invalid.
00520 }
00521 
00522 QList<radioStation *> stationlistModel::helper_listOfAllStreams(stationlistItem *parentItem)
00523 {
00524   QList<radioStation *> list;
00525   if (parentItem->type() == stationlistItem::stream) {
00526     list.append(parentItem->streamObject());
00527   } else {
00528     for (int i = 0; i < parentItem->childCount(); ++i) {
00529       list << helper_listOfAllStreams(parentItem->child(i));
00530     };
00531   };
00532   return list;
00533 }
00534 
00535 void stationlistModel::recalculate_numberOfActiveStreams_and_bandwidth()
00536 {
00537   // variables
00538   int i;
00539   int temp_numberOfActiveStreams = 0;
00540   quint64 temp_bandwidth = 0;
00541   QList<radioStation *> m_stationlist = helper_listOfAllStreams(rootItem);
00542 
00543   // code
00544 
00545   // calculate new values
00546   for (i=0; i < m_stationlist.size(); ++i) {
00547     if (m_stationlist.at(i)->status().internalValue.value<ripping::statusType>() != ripping::idle) {
00548       temp_numberOfActiveStreams++;
00549       if (m_stationlist.at(i)->bitrate().type == PropertyValue::value) {
00550         temp_bandwidth = temp_bandwidth +
00551                              m_stationlist.at(i)->bitrate().internalValue.toULongLong();
00552       };
00553     };
00554   };
00555 
00556   // actualize properties if necessary
00557   if (internal_numberOfActiveStreams != temp_numberOfActiveStreams) {
00558     internal_numberOfActiveStreams = temp_numberOfActiveStreams;
00559     emit numberOfActiveStreamsChanged();
00560     if (internal_numberOfActiveStreams == 0) {
00561       emit numberOfActiveStreamsIsZero();
00562     };
00563   };
00564   if (internal_bandwidth != temp_bandwidth) {
00565     internal_bandwidth = temp_bandwidth;
00566     emit bandwidthChanged();
00567   };
00568 }
00569 
00570 QModelIndex stationlistModel::modelindexOfItem(stationlistItem *item, int column)
00571 {
00572   if (item == rootItem || item == 0) {
00573     return QModelIndex();
00574   } else {
00575     return index(item->row(), column, modelindexOfItem(item->parent(), 0));
00576   };
00577 }
00578 
00579 void stationlistModel::reloadStreamName(void *stationIndex)
00580 {
00581   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 0),
00582                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 0));
00583 }
00584 
00585 void stationlistModel::reloadUri(void *stationIndex)
00586 {
00587   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 1),
00588                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 1));
00589 }
00590 
00591 void stationlistModel::reloadStatus(void *stationIndex)
00592 {
00593   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 2),
00594                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 2));
00595   emit statusChanged();
00596 }
00597 
00598 void stationlistModel::reloadSong(void *stationIndex)
00599 {
00600   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 3),
00601                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 3));
00602 }
00603 
00604 void stationlistModel::reloadDataSize(void *stationIndex)
00605 {
00606   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 4),
00607                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 4));
00608 }
00609 
00610 void stationlistModel::reloadBitrate(void *stationIndex)
00611 {
00612   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 5),
00613                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 5));
00614 }
00615 
00616 void stationlistModel::reloadMetaInterval(void *stationIndex)
00617 {
00618   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 6),
00619                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 6));
00620 }
00621 
00622 void stationlistModel::reloadMetaInterval_milliSeconds(void *stationIndex)
00623 {
00624   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 7),
00625                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 7));
00626 }
00627 
00628 void stationlistModel::reloadServerName(void *stationIndex)
00629 {
00630   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 8),
00631                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 8));
00632 }
00633 
00634 void stationlistModel::reloadRelayPort(void *stationIndex)
00635 {
00636   emit dataChanged(modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 9),
00637                    modelindexOfItem(static_cast<stationlistItem *>(stationIndex), 9));
00638   emit relayportChanged();
00639 }
00640 
00641 QVariant stationlistModel::headerData(int section, Qt::Orientation orientation, int role) const
00642 {
00643      if (orientation EQUAL Qt::Vertical) {
00644        if (role == Qt::DisplayRole) {
00645          return (int(section+1));
00646        } else {
00647          return QVariant();
00648        };
00649      } else {
00650        switch (role) {
00651          case Qt::DisplayRole:
00652            return columnInfo(columnHeaderTitle, section);
00653          case Qt::ToolTipRole:
00654            return columnInfo(columnHeaderToolTip, section);
00655          case Qt::WhatsThisRole:
00656            return columnInfo(columnHeaderWhatsThis, section);
00657          default:
00658            return QVariant();  // other "display roles" aren't supported.
00659        };
00660      };
00661      return QVariant();  // This point should never be reached. It just exists
00662                          // to be sure to deliver a return value, also when
00663                          // I introduce new bugs in the code above.
00664 }
00665 
00666 QVariant stationlistModel::data(const QModelIndex &index, int role) const
00667 {
00668   //variables
00669   QVariant returnValue;
00670   stationlistItem *indexItem;
00671 
00672   //code
00673   if ((index.model() EQUAL this) AND (index.isValid())) {
00674     indexItem = static_cast<stationlistItem *>(index.internalPointer());
00675     if (indexItem->type() == stationlistItem::stream) {
00676       switch (role) {
00677         case Qt::DisplayRole:
00678           returnValue = columnInfo(columnData, index.column(), indexItem->streamObject())
00679                           .value<PropertyValue>().formatedValue;
00680           break;
00681         case Qt::ToolTipRole:
00682           returnValue =
00683             columnInfo(columnData, index.column(), indexItem->streamObject()).
00684               value<PropertyValue>().toolTip;
00685           break;
00686         case Qt::WhatsThisRole:
00687           returnValue =
00688             columnInfo(columnData, index.column(), indexItem->streamObject()).
00689               value<PropertyValue>().whatsThis;
00690           break;
00691         case Qt::TextAlignmentRole:
00692           returnValue = static_cast<int>(
00693             columnInfo(columnData, index.column(), indexItem->streamObject()).
00694               value<PropertyValue>().formatedValueAlignment);
00695           break;
00696         case Qt::DecorationRole:
00697           if (index.column() == 0) {
00698             returnValue = KIcon("audio-x-generic");
00699           };
00700           break;
00701         default: // other "display roles" aren't supported.
00702           returnValue = QVariant();
00703           break;
00704       };
00705     } else {
00706       if (role == Qt::DisplayRole AND index.column() == 0) {
00707         returnValue = indexItem->folderName();
00708       } else if (role == Qt::DecorationRole AND index.column() == 0) {
00709         returnValue = KIcon("folder");
00710       };
00711     };
00712   };
00713 
00714   //return
00715   return returnValue;
00716 }
00717 
00718 void stationlistModel::sort(int column, Qt::SortOrder order)
00719 {
00720   // pre-check
00721   if (column < 0 || column >= columnCount()) {  // nothing to do
00722     return;
00723   };
00724 
00725   // variables
00726   PropertyValue temp;
00727   QList<radioStation *> sorted_list;
00728   QModelIndexList temp_indexList;
00729   QList<stationlistItem *> selection;
00730 
00731   // code
00732 
00733   // save the selection
00734   /*temp_indexList = view->selectionModel()->selectedRows();
00735   foreach (const QModelIndex & tempModelIndex, temp_indexList) {
00736     selection.append(static_cast<stationlistItem *>(tempModelIndex.internalPointer());
00737   };*/
00738 
00739   // sort
00740   sortChildItems(rootItem, column, order);
00741 
00742   // restore selection
00743 
00744   // save the new sort order
00745   settings_general::setSortingAscendingly(order == Qt::AscendingOrder);
00746   settings_general::setSortByColumn(column);
00747   settings_general::self()->writeConfig();
00748 }
00749 
00750 void stationlistModel::helper_moveItems(const QModelIndex &oldParent,
00751                                         int first,
00752                                         int last,
00753                                         const QModelIndex &newParent,
00754                                         int newRow)
00755 {
00756   QList<stationlistItem *> itemList = helper_removeItems(oldParent, first, last);
00757   helper_insertItems(itemList, newParent, newRow);
00758 }
00759 
00760 void stationlistModel::sortChildItems(stationlistItem *parent, int column, Qt::SortOrder order)
00761 {
00762   // consts
00763   const int childCount = parent->childCount();
00764   const int childCount_1 = childCount -1;
00765   QModelIndex parentIndex = modelindexOfItem(parent, 0);
00766 
00767   // variables
00768   int i;
00769 
00770   // code
00771   for (i = 0; i < childCount_1; ++i) {
00772     for (int j = i + 1; j < childCount; ++j) {
00773       if (helper_firstIsAfterSecond(parent->child(i), parent->child(j), column, order)) {
00774         helper_moveItems(parentIndex, j, j, parentIndex, i);
00775       };
00776     };
00777   };
00778   for (i = 0; i < childCount; ++i) {
00779     sortChildItems(parent->child(i), column, order);
00780   };
00781 }
00782 
00783 bool stationlistModel::helper_isNumericValue(const QVariant & value)
00784 {
00785   // variables
00786   QMetaType::Type type;
00787 
00788   // code
00789   type = static_cast<QMetaType::Type>(value.type());
00790   return (type == QMetaType::Int ||
00791           type == QMetaType::UInt ||
00792           type == QMetaType::Double ||
00793           type == QMetaType::Long ||
00794           type == QMetaType::LongLong ||
00795           type == QMetaType::Short ||
00796           type == QMetaType::Char ||
00797           type == QMetaType::ULong ||
00798           type == QMetaType::ULongLong ||
00799           type == QMetaType::UShort ||
00800           type == QMetaType::UChar ||
00801           type == QMetaType::Float ||
00802           // I don't understand why QString() is necessary, but without it doesn't work.
00803           value.typeName() == QString("ripping::statusType"));
00804 }
00805 
00806 qlonglong stationlistModel::helper_toLongLong(const PropertyValue & value)
00807 {
00808   // I don't understand why QString() is necessary, but without it doesn't work
00809   if (value.internalValue.typeName() == QString("ripping::statusType")) {
00810     return value.internalValue.value<ripping::statusType>();
00811   } else {
00812     return value.internalValue.toLongLong();
00813   };
00814 }
00815 
00816 bool stationlistModel::helper_firstIsAfterSecond(stationlistItem *firstItem,
00817                                                  stationlistItem *secondItem,
00818                                                  int column,
00819                                                  Qt::SortOrder order)
00820 {
00821   if (firstItem->type() == stationlistItem::stream) {
00822     if (secondItem->type() == stationlistItem::stream) {  // both are streams
00823       return helper_firstIsAfterSecond(
00824         columnInfo(columnData, column, firstItem->streamObject()).value<PropertyValue>(),
00825         columnInfo(columnData, column, secondItem->streamObject()).value<PropertyValue>(),
00826         order);
00827     } else {  // first is stream, second is folder
00828       return true;
00829     };
00830   } else {
00831     if (secondItem->type() == stationlistItem::stream) {  // first is folder, second is stream
00832       return false;
00833     } else {  // both are folders
00834       if (order == Qt::AscendingOrder) {
00835         return (QString::localeAwareCompare(firstItem->folderName(), secondItem->folderName()) >=
00836                   0);
00837       } else {
00838         return (QString::localeAwareCompare(firstItem->folderName(), secondItem->folderName()) <=
00839                   0);
00840       };
00841     };
00842   };
00843   kDebug() << "Function hasn't calculated a return value. TRUE is returned to prevent a crash.";
00844   return true;
00845 }
00846 
00847 bool stationlistModel::helper_firstIsAfterSecond(const PropertyValue & firstValue,
00848                                                  const PropertyValue & secondValue,
00849                                                  Qt::SortOrder order)
00850 {
00851   // code
00852   if (order == Qt::AscendingOrder) {
00853       switch (firstValue.type) {
00854           case PropertyValue::unset:
00855               return (secondValue.type == PropertyValue::unset);
00856           case PropertyValue::value:
00857               if (secondValue.type == PropertyValue::unset) {
00858                   return true;
00859               } else if (secondValue.type == PropertyValue::error) {
00860                   return false;
00861               } else {
00862                   if (helper_isNumericValue(firstValue.internalValue) &&
00863                       helper_isNumericValue(secondValue.internalValue)) {
00864                       return helper_toLongLong(firstValue) >= helper_toLongLong(secondValue);
00865                   } else {
00866                       return QString::localeAwareCompare(firstValue.formatedValue,
00867                                                          secondValue.formatedValue) >= 0;
00868                   };
00869               };
00870           case PropertyValue::error:
00871               if (secondValue.type == PropertyValue::error) {
00872                   return QString::localeAwareCompare(firstValue.formatedValue,
00873                                                      secondValue.formatedValue) >= 0;
00874               } else {
00875                   return true;
00876               };
00877       };
00878   } else {
00879       switch (firstValue.type) {
00880           case PropertyValue::unset:
00881               return true;
00882           case PropertyValue::value:
00883               if (secondValue.type == PropertyValue::unset) {
00884                   return false;
00885               } else if (secondValue.type == PropertyValue::error) {
00886                   return true;
00887               } else {
00888                   if (helper_isNumericValue(firstValue.internalValue) &&
00889                       helper_isNumericValue(secondValue.internalValue)) {
00890                       return helper_toLongLong(firstValue) <= helper_toLongLong(secondValue);
00891                   } else {
00892                       return QString::localeAwareCompare(firstValue.formatedValue,
00893                                                          secondValue.formatedValue) <= 0;
00894                   };
00895               };
00896           case PropertyValue::error:
00897               if (secondValue.type == PropertyValue::error) {
00898                   return QString::localeAwareCompare(firstValue.formatedValue,
00899                                                      secondValue.formatedValue) <= 0;
00900               } else {
00901                   return false;
00902               };
00903       };
00904   };
00905   kDebug() << "Function hasn't calculated a return value. TRUE is returned to prevent a crash.";
00906   return true;
00907 }
00908 
00909 bool stationlistModel::helper_isInTree(stationlistItem *child, stationlistItem *parent)
00910 {
00911   if (child == 0 OR parent == 0) {  // test if both pointern are not 0
00912     return false;
00913   };
00914   if (child->parent() == 0) {  // test if "child" has a parent
00915     return false;
00916   };
00917   if (child->parent() == parent) {
00918     return true;
00919   } else {
00920     return helper_isInTree(child->parent(), parent);
00921   };
00922 }
00923 
00924 QList<stationlistItem *> stationlistModel::helper_removeItems(const QModelIndex &parent,
00925                                                               int first,
00926                                                               int last)
00927 {
00928   // variables
00929   QList<stationlistItem *> returnValue;
00930   stationlistItem *parentItem = item(parent);
00931 
00932   // code
00933   beginRemoveRows(parent, first, last);
00934   for (int i = last; i >= first; --i) {
00935     returnValue.prepend(parentItem->child(i));
00936     returnValue.first()->detach();
00937   };
00938   endRemoveRows();
00939   return returnValue;
00940 }
00941 
00942 void stationlistModel::helper_insertItem(stationlistItem * item,
00943                                          const QModelIndex &parent,
00944                                          int row)
00945 {
00946   QList<stationlistItem *> itemList;
00947   itemList.append(item);
00948   helper_insertItems(itemList, parent, row);
00949 }
00950 
00951 void stationlistModel::helper_insertItems(QList<stationlistItem *> itemList,
00952                                           const QModelIndex &parent,
00953                                           int row)
00954 {
00955   // variables
00956   stationlistItem *parentItem = item(parent);
00957 
00958   // code
00959   beginInsertRows(parent, row, row + itemList.size() - 1);
00960   for (int i = 0; i < itemList.size(); ++i) {
00961     parentItem->insertChild(itemList.at(i), row + i);
00962   };
00963   endInsertRows();
00964 }
00965 
00966 stationlistItem *stationlistModel::helper_createStreamItem(radioStation *stream)
00967 {
00968   // variables
00969   stationlistItem *returnValue;
00970 
00971   // code
00972   returnValue = new stationlistItem(stream);
00973   stream->setIndex(returnValue);
00974   helper_connectSignalsAndSlots(stream);
00975   return returnValue;
00976 }
00977 
00978 void stationlistModel::helper_addNewFolder(const QModelIndex & index)
00979 {
00980   // variables
00981   int exitCode;
00982   stationlistItem *new_item, *parent_item;
00983   folderPropertiesDialog *dialog;
00984 
00985   // code
00986   dialog = new folderPropertiesDialog();
00987   exitCode = dialog->exec();
00988   if (exitCode == QDialog::Accepted) {  // insert the new station in our model
00989     new_item = new stationlistItem(dialog->centralWidget->text());
00990     parent_item = rootItem;
00991     if (index.isValid()) {
00992       if (static_cast<stationlistItem *>(index.internalPointer())->type() ==
00993             stationlistItem::folder) {
00994         parent_item = static_cast<stationlistItem *>(index.internalPointer());
00995       };
00996     };
00997     helper_insertItem(new_item,
00998                       modelindexOfItem(parent_item, 0),
00999                       parent_item->childCount());
01000     helper_selectAndScrollTo(QModelIndexList() << modelindexOfItem(new_item, 0));
01001     helper_writeStationList();
01002   };
01003 }
01004 
01005 void stationlistModel::helper_addNewStation(const QModelIndex & index)
01006 {
01007   // variables
01008   radioStation *m_newStation;
01009   int exitCode;
01010   stationlistItem *new_item, *parent_item;
01011 
01012   // code
01013   m_newStation = new radioStation(this, m_mainWidget, QString());
01014   exitCode = m_newStation->execSettingsDialogWithoutApplyButton();
01015   if (exitCode == QDialog::Accepted) {  // insert the new station in our model
01016     new_item = helper_createStreamItem(m_newStation);
01017     parent_item = rootItem;
01018     if (index.isValid()) {
01019       if (static_cast<stationlistItem *>(index.internalPointer())->type() ==
01020             stationlistItem::folder) {
01021         parent_item = static_cast<stationlistItem *>(index.internalPointer());
01022       };
01023     };
01024     helper_insertItem(new_item,
01025                       modelindexOfItem(parent_item, 0),
01026                       parent_item->childCount());
01027     helper_selectAndScrollTo(QModelIndexList() << modelindexOfItem(new_item, 0));
01028     helper_writeStationList();
01029   } else {
01030     helper_deleteRadiostationobjectAndRemoveConfigfiles(m_newStation);
01031   };
01032 }
01033 
01034 void stationlistModel::helper_selectAndScrollTo(const QModelIndexList & modelIndexList)
01035 {
01036   if (modelIndexList.size() > 0) {
01037     view->clearSelection();
01038     foreach (const QModelIndex & m_index, modelIndexList) {
01039       view->selectionModel()->select(m_index,
01040                                      QItemSelectionModel::Select | QItemSelectionModel::Rows);
01041       view->scrollToRow(m_index);  // necessary to expand all selected items
01042     };
01043   };
01044 }
01045 
01046 void stationlistModel::addNewStationInFolder()
01047 {
01048   QModelIndexList m_list = view->selectionModel()->selectedRows();
01049   if (m_list.size() == 1) {
01050     helper_addNewStation(m_list.at(0));
01051   } else {
01052     helper_addNewStation(QModelIndex());
01053   };
01054 }
01055 
01056 void stationlistModel::addNewFolderInFolder()
01057 {
01058   QModelIndexList m_list = view->selectionModel()->selectedRows();
01059   if (m_list.size() == 1) {
01060     helper_addNewFolder(m_list.at(0));
01061   } else {
01062     helper_addNewFolder(QModelIndex());
01063   };
01064 }
01065 
01066 void stationlistModel::addNewStation()
01067 {
01068   helper_addNewStation(QModelIndex());
01069 }
01070 
01071 void stationlistModel::addNewFolder()
01072 {
01073   helper_addNewFolder(QModelIndex());
01074 }
01075 
01076 void stationlistModel::helper_deleteRadiostationobjectAndRemoveConfigfiles(stationlistItem *item)
01077 {
01078   if (item->type() == stationlistItem::stream) {
01079     helper_deleteRadiostationobjectAndRemoveConfigfiles(item->streamObject());
01080   } else {
01081     for (int i = 0; i < item->childCount(); ++i) {
01082       helper_deleteRadiostationobjectAndRemoveConfigfiles(item->child(i));
01083     }
01084   };
01085 }
01086 
01087 void stationlistModel::helper_deleteRadiostationobjectAndRemoveConfigfiles(radioStation *station)
01088 {
01089   QString m_filename = station->fullConfigFileName();
01090   delete station;
01091   // We must wait with constructing QFile until the station
01092   // object has been deleted (we shouldn't open a file that's yet/still open!).
01093   QFile theFile(m_filename);
01094   theFile.remove();
01095 }
01096 
01097 stationlistItem *stationlistModel::item(const QModelIndex & index) const
01098 {
01099   if (index.isValid()) {
01100     return static_cast<stationlistItem *>(index.internalPointer());
01101   } else {
01102     return rootItem;
01103   };
01104 }
01105 
01106 bool stationlistModel::removeRows(int row, int count, const QModelIndex & parent)
01107 {
01108   // variables
01109   stationlistItem *parentItem = item(parent);
01110   QList<stationlistItem *> itemList;
01111 
01112   // code
01113   if (count == 0) {
01114     return true;
01115   };
01116   // test if the values are valid (if not, QList.at() would crash!):
01117   if ((row >= 0) &&
01118       (count > 0) &&
01119       ((row + count - 1) < parentItem->childCount())) {
01120     // detach the corresponding items from the model
01121     itemList = helper_removeItems(parent, row, row + count - 1);
01122     // delete the items
01123     foreach (stationlistItem *item, itemList) {
01124       helper_deleteRadiostationobjectAndRemoveConfigfiles(item);
01125       delete item;
01126     };
01127     // synchronize the general config file with our internal list:
01128     helper_writeStationList();
01129     return true;
01130   } else {
01131     return false;
01132   };
01133 }
01134 
01135 void stationlistModel::writeItemToFile(stationlistItem *item, QXmlStreamWriter &file)
01136 {
01137   if (item->type() == stationlistItem::stream) {
01138     file.writeTextElement("stream", item->streamObject()->configFileName());
01139   } else {
01140     file.writeStartElement("folder");
01141     file.writeAttribute("name", item->folderName());
01142     if (view->isExpanded(modelindexOfItem(item, 0))) {
01143       file.writeAttribute("expanded", "true");
01144     };
01145     for (int i = 0; i < item->childCount(); ++i) {
01146       writeItemToFile(item->child(i), file);
01147     };
01148     file.writeEndElement();
01149   };
01150 }
01151 
01152 inline void stationlistModel::helper_writeStationList()
01153 {
01154   // variables
01155   KTemporaryFile tempfile;
01156   QXmlStreamWriter writer;
01157 
01158   // code
01159   tempfile.open();
01160   writer.setDevice(&tempfile);
01161   writer.setAutoFormatting(true);
01162   writer.writeStartDocument();
01163   writer.writeStartElement("stationlist");
01164   for (int i = 0; i < rootItem->childCount(); ++i) {
01165     writeItemToFile(rootItem->child(i), writer);
01166   };
01167   writer.writeEndElement();  // stationlist
01168   writer.writeEndDocument();
01169   tempfile.close();
01170   KIO::FileCopyJob *copyjob = KIO::file_move(tempfile.fileName(),
01171                                     helper_stationlistXmlFilepath(),
01172                                     -1,
01173                                     KIO::HideProgressInfo | KIO::Overwrite);
01174   KIO::NetAccess::synchronousRun(copyjob, 0);
01175 }
01176 
01177 void stationlistModel::record()
01178 {
01179   foreach (radioStation *stream, internal_selectedStreams) {
01180     stream->startStreamripper();
01181   };
01182 }
01183 
01184 void stationlistModel::stopRecording()
01185 {
01186   foreach (radioStation *stream, internal_selectedStreams) {
01187     stream->shutDown();
01188   };
01189 }
01190 
01191 void stationlistModel::showConfigDialog()
01192 {
01193   QModelIndexList list = view->selectionModel()->selectedRows();
01194   if (list.size() == 1) {
01195     stationlistItem *item = static_cast<stationlistItem *>(list.at(0).internalPointer());
01196     if (item->type() == stationlistItem::stream) {
01197       item->streamObject()->showSettingsDialogWithApplyButton();
01198     } else {
01199       QPointer<folderPropertiesDialog> dialog = new folderPropertiesDialog(view);
01200       dialog->centralWidget->setText(item->folderName());
01201       int result = dialog->exec();
01202       // "dialog" coult be deleted during exec() by DBus or orthers - see
01203       // http://www.kdedevelopers.org/node/3919 for details. Therefore we use QPointer and check
01204       // if the object still exists.
01205       if (result == QDialog::Accepted && !dialog.isNull()) {
01206         item->setFolderName(dialog->centralWidget->text());
01207         reloadStreamName(item);
01208       };
01209       delete dialog;  // This is always safe, because "dialog" is a QPointer and if it was yet
01210       // deleted, that it was set to 0. Deleting 0 is always safe.
01211     };
01212   };
01213 }
01214 
01215 quint64 stationlistModel::bandwidth() const
01216 {
01217   return internal_bandwidth;
01218 }
01219 
01220 int stationlistModel::numberOfActiveStreams() const
01221 {
01222   return internal_numberOfActiveStreams;
01223 }
01224 
01225 void stationlistModel::rememberListOfStreamsWhichTheUserWantsToRip_ifNotYetDone()
01226 {
01227   if (m_listOfStreamsOfWhichTheUserWantsThatTheyRip == 0) {
01228     int i;
01229     QList<radioStation *> m_stationlist = helper_listOfAllStreams(rootItem);
01230     const int m_stationlist_size = m_stationlist.size();
01231     m_listOfStreamsOfWhichTheUserWantsThatTheyRip = new QStringList();
01232     for (i=0; i < m_stationlist_size; i++) {
01233       if (m_stationlist.at(i)->doesTheUserWantsThatTheStreamIsRipping()) {
01234         m_listOfStreamsOfWhichTheUserWantsThatTheyRip->
01235           append(m_stationlist.at(i)->configFileName());
01236       };
01237     };
01238   };
01239 }
01240 
01241 bool stationlistModel::queryClose()
01242 {
01243   // variables
01244   int i;
01245 
01246   // code
01247   helper_writeStationList();
01248   rememberListOfStreamsWhichTheUserWantsToRip_ifNotYetDone();
01249 
01250   // start shutdown for all processes
01251   if (numberOfActiveStreams() > 0) {
01252     QList<radioStation *> m_stationlist = helper_listOfAllStreams(rootItem);
01253     for (i = 0; i < m_stationlist.size(); ++i) {
01254       m_stationlist.at(i)->shutDown();
01255     };
01256   };
01257 
01258   /* Now we test a second time if there are still running streams. (This could
01259   have changed because we have shutted down before.) If there remain running
01260   streams (shutting down takes some seconds), we display a "busy" dialog until
01261   the shutdown is finished. */
01262   if (numberOfActiveStreams() > 0) {
01263     QPointer<KProgressDialog> m_dialog = new KProgressDialog(m_mainWidget,
01264       i18nc("@title:window", "Saving files..."),
01265       i18nc("@label", "Please wait while last files are saved..."));
01266     connect(this, SIGNAL(numberOfActiveStreamsIsZero()), m_dialog, SLOT(reject()));
01267     // min AND max = 0 means: show "busy" indicator instead of progress:
01268     m_dialog->progressBar()->setMinimum(0);
01269     m_dialog->progressBar()->setMaximum(0);
01270     m_dialog->setModal(true);
01271     m_dialog->setAutoClose(false);
01272     m_dialog->setMinimumDuration(0);
01273     // The following line hasn't any effect because of a bug in KProgressDialog.
01274     // Is fixed in KDE 4.2 (and maybe yet in 4.1.4).
01275     m_dialog->setButtonText(i18nc("@action:button", "Quit without saving"));
01276     m_dialog->exec();
01277     delete m_dialog;
01278   };
01279 
01280   return true;
01281 }
01282 
01283 void stationlistModel::saveProperties(KConfigGroup & m_configGroup)
01284 {
01285   helper_writeStationList();
01286   rememberListOfStreamsWhichTheUserWantsToRip_ifNotYetDone();
01287   m_configGroup.writePathEntry("streamsToResume",
01288                                 * m_listOfStreamsOfWhichTheUserWantsThatTheyRip);
01289   // No need to save the changes with sync() - KMainWindow and friends take care of this.
01290 }
01291 
01292 void stationlistModel::readProperties(const KConfigGroup & m_configGroup)
01293 {
01294   // variables
01295   QStringList temp_stringList;
01296   int i;
01297 
01298   // code
01299   temp_stringList = m_configGroup.readPathEntry("streamsToResume", temp_stringList);
01300   QList<radioStation *> m_stationlist = helper_listOfAllStreams(rootItem);
01301   const int m_stationlist_size = m_stationlist.size();
01302   for (i = 0; i < m_stationlist_size; ++i) {
01303     if (temp_stringList.contains(m_stationlist.at(i)->configFileName())) {
01304       m_stationlist.at(i)->startStreamripper();
01305     };
01306   };
01307 }
01308 
01309 QList<QUrl> stationlistModel::helper_convertToUrl(const QMimeData *data)
01310 {
01311   // variables
01312   QList<QUrl> returnValue;
01313 
01314   // code
01315   if (data->hasUrls()) {
01316     returnValue = data->urls();
01317   } else if (data->hasText()) {
01318     QStringList temp = data->text().split(QRegExp("\\s"), QString::SkipEmptyParts);
01319     foreach (const QString & singleString, temp) {
01320       returnValue.append(singleString);
01321     };
01322   };
01323   int i = 0;
01324   while (i < returnValue.size()) {
01325     if (returnValue.at(i).isValid() && (!returnValue.at(i).isEmpty())) {
01326       ++i;
01327     } else {
01328       returnValue.removeAt(i);
01329     };
01330   };
01331 
01332   return returnValue;
01333 }
01334 
01335 void stationlistModel::paste()
01336 {
01337   dropMimeData(QApplication::clipboard()->mimeData(),
01338                Qt::CopyAction,
01339                0,
01340                0,
01341                QModelIndex());
01342 }
01343 
01344 void stationlistModel::pasteSelection(const QModelIndex & index)
01345 {
01346   dropMimeData(QApplication::clipboard()->mimeData(QClipboard::Selection),
01347                Qt::CopyAction,
01348                index.row(),
01349                0,
01350                index.parent());
01351 }
01352 
01353 bool stationlistModel::dropMimeData(const QMimeData *data,
01354                                     Qt::DropAction action,
01355                                     int row,
01356                                     int,
01357                                     const QModelIndex &parent)
01358 {
01359   if (action == Qt::IgnoreAction) {
01360     return true;
01361   };
01362 
01363   if (!(action == Qt::CopyAction)) {
01364     return false;
01365   };
01366 
01367   QList<QUrl> urlList = helper_convertToUrl(data);
01368 
01369   if (urlList.isEmpty()) {
01370     return false;
01371   } else {
01372     // variables
01373     QPointer<radioStation> m_newStation;
01374     QList<stationlistItem *> m_itemList;
01375     QModelIndex m_parent;
01376     QModelIndexList m_modelIndexList;
01377 
01378     // code
01379     for (int i = 0; i < urlList.size(); ++i) {
01380       m_newStation = new radioStation(this, m_mainWidget, QString());
01381       m_newStation->setServerUri(urlList.at(i));
01382       m_itemList.append(helper_createStreamItem(m_newStation));
01383     };
01384 
01385     if (index(row, 0, parent).isValid()) {  // QModelIndex::child() returns an invalid index,
01386       m_parent = index(row, 0, parent);     // so we use index() to get the child.
01387     } else {
01388       m_parent = parent;
01389     };
01390     if (!(item(m_parent)->type() == stationlistItem::folder)) {
01391       row = m_parent.row();
01392       m_parent = m_parent.parent();
01393     } else {
01394       row = item(m_parent)->childCount();
01395     };
01396 
01397     helper_insertItems(m_itemList, m_parent, row);
01398     foreach (stationlistItem *itemInList, m_itemList) {
01399       m_modelIndexList.append(modelindexOfItem(itemInList, 0));
01400     };
01401     helper_selectAndScrollTo(m_modelIndexList);
01402     // TODO apply sorting?
01403     helper_writeStationList();
01404     return true;
01405   };
01406 
01407   return false;  // safety fallback
01408 }
01409 
01410 Qt::ItemFlags stationlistModel::flags(const QModelIndex & index) const
01411 {
01412   return (Qt::ItemIsDropEnabled | QAbstractItemModel::flags(index));
01413 }
01414 
01415 QStringList stationlistModel::mimeTypes () const
01416 {
01417   QStringList value;
01418   value << "text/plain" << "text/uri-list";
01419   return value;
01420 }
01421 
01422 void stationlistModel::enableListeningIn()
01423 {
01424   QModelIndexList actuallySelectedRows = view->selectionModel()->selectedRows();
01425   if (actuallySelectedRows.size() == 1) {
01426     stationlistItem *myItem =
01427       static_cast<stationlistItem *>(actuallySelectedRows.at(0).internalPointer());
01428     if (myItem->type() == stationlistItem::stream) {
01429       listen.setStation(myItem->streamObject());
01430       return;
01431     };
01432   };
01433   listen.setStation(0);
01434 }
01435 
01436 void stationlistModel::disableListeningIn()
01437 {
01438   listen.setStation(0);
01439 }
01440 
01441 QModelIndex stationlistModel::parent(const QModelIndex & index) const
01442 {
01443   if (!index.isValid()) {
01444     return QModelIndex();
01445   };
01446 
01447   stationlistItem *childItem = static_cast<stationlistItem *>(index.internalPointer());
01448   stationlistItem *parentItem = childItem->parent();
01449   if (parentItem == rootItem) {
01450     return QModelIndex();
01451   } else {
01452     return createIndex(parentItem->row(), 0, parentItem);
01453   };
01454 }
01455 
01456 QModelIndex stationlistModel::index(int row, int column, const QModelIndex & parent) const
01457 {
01458   // variables
01459   stationlistItem *parentItem = item(parent);
01460   stationlistItem *childItem;
01461 
01462   // code
01463   if (!hasIndex(row, column, parent)) {
01464     return QModelIndex();
01465   };
01466 
01467   childItem = parentItem->child(row);
01468   if (childItem) {
01469     return createIndex(row, column, childItem);
01470   } else {
01471     return QModelIndex();
01472   };
01473 }
01474 
01475 bool stationlistModel::helper_hasStreams(stationlistItem *item)
01476 {
01477   bool returnValue = false;
01478   int i = 0;
01479   if (item->type() == stationlistItem::folder) {
01480     while (!returnValue && i < item->childCount()) {
01481       returnValue = helper_hasStreams(item->child(i));
01482       ++i;
01483     };
01484   } else {
01485     returnValue = true;
01486   };
01487   return returnValue;
01488 }
01489 
01490 void stationlistModel::recalculateSelectedStreams()
01491 {
01492   // variables
01493   const QModelIndexList indexList = view->selectionModel()->selectedRows();
01494 
01495   // code
01496   internal_selectedStreams.clear();
01497   foreach (const QModelIndex &index, indexList) {
01498     internal_selectedStreams +=
01499       helper_listOfAllStreams(static_cast<stationlistItem *>(index.internalPointer()));
01500   };
01501   for (int i = 0; i < internal_selectedStreams.size() - 1; ++i) {
01502     for (int j = i + 1; j < internal_selectedStreams.size(); ++j) {
01503       if (internal_selectedStreams.at(i) == internal_selectedStreams.at(j)) {
01504         internal_selectedStreams.removeAt(j);
01505       };
01506     };
01507   };
01508   emit selectedStreamsChanged();
01509 }
01510 
01511 QList<radioStation *> stationlistModel::selectedStreams() const
01512 {
01513   return internal_selectedStreams;
01514 }

doxygen