00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "MessageLog.h"
00018 #include "StatusEventItem.h"
00019 #include "Vidalia.h"
00020 #include "VMessageBox.h"
00021
00022 #include "html.h"
00023
00024 #include <QMessageBox>
00025 #include <QFileDialog>
00026 #include <QInputDialog>
00027 #include <QMessageBox>
00028 #include <QClipboard>
00029
00030
00031 #define SETTING_MSG_FILTER "MessageFilter"
00032 #define SETTING_MAX_MSG_COUNT "MaxMsgCount"
00033 #define SETTING_ENABLE_LOGFILE "EnableLogFile"
00034 #define SETTING_LOGFILE "LogFile"
00035 #define DEFAULT_MSG_FILTER \
00036 (tc::ErrorSeverity|tc::WarnSeverity|tc::NoticeSeverity)
00037 #define DEFAULT_MAX_MSG_COUNT 50
00038 #define DEFAULT_ENABLE_LOGFILE false
00039 #if defined(Q_OS_WIN32)
00040
00041
00042 #define DEFAULT_LOGFILE \
00043 (win32_program_files_folder()+"\\Tor\\tor-log.txt")
00044 #else
00045 #define DEFAULT_LOGFILE (QDir::homePath() + "/.tor/tor-log.txt")
00046 #endif
00047
00048 #define ADD_TO_FILTER(f,v,b) (f = ((b) ? ((f) | (v)) : ((f) & ~(v))))
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 MessageLog::MessageLog(QWidget *parent, Qt::WFlags flags)
00059 : VidaliaWindow("MessageLog", parent, flags)
00060 {
00061
00062 ui.setupUi(this);
00063
00064
00065 _torControl = Vidalia::torControl();
00066 connect(_torControl, SIGNAL(logMessage(tc::Severity, QString)),
00067 this, SLOT(log(tc::Severity, QString)));
00068
00069
00070 createActions();
00071
00072
00073 setToolTips();
00074
00075
00076 loadSettings();
00077
00078
00079 ui.listMessages->sortItems(LogTreeWidget::TimeColumn,
00080 Qt::AscendingOrder);
00081 ui.listNotifications->sortItems(0, Qt::AscendingOrder);
00082 }
00083
00084
00085
00086 MessageLog::~MessageLog()
00087 {
00088 _logFile.close();
00089 }
00090
00091
00092 void
00093 MessageLog::createActions()
00094 {
00095 connect(ui.actionSave_Selected, SIGNAL(triggered()),
00096 this, SLOT(saveSelected()));
00097
00098 connect(ui.actionSave_All, SIGNAL(triggered()),
00099 this, SLOT(saveAll()));
00100
00101 connect(ui.actionSelect_All, SIGNAL(triggered()),
00102 this, SLOT(selectAll()));
00103
00104 connect(ui.actionCopy, SIGNAL(triggered()),
00105 this, SLOT(copy()));
00106
00107 connect(ui.actionFind, SIGNAL(triggered()),
00108 this, SLOT(find()));
00109
00110 connect(ui.actionClear, SIGNAL(triggered()),
00111 this, SLOT(clear()));
00112
00113 connect(ui.actionHelp, SIGNAL(triggered()),
00114 this, SLOT(help()));
00115
00116 connect(ui.btnSaveSettings, SIGNAL(clicked()),
00117 this, SLOT(saveSettings()));
00118
00119 connect(ui.btnCancelSettings, SIGNAL(clicked()),
00120 this, SLOT(cancelChanges()));
00121
00122 connect(ui.btnBrowse, SIGNAL(clicked()),
00123 this, SLOT(browse()));
00124
00125 #if defined(Q_WS_MAC)
00126 ui.actionHelp->setShortcut(QString("Ctrl+?"));
00127 #endif
00128 ui.actionClose->setShortcut(QString("Esc"));
00129 Vidalia::createShortcut("Ctrl+W", this, ui.actionClose, SLOT(trigger()));
00130 }
00131
00132
00133
00134 void
00135 MessageLog::setToolTips()
00136 {
00137 ui.chkTorErr->setToolTip(tr("Messages that appear when something has \n"
00138 "gone very wrong and Tor cannot proceed."));
00139 ui.chkTorWarn->setToolTip(tr("Messages that only appear when \n"
00140 "something has gone wrong with Tor."));
00141 ui.chkTorNote->setToolTip(tr("Messages that appear infrequently \n"
00142 "during normal Tor operation and are \n"
00143 "not considered errors, but you may \n"
00144 "care about."));
00145 ui.chkTorInfo->setToolTip(tr("Messages that appear frequently \n"
00146 "during normal Tor operation."));
00147 ui.chkTorDebug->setToolTip(tr("Hyper-verbose messages primarily of \n"
00148 "interest to Tor developers."));
00149 }
00150
00151
00152 void
00153 MessageLog::retranslateUi()
00154 {
00155 ui.retranslateUi(this);
00156 setToolTips();
00157 }
00158
00159
00160 void
00161 MessageLog::loadSettings()
00162 {
00163
00164 uint maxMsgCount = getSetting(SETTING_MAX_MSG_COUNT,
00165 DEFAULT_MAX_MSG_COUNT).toUInt();
00166 ui.spnbxMaxCount->setValue(maxMsgCount);
00167 ui.listMessages->setMaximumMessageCount(maxMsgCount);
00168 ui.listNotifications->setMaximumItemCount(maxMsgCount);
00169
00170
00171 _enableLogging = getSetting(SETTING_ENABLE_LOGFILE,
00172 DEFAULT_ENABLE_LOGFILE).toBool();
00173 QString logfile = getSetting(SETTING_LOGFILE,
00174 DEFAULT_LOGFILE).toString();
00175 ui.lineFile->setText(QDir::convertSeparators(logfile));
00176 rotateLogFile(logfile);
00177 ui.chkEnableLogFile->setChecked(_logFile.isOpen());
00178
00179
00180 _filter = getSetting(SETTING_MSG_FILTER, DEFAULT_MSG_FILTER).toUInt();
00181 ui.chkTorErr->setChecked(_filter & tc::ErrorSeverity);
00182 ui.chkTorWarn->setChecked(_filter & tc::WarnSeverity);
00183 ui.chkTorNote->setChecked(_filter & tc::NoticeSeverity);
00184 ui.chkTorInfo->setChecked(_filter & tc::InfoSeverity);
00185 ui.chkTorDebug->setChecked(_filter & tc::DebugSeverity);
00186 registerLogEvents();
00187
00188
00189 QApplication::setOverrideCursor(Qt::WaitCursor);
00190 ui.listMessages->filter(_filter);
00191 QApplication::restoreOverrideCursor();
00192 }
00193
00194
00195
00196 void
00197 MessageLog::registerLogEvents()
00198 {
00199 _filter = getSetting(SETTING_MSG_FILTER, DEFAULT_MSG_FILTER).toUInt();
00200 _torControl->setEvent(TorEvents::LogDebug,
00201 _filter & tc::DebugSeverity, false);
00202 _torControl->setEvent(TorEvents::LogInfo,
00203 _filter & tc::InfoSeverity, false);
00204 _torControl->setEvent(TorEvents::LogNotice,
00205 _filter & tc::NoticeSeverity, false);
00206 _torControl->setEvent(TorEvents::LogWarn,
00207 _filter & tc::WarnSeverity, false);
00208 _torControl->setEvent(TorEvents::LogError,
00209 _filter & tc::ErrorSeverity, false);
00210
00211 QString errmsg;
00212 if (_torControl->isConnected() && !_torControl->setEvents(&errmsg)) {
00213 VMessageBox::warning(this, tr("Error Setting Filter"),
00214 p(tr("Vidalia was unable to register for Tor's log events.")) + p(errmsg),
00215 VMessageBox::Ok);
00216 }
00217 }
00218
00219
00220
00221
00222
00223 bool
00224 MessageLog::rotateLogFile(const QString &filename)
00225 {
00226 QString errmsg;
00227 if (_enableLogging) {
00228 if (!_logFile.open(filename, &errmsg)) {
00229 VMessageBox::warning(this, tr("Error Opening Log File"),
00230 p(tr("Vidalia was unable to open the specified log file."))+p(errmsg),
00231 VMessageBox::Ok);
00232 return false;
00233 }
00234 } else {
00235
00236 _logFile.close();
00237 }
00238 return true;
00239 }
00240
00241
00242
00243 void
00244 MessageLog::saveSettings()
00245 {
00246
00247 _enableLogging = ui.chkEnableLogFile->isChecked();
00248 if (_enableLogging && ui.lineFile->text().isEmpty()) {
00249
00250
00251 VMessageBox::warning(this, tr("Log Filename Required"),
00252 p(tr("You must enter a filename to be able to save log "
00253 "messages to a file.")), VMessageBox::Ok);
00254 return;
00255 }
00256 if (rotateLogFile(ui.lineFile->text())) {
00257 saveSetting(SETTING_LOGFILE, ui.lineFile->text());
00258 saveSetting(SETTING_ENABLE_LOGFILE, _logFile.isOpen());
00259 }
00260 ui.lineFile->setText(QDir::convertSeparators(ui.lineFile->text()));
00261 ui.chkEnableLogFile->setChecked(_logFile.isOpen());
00262
00263
00264 saveSetting(SETTING_MAX_MSG_COUNT, ui.spnbxMaxCount->value());
00265 ui.listMessages->setMaximumMessageCount(ui.spnbxMaxCount->value());
00266 ui.listNotifications->setMaximumItemCount(ui.spnbxMaxCount->value());
00267
00268
00269 uint filter = 0;
00270 ADD_TO_FILTER(filter, tc::ErrorSeverity, ui.chkTorErr->isChecked());
00271 ADD_TO_FILTER(filter, tc::WarnSeverity, ui.chkTorWarn->isChecked());
00272 ADD_TO_FILTER(filter, tc::NoticeSeverity, ui.chkTorNote->isChecked());
00273 ADD_TO_FILTER(filter, tc::InfoSeverity, ui.chkTorInfo->isChecked());
00274 ADD_TO_FILTER(filter, tc::DebugSeverity, ui.chkTorDebug->isChecked());
00275 saveSetting(SETTING_MSG_FILTER, filter);
00276 registerLogEvents();
00277
00278
00279 QApplication::setOverrideCursor(Qt::WaitCursor);
00280 ui.listMessages->filter(_filter);
00281 QApplication::restoreOverrideCursor();
00282
00283
00284 ui.actionSettings->toggle();
00285 }
00286
00287
00288
00289 void
00290 MessageLog::cancelChanges()
00291 {
00292
00293 ui.actionSettings->toggle();
00294
00295 loadSettings();
00296 }
00297
00298
00299 void
00300 MessageLog::browse()
00301 {
00302
00303 QString filename = QDir::convertSeparators(
00304 QFileDialog::getSaveFileName(this,
00305 tr("Select Log File"), "tor-log.txt"));
00306 if (!filename.isEmpty()) {
00307 ui.lineFile->setText(filename);
00308 }
00309 }
00310
00311
00312
00313
00314 void
00315 MessageLog::save(const QStringList &messages)
00316 {
00317 if (!messages.size()) {
00318 return;
00319 }
00320
00321 QString fileName = QFileDialog::getSaveFileName(this,
00322 tr("Save Log Messages"),
00323 "VidaliaLog-" +
00324 QDateTime::currentDateTime().toString("MM.dd.yyyy")
00325 + ".txt", tr("Text Files (*.txt)"));
00326
00327
00328 if (!fileName.isEmpty()) {
00329 LogFile logFile;
00330 QString errmsg;
00331
00332
00333 if (!logFile.open(fileName, &errmsg)) {
00334 VMessageBox::warning(this, tr("Vidalia"),
00335 p(tr("Cannot write file %1\n\n%2."))
00336 .arg(fileName)
00337 .arg(errmsg),
00338 VMessageBox::Ok);
00339 return;
00340 }
00341
00342
00343 QApplication::setOverrideCursor(Qt::WaitCursor);
00344 foreach (QString msg, messages) {
00345 logFile << msg << "\n";
00346 }
00347 QApplication::restoreOverrideCursor();
00348 }
00349 }
00350
00351
00352 void
00353 MessageLog::saveSelected()
00354 {
00355 if (ui.tabWidget->currentIndex() == 0)
00356 save(ui.listNotifications->selectedEvents());
00357 else
00358 save(ui.listMessages->selectedMessages());
00359 }
00360
00361
00362 void
00363 MessageLog::saveAll()
00364 {
00365 if (ui.tabWidget->currentIndex() == 0)
00366 save(ui.listNotifications->allEvents());
00367 else
00368 save(ui.listMessages->allMessages());
00369 }
00370
00371 void
00372 MessageLog::selectAll()
00373 {
00374 if (ui.tabWidget->currentIndex() == 0)
00375 ui.listNotifications->selectAll();
00376 else
00377 ui.listMessages->selectAll();
00378 }
00379
00380
00381 void
00382 MessageLog::copy()
00383 {
00384 QString contents;
00385
00386 if (ui.tabWidget->currentIndex() == 0)
00387 contents = ui.listNotifications->selectedEvents().join("\n");
00388 else
00389 contents = ui.listMessages->selectedMessages().join("\n");
00390
00391 if (!contents.isEmpty()) {
00392
00393 QApplication::clipboard()->setText(contents);
00394 }
00395 }
00396
00397
00398
00399 void
00400 MessageLog::clear()
00401 {
00402 if (ui.tabWidget->currentIndex() == 0)
00403 ui.listNotifications->clear();
00404 else
00405 ui.listMessages->clearMessages();
00406 }
00407
00408
00409
00410
00411
00412
00413 void
00414 MessageLog::find()
00415 {
00416 bool ok;
00417 QString text = QInputDialog::getText(this, tr("Find in Message Log"),
00418 tr("Find:"), QLineEdit::Normal, QString(), &ok);
00419
00420 if (ok && !text.isEmpty()) {
00421 QTreeWidget *tree;
00422 QTreeWidgetItem *firstItem = 0;
00423
00424
00425 if (ui.tabWidget->currentIndex() == 0) {
00426 QList<StatusEventItem *> results = ui.listNotifications->find(text, true);
00427 if (results.size() > 0) {
00428 tree = ui.listNotifications;
00429 firstItem = dynamic_cast<QTreeWidgetItem *>(results.at(0));
00430 }
00431 } else {
00432 QList<LogTreeItem *> results = ui.listMessages->find(text, true);
00433 if (results.size() > 0) {
00434 tree = ui.listMessages;
00435 firstItem = dynamic_cast<QTreeWidgetItem *>(results.at(0));
00436 }
00437 }
00438
00439 if (! firstItem) {
00440 VMessageBox::information(this, tr("Not Found"),
00441 p(tr("Search found 0 matches.")),
00442 VMessageBox::Ok);
00443 } else {
00444 tree->scrollToItem(firstItem);
00445 }
00446 }
00447 }
00448
00449
00450
00451
00452
00453
00454 void
00455 MessageLog::log(tc::Severity type, const QString &message)
00456 {
00457
00458 if (_filter & (uint)type) {
00459
00460 LogTreeItem *item = ui.listMessages->log(type, message);
00461
00462
00463
00464 QString currStatusTip = ui.statusbar->currentMessage();
00465 if (!currStatusTip.isEmpty()) {
00466 currStatusTip = ui.listMessages->statusTip();
00467 ui.statusbar->showMessage(currStatusTip);
00468 }
00469
00470
00471 if (_enableLogging) {
00472 _logFile << item->toString() << "\n";
00473 }
00474 }
00475 }
00476
00477
00478 void
00479 MessageLog::help()
00480 {
00481 emit helpRequested("log");
00482 }
00483