vidalia.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file vidalia.cpp
00013 ** \version $Id: vidalia.cpp 2981 2008-08-17 05:49:08Z edmanm $
00014 ** \brief Main Vidalia QApplication object
00015 */
00016 
00017 #include <QDir>
00018 #include <QTimer>
00019 #include <QTextStream>
00020 #include <QStyleFactory>
00021 #include <QShortcut>
00022 #include <languagesupport.h>
00023 #include <vmessagebox.h>
00024 #include <stringutil.h>
00025 #include <html.h>
00026 #include <stdlib.h>
00027 
00028 #include "vidalia.h"
00029 
00030 /* Available command-line arguments. */
00031 #define ARG_LANGUAGE   "lang"     /**< Argument specifying language.    */
00032 #define ARG_GUISTYLE   "style"    /**< Argument specfying GUI style.    */
00033 #define ARG_RESET      "reset"    /**< Reset Vidalia's saved settings.  */
00034 #define ARG_HELP       "help"     /**< Display usage informatino.       */
00035 #define ARG_DATADIR    "datadir"  /**< Directory to use for data files. */
00036 #define ARG_PIDFILE    "pidfile"  /**< Location and name of our pidfile.*/
00037 #define ARG_LOGFILE    "logfile"  /**< Location of our logfile.         */
00038 #define ARG_LOGLEVEL   "loglevel" /**< Log verbosity.                   */
00039 
00040 
00041 /* Static member variables */
00042 QMap<QString, QString> Vidalia::_args; /**< List of command-line arguments.  */
00043 QString Vidalia::_style;               /**< The current GUI style.           */
00044 QString Vidalia::_language;            /**< The current language.            */
00045 TorControl* Vidalia::_torControl = 0;  /**< Main TorControl object.          */
00046 Log Vidalia::_log;
00047 
00048 /** Catches debugging messages from Qt and sends them to Vidalia's logs. If Qt
00049  * emits a QtFatalMsg, we will write the message to the log and then abort().
00050  */
00051 void
00052 Vidalia::qt_msg_handler(QtMsgType type, const char *s)
00053 {
00054   QString msg(s);
00055   switch (type) {
00056     case QtDebugMsg:
00057       vDebug("QtDebugMsg: %1").arg(msg);
00058       break;
00059     case QtWarningMsg:
00060       vNotice("QtWarningMsg: %1").arg(msg);
00061       break;
00062     case QtCriticalMsg:
00063       vWarn("QtCriticalMsg: %1").arg(msg);
00064       break;
00065     case QtFatalMsg:
00066       vError("QtFatalMsg: %1").arg(msg);
00067       break;
00068   }
00069   if (type == QtFatalMsg) {
00070     vError("Fatal Qt error. Aborting.");
00071     abort();
00072   }
00073 }
00074 
00075 /** Constructor. Parses the command-line arguments, resets Vidalia's
00076  * configuration (if requested), and sets up the GUI style and language
00077  * translation. */
00078 Vidalia::Vidalia(QStringList args, int &argc, char **argv)
00079 : QApplication(argc, argv)
00080 {
00081   qInstallMsgHandler(qt_msg_handler);
00082 
00083   /* Read in all our command-line arguments. */
00084   parseArguments(args);
00085 
00086   /* Check if we're supposed to reset our config before proceeding. */
00087   if (_args.contains(ARG_RESET))
00088     VidaliaSettings::reset();
00089 
00090   /* Handle the -loglevel and -logfile options. */
00091   if (_args.contains(ARG_LOGFILE))
00092     _log.open(_args.value(ARG_LOGFILE));
00093   if (_args.contains(ARG_LOGLEVEL)) {
00094     _log.setLogLevel(Log::stringToLogLevel(
00095                       _args.value(ARG_LOGLEVEL)));
00096     if (!_args.contains(ARG_LOGFILE))
00097       _log.open(stdout);
00098   }
00099   if (!_args.contains(ARG_LOGLEVEL) && 
00100       !_args.contains(ARG_LOGFILE))
00101     _log.setLogLevel(Log::Off);
00102 
00103   /* Translate the GUI to the appropriate language. */
00104   setLanguage(_args.value(ARG_LANGUAGE));
00105   /* Set the GUI style appropriately. */
00106   setStyle(_args.value(ARG_GUISTYLE));
00107 
00108   /* Creates a TorControl object, used to talk to Tor. */
00109   _torControl = new TorControl();
00110 }
00111 
00112 /** Destructor */
00113 Vidalia::~Vidalia()
00114 {
00115   delete _torControl;
00116 }
00117 
00118 /** Enters the main event loop and waits until exit() is called. The signal
00119  * running() will be emitted when the event loop has started. */
00120 int
00121 Vidalia::run()
00122 {
00123   QTimer::singleShot(0, vApp, SLOT(onEventLoopStarted()));
00124   return vApp->exec();
00125 }
00126 
00127 /** Called when the application's main event loop has started. This method
00128  * will emit the running() signal to indicate that the application's event
00129  * loop is running. */
00130 void
00131 Vidalia::onEventLoopStarted()
00132 {
00133   emit running();
00134 }
00135 
00136 #if defined(Q_OS_WIN)
00137 /** On Windows, we need to catch the WM_QUERYENDSESSION message
00138  * so we know that it is time to shutdown. */
00139 bool
00140 Vidalia::winEventFilter(MSG *msg, long *result)
00141 {
00142   if (msg->message == WM_QUERYENDSESSION) {
00143     emit shutdown();
00144   }
00145   return QApplication::winEventFilter(msg, result);
00146 }
00147 #endif
00148 
00149 /** Returns true if the user wants to see usage information. */
00150 bool
00151 Vidalia::showUsage()
00152 {
00153   return _args.contains(ARG_HELP);
00154 }
00155 
00156 /** Displays usage information for command-line args. */
00157 void
00158 Vidalia::showUsageMessageBox()
00159 {
00160   QString usage;
00161   QTextStream out(&usage);
00162 
00163   out << "Available Options:" << endl;
00164   out << "<table>";
00165   out << trow(tcol("-"ARG_HELP) + 
00166               tcol(tr("Displays this usage message and exits.")));
00167   out << trow(tcol("-"ARG_RESET) +
00168               tcol(tr("Resets ALL stored Vidalia settings.")));
00169   out << trow(tcol("-"ARG_DATADIR" &lt;dir&gt;") +
00170               tcol(tr("Sets the directory Vidalia uses for data files.")));
00171   out << trow(tcol("-"ARG_PIDFILE" &lt;file&gt;") +
00172               tcol(tr("Sets the name and location of Vidalia's pidfile.")));
00173   out << trow(tcol("-"ARG_LOGFILE" &lt;file&gt;") +
00174               tcol(tr("Sets the name and location of Vidalia's logfile.")));
00175   out << trow(tcol("-"ARG_LOGLEVEL" &lt;level&gt;") +
00176               tcol(tr("Sets the verbosity of Vidalia's logging.") +
00177                    "<br>[" + Log::logLevels().join("|") +"]"));
00178   out << trow(tcol("-"ARG_GUISTYLE" &lt;style&gt;") +
00179               tcol(tr("Sets Vidalia's interface style.") +
00180                    "<br>[" + QStyleFactory::keys().join("|") + "]"));
00181   out << trow(tcol("-"ARG_LANGUAGE" &lt;language&gt;") + 
00182               tcol(tr("Sets Vidalia's language.") +
00183                    "<br>[" + LanguageSupport::languageCodes().join("|") + "]"));
00184   out << "</table>";
00185 
00186   VMessageBox::information(0, 
00187     tr("Vidalia Usage Information"), usage, VMessageBox::Ok);
00188 }
00189 
00190 /** Returns true if the specified argument expects a value. */
00191 bool
00192 Vidalia::argNeedsValue(QString argName)
00193 {
00194   return (argName == ARG_GUISTYLE ||
00195           argName == ARG_LANGUAGE ||
00196           argName == ARG_DATADIR  ||
00197           argName == ARG_PIDFILE  ||
00198           argName == ARG_LOGFILE  ||
00199           argName == ARG_LOGLEVEL);
00200 }
00201 
00202 /** Parses the list of command-line arguments for their argument names and
00203  * values. */
00204 void
00205 Vidalia::parseArguments(QStringList args)
00206 {
00207   QString arg, value;
00208 
00209   /* Loop through all command-line args/values and put them in a map */
00210   for (int i = 0; i < args.size(); i++) {
00211     /* Get the argument name and set a blank value */
00212     arg   = args.at(i).toLower();
00213     value = "";
00214 
00215     /* Check if it starts with a - or -- */
00216     if (arg.startsWith("-")) {
00217       arg = arg.mid((arg.startsWith("--") ? 2 : 1));
00218     }
00219     /* Check if it takes a value and there is one on the command-line */
00220     if (i < args.size()-1 && argNeedsValue(arg)) {
00221       value = args.at(++i);
00222     }
00223     /* Place this arg/value in the map */
00224     _args.insert(arg, value);
00225   }
00226 }
00227 
00228 /** Verifies that all specified arguments were valid. */
00229 bool
00230 Vidalia::validateArguments(QString &errmsg)
00231 {
00232   /* Check for a language that Vidalia recognizes. */
00233   if (_args.contains(ARG_LANGUAGE) &&
00234       !LanguageSupport::isValidLanguageCode(_args.value(ARG_LANGUAGE))) {
00235     errmsg = tr("Invalid language code specified: ") + _args.value(ARG_LANGUAGE);
00236     return false;
00237   }
00238   /* Check for a valid GUI style */
00239   if (_args.contains(ARG_GUISTYLE) &&
00240       !QStyleFactory::keys().contains(_args.value(ARG_GUISTYLE),
00241                                       Qt::CaseInsensitive)) {
00242     errmsg = tr("Invalid GUI style specified: ") + _args.value(ARG_GUISTYLE);
00243     return false;
00244   }
00245   /* Check for a valid log level */
00246   if (_args.contains(ARG_LOGLEVEL) &&
00247       !Log::logLevels().contains(_args.value(ARG_LOGLEVEL))) {
00248     errmsg = tr("Invalid log level specified: ") + _args.value(ARG_LOGLEVEL);
00249     return false;
00250   }
00251   /* Check for a writable log file */
00252   if (_args.contains(ARG_LOGFILE) && !_log.isOpen()) {
00253     errmsg = tr("Unable to open log file '%1': %2")
00254                            .arg(_args.value(ARG_LOGFILE))
00255                            .arg(_log.errorString());
00256     return false;
00257   }
00258   return true;
00259 }
00260 
00261 /** Sets the translation Vidalia will use. If one was specified on the
00262  * command-line, we will use that. Otherwise, we'll check to see if one was
00263  * saved previously. If not, we'll default to one appropriate for the system
00264  * locale. */
00265 bool
00266 Vidalia::setLanguage(QString languageCode)
00267 {
00268   /* If the language code is empty, use the previously-saved setting */
00269   if (languageCode.isEmpty()) {
00270     VidaliaSettings settings;
00271     languageCode = settings.getLanguageCode();
00272   }
00273   /* Translate into the desired langauge */
00274   if (LanguageSupport::translate(languageCode)) {
00275     _language = languageCode;
00276     return true;
00277   }
00278   return false;
00279 }
00280 
00281 /** Sets the GUI style Vidalia will use. If one was specified on the
00282  * command-line, we will use that. Otherwise, we'll check to see if one was
00283  * saved previously. If not, we'll default to one appropriate for the
00284  * operating system. */
00285 bool
00286 Vidalia::setStyle(QString styleKey)
00287 {
00288   /* If no style was specified, use the previously-saved setting */
00289   if (styleKey.isEmpty()) {
00290     VidaliaSettings settings;
00291     styleKey = settings.getInterfaceStyle();
00292   }
00293   /* Apply the specified GUI style */
00294   if (QApplication::setStyle(styleKey)) {
00295     _style = styleKey;
00296     return true;
00297   }
00298   return false;
00299 }
00300 
00301 /** Returns the directory Vidalia uses for its data files. */
00302 QString
00303 Vidalia::dataDirectory()
00304 {
00305   if (_args.contains(ARG_DATADIR)) {
00306     return _args.value(ARG_DATADIR);
00307   }
00308   return defaultDataDirectory();
00309 }
00310 
00311 /** Returns the default location of Vidalia's data directory. */
00312 QString
00313 Vidalia::defaultDataDirectory()
00314 {
00315 #if defined(Q_OS_WIN32)
00316   return (win32_app_data_folder() + "\\Vidalia");
00317 #else
00318   return (QDir::homePath() + "/.vidalia");
00319 #endif
00320 }
00321 
00322 /** Returns the location of Vidalia's pid file. */
00323 QString
00324 Vidalia::pidFile()
00325 {
00326   if (_args.contains(ARG_PIDFILE)) {
00327     return _args.value(ARG_PIDFILE);
00328   }
00329   return QDir::convertSeparators(dataDirectory() + "/vidalia.pid");
00330 }
00331 
00332 /** Writes <b>msg</b> with severity <b>level</b> to Vidalia's log. */
00333 Log::LogMessage
00334 Vidalia::log(Log::LogLevel level, QString msg)
00335 {
00336   return _log.log(level, msg);
00337 }
00338 
00339 /** Creates and binds a shortcut such that when <b>key</b> is pressed in
00340  * <b>sender</b>'s context, <b>receiver</b>'s <b>slot</b> will be called. */
00341 void
00342 Vidalia::createShortcut(const QKeySequence &key, QWidget *sender,
00343                         QObject *receiver, const char *slot)
00344 {
00345   QShortcut *s = new QShortcut(key, sender);
00346   connect(s, SIGNAL(activated()), receiver, slot);
00347 }
00348 
00349 /** Creates and binds a shortcut such that when <b>key</b> is pressed in
00350  * <b>sender</b>'s context, <b>receiver</b>'s <b>slot</b> will be called. */
00351 void
00352 Vidalia::createShortcut(const QString &key, QWidget *sender,
00353                         QObject *receiver, const char *slot)
00354 {
00355   createShortcut(QKeySequence(key), sender, receiver, slot);
00356 }

Generated on Tue Jul 7 17:00:56 2009 for Vidalia by  doxygen 1.4.7