mirror of
https://github.com/ashaduri/gsmartcontrol.git
synced 2026-09-26 22:05:34 +00:00
Refactored gtkmm utils and app builder to simply the code and document it better.
This commit is contained in:
+133
-76
@@ -24,10 +24,9 @@ Copyright:
|
||||
|
||||
|
||||
|
||||
// These allow easy attaching of gtkbuilder widget signals to member functions
|
||||
|
||||
/// Connect member function (callback) to signal \c signal_name on widget
|
||||
/// \c ui_element, where \c ui_element is the widget's gtkbuilder name.
|
||||
/// Connect member function (callback) to signal \ref signal_name on widget
|
||||
/// \ref ui_element, where \ref ui_element is the widget's gtkbuilder name.
|
||||
/// This allows easy attaching of gtkbuilder widget signals to member functions.
|
||||
#define APP_BUILDER_CONNECT(ui_element, signal_name, callback) \
|
||||
if (true) { \
|
||||
if (!(ui_element)) \
|
||||
@@ -38,6 +37,7 @@ Copyright:
|
||||
} else (void)0
|
||||
|
||||
|
||||
|
||||
/// Connect member function (callback) with a name of \c on_<widget_name>_<signal_name>
|
||||
/// to signal \c signal_name on widget \c ui_element, where \c ui_element is the
|
||||
/// widget's gtkbuilder name.
|
||||
@@ -46,6 +46,7 @@ Copyright:
|
||||
|
||||
|
||||
|
||||
|
||||
/// Inherit this when using GtkBuilder-enabled windows (or any other GtkBuilder-enabled objects).
|
||||
/// \c Child is the child class that inherits all the functionality of having instance lifetime
|
||||
/// management and other benefits.
|
||||
@@ -54,106 +55,62 @@ template<class Child, bool MultiInstance, class WidgetType = Gtk::Window>
|
||||
class AppBuilderWidget : public WidgetType, public hz::InstanceManager<Child, MultiInstance> {
|
||||
public:
|
||||
|
||||
/// Instance class type, which is also the parent class.
|
||||
friend class Gtk::Builder; // allow construction through gtkbuilder
|
||||
friend class hz::InstanceManager<Child, MultiInstance>; // allow construction through instance class
|
||||
friend class Gtk::Builder; // allow construction via GtkBuilder
|
||||
// friend class hz::InstanceManager<Child, MultiInstance>; // allow construction through instance class
|
||||
|
||||
|
||||
/// Override parent hz::InstanceManager's function because of non-trivial constructor
|
||||
static Child* create()
|
||||
{
|
||||
if constexpr(!MultiInstance) { // for single-instance objects
|
||||
if (hz::InstanceManager<Child, MultiInstance>::get_single_instance()) {
|
||||
return hz::InstanceManager<Child, MultiInstance>::get_single_instance();
|
||||
}
|
||||
}
|
||||
/// Disallow
|
||||
AppBuilderWidget(const AppBuilderWidget& other) = delete;
|
||||
|
||||
std::string error_msg;
|
||||
/// Disallow
|
||||
AppBuilderWidget(const AppBuilderWidget&& other) = delete;
|
||||
|
||||
auto ui_path = hz::data_file_find("ui", std::string(Child::ui_name) + ".glade");
|
||||
try {
|
||||
auto ui = Gtk::Builder::create_from_file(ui_path.u8string()); // may throw
|
||||
/// Disallow
|
||||
AppBuilderWidget& operator=(const AppBuilderWidget& other) = delete;
|
||||
|
||||
Child* o = nullptr;
|
||||
ui->get_widget_derived({Child::ui_name.data(), Child::ui_name.size()}, o); // Calls Child's constructor
|
||||
/// Disallow
|
||||
AppBuilderWidget& operator=(const AppBuilderWidget&& other) = delete;
|
||||
|
||||
if (!o) {
|
||||
debug_out_fatal("app", "Fatal error: Cannot get root widget from UI-resource-created hierarchy.\n");
|
||||
gui_show_error_dialog(_("Fatal error: Cannot get root widget from UI-resource-created hierarchy."));
|
||||
return nullptr;
|
||||
}
|
||||
/// Default
|
||||
~AppBuilderWidget() = default;
|
||||
|
||||
if constexpr(!MultiInstance) {
|
||||
hz::InstanceManager<Child, MultiInstance>::set_single_instance(o); // for single-instance objects
|
||||
}
|
||||
return o;
|
||||
}
|
||||
catch (Glib::Exception& ex) {
|
||||
error_msg = ex.what();
|
||||
}
|
||||
|
||||
if (!error_msg.empty()) {
|
||||
debug_out_fatal("app", "Fatal error: Cannot create UI-resource widgets: " << error_msg << "\n");
|
||||
gui_show_error_dialog(Glib::ustring::compose(_("Fatal error: Cannot create UI-resource widgets: %1"), error_msg));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Create an instance of this class, returning an existing instance if not MultiInstance.
|
||||
/// A glade file in "ui" data domain is loaded with Child::ui_name filename base and is available as
|
||||
/// `get_ui()` in child object.
|
||||
/// \return nullptr if widget could not be loaded.
|
||||
static Child* create();
|
||||
|
||||
|
||||
/// Get UI resource
|
||||
Glib::RefPtr<Gtk::Builder> get_ui()
|
||||
{
|
||||
return ui_;
|
||||
}
|
||||
Glib::RefPtr<Gtk::Builder> get_ui();
|
||||
|
||||
|
||||
/// Find a widget in UI and return it.
|
||||
Gtk::Widget* lookup_widget(const Glib::ustring& name)
|
||||
{
|
||||
return lookup_widget<Gtk::Widget*>(name);
|
||||
}
|
||||
/// \return nullptr if widget was not found.
|
||||
Gtk::Widget* lookup_widget(const Glib::ustring& name);
|
||||
|
||||
|
||||
/// Find a widget in UI and return it.
|
||||
/// \return nullptr if widget was not found.
|
||||
template<typename WidgetPtr>
|
||||
WidgetPtr lookup_widget(const Glib::ustring& name)
|
||||
{
|
||||
WidgetPtr w = nullptr;
|
||||
return lookup_widget(name, w);
|
||||
}
|
||||
WidgetPtr lookup_widget(const Glib::ustring& name);
|
||||
|
||||
|
||||
/// Find a widget in UI and return it.
|
||||
/// Find a widget in UI and return it in \ref w.
|
||||
/// \return false if widget was not found.
|
||||
template<typename Widget>
|
||||
Widget* lookup_widget(const Glib::ustring& name, Widget*& w)
|
||||
{
|
||||
ui_->get_widget(name, w);
|
||||
return w;
|
||||
}
|
||||
bool lookup_widget(const Glib::ustring& name, Widget*& w);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// protected constructor / destructor, use create() / destroy() instead of new / delete.
|
||||
|
||||
/// Protected constructor, use `create()` instead.
|
||||
/// GtkBuilder needs this constructor in a child.
|
||||
/// BaseObjectType is a C type, defined in specific Gtk:: widget class.
|
||||
AppBuilderWidget(typename WidgetType::BaseObjectType* gtkcobj, Glib::RefPtr<Gtk::Builder> ui)
|
||||
: WidgetType(gtkcobj), ui_(std::move(ui))
|
||||
{
|
||||
// manually connecting signals:
|
||||
// this->signal_delete_event().connect(sigc::mem_fun(*this, &MainWindow::on_main_window_delete));
|
||||
|
||||
// signals of GtkBuilder-created objects:
|
||||
// Gtk::ToolButton* rescan_devices_toolbutton = 0;
|
||||
// APP_BUILDER_AUTO_CONNECT(rescan_devices_toolbutton, clicked);
|
||||
|
||||
// show();
|
||||
}
|
||||
|
||||
|
||||
/// Virtual destructor
|
||||
~AppBuilderWidget() = default;
|
||||
AppBuilderWidget(typename WidgetType::BaseObjectType* gtkcobj, Glib::RefPtr<Gtk::Builder> ui);
|
||||
|
||||
|
||||
private:
|
||||
@@ -166,6 +123,106 @@ class AppBuilderWidget : public WidgetType, public hz::InstanceManager<Child, Mu
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------- Implementation
|
||||
|
||||
|
||||
template<class Child, bool MultiInstance, class WidgetType>
|
||||
Child* AppBuilderWidget<Child, MultiInstance, WidgetType>::create()
|
||||
{
|
||||
if constexpr(!MultiInstance) { // for single-instance objects
|
||||
if (auto* inst = hz::InstanceManager<Child, MultiInstance>::instance()) {
|
||||
return inst;
|
||||
}
|
||||
}
|
||||
|
||||
std::string error_msg;
|
||||
|
||||
auto ui_path = hz::data_file_find("ui", std::string(Child::ui_name) + ".glade");
|
||||
try {
|
||||
auto ui = Gtk::Builder::create_from_file(ui_path.u8string()); // may throw
|
||||
|
||||
Child* o = nullptr;
|
||||
ui->get_widget_derived({Child::ui_name.data(), Child::ui_name.size()}, o); // Calls Child's constructor
|
||||
|
||||
if (!o) {
|
||||
debug_out_fatal("app", "Fatal error: Cannot get root widget from UI-resource-created hierarchy.\n");
|
||||
gui_show_error_dialog(_("Fatal error: Cannot get root widget from UI-resource-created hierarchy."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if constexpr(!MultiInstance) {
|
||||
hz::InstanceManager<Child, MultiInstance>::set_single_instance(o); // for single-instance objects
|
||||
}
|
||||
return o;
|
||||
}
|
||||
catch (Glib::Exception& ex) {
|
||||
error_msg = ex.what();
|
||||
}
|
||||
|
||||
if (!error_msg.empty()) {
|
||||
debug_out_fatal("app", "Fatal error: Cannot create UI-resource widgets: " << error_msg << "\n");
|
||||
gui_show_error_dialog(Glib::ustring::compose(_("Fatal error: Cannot create UI-resource widgets: %1"), error_msg));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Child, bool MultiInstance, class WidgetType>
|
||||
Glib::RefPtr<Gtk::Builder> AppBuilderWidget<Child, MultiInstance, WidgetType>::get_ui()
|
||||
{
|
||||
return ui_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Child, bool MultiInstance, class WidgetType>
|
||||
template<typename WidgetPtr>
|
||||
WidgetPtr AppBuilderWidget<Child, MultiInstance, WidgetType>::lookup_widget(const Glib::ustring& name)
|
||||
{
|
||||
WidgetPtr w = nullptr;
|
||||
lookup_widget(name, w);
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Child, bool MultiInstance, class WidgetType>
|
||||
Gtk::Widget* AppBuilderWidget<Child, MultiInstance, WidgetType>::lookup_widget(const Glib::ustring& name)
|
||||
{
|
||||
return lookup_widget<Gtk::Widget*>(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Child, bool MultiInstance, class WidgetType>
|
||||
template<typename Widget>
|
||||
bool AppBuilderWidget<Child, MultiInstance, WidgetType>::lookup_widget(const Glib::ustring& name, Widget*& w)
|
||||
{
|
||||
ui_->get_widget(name, w);
|
||||
return w != nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Child, bool MultiInstance, class WidgetType>
|
||||
AppBuilderWidget<Child, MultiInstance, WidgetType>::AppBuilderWidget(typename WidgetType::BaseObjectType* gtkcobj, Glib::RefPtr<Gtk::Builder> ui)
|
||||
: WidgetType(gtkcobj), ui_(std::move(ui))
|
||||
{
|
||||
// An example of Child's constructor:
|
||||
|
||||
// Manually connect signals:
|
||||
// this->signal_delete_event().connect(sigc::mem_fun(*this, &MainWindow::on_main_window_delete));
|
||||
|
||||
// Automatically connect signals of GtkBuilder-created objects to member functions:
|
||||
// Gtk::ToolButton* rescan_devices_toolbutton = 0;
|
||||
// APP_BUILDER_AUTO_CONNECT(rescan_devices_toolbutton, clicked);
|
||||
|
||||
// show();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -16,8 +16,10 @@ Copyright:
|
||||
#include <gtkmm.h>
|
||||
|
||||
|
||||
|
||||
/// \def APP_GTKMM_CHECK_VERSION(major, minor, micro)
|
||||
/// Similar to GTK_CHECK_VERSION, but for gtkmm, which lacks this for some reason.
|
||||
/// Similar to GTK_CHECK_VERSION, but for Gtkmm, which lacks this before gtkmm4.
|
||||
/// This is useful as Gtk and Gtkmm versions may differ.
|
||||
#ifndef APP_GTKMM_CHECK_VERSION
|
||||
#define APP_GTKMM_CHECK_VERSION(major, minor, micro) \
|
||||
(GTKMM_MAJOR_VERSION > (major) \
|
||||
|
||||
@@ -20,7 +20,6 @@ Copyright:
|
||||
|
||||
|
||||
|
||||
// Note: This works only if the column has custom widget set.
|
||||
Gtk::Widget* app_gtkmm_get_column_header(Gtk::TreeViewColumn& column)
|
||||
{
|
||||
Gtk::Widget* w = column.get_widget();
|
||||
@@ -37,19 +36,16 @@ Gtk::Widget* app_gtkmm_get_column_header(Gtk::TreeViewColumn& column)
|
||||
|
||||
|
||||
|
||||
// Read column header text and create a label with that text, set it as column's custom widget.
|
||||
Gtk::Widget* app_gtkmm_labelize_column(Gtk::TreeViewColumn& column)
|
||||
Gtk::Label& app_gtkmm_labelize_column(Gtk::TreeViewColumn& column)
|
||||
{
|
||||
Gtk::Label* label = Gtk::manage(new Gtk::Label(column.get_title()));
|
||||
label->show();
|
||||
column.set_widget(*label);
|
||||
return label;
|
||||
return *label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// A wrapper around set_tooltip_*() for portability across different gtkmm versions.
|
||||
void app_gtkmm_set_widget_tooltip(Gtk::Widget& widget,
|
||||
const Glib::ustring& tooltip_text, bool use_markup)
|
||||
{
|
||||
@@ -67,7 +63,7 @@ namespace {
|
||||
/// This has been copied from _g_utf8_make_valid() (glib-2.20.4).
|
||||
/// _g_utf8_make_valid() is GLib's private function for auto-correcting
|
||||
/// the potentially invalid utf-8 data.
|
||||
inline gchar* gsc_g_utf8_make_valid (const gchar* name)
|
||||
inline gchar* app_make_valid_utf_c (const gchar* name)
|
||||
{
|
||||
GString* str = nullptr;
|
||||
const gchar* remainder = nullptr;
|
||||
@@ -123,29 +119,23 @@ Glib::ustring app_ustring_from_gchar(gchar* str)
|
||||
|
||||
|
||||
|
||||
Glib::ustring app_utf8_make_valid(const Glib::ustring& str)
|
||||
Glib::ustring app_make_valid_utf8(const Glib::ustring& str)
|
||||
{
|
||||
char* s = gsc_g_utf8_make_valid(str.c_str());
|
||||
if (!s) {
|
||||
return Glib::ustring();
|
||||
}
|
||||
Glib::ustring res(s);
|
||||
g_free(s);
|
||||
return res;
|
||||
return app_ustring_from_gchar(app_make_valid_utf_c(str.c_str()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Glib::ustring app_output_make_valid(const Glib::ustring& str)
|
||||
Glib::ustring app_make_valid_utf8_from_command_output(const std::string& str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
try {
|
||||
return app_utf8_make_valid(Glib::locale_to_utf8(str));
|
||||
return Glib::locale_to_utf8(str); // detects invalid utf-8 sequences
|
||||
} catch (Glib::ConvertError& e) {
|
||||
// nothing, try to fix as it is
|
||||
}
|
||||
#endif
|
||||
return app_utf8_make_valid(str);
|
||||
return app_ustring_from_gchar(app_make_valid_utf_c(str.c_str()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,49 +19,26 @@ Copyright:
|
||||
|
||||
/// Get column header widget of a tree view column.
|
||||
/// Note: This works only if the column has custom widget set.
|
||||
/// \return nullptr on failure.
|
||||
Gtk::Widget* app_gtkmm_get_column_header(Gtk::TreeViewColumn& column);
|
||||
|
||||
|
||||
/// Read column header text and create a label with that text. Set the label as
|
||||
/// column's custom widget and return it.
|
||||
Gtk::Widget* app_gtkmm_labelize_column(Gtk::TreeViewColumn& column);
|
||||
Gtk::Label& app_gtkmm_labelize_column(Gtk::TreeViewColumn& column);
|
||||
|
||||
|
||||
/// A wrapper around set_tooltip_*() for portability across different gtkmm versions.
|
||||
/// A wrapper around set_tooltip_*(), calling appropriate method depending on `use_markup`.
|
||||
void app_gtkmm_set_widget_tooltip(Gtk::Widget& widget,
|
||||
const Glib::ustring& tooltip_text, bool use_markup = false);
|
||||
|
||||
|
||||
|
||||
/// Convenience function for creating a TreeViewColumn .
|
||||
template<typename T>
|
||||
int app_gtkmm_create_tree_view_column(Gtk::TreeModelColumn<T>& mcol, Gtk::TreeView& treeview,
|
||||
const Glib::ustring& title, const Glib::ustring& tooltip_text, bool sortable = false, bool cell_markup = false, bool tooltip_markup = false)
|
||||
{
|
||||
int num_tree_cols = treeview.append_column(title, mcol);
|
||||
Gtk::TreeViewColumn* tcol = treeview.get_column(num_tree_cols - 1);
|
||||
if (tcol) {
|
||||
if (sortable)
|
||||
tcol->set_sort_column(mcol);
|
||||
|
||||
app_gtkmm_labelize_column(*tcol);
|
||||
tcol->set_reorderable(true);
|
||||
tcol->set_resizable(true);
|
||||
|
||||
Gtk::Widget* header = app_gtkmm_get_column_header(*tcol);
|
||||
if (header)
|
||||
app_gtkmm_set_widget_tooltip(*header, tooltip_text, tooltip_markup);
|
||||
}
|
||||
|
||||
if (cell_markup) {
|
||||
if (auto cr_type = dynamic_cast<Gtk::CellRendererText*>(treeview.get_column_cell_renderer(num_tree_cols - 1))) {
|
||||
treeview.get_column(num_tree_cols - 1)->clear_attributes(*cr_type); // clear "text" attribute. "markup" won't work without this.
|
||||
treeview.get_column(num_tree_cols - 1)->add_attribute(cr_type->property_markup(), mcol); // render col_type as markup.
|
||||
}
|
||||
}
|
||||
|
||||
return num_tree_cols;
|
||||
}
|
||||
/// Convenience function for creating a TreeViewColumn from model column.
|
||||
/// \return tree column index
|
||||
template<typename DataType>
|
||||
int app_gtkmm_create_tree_view_column(const Gtk::TreeModelColumn<DataType>& model_column,
|
||||
Gtk::TreeView& treeview, const Glib::ustring& header_title, const Glib::ustring& header_tooltip_text,
|
||||
bool sortable = false, bool use_cell_markup = false, bool header_tooltip_is_markup = false);
|
||||
|
||||
|
||||
|
||||
@@ -71,14 +48,55 @@ Glib::ustring app_ustring_from_gchar(gchar* str);
|
||||
|
||||
/// Convert a possibly invalid utf-8 string to valid utf-8.
|
||||
/// \param str string to test and fix.
|
||||
Glib::ustring app_utf8_make_valid(const Glib::ustring& str);
|
||||
Glib::ustring app_make_valid_utf8(const Glib::ustring& str);
|
||||
|
||||
|
||||
/// Make command output a valid utf-8 string. Essentially, this calls app_utf8_make_valid(),
|
||||
/// supplying true for \c in_locale under Win32, and false under other systems.
|
||||
/// Make command output a valid utf-8 string. This function takes command output
|
||||
/// (in locale encoding under Windows, utf-8 encoding under other OSes), and converts
|
||||
/// it to valid utf-8.
|
||||
/// The reason for this is that in Win32 we can't execute commands under C locale,
|
||||
/// but we do execute them under C in other systems.
|
||||
Glib::ustring app_output_make_valid(const Glib::ustring& str);
|
||||
Glib::ustring app_make_valid_utf8_from_command_output(const std::string& str);
|
||||
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------- Implementation
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename DataType>
|
||||
int app_gtkmm_create_tree_view_column(const Gtk::TreeModelColumn<DataType>& model_column,
|
||||
Gtk::TreeView& treeview, const Glib::ustring& header_title, const Glib::ustring& header_tooltip_text,
|
||||
bool sortable, bool use_cell_markup, bool header_tooltip_is_markup)
|
||||
{
|
||||
int num_tree_cols = treeview.append_column(header_title, model_column);
|
||||
Gtk::TreeViewColumn* tcol = treeview.get_column(num_tree_cols - 1);
|
||||
if (tcol) {
|
||||
if (sortable) {
|
||||
tcol->set_sort_column(model_column);
|
||||
}
|
||||
|
||||
app_gtkmm_labelize_column(*tcol);
|
||||
tcol->set_reorderable(true);
|
||||
tcol->set_resizable(true);
|
||||
|
||||
Gtk::Widget* header = app_gtkmm_get_column_header(*tcol);
|
||||
if (header) {
|
||||
app_gtkmm_set_widget_tooltip(*header, header_tooltip_text, header_tooltip_is_markup);
|
||||
}
|
||||
}
|
||||
|
||||
if (use_cell_markup) {
|
||||
if (auto* cr_type = dynamic_cast<Gtk::CellRendererText*>(treeview.get_column_cell_renderer(num_tree_cols - 1))) {
|
||||
treeview.get_column(num_tree_cols - 1)->clear_attributes(*cr_type); // clear "text" attribute. "markup" won't work without this.
|
||||
treeview.get_column(num_tree_cols - 1)->add_attribute(cr_type->property_markup(), model_column); // render col_type as markup.
|
||||
}
|
||||
}
|
||||
|
||||
return num_tree_cols - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ void GscAboutDialog::on_response(int response_id)
|
||||
if (response_id == Gtk::RESPONSE_NONE || response_id == Gtk::RESPONSE_DELETE_EVENT
|
||||
|| response_id == Gtk::RESPONSE_CANCEL || response_id == Gtk::RESPONSE_CLOSE) {
|
||||
debug_out_info("app", DBG_FUNC_MSG << "Closing the dialog.\n");
|
||||
destroy(); // close the window and delete the object
|
||||
delete this; // close the window and delete the object
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ bool GscAddDeviceWindow::on_delete_event([[maybe_unused]] GdkEventAny* e)
|
||||
|
||||
void GscAddDeviceWindow::on_window_cancel_button_clicked()
|
||||
{
|
||||
destroy(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ void GscAddDeviceWindow::on_window_ok_button_clicked()
|
||||
main_window_->add_device(dev, type, params);
|
||||
}
|
||||
|
||||
destroy(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ void gsc_no_info_dialog_show(const std::string& message, const std::string& sec_
|
||||
|
||||
if (response == Gtk::RESPONSE_HELP) {
|
||||
GscTextWindow<SmartctlOutputInstance>* win = GscTextWindow<SmartctlOutputInstance>::create();
|
||||
win->set_text(output_window_title, output, true, true);
|
||||
win->set_text_from_command(output_window_title, output);
|
||||
|
||||
if (!default_save_filename.empty())
|
||||
win->set_save_filename(default_save_filename);
|
||||
|
||||
@@ -421,7 +421,7 @@ void GscExecutorLogWindow::on_tree_selection_changed()
|
||||
if (auto* output_textview = this->lookup_widget<Gtk::TextView*>("output_textview")) {
|
||||
Glib::RefPtr<Gtk::TextBuffer> buffer = output_textview->get_buffer();
|
||||
if (buffer) {
|
||||
buffer->set_text(app_output_make_valid(entry->std_output));
|
||||
buffer->set_text(app_make_valid_utf8_from_command_output(entry->std_output));
|
||||
|
||||
Glib::RefPtr<Gtk::TextTag> tag;
|
||||
Glib::RefPtr<Gtk::TextTagTable> table = buffer->get_tag_table();
|
||||
@@ -437,7 +437,7 @@ void GscExecutorLogWindow::on_tree_selection_changed()
|
||||
|
||||
if (auto* command_entry = this->lookup_widget<Gtk::Entry*>("command_entry")) {
|
||||
std::string cmd_text = entry->command + " " + entry->parameters;
|
||||
command_entry->set_text(app_output_make_valid(cmd_text));
|
||||
command_entry->set_text(app_make_valid_utf8_from_command_output(cmd_text));
|
||||
}
|
||||
|
||||
if (auto* window_save_current_button = this->lookup_widget<Gtk::Button*>("window_save_current_button"))
|
||||
|
||||
+46
-46
@@ -722,7 +722,7 @@ void GscInfoWindow::on_view_output_button_clicked()
|
||||
output = this->drive->get_info_output();
|
||||
}
|
||||
|
||||
win->set_text(_("Smartctl Output"), output, true, true);
|
||||
win->set_text_from_command(_("Smartctl Output"), output);
|
||||
|
||||
std::string filename = drive->get_save_filename();
|
||||
if (!filename.empty())
|
||||
@@ -838,7 +838,7 @@ void GscInfoWindow::on_close_window_button_clicked()
|
||||
if (drive && drive->get_test_is_active()) { // disallow close if test is active.
|
||||
gui_show_warn_dialog(_("Please wait until all tests are finished."), this);
|
||||
} else {
|
||||
destroy(this); // deletes this object and nullifies instance
|
||||
delete this; // deletes this object and nullifies instance
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,63 +963,63 @@ void GscInfoWindow::fill_ui_attributes(const std::vector<StorageProperty>& props
|
||||
auto* treeview = lookup_widget<Gtk::TreeView*>("attributes_treeview");
|
||||
|
||||
Gtk::TreeModelColumnRecord model_columns;
|
||||
int num_tree_cols = 0;
|
||||
[[maybe_unused]] int num_tree_col = 0;
|
||||
|
||||
// ID (int), Name, Flag (hex), Normalized Value (uint8), Worst (uint8), Thresh (uint8), Raw (int64), Type (string),
|
||||
// Updated (string), When Failed (string)
|
||||
|
||||
Gtk::TreeModelColumn<int32_t> col_id;
|
||||
model_columns.add(col_id); // we can use the column variable by value after this.
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_id, *treeview, _("ID"), _("Attribute ID"), true);
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_id, *treeview, _("ID"), _("Attribute ID"), true);
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_name;
|
||||
model_columns.add(col_name);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_name, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_name, *treeview,
|
||||
_("Name"), _("Attribute name (this is deduced from ID by smartctl and may be incorrect, as it's highly vendor-specific)"), true);
|
||||
treeview->set_search_column(col_name.index());
|
||||
auto* cr_name = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_cols - 1));
|
||||
auto* cr_name = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_col));
|
||||
if (cr_name)
|
||||
cr_name->property_weight() = Pango::WEIGHT_BOLD;
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_failed;
|
||||
model_columns.add(col_failed);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_failed, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_failed, *treeview,
|
||||
_("Failed"), _("When failed (that is, the normalized value became equal to or less than threshold)"), true, true);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_value;
|
||||
model_columns.add(col_value);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_value, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_value, *treeview,
|
||||
C_("value", "Normalized"), _("Normalized value (highly vendor-specific; converted from Raw value by the drive's firmware)"), false);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_worst;
|
||||
model_columns.add(col_worst);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_worst, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_worst, *treeview,
|
||||
C_("value", "Worst"), _("The worst normalized value recorded for this attribute during the drive's lifetime (with SMART enabled)"), false);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_threshold;
|
||||
model_columns.add(col_threshold);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_threshold, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_threshold, *treeview,
|
||||
C_("value", "Threshold"), _("Threshold for normalized value. Normalized value should be greater than threshold (unless vendor thinks otherwise)."), false);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_raw;
|
||||
model_columns.add(col_raw);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_raw, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_raw, *treeview,
|
||||
_("Raw value"), _("Raw value as reported by drive. May or may not be sensible."), false);
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_type;
|
||||
model_columns.add(col_type);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_type, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_type, *treeview,
|
||||
_("Type"), _("Alarm condition is reached when normalized value becomes less than or equal to threshold. Type indicates whether it's a signal of drive's pre-failure time or just an old age."), false, true);
|
||||
|
||||
// Doesn't carry that much info. Advanced users can look at the flags.
|
||||
// Gtk::TreeModelColumn<Glib::ustring> col_updated;
|
||||
// model_columns.add(col_updated);
|
||||
// num_tree_cols = app_gtkmm_create_tree_view_column(col_updated, *treeview,
|
||||
// tree_col = app_gtkmm_create_tree_view_column(col_updated, *treeview,
|
||||
// "Updated", "The attribute is usually updated continuously, or during Offline Data Collection only. This column indicates that.", true);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_flag_value;
|
||||
model_columns.add(col_flag_value);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_flag_value, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_flag_value, *treeview,
|
||||
_("Flags"), _("Flags") + "\n\n"s
|
||||
+ Glib::ustring::compose(_("If given in %1 format, the presence of each letter indicates that the flag is on."), "POSRCK+") + "\n"
|
||||
+ _("P: pre-failure attribute (if the attribute failed, the drive is failing)") + "\n"
|
||||
@@ -1044,7 +1044,7 @@ void GscInfoWindow::fill_ui_attributes(const std::vector<StorageProperty>& props
|
||||
list_store->set_sort_column(col_id, Gtk::SORT_ASCENDING); // default sort
|
||||
treeview->set_model(list_store);
|
||||
|
||||
for (int i = 0; i < num_tree_cols; ++i) {
|
||||
for (int i = 0; i < int(treeview->get_n_columns()); ++i) {
|
||||
Gtk::TreeViewColumn* tcol = treeview->get_column(i);
|
||||
tcol->set_cell_data_func(*(tcol->get_first_cell()),
|
||||
sigc::bind(sigc::ptr_fun(app_list_cell_renderer_func), col_storage));
|
||||
@@ -1111,25 +1111,25 @@ void GscInfoWindow::fill_ui_statistics(const std::vector<StorageProperty>& props
|
||||
auto* treeview = lookup_widget<Gtk::TreeView*>("statistics_treeview");
|
||||
|
||||
Gtk::TreeModelColumnRecord model_columns;
|
||||
int num_tree_cols = 0;
|
||||
[[maybe_unused]] int num_tree_col = 0;
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_description;
|
||||
model_columns.add(col_description);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_description, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_description, *treeview,
|
||||
_("Description"), _("Entry description"), true);
|
||||
treeview->set_search_column(col_description.index());
|
||||
// Gtk::CellRendererText* cr_name = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_cols - 1));
|
||||
// Gtk::CellRendererText* cr_name = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_col));
|
||||
// if (cr_name)
|
||||
// cr_name->property_weight() = Pango::WEIGHT_BOLD ;
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_value;
|
||||
model_columns.add(col_value);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_value, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_value, *treeview,
|
||||
_("Value"), Glib::ustring::compose(_("Value (can be normalized if '%1' flag is present)"), "N"), false);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_flags;
|
||||
model_columns.add(col_flags);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_flags, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_flags, *treeview,
|
||||
_("Flags"), _("Flags") + "\n\n"s
|
||||
+ _("N: value is normalized") + "\n"
|
||||
+ _("D: supports Device Statistics Notification (DSN)") + "\n"
|
||||
@@ -1138,7 +1138,7 @@ void GscInfoWindow::fill_ui_statistics(const std::vector<StorageProperty>& props
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_page_offset;
|
||||
model_columns.add(col_page_offset);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_page_offset, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_page_offset, *treeview,
|
||||
_("Page, Offset"), _("Page and offset of the entry"), false);
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_tooltip;
|
||||
@@ -1154,7 +1154,7 @@ void GscInfoWindow::fill_ui_statistics(const std::vector<StorageProperty>& props
|
||||
treeview->set_model(list_store);
|
||||
// No sorting (we don't want to screw up the headers).
|
||||
|
||||
for (int i = 0; i < num_tree_cols; ++i) {
|
||||
for (int i = 0; i < int(treeview->get_n_columns()); ++i) {
|
||||
Gtk::TreeViewColumn* tcol = treeview->get_column(i);
|
||||
tcol->set_cell_data_func(*(tcol->get_first_cell()),
|
||||
sigc::bind(sigc::ptr_fun(app_list_cell_renderer_func), col_storage));
|
||||
@@ -1291,42 +1291,42 @@ void GscInfoWindow::fill_ui_self_test_log(const std::vector<StorageProperty>& pr
|
||||
auto* treeview = lookup_widget<Gtk::TreeView*>("selftest_log_treeview");
|
||||
|
||||
Gtk::TreeModelColumnRecord model_columns;
|
||||
int num_tree_cols = 0;
|
||||
[[maybe_unused]] int num_tree_col = 0;
|
||||
|
||||
// Test num., Type, Status, % Completed, Lifetime hours, LBA of the first error
|
||||
|
||||
Gtk::TreeModelColumn<uint32_t> col_num;
|
||||
model_columns.add(col_num); // we can use the column variable by value after this.
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_num, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_num, *treeview,
|
||||
_("Test #"), _("Test # (greater may mean newer or older depending on drive model)"), true);
|
||||
auto* cr_test_num = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_cols - 1));
|
||||
auto* cr_test_num = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_col));
|
||||
if (cr_test_num)
|
||||
cr_test_num->property_weight() = Pango::WEIGHT_BOLD ;
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_type;
|
||||
model_columns.add(col_type);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_type, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_type, *treeview,
|
||||
_("Type"), _("Type of the test performed"), true);
|
||||
treeview->set_search_column(col_type.index());
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_status;
|
||||
model_columns.add(col_status);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_status, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_status, *treeview,
|
||||
_("Status"), _("Test completion status"), true);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_percent;
|
||||
model_columns.add(col_percent);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_percent, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_percent, *treeview,
|
||||
_("% Completed"), _("Percentage of the test completed. Instantly-aborted tests have 10%, while unsupported ones <i>may</i> have 100%."), true, false, true);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_hours;
|
||||
model_columns.add(col_hours);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_hours, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_hours, *treeview,
|
||||
_("Lifetime hours"), _("During which hour of the drive's (powered on) lifetime did the test complete (or abort)"), true);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_lba;
|
||||
model_columns.add(col_lba);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_lba, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_lba, *treeview,
|
||||
_("LBA of the first error"), _("LBA of the first error (if an LBA-related error happened)"), true);
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_tooltip;
|
||||
@@ -1342,7 +1342,7 @@ void GscInfoWindow::fill_ui_self_test_log(const std::vector<StorageProperty>& pr
|
||||
list_store->set_sort_column(col_num, Gtk::SORT_ASCENDING); // default sort
|
||||
treeview->set_model(list_store);
|
||||
|
||||
for (int i = 0; i < num_tree_cols; ++i) {
|
||||
for (int i = 0; i < int(treeview->get_n_columns()); ++i) {
|
||||
Gtk::TreeViewColumn* tcol = treeview->get_column(i);
|
||||
tcol->set_cell_data_func(*(tcol->get_first_cell()),
|
||||
sigc::bind(sigc::ptr_fun(app_list_cell_renderer_func), col_storage));
|
||||
@@ -1402,35 +1402,35 @@ void GscInfoWindow::fill_ui_error_log(const std::vector<StorageProperty>& props)
|
||||
auto* treeview = lookup_widget<Gtk::TreeView*>("error_log_treeview");
|
||||
|
||||
Gtk::TreeModelColumnRecord model_columns;
|
||||
int num_tree_cols = 0;
|
||||
[[maybe_unused]] int num_tree_col = 0;
|
||||
|
||||
// Error Number, Lifetime Hours, State, Type, Details, [tooltips]
|
||||
|
||||
Gtk::TreeModelColumn<uint32_t> col_num;
|
||||
model_columns.add(col_num); // we can use the column variable by value after this.
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_num, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_num, *treeview,
|
||||
_("Error #"), _("Error # in the error log (greater means newer)"), true);
|
||||
if (auto* cr_name = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_cols - 1)))
|
||||
if (auto* cr_name = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_col)))
|
||||
cr_name->property_weight() = Pango::WEIGHT_BOLD ;
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_hours;
|
||||
model_columns.add(col_hours);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_hours, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_hours, *treeview,
|
||||
_("Lifetime hours"), _("During which hour of the drive's (powered on) lifetime did the error happen."), true);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_state;
|
||||
model_columns.add(col_state);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_state, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_state, *treeview,
|
||||
C_("power", "State"), _("Power state of the drive when the error occurred"), false);
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_type;
|
||||
model_columns.add(col_type);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_type, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_type, *treeview,
|
||||
_("Type"), _("Type of error"), true);
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_details;
|
||||
model_columns.add(col_details);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_details, *treeview,
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_details, *treeview,
|
||||
_("Details"), _("Additional details (e.g. LBA where the error occurred, etc...)"), true);
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_tooltip;
|
||||
@@ -1449,7 +1449,7 @@ void GscInfoWindow::fill_ui_error_log(const std::vector<StorageProperty>& props)
|
||||
list_store->set_sort_column(col_num, Gtk::SORT_DESCENDING); // default sort
|
||||
treeview->set_model(list_store);
|
||||
|
||||
for (int i = 0; i < num_tree_cols; ++i) {
|
||||
for (int i = 0; i < int(treeview->get_n_columns()); ++i) {
|
||||
Gtk::TreeViewColumn* tcol = treeview->get_column(i);
|
||||
tcol->set_cell_data_func(*(tcol->get_first_cell()),
|
||||
sigc::bind(sigc::ptr_fun(app_list_cell_renderer_func), col_storage));
|
||||
@@ -1607,29 +1607,29 @@ WarningLevel GscInfoWindow::fill_ui_capabilities(const std::vector<StorageProper
|
||||
auto* treeview = lookup_widget<Gtk::TreeView*>("capabilities_treeview");
|
||||
|
||||
Gtk::TreeModelColumnRecord model_columns;
|
||||
int num_tree_cols = 0;
|
||||
[[maybe_unused]] int num_tree_col = 0;
|
||||
|
||||
// N, Name, Flag, Capabilities, [tooltips]
|
||||
|
||||
Gtk::TreeModelColumn<int> col_index;
|
||||
model_columns.add(col_index); // we can use the column variable by value after this.
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_index, *treeview, _("#"), _("Entry #"), true);
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_index, *treeview, _("#"), _("Entry #"), true);
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_name;
|
||||
model_columns.add(col_name);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_name, *treeview, _("Name"), _("Name"), true);
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_name, *treeview, _("Name"), _("Name"), true);
|
||||
treeview->set_search_column(col_name.index());
|
||||
auto* cr_name = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_cols - 1));
|
||||
auto* cr_name = dynamic_cast<Gtk::CellRendererText*>(treeview->get_column_cell_renderer(num_tree_col));
|
||||
if (cr_name)
|
||||
cr_name->property_weight() = Pango::WEIGHT_BOLD ;
|
||||
|
||||
Gtk::TreeModelColumn<std::string> col_flag_value;
|
||||
model_columns.add(col_flag_value);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_flag_value, *treeview, _("Flags"), _("Flags"), false);
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_flag_value, *treeview, _("Flags"), _("Flags"), false);
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_str_values;
|
||||
model_columns.add(col_str_values);
|
||||
num_tree_cols = app_gtkmm_create_tree_view_column(col_str_values, *treeview, _("Capabilities"), _("Capabilities"), false);
|
||||
num_tree_col = app_gtkmm_create_tree_view_column(col_str_values, *treeview, _("Capabilities"), _("Capabilities"), false);
|
||||
|
||||
Gtk::TreeModelColumn<Glib::ustring> col_tooltip;
|
||||
model_columns.add(col_tooltip);
|
||||
@@ -1644,7 +1644,7 @@ WarningLevel GscInfoWindow::fill_ui_capabilities(const std::vector<StorageProper
|
||||
list_store->set_sort_column(col_index, Gtk::SORT_ASCENDING); // default sort
|
||||
treeview->set_model(list_store);
|
||||
|
||||
for (int i = 0; i < num_tree_cols; ++i) {
|
||||
for (int i = 0; i < int(treeview->get_n_columns()); ++i) {
|
||||
Gtk::TreeViewColumn* tcol = treeview->get_column(i);
|
||||
tcol->set_cell_data_func(*(tcol->get_first_cell()),
|
||||
sigc::bind(sigc::ptr_fun(app_list_cell_renderer_func), col_storage));
|
||||
|
||||
+2
-2
@@ -543,9 +543,9 @@ bool app_init_and_loop(int& argc, char**& argv)
|
||||
debug_out_info("app", "Main loop exited.\n");
|
||||
|
||||
// close the main window and delete its object
|
||||
GscMainWindow::destroy();
|
||||
delete GscMainWindow::instance();
|
||||
|
||||
GscExecutorLogWindow::destroy();
|
||||
delete GscExecutorLogWindow::instance();
|
||||
|
||||
|
||||
// std::cerr << app_get_debug_buffer_str(); // this will output everything that went through libdebug.
|
||||
|
||||
@@ -458,7 +458,7 @@ bool GscPreferencesWindow::on_delete_event([[maybe_unused]] GdkEventAny* e)
|
||||
|
||||
void GscPreferencesWindow::on_window_cancel_button_clicked()
|
||||
{
|
||||
destroy(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
@@ -491,7 +491,7 @@ void GscPreferencesWindow::on_window_ok_button_clicked()
|
||||
main_window_->show_prefs_updated_message();
|
||||
}
|
||||
|
||||
destroy(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
@@ -506,7 +506,7 @@ void GscPreferencesWindow::on_window_reset_all_button_clicked()
|
||||
rconfig::clear_config();
|
||||
import_config();
|
||||
// close the window, because the user might get the impression that "Cancel" will revert.
|
||||
destroy(this);
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+38
-7
@@ -16,6 +16,7 @@ Copyright:
|
||||
#include <gtkmm.h>
|
||||
#include <gdk/gdk.h> // GDK_KEY_Escape
|
||||
#include <memory>
|
||||
#include <variant>
|
||||
|
||||
#include "hz/debug.h"
|
||||
#include "hz/fs.h"
|
||||
@@ -72,18 +73,36 @@ class GscTextWindow : public AppBuilderWidget<GscTextWindow<InstanceSwitch>, Ins
|
||||
}
|
||||
|
||||
|
||||
/// Set the text to display
|
||||
void set_text_from_command(const Glib::ustring& title, const std::string& contents)
|
||||
{
|
||||
this->contents_ = contents; // we save it to prevent its mangling through the widget
|
||||
this->set_text_helper(title, true, true);
|
||||
}
|
||||
|
||||
|
||||
void set_text(const Glib::ustring& title, const Glib::ustring& contents,
|
||||
bool save_visible = false, bool use_monospace = false)
|
||||
{
|
||||
this->contents_ = contents;
|
||||
this->set_text_helper(title, save_visible, use_monospace);
|
||||
}
|
||||
|
||||
|
||||
/// Set the text to display
|
||||
void set_text_helper(const Glib::ustring& title,
|
||||
bool save_visible = false, bool use_monospace = false)
|
||||
{
|
||||
this->set_title(title + " - " + default_title_); // something - gsmartcontrol
|
||||
|
||||
this->contents_ = contents; // we save it to prevent its mangling through the widget
|
||||
|
||||
Gtk::TextView* textview = this->template lookup_widget<Gtk::TextView*>("main_textview");
|
||||
if (textview) {
|
||||
Glib::RefPtr<Gtk::TextBuffer> buffer = textview->get_buffer();
|
||||
buffer->set_text(app_output_make_valid(contents));
|
||||
|
||||
if (std::holds_alternative<std::string>(contents_)) {
|
||||
buffer->set_text(app_make_valid_utf8_from_command_output(std::get<std::string>(contents_)));
|
||||
} else {
|
||||
buffer->set_text(std::get<Glib::ustring>(contents_));
|
||||
}
|
||||
|
||||
if (use_monospace) {
|
||||
Glib::RefPtr<Gtk::TextTag> tag = buffer->create_tag();
|
||||
@@ -207,7 +226,13 @@ class GscTextWindow : public AppBuilderWidget<GscTextWindow<InstanceSwitch>, Ins
|
||||
file += ".txt";
|
||||
}
|
||||
|
||||
auto ec = hz::fs_file_put_contents(hz::fs::u8path(file), this->contents_.c_str());
|
||||
std::string text;
|
||||
if (std::holds_alternative<std::string>(contents_)) {
|
||||
text = std::get<std::string>(contents_);
|
||||
} else {
|
||||
text = std::get<Glib::ustring>(contents_);
|
||||
}
|
||||
auto ec = hz::fs_file_put_contents(hz::fs::u8path(file), text);
|
||||
if (ec) {
|
||||
gui_show_error_dialog(_("Cannot save data to file"), ec.message(), this);
|
||||
}
|
||||
@@ -228,14 +253,20 @@ class GscTextWindow : public AppBuilderWidget<GscTextWindow<InstanceSwitch>, Ins
|
||||
/// Button click callback
|
||||
void on_close_window_button_clicked()
|
||||
{
|
||||
this->destroy(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Glib::ustring default_title_; ///< Window title
|
||||
Glib::ustring contents_; ///< The text to display
|
||||
|
||||
/// The text to display
|
||||
std::variant<
|
||||
std::string, // command output
|
||||
Glib::ustring // utf-8 text
|
||||
> contents_;
|
||||
|
||||
std::string save_filename_; ///< Default filename for Save As
|
||||
|
||||
};
|
||||
|
||||
+36
-69
@@ -12,15 +12,15 @@ Copyright:
|
||||
#ifndef HZ_INSTANCE_MANAGER_H
|
||||
#define HZ_INSTANCE_MANAGER_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
|
||||
namespace hz {
|
||||
|
||||
|
||||
/**
|
||||
Inherit this class to have a single- or multi-instance objects, e.g. windows.
|
||||
This is a multi-instance specialization.
|
||||
*/
|
||||
/// Inherit this class template to have a single- or multi-instance objects, e.g. windows.
|
||||
/// This is a multi-instance implementation.
|
||||
template<class Child, bool MultiInstance>
|
||||
class InstanceManager {
|
||||
protected:
|
||||
@@ -28,49 +28,27 @@ class InstanceManager {
|
||||
/// Can't construct / delete this directly! use create() and destroy()
|
||||
InstanceManager() = default;
|
||||
|
||||
/// Can't construct / delete this directly! use create() and destroy()
|
||||
~InstanceManager() = default;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// Non-copyable
|
||||
/// Deleted
|
||||
InstanceManager(const InstanceManager& other) = delete;
|
||||
|
||||
/// Non-copyable
|
||||
/// Deleted
|
||||
InstanceManager(const InstanceManager&& other) = delete;
|
||||
|
||||
/// Deleted
|
||||
InstanceManager& operator=(const InstanceManager&) = delete;
|
||||
|
||||
/// Deleted
|
||||
InstanceManager& operator=(const InstanceManager&&) = delete;
|
||||
|
||||
/// Create a new instance or return an already created one if single-instance.
|
||||
/// If single-instance, the call will be serialized.
|
||||
static Child* create()
|
||||
{
|
||||
return new Child();
|
||||
}
|
||||
/// Default
|
||||
~InstanceManager() = default;
|
||||
|
||||
|
||||
/// Destroy an instance. \c instance must be passed if using
|
||||
/// multi-instance object. If single-instance, \c instance has no effect.
|
||||
/// If single-instance, the call will be serialized.
|
||||
static void destroy(Child* instance)
|
||||
{
|
||||
if (instance) {
|
||||
delete instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// We have these functions for multi-instance variant too to
|
||||
// support transparently switching between them.
|
||||
|
||||
/// Returns true if there is a valid single-instance object.
|
||||
/// In multi-instance version this always returns false.
|
||||
static constexpr bool has_single_instance()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/// The default multi-instance implementation doesn't support `instance()`
|
||||
static Child* instance() = delete;
|
||||
|
||||
};
|
||||
|
||||
@@ -82,59 +60,48 @@ template<class Child>
|
||||
class InstanceManager<Child, false> {
|
||||
protected:
|
||||
|
||||
/// Can't construct / delete this directly! use create() and destroy()
|
||||
InstanceManager() = default;
|
||||
|
||||
~InstanceManager() = default;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// Non-construction-copyable
|
||||
/// Deleted
|
||||
InstanceManager(const InstanceManager& other) = delete;
|
||||
|
||||
/// Non-copyable
|
||||
/// Deleted
|
||||
InstanceManager(const InstanceManager&& other) = delete;
|
||||
|
||||
/// Deleted
|
||||
InstanceManager& operator=(const InstanceManager&) = delete;
|
||||
|
||||
/// Deleted
|
||||
InstanceManager& operator=(const InstanceManager&&) = delete;
|
||||
|
||||
static Child* create()
|
||||
/// Default
|
||||
~InstanceManager() = default;
|
||||
|
||||
|
||||
/// Return a single existing instance of this template instantiation.
|
||||
/// \return nullptr if no instances were created yet.
|
||||
static Child* instance()
|
||||
{
|
||||
if (instance_) // for single-instance objects
|
||||
return instance_;
|
||||
|
||||
instance_ = new Child();
|
||||
return instance_;
|
||||
}
|
||||
|
||||
|
||||
static void destroy()
|
||||
{
|
||||
if (instance_) {
|
||||
delete instance_;
|
||||
instance_ = nullptr;
|
||||
}
|
||||
return instance_.get();
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
static constexpr bool has_single_instance()
|
||||
{
|
||||
return (bool)instance_;
|
||||
}
|
||||
|
||||
static Child* get_single_instance()
|
||||
{
|
||||
return instance_;
|
||||
}
|
||||
|
||||
/// Set the instance.
|
||||
static void set_single_instance(Child* instance)
|
||||
{
|
||||
instance_ = instance;
|
||||
instance_.reset(instance);
|
||||
}
|
||||
|
||||
|
||||
// if an object is allowed to have a single instance only, these are needed.
|
||||
static inline Child* instance_ = nullptr; ///< Single instance pointer
|
||||
private:
|
||||
|
||||
static inline std::unique_ptr<Child> instance_; ///< Single instance pointer
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user