From 4f5690c89b7ef9704ce6340a3150b75bbf613b83 Mon Sep 17 00:00:00 2001 From: Alexander Shaduri Date: Sun, 6 Mar 2011 18:06:14 +0000 Subject: [PATCH] Added ability to show smartctl output for devices whose info could not be parsed fully. --- gsmartcontrol/TODO | 5 - gsmartcontrol/src/applib/gui_utils.cpp | 3 +- .../src/gsc_executor_error_dialog.cpp | 109 +++++++++++++----- gsmartcontrol/src/gsc_executor_error_dialog.h | 14 ++- gsmartcontrol/src/gsc_main_window.cpp | 7 +- gsmartcontrol/src/gsc_text_window.h | 1 + 6 files changed, 97 insertions(+), 42 deletions(-) diff --git a/gsmartcontrol/TODO b/gsmartcontrol/TODO index e4504da..e4f6b7b 100644 --- a/gsmartcontrol/TODO +++ b/gsmartcontrol/TODO @@ -46,11 +46,6 @@ Testing: may be stuck due to bad firmware). Allow quitting when test is running (ask first). -Add ability to configure default save filename (in config-file only?): - "{serial}-{model}-{date}.txt", with the default being "{model}-{date}.txt". - Add string_replace_linear(), where multiple strings are replaced into the - original string (as opposed to previous result). - Add support for launching with consolehelper (from usermode package). Fedora uses this by default. Investigate Fedora selinux situation. diff --git a/gsmartcontrol/src/applib/gui_utils.cpp b/gsmartcontrol/src/applib/gui_utils.cpp index 40d399b..d12e2e2 100644 --- a/gsmartcontrol/src/applib/gui_utils.cpp +++ b/gsmartcontrol/src/applib/gui_utils.cpp @@ -15,8 +15,7 @@ #include "gui_utils.h" -namespace -{ +namespace { inline void show_dialog(const std::string& message, const std::string& sec_message, Gtk::Window* parent, Gtk::MessageType type, bool sec_msg_markup) diff --git a/gsmartcontrol/src/gsc_executor_error_dialog.cpp b/gsmartcontrol/src/gsc_executor_error_dialog.cpp index e7854f7..44d2f2f 100644 --- a/gsmartcontrol/src/gsc_executor_error_dialog.cpp +++ b/gsmartcontrol/src/gsc_executor_error_dialog.cpp @@ -9,50 +9,50 @@ #include "gsc_executor_log_window.h" #include "gsc_executor_error_dialog.h" +#include "gsc_text_window.h" -void gsc_executor_error_dialog_show(const std::string& message, const std::string& sec_message, - Gtk::Window* parent, bool show_output_button, bool sec_msg_markup) -{ - // no markup, modal - Gtk::MessageDialog dialog("\n" + message + (sec_message.empty() ? "\n" : ""), - false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_NONE, true); +namespace { - if (!sec_message.empty()) - dialog.set_secondary_text(sec_message, sec_msg_markup); + inline int show_executor_dialog(Gtk::MessageType type, + const std::string& message, const std::string& sec_message, + Gtk::Window* parent, bool sec_msg_markup, bool show_output_button) + { + // no markup, modal + Gtk::MessageDialog dialog("\n" + message + (sec_message.empty() ? "\n" : ""), + false, type, Gtk::BUTTONS_NONE, true); - if (parent) { - dialog.set_transient_for(*parent); - dialog.set_position(Gtk::WIN_POS_CENTER_ON_PARENT); - } else { - dialog.set_position(Gtk::WIN_POS_MOUSE); - } + if (!sec_message.empty()) + dialog.set_secondary_text(sec_message, sec_msg_markup); + + if (parent) { + dialog.set_transient_for(*parent); + dialog.set_position(Gtk::WIN_POS_CENTER_ON_PARENT); + } else { + dialog.set_position(Gtk::WIN_POS_MOUSE); + } - Gtk::Button ok_button(Gtk::Stock::OK); - ok_button.show_all(); - ok_button.set_flags(ok_button.get_flags() | Gtk::CAN_DEFAULT); - dialog.add_action_widget(ok_button, Gtk::RESPONSE_OK); + Gtk::Button ok_button(Gtk::Stock::OK); + ok_button.show_all(); + ok_button.set_flags(ok_button.get_flags() | Gtk::CAN_DEFAULT); + dialog.add_action_widget(ok_button, Gtk::RESPONSE_OK); - Gtk::Button output_button("_Show Output", true); // don't put this inside if, it needs to live beyond it. - if (show_output_button) { - output_button.show_all(); - dialog.add_action_widget(output_button, Gtk::RESPONSE_HELP); - } + Gtk::Button output_button("_Show Output", true); // don't put this inside if, it needs to live beyond it. + if (show_output_button) { + output_button.show_all(); + dialog.add_action_widget(output_button, Gtk::RESPONSE_HELP); + } - dialog.set_default_response(Gtk::RESPONSE_OK); + dialog.set_default_response(Gtk::RESPONSE_OK); - int response = dialog.run(); // blocks until the dialog is closed + int response = dialog.run(); // blocks until the dialog is closed - if (response == Gtk::RESPONSE_HELP) { - // this one will only hide on close. - GscExecutorLogWindow* win = GscExecutorLogWindow::create(); // probably already created - // win->set_transient_for(*this); // don't do this - it will make it always-on-top of this. - win->show_last(); // show the window and select last entry + return response; } } @@ -61,3 +61,52 @@ void gsc_executor_error_dialog_show(const std::string& message, const std::strin +void gsc_executor_error_dialog_show(const std::string& message, const std::string& sec_message, + Gtk::Window* parent, bool sec_msg_markup, bool show_output_button) +{ + int response = show_executor_dialog(Gtk::MESSAGE_ERROR, message, sec_message, + parent, sec_msg_markup, show_output_button); + + if (response == Gtk::RESPONSE_HELP) { + // this one will only hide on close. + GscExecutorLogWindow* win = GscExecutorLogWindow::create(); // probably already created + // win->set_transient_for(*this); // don't do this - it will make it always-on-top of this. + win->show_last(); // show the window and select last entry + } +} + + + +void gsc_no_info_dialog_show(const std::string& message, const std::string& sec_message, + Gtk::Window* parent, bool sec_msg_markup, const std::string& output, + const std::string& output_window_title, const std::string& default_save_filename) +{ + int response = show_executor_dialog(Gtk::MESSAGE_WARNING, message, sec_message, + parent, sec_msg_markup, !output.empty()); + + if (response == Gtk::RESPONSE_HELP) { + GscTextWindow* win = GscTextWindow::create(); + // make save visible and enable monospace font + + std::string buf_text = output; + // We receive locale'd thousands separators in win32, so convert them. + #ifdef _WIN32 + try { + buf_text = Glib::locale_to_utf8(buf_text); + } catch (Glib::ConvertError& e) { + buf_text = ""; // inserting invalid utf8 may trigger a segfault, so empty is better. + } + #endif + win->set_text(output_window_title, buf_text, true, true); + + if (!default_save_filename.empty()) + win->set_save_filename(default_save_filename); + + win->show(); + } + +} + + + + diff --git a/gsmartcontrol/src/gsc_executor_error_dialog.h b/gsmartcontrol/src/gsc_executor_error_dialog.h index 5721672..f2e2a21 100644 --- a/gsmartcontrol/src/gsc_executor_error_dialog.h +++ b/gsmartcontrol/src/gsc_executor_error_dialog.h @@ -12,9 +12,19 @@ - +/// Show a dialog when an execution error occurs. A dialog +/// will have a "Show Output" button, which shows the last executed +/// command details. void gsc_executor_error_dialog_show(const std::string& message, const std::string& sec_message, - Gtk::Window* parent, bool show_output_button = true, bool sec_msg_markup = false); + Gtk::Window* parent, bool sec_msg_markup = false, bool show_output_button = true); + + +/// Show a dialog when no additional information is available. +/// If \c output is not empty, a "Show Output" button will be displayed +/// which shows this output. +void gsc_no_info_dialog_show(const std::string& message, const std::string& sec_message, + Gtk::Window* parent, bool sec_msg_markup, const std::string& output, + const std::string& output_window_title, const std::string& default_save_filename); diff --git a/gsmartcontrol/src/gsc_main_window.cpp b/gsmartcontrol/src/gsc_main_window.cpp index 715a4c1..2794a38 100644 --- a/gsmartcontrol/src/gsc_main_window.cpp +++ b/gsmartcontrol/src/gsc_main_window.cpp @@ -108,7 +108,7 @@ GscMainWindow::GscMainWindow(BaseObjectType* gtkcobj, const app_ui_res_ref_t& re if (!smartctl_valid) { gsc_executor_error_dialog_show("There was an error while executing smartctl", error_msg + "\n\nPlease specify the correct smartctl binary in Preferences.", - this, show_output_button, true); + this, true, show_output_button); } // Scan @@ -1000,7 +1000,7 @@ void GscMainWindow::rescan_devices() if (!error && !error_msg.empty()) { // generic scan error. smartctl errors are not reported during scan at all. // we don't show output button here gsc_executor_error_dialog_show("An error occurred while scanning the system", - error_msg, this, false); + error_msg, this, false, false); error = true; // add them anyway, in case the error was only on one drive. @@ -1163,7 +1163,8 @@ GscInfoWindow* GscMainWindow::show_device_info_window(StorageDeviceRefPtr drive) // usb devices), only very basic info is available and there's no point // in showing this window. - for both virtual and non-virtual. if (!drive->get_fully_parsed()) { - gui_show_warn_dialog("No additional information is available for this drive.", this); + gsc_no_info_dialog_show("No additional information is available for this drive.", + "", this, false, drive->get_info_output(), "Smartctl Output", drive->get_save_filename()); return 0; } diff --git a/gsmartcontrol/src/gsc_text_window.h b/gsmartcontrol/src/gsc_text_window.h index d207681..d36250d 100644 --- a/gsmartcontrol/src/gsc_text_window.h +++ b/gsmartcontrol/src/gsc_text_window.h @@ -11,6 +11,7 @@ #include #include #include +#include #include // GDK_Escape #include "hz/debug.h"