1 /**************************************************************************
2  Copyright:
3       (C) 2011 - 2012  Alexander Shaduri <ashaduri 'at' gmail.com>
4  License: See LICENSE_gsmartcontrol.txt
5 ***************************************************************************/
6 /// \file
7 /// \author Alexander Shaduri
8 /// \ingroup gsc
9 /// \weakgroup gsc
10 /// @{
11 
12 #include <gtkmm.h>
13 #include <gdk/gdk.h>  // GDK_KEY_Escape
14 #include <gtk/gtk.h>
15 
16 #include "hz/fs_path.h"
17 #include "hz/string_sprintf.h"
18 #include "hz/scoped_ptr.h"
19 #include "applib/app_gtkmm_utils.h"
20 
21 #include "gsc_add_device_window.h"
22 #include "gsc_main_window.h"
23 
24 
25 
26 
GscAddDeviceWindow(BaseObjectType * gtkcobj,const app_ui_res_ref_t & ref_ui)27 GscAddDeviceWindow::GscAddDeviceWindow(BaseObjectType* gtkcobj, const app_ui_res_ref_t& ref_ui)
28 		: AppUIResWidget<GscAddDeviceWindow, true>(gtkcobj, ref_ui), main_window_(0)
29 {
30 	// Connect callbacks
31 
32 	APP_GTKMM_CONNECT_VIRTUAL(delete_event);  // make sure the event handler is called
33 
34 	Gtk::Button* window_cancel_button = 0;
35 	APP_UI_RES_AUTO_CONNECT(window_cancel_button, clicked);
36 
37 	Gtk::Button* window_ok_button = 0;
38 	APP_UI_RES_AUTO_CONNECT(window_ok_button, clicked);
39 
40 	Gtk::Button* device_name_browse_button = 0;
41 	APP_UI_RES_AUTO_CONNECT(device_name_browse_button, clicked);
42 
43 
44 	Glib::ustring device_name_tooltip = "Device name";
45 #if defined CONFIG_KERNEL_FAMILY_WINDOWS
46 	device_name_tooltip = "Device name (for example, use \"pd0\" for the first physical drive)";
47 #elif defined CONFIG_KERNEL_LINUX
48 	device_name_tooltip = "Device name (for example, /dev/sda or /dev/twa0)";
49 #endif
50 	if (Gtk::Label* device_name_label = lookup_widget<Gtk::Label*>("device_name_label")) {
51 		app_gtkmm_set_widget_tooltip(*device_name_label, device_name_tooltip);
52 	}
53 
54 	Gtk::Entry* device_name_entry = 0;
55 	APP_UI_RES_AUTO_CONNECT(device_name_entry, changed);
56 	if (device_name_entry) {
57 		app_gtkmm_set_widget_tooltip(*device_name_entry, device_name_tooltip);
58 	}
59 
60 
61 	Glib::ustring device_type_tooltip = "Smartctl -d option parameter";
62 #if defined CONFIG_KERNEL_LINUX || defined CONFIG_KERNEL_FAMILY_WINDOWS
63 	device_type_tooltip = "Smartctl -d option parameter. For example, use areca,1 for the first drive behind Areca RAID controller.";
64 #endif
65 	if (Gtk::Label* device_type_label = lookup_widget<Gtk::Label*>("device_type_label")) {
66 		app_gtkmm_set_widget_tooltip(*device_type_label, device_type_tooltip);
67 	}
68 	if (Gtk::ComboBoxText* type_combo = lookup_widget<Gtk::ComboBoxText*>("device_type_combo")) {
69 		app_gtkmm_set_widget_tooltip(*type_combo, device_type_tooltip);
70 	}
71 
72 
73 	// Accelerators
74 
75 	Glib::RefPtr<Gtk::AccelGroup> accel_group = this->get_accel_group();
76 	if (window_cancel_button) {
77 		window_cancel_button->add_accelerator("clicked", accel_group, GDK_KEY_Escape,
78 				Gdk::ModifierType(0), Gtk::AccelFlags(0));
79 	}
80 
81 
82 #ifdef _WIN32
83 	// "Browse" doesn't make sense in win32, hide it.
84 	if (device_name_browse_button) {
85 		device_name_browse_button->hide();
86 	}
87 #endif
88 
89 
90 	// Populate type combo with common types
91 	Gtk::ComboBoxText* type_combo = lookup_widget<Gtk::ComboBoxText*>("device_type_combo");
92 	if (type_combo) {
93 		type_combo->append("sat,12");
94 		type_combo->append("sat,16");
95 		type_combo->append("usbcypress");
96 		type_combo->append("usbjmicron");
97 		type_combo->append("usbsunplus");
98 		type_combo->append("ata");
99 		type_combo->append("scsi");
100 #if defined CONFIG_KERNEL_LINUX
101 		type_combo->append("marvell");
102 		type_combo->append("megaraid,N");
103 		type_combo->append("areca,N");
104 		type_combo->append("areca,N/E");
105 #endif
106 #if defined CONFIG_KERNEL_LINUX || defined CONFIG_KERNEL_FREEBSD || defined CONFIG_KERNEL_DRAGONFLY
107 		type_combo->append("3ware,N");  // this option is not needed in windows
108 		type_combo->append("cciss,N");
109 		type_combo->append("hpt,L/M");
110 		type_combo->append("hpt,L/M/N");
111 #endif
112 	}
113 
114 
115 	// This sets the initial state of OK button
116 	on_device_name_entry_changed();
117 
118 	// show();
119 }
120 
121 
122 
set_main_window(GscMainWindow * main_window)123 void GscAddDeviceWindow::set_main_window(GscMainWindow* main_window)
124 {
125 	main_window_ = main_window;
126 }
127 
128 
129 
on_delete_event_before(GdkEventAny * e)130 bool GscAddDeviceWindow::on_delete_event_before(GdkEventAny* e)
131 {
132 	destroy(this);  // deletes this object and nullifies instance
133 	return true;  // event handled, don't call default virtual handler
134 }
135 
136 
137 
on_window_cancel_button_clicked()138 void GscAddDeviceWindow::on_window_cancel_button_clicked()
139 {
140 	destroy(this);
141 }
142 
143 
144 
on_window_ok_button_clicked()145 void GscAddDeviceWindow::on_window_ok_button_clicked()
146 {
147 	std::string dev, type, params;
148 	if (Gtk::Entry* entry = lookup_widget<Gtk::Entry*>("device_name_entry")) {
149 		dev = entry->get_text();
150 	}
151 	if (Gtk::ComboBoxText* type_combo = lookup_widget<Gtk::ComboBoxText*>("device_type_combo")) {
152 		type = type_combo->get_entry_text();
153 	}
154 	if (Gtk::Entry* entry = lookup_widget<Gtk::Entry*>("smartctl_params_entry")) {
155 		params = entry->get_text();
156 	}
157 	if (main_window_ && !dev.empty()) {
158 		main_window_->add_device(dev, type, params);
159 	}
160 
161 	destroy(this);
162 }
163 
164 
165 
on_device_name_browse_button_clicked()166 void GscAddDeviceWindow::on_device_name_browse_button_clicked()
167 {
168 	std::string default_file;
169 
170 	Gtk::Entry* entry = this->lookup_widget<Gtk::Entry*>("device_name_entry");
171 	if (!entry)
172 		return;
173 
174 	hz::FsPath path(entry->get_text());
175 
176 	int result = 0;
177 
178 #if GTK_CHECK_VERSION(3, 20, 0)
179 	hz::scoped_ptr<GtkFileChooserNative> dialog(gtk_file_chooser_native_new(
180 			"Choose Device...", this->gobj(), GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL), g_object_unref);
181 
182 	if (path.is_absolute())
183 		gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog.get()), path.c_str());
184 
185 	result = gtk_native_dialog_run(GTK_NATIVE_DIALOG(dialog.get()));
186 
187 #else
188 	Gtk::FileChooserDialog dialog(*this, "Choose Device...",
189 			Gtk::FILE_CHOOSER_ACTION_OPEN);
190 
191 	// Add response buttons the the dialog
192 	dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
193 	dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
194 
195 	// Note: This works on absolute paths only (otherwise it's gtk warning).
196 	if (path.is_absolute())
197 		dialog.set_filename(path.str());  // change to its dir and select it if exists.
198 
199 	// Show the dialog and wait for a user response
200 	result = dialog.run();  // the main cycle blocks here
201 #endif
202 
203 	// Handle the response
204 	switch (result) {
205 		case Gtk::RESPONSE_ACCEPT:
206 		{
207 			Glib::ustring file;
208 #if GTK_CHECK_VERSION(3, 20, 0)
209 			file = app_ustring_from_gchar(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog.get())));
210 #else
211 			file = dialog.get_filename();  // in fs encoding
212 #endif
213 			entry->set_text(file);
214 			break;
215 		}
216 
217 		case Gtk::RESPONSE_CANCEL: case Gtk::RESPONSE_DELETE_EVENT:
218 			// nothing, the dialog is closed already
219 			break;
220 
221 		default:
222 			debug_out_error("app", DBG_FUNC_MSG << "Unknown dialog response code: " << result << ".\n");
223 			break;
224 	}
225 
226 }
227 
228 
229 
on_device_name_entry_changed()230 void GscAddDeviceWindow::on_device_name_entry_changed()
231 {
232 	// Allow OK only if name is not empty
233 	Gtk::Entry* entry = lookup_widget<Gtk::Entry*>("device_name_entry");
234 	Gtk::Button* ok_button = lookup_widget<Gtk::Button*>("window_ok_button");
235 	if (entry && ok_button) {
236 		ok_button->set_sensitive(!entry->get_text().empty());
237 	}
238 }
239 
240 
241 
242 
243 
244 
245 
246 /// @}
247