This is an automated email from the git hooks/post-receive script. omegaphil pushed a commit to branch omegaphil/graph-disk-io in repository panel-plugins/xfce4-hardware-monitor-plugin.
commit 16a0c6a23721c9e38e0a7a1c7e24839b7d7de36b Author: OmegaPhil <omegap...@startmail.com> Date: Thu Jun 16 21:06:58 2016 +0100 Implement Generic Monitor --- src/choose-monitor-window.cpp | 276 ++++++++++++++++++++++- src/choose-monitor-window.hpp | 26 ++- src/monitor-impls.cpp | 260 +++++++++++++++++++++- src/monitor-impls.hpp | 48 +++- src/ui.glade | 494 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1074 insertions(+), 30 deletions(-) diff --git a/src/choose-monitor-window.cpp b/src/choose-monitor-window.cpp index 501359c..e9041bc 100644 --- a/src/choose-monitor-window.cpp +++ b/src/choose-monitor-window.cpp @@ -62,6 +62,7 @@ ChooseMonitorWindow::ChooseMonitorWindow(XfcePanelPlugin* panel_applet_local, ui->get_widget("network_load_radiobutton", network_load_radiobutton); ui->get_widget("temperature_radiobutton", temperature_radiobutton); ui->get_widget("fan_speed_radiobutton", fan_speed_radiobutton); + ui->get_widget("generic_radiobutton", generic_radiobutton); ui->get_widget("cpu_usage_options", cpu_usage_options); ui->get_widget("load_average_options", load_average_options); @@ -113,6 +114,32 @@ ChooseMonitorWindow::ChooseMonitorWindow(XfcePanelPlugin* panel_applet_local, ui->get_widget("fan_speed_combobox", fan_speed_combobox); ui->get_widget("fan_speed_tag_entry", fan_speed_tag); + ui->get_widget("generic_box", generic_box); + ui->get_widget("generic_options", generic_options); + ui->get_widget("generic_file_path_entry", generic_file_path_entry); + ui->get_widget("generic_number_regex_hbox", generic_number_regex_hbox); + ui->get_widget("generic_read_all_contents_radiobutton", + generic_read_all_contents_radiobutton); + ui->get_widget("generic_extract_via_regex_radiobutton", + generic_extract_via_regex_radiobutton); + ui->get_widget("generic_regex_entry", generic_regex_entry); + ui->get_widget("generic_change_in_value_checkbutton", + generic_change_in_value_checkbutton); + ui->get_widget("generic_change_in_value_hbox", generic_change_in_value_hbox); + ui->get_widget("generic_change_in_value_positive_radiobutton", + generic_change_in_value_positive_radiobutton); + ui->get_widget("generic_change_in_value_negative_radiobutton", + generic_change_in_value_negative_radiobutton); + ui->get_widget("generic_change_in_value_both_radiobutton", + generic_change_in_value_both_radiobutton); + ui->get_widget("generic_data_source_name_long_entry", + generic_data_source_name_long_entry); + ui->get_widget("generic_data_source_name_short_entry", + generic_data_source_name_short_entry); + ui->get_widget("generic_units_long_entry", generic_units_long_entry); + ui->get_widget("generic_units_short_entry", generic_units_short_entry); + ui->get_widget("generic_tag_entry", generic_tag); + cpu_usage_radiobutton->signal_toggled() .connect(sigc::mem_fun(*this, &ChooseMonitorWindow:: on_cpu_usage_radiobutton_toggled)); @@ -153,6 +180,18 @@ ChooseMonitorWindow::ChooseMonitorWindow(XfcePanelPlugin* panel_applet_local, .connect(sigc::mem_fun(*this, &ChooseMonitorWindow:: on_fan_speed_radiobutton_toggled)); + generic_radiobutton->signal_toggled() + .connect(sigc::mem_fun(*this, &ChooseMonitorWindow:: + on_generic_radiobutton_toggled)); + + generic_extract_via_regex_radiobutton->signal_toggled() + .connect(sigc::mem_fun(*this, &ChooseMonitorWindow:: + on_generic_extract_via_regex_radiobutton_toggled)); + + generic_change_in_value_checkbutton->signal_toggled() + .connect(sigc::mem_fun(*this, &ChooseMonitorWindow:: + on_generic_change_in_value_checkbutton_toggled)); + // Note 1 off to avoid counting from zero in the interface cpu_no_spinbutton->set_range(1, CpuUsageMonitor::max_no_cpus); @@ -358,6 +397,15 @@ Monitor *ChooseMonitorWindow::run(const Glib::ustring &mon_dir) temperature_radiobutton->set_active(); temperature_tag->set_text(tag); } + + // TODO: When I start supporting it, why no fan stuff here? + + else if (type == "generic") + { + device_notebook->set_current_page(4); + generic_radiobutton->set_active(); + generic_tag->set_text(tag); + } else { device_notebook->set_current_page(0); @@ -488,10 +536,61 @@ Monitor *ChooseMonitorWindow::run(const Glib::ustring &mon_dir) network_direction_combobox->set_active(0); } - int temperature_no = xfce_rc_read_int_entry(settings_ro, - "temperature_no", 0); + // Fill in temperature info + if (xfce_rc_has_entry(settings_ro, "temperature_no")) + { + int temperature_no = xfce_rc_read_int_entry(settings_ro, + "temperature_no", 0); + temperature_combobox->set_active(temperature_no); + } - temperature_combobox->set_active(temperature_no); + // Fill in generic info + if (xfce_rc_has_entry(settings_ro, "file_path")) + { + Glib::ustring file_path = xfce_rc_read_entry(settings_ro, "file_path", + ""), + regex_string = xfce_rc_read_entry(settings_ro, "regex", ""), + data_source_name_long = xfce_rc_read_entry(settings_ro, + "data_source_name_long", ""), + data_source_name_short = xfce_rc_read_entry(settings_ro, + "data_source_name_short", ""), + units_long = xfce_rc_read_entry(settings_ro, "units_long", ""), + units_short = xfce_rc_read_entry(settings_ro, "units_short", ""); + bool value_from_contents = xfce_rc_read_bool_entry(settings_ro, + "value_from_contents", + false), + follow_change = xfce_rc_read_bool_entry(settings_ro, "follow_change", + false); + int direction = xfce_rc_read_int_entry(settings_ro, + "value_change_direction", + GenericMonitor::positive); + + generic_file_path_entry->set_text(file_path); + + if (!value_from_contents) + generic_extract_via_regex_radiobutton->set_active(); + + generic_regex_entry->set_text(regex_string); + generic_change_in_value_checkbutton->set_active(follow_change); + + switch (direction) + { + case GenericMonitor::positive: + generic_change_in_value_positive_radiobutton->activate(); + break; + case GenericMonitor::negative: + generic_change_in_value_negative_radiobutton->activate(); + break; + case GenericMonitor::both: + generic_change_in_value_both_radiobutton->activate(); + break; + } + + generic_data_source_name_long_entry->set_text(data_source_name_long); + generic_data_source_name_short_entry->set_text(data_source_name_short); + generic_units_long_entry->set_text(units_long); + generic_units_short_entry->set_text(units_short); + } xfce_rc_close(settings_ro); } @@ -683,6 +782,141 @@ Monitor *ChooseMonitorWindow::run(const Glib::ustring &mon_dir) else if (fan_speed_radiobutton->get_active()) mon = new FanSpeedMonitor(fan_speed_combobox->get_active_row_number(), fan_speed_tag->get_text()); + else if (generic_radiobutton->get_active()) + { + Glib::ustring file_path = generic_file_path_entry->get_text(), + regex_string = generic_regex_entry->get_text(), + data_source_name_long = generic_data_source_name_long_entry->get_text(), + data_source_name_short = generic_data_source_name_short_entry->get_text(), + units_long = generic_units_long_entry->get_text(), + units_short = generic_units_short_entry->get_text(); + bool value_from_contents = generic_read_all_contents_radiobutton->get_active(), + follow_change = generic_change_in_value_checkbutton->get_active(); + GenericMonitor::ValueChangeDirection dir; + if (generic_change_in_value_positive_radiobutton->get_active()) + dir = GenericMonitor::positive; + else if (generic_change_in_value_negative_radiobutton->get_active()) + dir = GenericMonitor::negative; + else if (generic_change_in_value_both_radiobutton->get_active()) + dir = GenericMonitor::both; + + // Making sure that the path passed is valid + if (!Glib::file_test(file_path, Glib::FileTest::FILE_TEST_EXISTS)) + { + /* Making sure the user is OK with specifying a non-existent file + * (i.e. it may appear later) */ + Glib::ustring msg = Glib::ustring:: + compose(_("Specified file '%1' does not currently exist - do " + "you still want to proceed?"), file_path); + + /* See helpers.hpp - tried to host a generic warning dialog + * implementation there but got endless include bullshit */ + Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_YES_NO); + d.set_modal(); + d.set_title(_("Generic Monitor")); + d.set_icon(window->get_icon()); + if (d.run() != Gtk::RESPONSE_YES) + { + generic_file_path_entry->grab_focus(); + response = Gtk::RESPONSE_HELP; + continue; + } + } + + // Validating regex if necessary + if (!value_from_contents) + { + if (regex_string == "") + { + Glib::ustring msg = _("When 'number from regex' is specified, you " + "must provide a regex to use."); + + /* See helpers.hpp - tried to host a generic warning dialog + * implementation there but got endless include bullshit */ + Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_OK); + d.set_modal(); + d.set_title(_("Generic Monitor")); + d.set_icon(window->get_icon()); + d.run(); + generic_regex_entry->grab_focus(); + response = Gtk::RESPONSE_HELP; + continue; + } + + Glib::RefPtr<Glib::Regex> regex; + try + { + regex = Glib::Regex::create(regex_string); + } + catch (Glib::Error &e) + { + /* Regex validation failed - informing the user - error message + * already includes the regex */ + Glib::ustring msg = Glib::ustring::compose( + _("The regex provided is not a valid:\n\n%1"), e.what()); + + /* See helpers.hpp - tried to host a generic warning dialog + * implementation there but got endless include bullshit */ + Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_OK); + d.set_modal(); + d.set_title(_("Generic Monitor")); + d.set_icon(window->get_icon()); + d.run(); + generic_regex_entry->grab_focus(); + response = Gtk::RESPONSE_HELP; + continue; + } + + // Making sure there is at least one capture group + if (regex->get_capture_count() == 0) + { + Glib::ustring msg = _("Please ensure the regex provided has one " + "capture group to use to extract the number."); + + /* See helpers.hpp - tried to host a generic warning dialog + * implementation there but got endless include bullshit */ + Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_OK); + d.set_modal(); + d.set_title(_("Generic Monitor")); + d.set_icon(window->get_icon()); + d.run(); + generic_regex_entry->grab_focus(); + response = Gtk::RESPONSE_HELP; + continue; + } + } + + // Ensuring mandatory fields have been filled in + if (data_source_name_long == "" || data_source_name_short == "") + { + Glib::ustring msg = _("Data source name (long and short forms) must be" + " specified to create this monitor."); + + /* See helpers.hpp - tried to host a generic warning dialog + * implementation there but got endless include bullshit */ + Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_OK); + d.set_modal(); + d.set_title(_("Generic Monitor")); + d.set_icon(window->get_icon()); + d.run(); + if (data_source_name_long == "") + generic_data_source_name_long_entry->grab_focus(); + else + generic_data_source_name_short_entry->grab_focus(); + response = Gtk::RESPONSE_HELP; + continue; + } + + mon = new GenericMonitor(file_path, value_from_contents, regex_string, + follow_change, dir, data_source_name_long, + data_source_name_short, units_long, units_short, + generic_tag->get_text()); + } return mon; } @@ -719,22 +953,16 @@ void ChooseMonitorWindow::on_disk_stats_radiobutton_toggled() = disk_stats_radiobutton->get_active(); } -void ChooseMonitorWindow::on_memory_usage_radiobutton_toggled() -{ - memory_usage_options->property_sensitive() - = memory_usage_radiobutton->get_active(); -} - void ChooseMonitorWindow::on_swap_usage_radiobutton_toggled() { swap_usage_options->property_sensitive() = swap_usage_radiobutton->get_active(); } -void ChooseMonitorWindow::on_fan_speed_radiobutton_toggled() +void ChooseMonitorWindow::on_memory_usage_radiobutton_toggled() { - fan_speed_options->property_sensitive() - = fan_speed_radiobutton->get_active(); + memory_usage_options->property_sensitive() + = memory_usage_radiobutton->get_active(); } /* Triggered when user edits a network interface name after revealing the @@ -852,6 +1080,30 @@ void ChooseMonitorWindow::on_temperature_radiobutton_toggled() = temperature_radiobutton->get_active(); } +void ChooseMonitorWindow::on_fan_speed_radiobutton_toggled() +{ + fan_speed_options->property_sensitive() + = fan_speed_radiobutton->get_active(); +} + +void ChooseMonitorWindow::on_generic_radiobutton_toggled() +{ + generic_options->property_sensitive() + = generic_radiobutton->get_active(); +} + +void ChooseMonitorWindow::on_generic_extract_via_regex_radiobutton_toggled() +{ + generic_number_regex_hbox->property_sensitive() + = generic_extract_via_regex_radiobutton->get_active(); +} + +void ChooseMonitorWindow::on_generic_change_in_value_checkbutton_toggled() +{ + generic_change_in_value_hbox->property_sensitive() + = generic_change_in_value_checkbutton->get_active(); +} + bool ChooseMonitorWindow::on_closed(GdkEventAny *) { window->hide(); diff --git a/src/choose-monitor-window.hpp b/src/choose-monitor-window.hpp index 05396c0..cb9b86a 100644 --- a/src/choose-monitor-window.hpp +++ b/src/choose-monitor-window.hpp @@ -69,7 +69,7 @@ private: Gtk::RadioButton *cpu_usage_radiobutton, *memory_usage_radiobutton, *swap_usage_radiobutton, *load_average_radiobutton, *disk_usage_radiobutton, *disk_stats_radiobutton, *network_load_radiobutton, *temperature_radiobutton, - *fan_speed_radiobutton; + *fan_speed_radiobutton, *generic_radiobutton; Gtk::Box *cpu_usage_options, *load_average_options; Gtk::RadioButton *all_cpus_radiobutton, *one_cpu_radiobutton; @@ -95,6 +95,19 @@ private: Gtk::ComboBox *temperature_combobox, *fan_speed_combobox; Gtk::Entry *temperature_tag, *fan_speed_tag; + Gtk::Box *generic_box, *generic_options, *generic_change_in_value_hbox, + *generic_number_regex_hbox; + Gtk::Entry *generic_file_path_entry, *generic_regex_entry, + *generic_data_source_name_long_entry, + *generic_data_source_name_short_entry, *generic_units_long_entry, + *generic_units_short_entry, *generic_tag; + Gtk::CheckButton *generic_change_in_value_checkbutton; + Gtk::RadioButton *generic_read_all_contents_radiobutton, + *generic_extract_via_regex_radiobutton, + *generic_change_in_value_positive_radiobutton, + *generic_change_in_value_negative_radiobutton, + *generic_change_in_value_both_radiobutton; + XfcePanelPlugin* panel_applet; // For disk statistics device name combobox @@ -176,14 +189,17 @@ private: void on_load_average_radiobutton_toggled(); void on_disk_usage_radiobutton_toggled(); void on_disk_stats_radiobutton_toggled(); - void on_memory_usage_radiobutton_toggled(); void on_swap_usage_radiobutton_toggled(); - void on_fan_speed_radiobutton_toggled(); - void on_network_load_radiobutton_toggled(); + void on_memory_usage_radiobutton_toggled(); void on_network_interfaces_restore_defaults_button_clicked(); - void on_temperature_radiobutton_toggled(); void on_network_interface_name_edited(const Glib::ustring& path, const Glib::ustring& new_text); + void on_network_load_radiobutton_toggled(); + void on_temperature_radiobutton_toggled(); + void on_fan_speed_radiobutton_toggled(); + void on_generic_radiobutton_toggled(); + void on_generic_extract_via_regex_radiobutton_toggled(); + void on_generic_change_in_value_checkbutton_toggled(); bool on_closed(GdkEventAny *); }; diff --git a/src/monitor-impls.cpp b/src/monitor-impls.cpp index 510f4c2..1059bd2 100644 --- a/src/monitor-impls.cpp +++ b/src/monitor-impls.cpp @@ -20,8 +20,10 @@ */ #include <algorithm> +#include <cmath> // For fabs #include <iomanip> // Needed for Precision helper #include <iostream> +#include <limits> // Used for sentinel value in Generic Monitor #include <string> #include <vector> @@ -187,6 +189,7 @@ load_monitors(XfceRc *settings_ro, XfcePanelPlugin *panel_plugin) "interface_direction", NetworkLoadMonitor::all_data); // Converting direction setting into dedicated type + // TODO: I think I need to standardise my enum loading/dealing with code NetworkLoadMonitor::Direction dir; if (inter_direction == NetworkLoadMonitor::incoming_data) @@ -218,6 +221,36 @@ load_monitors(XfceRc *settings_ro, XfcePanelPlugin *panel_plugin) monitors.push_back(new FanSpeedMonitor(fan_no, tag)); } + else if (type == "generic") + { + // Fetching settings + Glib::ustring file_path = xfce_rc_read_entry(settings_ro, "file_path", + ""), + regex_string = xfce_rc_read_entry(settings_ro, "regex", ""), + data_source_name_long = xfce_rc_read_entry(settings_ro, + "data_source_name_long", ""), + data_source_name_short = xfce_rc_read_entry(settings_ro, + "data_source_name_short", ""), + units_long = xfce_rc_read_entry(settings_ro, "units_long", ""), + units_short = xfce_rc_read_entry(settings_ro, "units_short", ""); + bool value_from_contents = xfce_rc_read_bool_entry(settings_ro, + "value_from_contents", + false), + follow_change = xfce_rc_read_bool_entry(settings_ro, "follow_change", + false); + GenericMonitor::ValueChangeDirection dir = + static_cast<GenericMonitor::ValueChangeDirection>( + xfce_rc_read_int_entry(settings_ro, "value_change_direction", + GenericMonitor::positive)); + + // Creating generic monitor + monitors.push_back(new GenericMonitor(file_path, value_from_contents, + regex_string, follow_change, dir, + data_source_name_long, + data_source_name_short, units_long, + units_short, tag)); + } + // Saving the monitor's settings root monitors.back()->set_settings_dir(settings_monitors[i]); } @@ -226,7 +259,7 @@ load_monitors(XfceRc *settings_ro, XfcePanelPlugin *panel_plugin) g_strfreev(settings_monitors); } - // Always start with a CpuUsageMonitor - FIXME: use schema? + // Always start with a CpuUsageMonitor if (monitors.empty()) monitors.push_back(new CpuUsageMonitor("")); @@ -728,7 +761,7 @@ DiskStatsMonitor::DiskStatsMonitor(const Glib::ustring &device_name, double DiskStatsMonitor::do_measure() { // Making sure stats file is available - if (!stats_available()) + if (!Glib::file_test(diskstats_path, Glib::FileTest::FILE_TEST_EXISTS)) { std::cerr << Glib::ustring::compose(_("The file '%1' is not available - " "unable to obtain %2 for device '%3'!" @@ -835,15 +868,6 @@ void DiskStatsMonitor::save(XfceRc *settings_w) xfce_rc_write_entry(settings_w, "tag", tag.c_str()); } -bool DiskStatsMonitor::stats_available() -{ - // Make sure file exists - return Glib::file_test(diskstats_path, Glib::FileTest::FILE_TEST_EXISTS); - - /* The contents of the file will be validated as it is processed, so not - * duplicating this here */ -} - std::map<Glib::ustring, std::vector<unsigned long int>> DiskStatsMonitor::parse_disk_stats() { @@ -1952,3 +1976,217 @@ void FanSpeedMonitor::save(XfceRc *settings_w) xfce_rc_write_entry(settings_w, "max", setting.c_str()); } + +// +// class GenericMonitor +// + +GenericMonitor::GenericMonitor(const Glib::ustring &file_path, + const bool value_from_contents, + const Glib::ustring ®ex_string, + const bool follow_change, + const ValueChangeDirection dir, + const Glib::ustring &data_source_name_long, + const Glib::ustring &data_source_name_short, + const Glib::ustring &units_long, + const Glib::ustring &units_short, + const Glib::ustring &tag_string) + : Monitor(tag_string), max_value(0), + previous_value(std::numeric_limits<double>::min()), + file_path(file_path), value_from_contents(value_from_contents), + follow_change(follow_change), dir(dir), + data_source_name_long(data_source_name_long), + data_source_name_short(data_source_name_short), units_long(units_long), + units_short(units_short) +{ + // Compiling regex if provided (at this stage its already been validated) + if (regex_string != "") + regex = Glib::Regex::create(regex_string); +} + +double GenericMonitor::do_measure() +{ + // Making sure stats file is available + if (!Glib::file_test(file_path, Glib::FileTest::FILE_TEST_EXISTS)) + { + std::cerr << Glib::ustring::compose(_("The file '%1' for the Generic Monitor" + " data source '%2' is not available!\n"), + file_path, data_source_name_long); + return 0; + } + + // Attempting to read contents of provided file + Glib::ustring file_contents; + try + { + file_contents = Glib::file_get_contents(file_path); + } + catch (Glib::FileError const &e) + { + std::cerr << Glib::ustring::compose(_("Unable read the contents of '%1' for " + "the Generic Monitor data source '%2' " + "due to error '%3'\n"), + file_path, data_source_name_long, + e.what()); + return 0; + } + + // Removing trailing newline if present + if (file_contents.substr(file_contents.length() - 1, + file_contents.length() - 1) == "\n") + file_contents = file_contents.substr(0, file_contents.length() - 1); + + // Obtaining number + double val; + std::stringstream data; + if (value_from_contents) + { + // Obtain number from the entire contents of the file + data.str(file_contents); + if (!(data >> val)) + { + std::cerr << Glib::ustring::compose(_("Unable to convert data '%1' from file " + "'%2' associated with Generic Monitor " + "data source '%3' into a number to " + "process! Defaulting to 0\n"), + file_contents, file_path, + data_source_name_long); + return 0; + } + } + else + { + /* Obtain number via a regex - the regex has already been validated with one + * matching group */ + Glib::MatchInfo match_info; + if (!regex->match(file_contents, match_info)) + { + // Unable to extract the number - warning user + std::cerr << Glib::ustring::compose(_("Unable extract number from file " + "contents '%1' from '%2' associated " + "with Generic Monitor data source '%3'" + " using the regex '%4'! Defaulting to " + "0\n"), file_contents, file_path, + data_source_name_long, + regex->get_pattern()); + return 0; + } + + // Fetching matching group results and attempting to convert to number + data.str(match_info.fetch(0)); + if (!(data >> val)) + { + std::cerr << Glib::ustring::compose(_("Unable to convert data '%1' from file " + "'%2' associated with Generic Monitor " + "data source '%3' into a number to " + "process! Defaulting to 0\n"), + file_contents, file_path, + data_source_name_long); + return 0; + } + } + + double return_value; + if (follow_change) + { + /* User has requested to diff the data to make a rate of change + * Dealing with the first value to be processed */ + if (previous_value == std::numeric_limits<double>::min()) + previous_value = val; + + /* Returning desired stat, based on whether the user wants only positive + * changes, negative changes, or both reported (these are intended for views + * that don't have a negative axis) */ + switch (dir) + { + case positive: + return_value = val - previous_value; + if (return_value <0) + return_value = 0; + break; + + case negative: + return_value = previous_value - val; + if (return_value <0) + return_value = 0; + break; + + case both: + return_value = fabs(val - previous_value); + } + previous_value = val; + } + else + return_value = val; + + // TODO: How do negative values affect this? + /* Note - max_value is no longer used to determine the graph max for + * Curves - the actual maxima stored in the ValueHistories are used */ + if (val != 0) // Reduce scale gradually + max_value = guint64(max_value * max_decay); + + if (val > max_value) + max_value = guint64(val * 1.05); + + // Debug code + /*std::cerr << Glib::ustring::compose("Generic Monitor '%1' data: %2, previous " + "data: %3\n", data_source_name_long, val, + previous_value);*/ + + return return_value; +} + +double GenericMonitor::max() +{ + return max_value; +} + +bool GenericMonitor::fixed_max() +{ + return false; +} + +Glib::ustring GenericMonitor::format_value(double val, bool compact) +{ + return Glib::ustring::compose("%1%2", val, + (compact) ? units_short : units_long); +} + +Glib::ustring GenericMonitor::get_name() +{ + return data_source_name_long; +} + + +Glib::ustring GenericMonitor::get_short_name() +{ + return data_source_name_short; +} + +int GenericMonitor::update_interval() +{ + return 1000; +} + +void GenericMonitor::save(XfceRc *settings_w) +{ + // Fetching assigned settings group + Glib::ustring directory = get_settings_dir(); + + // Saving settings + xfce_rc_set_group(settings_w, directory.c_str()); + xfce_rc_write_entry(settings_w, "type", "generic"); + xfce_rc_write_entry(settings_w, "file_path", file_path.c_str()); + xfce_rc_write_bool_entry(settings_w, "value_from_contents", value_from_contents); + xfce_rc_write_entry(settings_w, "regex", regex->get_pattern().c_str()); + xfce_rc_write_bool_entry(settings_w, "follow_change", follow_change); + xfce_rc_write_int_entry(settings_w, "value_change_direction", dir); + xfce_rc_write_entry(settings_w, "data_source_name_long", + data_source_name_long.c_str()); + xfce_rc_write_entry(settings_w, "data_source_name_short", + data_source_name_short.c_str()); + xfce_rc_write_entry(settings_w, "units_long", units_long.c_str()); + xfce_rc_write_entry(settings_w, "units_short", units_short.c_str()); + xfce_rc_write_entry(settings_w, "tag", tag.c_str()); +} + diff --git a/src/monitor-impls.hpp b/src/monitor-impls.hpp index 89ed4bd..2c17ff7 100644 --- a/src/monitor-impls.hpp +++ b/src/monitor-impls.hpp @@ -29,6 +29,7 @@ #include <vector> #include <glib/gtypes.h> +#include <glibmm/regex.h> #if HAVE_LIBSENSORS #include <sensors/sensors.h> @@ -184,13 +185,12 @@ public: virtual double max(); virtual bool fixed_max(); - virtual Glib::ustring format_value(double val, bool compact= false); + virtual Glib::ustring format_value(double val, bool compact=false); virtual Glib::ustring get_name(); virtual Glib::ustring get_short_name(); virtual int update_interval(); virtual void save(XfceRc *settings_w); - static bool stats_available(); static std::vector<Glib::ustring> current_device_names(); static Glib::ustring stat_to_string( const DiskStatsMonitor::Stat &stat, const bool short_ver); @@ -357,6 +357,50 @@ private: }; +class GenericMonitor: public Monitor +{ +public: + + // Used for the 'follow change in value' implementation setting + enum ValueChangeDirection { + positive, + negative, + both, + NUM_DIRECTIONS + }; + + GenericMonitor(const Glib::ustring &file_path, + const bool value_from_contents, + const Glib::ustring ®ex_string, + const bool follow_change, + const ValueChangeDirection dir, + const Glib::ustring &data_source_name_long, + const Glib::ustring &data_source_name_short, + const Glib::ustring &units_long, + const Glib::ustring &units_short, + const Glib::ustring &tag_string); + + virtual double max(); + virtual bool fixed_max(); + virtual Glib::ustring format_value(double val, bool compact=false); + virtual Glib::ustring get_name(); + virtual Glib::ustring get_short_name(); + virtual int update_interval(); + virtual void save(XfceRc *settings_w); + +private: + virtual double do_measure(); + + double max_value, previous_value; + + Glib::ustring file_path, data_source_name_long, + data_source_name_short, units_long, units_short, tag; + bool value_from_contents, follow_change; + ValueChangeDirection dir; + Glib::RefPtr<Glib::Regex> regex; +}; + + // a singleton for initializing the sensors library class Sensors: noncopyable { diff --git a/src/ui.glade b/src/ui.glade index c96a540..9a27b47 100644 --- a/src/ui.glade +++ b/src/ui.glade @@ -1375,6 +1375,500 @@ view</property> <property name="tab_fill">False</property> </packing> </child> + <child> + <object class="GtkVBox" id="generic_vbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">12</property> + <property name="spacing">12</property> + <child> + <object class="GtkVBox" id="generic_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkRadioButton" id="generic_radiobutton"> + <property name="label" translatable="yes">_Generic</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Data/numbers read from a user-defined file</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + <property name="group">cpu_usage_radiobutton</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="generic_options"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkVBox" id="generic_options_vbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkHBox" id="generic_file_path_hbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="file_path_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">File to read from:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="generic_file_path_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Enter the path to the file to read a number from</property> + <property name="invisible_char">●</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="primary_icon_sensitive">True</property> + <property name="secondary_icon_sensitive">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="generic_number_reading_hbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkRadioButton" id="generic_read_all_contents_radiobutton"> + <property name="label" translatable="yes">Number from entire contents</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="generic_extract_via_regex_radiobutton"> + <property name="label" translatable="yes">Number from regex</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + <property name="group">generic_read_all_contents_radiobutton</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="generic_number_regex_hbox"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="regex_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Regex to use:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="generic_regex_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Regex to extract the number from the file contents with (must have one capture group for the number)</property> + <property name="invisible_char">●</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="primary_icon_sensitive">True</property> + <property name="secondary_icon_sensitive">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="generic_change_in_value_checkbutton"> + <property name="label" translatable="yes">Follow _change in value</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">When visualised, rather than plotting the data direct, the difference between the current and previous measurement will be used</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="generic_change_in_value_hbox"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">False</property> + <child> + <object class="GtkRadioButton" id="generic_change_in_value_positive_radiobutton"> + <property name="label" translatable="yes">Positive change</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Return absolute difference between current value and previous value, when change is positive</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="generic_change_in_value_negative_radiobutton"> + <property name="label" translatable="yes">Negative change</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Return absolute difference between current value and previous value, when change is negative</property> + <property name="draw_indicator">True</property> + <property name="group">generic_change_in_value_positive_radiobutton</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="generic_change_in_value_both_radiobutton"> + <property name="label" translatable="yes">Both</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Return absolute difference between current value and previous value in either case</property> + <property name="draw_indicator">True</property> + <property name="group">generic_change_in_value_positive_radiobutton</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="data_source_name_long_hbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="data_source_name_long_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Data source name (long):</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="generic_data_source_name_long_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">The full name of your data source</property> + <property name="invisible_char">●</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="primary_icon_sensitive">True</property> + <property name="secondary_icon_sensitive">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">5</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="data_source_name_short_hbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="data_source_name_short_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Data source name (short):</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="generic_data_source_name_short_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">A short version of your data source name for display in crampt areas</property> + <property name="invisible_char">●</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="primary_icon_sensitive">True</property> + <property name="secondary_icon_sensitive">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">6</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="units_long_hbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="units_long_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Units (long):</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="generic_units_long_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Units the data source is in</property> + <property name="invisible_char">●</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="primary_icon_sensitive">True</property> + <property name="secondary_icon_sensitive">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">7</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="units_short_hbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="units_short_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Units (short):</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="generic_units_short_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Units the data source is in for display in crampt areas</property> + <property name="invisible_char">●</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="primary_icon_sensitive">True</property> + <property name="secondary_icon_sensitive">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">8</property> + </packing> + </child> + <child> + <object class="GtkHBox" id="generic_tag_hbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkLabel" id="generic_tag_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Tag: </property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="generic_tag_entry"> + <property name="width_request">80</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="tooltip_text" translatable="yes">Tag to display along with monitor data +in the optional text overlay in a curve +view</property> + <property name="invisible_char">●</property> + <property name="invisible_char_set">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="primary_icon_sensitive">True</property> + <property name="secondary_icon_sensitive">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">9</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">18</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="position">4</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="generic_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Generic</property> + </object> + <packing> + <property name="position">4</property> + <property name="tab_fill">False</property> + </packing> + </child> </object> <packing> <property name="expand">True</property> -- To stop receiving notification emails like this one, please contact the administrator of this repository. _______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org https://mail.xfce.org/mailman/listinfo/xfce4-commits