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

doxygen