radiostation.cpp

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2008  Tim Fechtner < urwald at users dot sourceforge dot net >
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 "radiostation.h"
00022 
00023 #include <QFileInfo>
00024 #include <KStandardDirs>
00025 #include <KConfig>
00026 #include <KTemporaryFile>
00027 #include "settings_general.h"
00028 
00029 #define AND  &&
00030 #define OR  ||
00031 #define NOT  !
00032 #define EQUAL  ==
00033 
00034 radioStation::radioStation(QObject *parent,
00035                            QWidget *mainWidget,
00036                            const QString & configFileName) : ripping(parent)
00037 {
00038   m_mainWidget = mainWidget;
00039   helper_setupConfigSystem(configFileName);
00040   helper_write_properties_from_file_to_class_ripping();
00041 }
00042 
00043 radioStation::radioStation(QObject *parent,
00044                            QWidget *mainWidget,
00045                            const QString & configFileName,
00046                            qlonglong index) : ripping(parent)
00047 {
00048   setIndex(index);
00049   m_mainWidget = mainWidget;
00050   helper_setupConfigSystem(configFileName);
00051   helper_write_properties_from_file_to_class_ripping();
00052 }
00053 
00054 void radioStation::helper_write_properties_from_file_to_class_ripping()
00055 {
00056   ripping::setBitrate(config_skeleton->info_bitrate());
00057   ripping::setMetaInterval(config_skeleton->info_metaInterval());
00058   ripping::setServerName(config_skeleton->info_serverName());
00059   ripping::setStreamName(config_skeleton->info_streamName());
00060   emit uriChanged(index(), formatedUri(config_skeleton->serverUri()));
00061 }
00062 
00063 radioStation::~radioStation()
00064 {
00065   delete config_skeleton;  /*  We have to delete the object on which config_skeleton
00066     points to - _befor_ deleting the object shared_config points on because the first
00067     makes use of the second. As the object shared_config points on is deleted when it's
00068     pointer (shared_config is a special pointer managing this) is deleted (and that's
00069     done - as the pointer is a member of this class - after the descturctor call) we
00070     can make sure by deleting config_skeleton explicitly here that the object config_skeleton
00071     points on is deleted _befor_ the object shared_config points on. I don't want to
00072     relay on the QObject-parentship-system because I don't know _when_ exactly the child
00073     object is deleted, and this way it is sure. */
00074   delete settingsDialog;  /* Maybe there exists still a settingsDialog. (Because settingsDialog
00075     deletes itself after closing, this is only the case if the settingsDialog is still open.)
00076     Because the parent isn't this object, but m_mainWidget, the settingsDialog will not be
00077     automatically deleted by Qt and we have to do it manually. */
00078 }
00079 
00080 inline void radioStation::helper_setupConfigSystem(const QString & configFileName)
00081 {
00082   // variables
00083   QFileInfo info;
00084 
00085   // code
00086   info.setFile(configFileName);
00087   if (info.exists() && info.isFile() && info.isReadable() && info.isWritable()) {
00088     internal_configFileName = configFileName;
00089   } else {  // create a new file
00090     KTemporaryFile newConfigFile;
00091     // Maybe directories are missing in our desired path - locateLocal() will
00092     // create them if nesessary...
00093     newConfigFile.setPrefix(KStandardDirs::locateLocal("appdata", "stream_"));
00094     newConfigFile.setSuffix("_rc");
00095     newConfigFile.open();
00096     newConfigFile.setAutoRemove(false);
00097     internal_configFileName = newConfigFile.fileName();
00098     newConfigFile.close();
00099   };
00100 
00101   // setup configuration system
00102   shared_config = KSharedConfig::openConfig(internal_configFileName, KConfig::SimpleConfig);
00103   // We don't use a full-featured config system (with kiosk system and system-wide settings),
00104   // but we only read our streamConfig file.
00105   config_skeleton = new settings_stream(shared_config); // no constructor where I
00106   // can pass a parent
00107   /* config_skeleton->setParent(this) would also be a bad idea;
00108   So here I don't use QObject's parent-child-system but delete
00109   the object in the destructor. See there for further explications. */
00110 
00111   connect(config_skeleton,
00112           SIGNAL(configChanged()),
00113           this,
00114           SLOT(helper_write_properties_from_file_to_class_ripping()));
00115 }
00116 
00117 QString radioStation::configFileName() const
00118 {
00119   return internal_configFileName;
00120 }
00121 
00122 void radioStation::setStreamName(const QString & streamName)
00123 {
00124   if (config_skeleton->info_streamName() != streamName) {
00125     config_skeleton->setInfo_streamName(streamName);
00126     config_skeleton->writeConfig();
00127   };
00128 }
00129 
00130 void radioStation::setServerName(const QString & serverName)
00131 {
00132   if (config_skeleton->info_serverName() != serverName) {
00133     config_skeleton->setInfo_serverName(serverName);
00134     config_skeleton->writeConfig();
00135   };
00136 }
00137 
00138 void radioStation::setBitrate(const qint64 bitrate)
00139 {
00140   // config_skeleton makes sure that no invalid value is stored
00141   if (config_skeleton->info_bitrate() != bitrate) {
00142     config_skeleton->setInfo_bitrate(bitrate);
00143     config_skeleton->writeConfig();
00144   };
00145 }
00146 
00147 void radioStation::setMetaInterval(const qint64 metaInterval)
00148 {
00149   // config_skeleton makes sure that no value < -1 is stored...
00150   if (config_skeleton->info_metaInterval() != metaInterval) {
00151     config_skeleton->setInfo_metaInterval(metaInterval);
00152     config_skeleton->writeConfig();
00153   };
00154 }
00155 
00156 QString radioStation::serverUri() const
00157 {
00158   return config_skeleton->serverUri();
00159 }
00160 
00161 QStringList radioStation::parameterList() const
00162 {
00163   // variables
00164   QStringList parameters;
00165 
00166   //code
00167   // calculate all parameters
00168   parameters += ripping::parameterList();
00169 
00170   parameters.append(QString("-u"));
00171   parameters.append(config_skeleton->advanced_userAgentString());
00172 
00173   parameters.append(QString("--xs_offset=%1").
00174                      arg(config_skeleton->offset()));
00175 
00176   /* The following code produces a search window which length corresponds exactly
00177   to the value in the settings. When the value is odd, the last half of the window
00178   is 1 ms longer. */
00179   parameters.append(QString("--xs_search_window=%1:%2").
00180                      arg(config_skeleton->searchWindow() / 2).
00181                      arg((config_skeleton->searchWindow() / 2) +
00182                           (config_skeleton->searchWindow() % 2)));
00183 
00184   parameters.append(QString("--xs_silence_length=%1").
00185                      arg(config_skeleton->silenceWindow()));
00186 
00187   if (config_skeleton->writeSingleFile()) {
00188     parameters.append(QString("-a"));    //TODO file name schemes for single files: append here
00189   };
00190 
00191   if (config_skeleton->writeSplittedFiles()) {
00192     //TODO file name schemes splitted files
00193     parameters.append(QString("--xs_padding=%1:%2").
00194                        arg(config_skeleton->splittedFilesPostpad()).
00195                        arg(config_skeleton->splittedFilesPrepad()));
00196   } else {
00197     parameters.append(QString("-A"));
00198   };
00199 
00200   parameters.append(QString("-k"));
00201   parameters.append(QString::number(config_skeleton->skipFirstXTracks()));
00202 
00203   if (config_skeleton->advanced_useTimeout()) {
00204     parameters.append(QString("-m"));
00205     parameters.append(QString::number(config_skeleton->advanced_timeoutAfterXSeconds()));
00206   }
00207 
00208   if (config_skeleton->truncateDuplicatesInIncomplete()) {
00209     parameters.append(QString("-T"));
00210   };
00211 
00212   return parameters;
00213 }
00214 
00215 int radioStation::helper_displaySettingsDialog(const bool returnImmediately)
00216 {
00217   // variables
00218   int exitCode;
00219 
00220   // code
00221   /* If the dialog object yet exists, we can display it directly and return.
00222   (Should normally not happen, because we delete it after the use. And the dialog
00223   is modal, so the user can't open a second dialog. We do this here just to be
00224   absolutly sure.) We are using name of the config file as name of the dialog because
00225   this name is unique! */
00226   if (settingsDialog.isNull()) {
00227     settingsDialog = new settings_stream_dialog(m_mainWidget,
00228                                                 internal_configFileName,
00229                                                 config_skeleton);
00230     connect(settingsDialog,
00231              SIGNAL(finished()),
00232              settingsDialog,
00233              SLOT(deleteLater()));
00234   };
00235   if (returnImmediately) {
00236     settingsDialog->show();
00237     exitCode = KDialog::Accepted;
00238   } else {
00239     exitCode = settingsDialog->exec();
00240   };
00241   return exitCode;
00242 }
00243 
00244 void radioStation::showSettingsDialog()
00245 {
00246   helper_displaySettingsDialog(true);
00247 }
00248 
00249 int radioStation::execSettingsDialog()
00250 {
00251   return helper_displaySettingsDialog(false);
00252 }
00253 
00254 void radioStation::setServerUri(const QUrl & uri)
00255 {
00256   if (QUrl(config_skeleton->serverUri()) != uri) {
00257     // delete old metadata
00258     setBitrate(default_value_of_bitrate());
00259     setMetaInterval(default_value_of_metaInterval());
00260     setServerName(default_value_of_serverName());
00261     setStreamName(default_value_of_streamName());
00262 
00263     // save new URI
00264     config_skeleton->setServerUri(uri.toString());
00265     // notify signal is emitted automatically when config file changes...
00266     config_skeleton->writeConfig();
00267 
00268     // get new metadata
00269     updateMetaData();
00270   };
00271 }
00272 
00273 PropertyValue radioStation::uri() const
00274 {
00275   return formatedUri(config_skeleton->serverUri());
00276 }
00277 
00278 PropertyValue radioStation::formatedUri(const QString & theUri)
00279 {
00280     // variables
00281     PropertyValue temp_uri;
00282 
00283     // code
00284     temp_uri.internalValue = theUri;
00285     temp_uri.formatedValue = theUri;
00286     if (theUri.isEmpty()) {
00287       temp_uri.type = PropertyValue::unset;
00288     } else {
00289       temp_uri.type = PropertyValue::value;
00290     };
00291     // there's never a toolTip or whatsThis, so no need to clear them.
00292     return temp_uri;
00293 }
00294 
00295 QString radioStation::workingDirectory() const
00296 {
00297   return settings_general::saveDirectory();
00298 }
00299 
00300 void radioStation::updateMetaData()
00301 {
00302   delete infoCatcher;
00303   infoCatcher = new get_stream_info(this);
00304   infoCatcher->setServerUri(serverUri());
00305   connect(infoCatcher,
00306           SIGNAL(bitrateChanged(qlonglong, PropertyValue)),
00307           this,
00308           SLOT(setBitrate(qlonglong, PropertyValue)));
00309   connect(infoCatcher,
00310           SIGNAL(metaIntervalChanged(qlonglong, PropertyValue)),
00311           this,
00312           SLOT(setMetaInterval(qlonglong, PropertyValue)));
00313   connect(infoCatcher,
00314           SIGNAL(serverNameChanged(qlonglong, PropertyValue)),
00315           this,
00316           SLOT(setServerName(qlonglong, PropertyValue)));
00317   connect(infoCatcher,
00318           SIGNAL(streamNameChanged(qlonglong, PropertyValue)),
00319           this,
00320           SLOT(setStreamName(qlonglong, PropertyValue)));
00321   infoCatcher->startStreamripper();
00322 }
00323 
00324 void radioStation::setBitrate(const qlonglong, const PropertyValue & newBitrate)
00325 {
00326   setBitrate(newBitrate.internalValue.toLongLong());
00327 }
00328 
00329 void radioStation::setMetaInterval(const qlonglong,
00330                                    const PropertyValue & newMetaInterval)
00331 {
00332   setMetaInterval(newMetaInterval.internalValue.toLongLong());
00333 }
00334 
00335 void radioStation::setServerName(const qlonglong, const PropertyValue & newServerName)
00336 {
00337   setServerName(newServerName.internalValue.toString());
00338 }
00339 
00340 void radioStation::setStreamName(const qlonglong, const PropertyValue & newStreamName)
00341 {
00342   setStreamName(newStreamName.internalValue.toString());
00343 }

doxygen