~ximion/listaller-gnome/listaller-gnome

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
/* li-setup.vala
 *
 * Copyright (C) 2010-2011 Matthias Klumpp
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Author:
 * 	Matthias Klumpp <matthias@nlinux.org>
 */

using GLib;
using Gee;
using Gtk;
using Listaller;

static string datadir;

public class InstallWizard : Object {
	private Builder ui;
	private Assistant assistant;

	private string ipkfname;
	private Setup inst;
	private Listaller.Settings liconf;
	private IPK.Control ipkmeta;
	private AppItem appID;
	private bool testmode_enabled = false;

	public int exit_code { set; get; }

	public InstallWizard (string ipkfile, bool testmode) {
		try {
			ui = new Builder ();
			ui.add_from_file (Path.build_filename (datadir, "ui", "install-wizard.ui", null));
		} catch (Error e) {
			error ("Could not load UI: %s\n", e.message);
			exit_code = 1;
			return;
		}

		ipkfname = ipkfile;
		testmode_enabled = testmode;

		assistant = new Assistant ();

		// Add pages and format them
		Widget w;
		w = get_widget ("page_loading");
		assistant.append_page (w);
		assistant.set_page_title (w, _("Initialization"));
		assistant.set_page_type (w, AssistantPageType.CUSTOM);

		w = get_widget ("page_welcome");
		assistant.append_page (w);
		assistant.set_page_title (w, _("Welcome!"));
		assistant.set_page_type (w, AssistantPageType.INTRO);
		assistant.set_page_complete (w, true);

		w = get_widget ("page_details");
		assistant.append_page (w);
		assistant.set_page_title (w, _("Details"));
		assistant.set_page_complete (w, true);

		w = get_widget ("page_description");
		assistant.append_page (w);
		assistant.set_page_title (w, _("Description"));
		assistant.set_page_complete (w, true);

		w = get_widget ("page_license");
		assistant.append_page (w);
		assistant.set_page_title (w, _("License"));
		assistant.set_page_type (w, AssistantPageType.CONFIRM);
		assistant.set_page_complete (w, true);

		w = get_widget ("page_running");
		assistant.append_page (w);
		assistant.set_page_title (w, _("Installation"));
		assistant.set_page_type (w, AssistantPageType.PROGRESS);

		w = get_widget ("page_finished");
		assistant.append_page (w);
		assistant.set_page_title (w, _("Finished"));
		assistant.set_page_type (w, AssistantPageType.SUMMARY);

		assistant.title = _("Application Installer");
		assistant.icon_name = "system-software-install";
		assistant.set_default_size (600, 400);

		// Connect assistant
		assistant.prepare.connect (on_page_prepare);
		assistant.destroy.connect (quit_wizard);
		assistant.cancel.connect (quit_wizard);
		assistant.apply.connect (run_installation);

		// Connect other stuff
		(get_widget ("checkbox_suinstall") as CheckButton).toggled.connect (sumode_checkbox_toggled);
	}

	public Widget? get_widget (string name) {
		Widget? obj = ui.get_object (name) as Widget;
		if (obj == null)
			return null;
		return obj;
	}

	private Object? get_object (string name) {
		Object? obj = ui.get_object (name);
		if (obj == null)
			return null;
		return obj;
	}

	public void format_label_text (string labelName, string text) {
		Label l = (get_widget (labelName) as Label);
		string h = l.get_label ().printf (text);
		l.set_label (h);
	}

	public void set_label_text (string labelName, string text) {
		(get_widget (labelName) as Label).set_label (text);
	}

	public void show () {
		assistant.show ();
	}

	public void goto_welcome () {
		assistant.set_current_page (1);
	}

	private void on_page_prepare (Widget page) {

	}

	public void set_main_progress (int progress) {
		double mp = 0;
		mp = progress / 100d;
		(get_widget ("progressbarMain") as ProgressBar).fraction = mp;
	}

	public void set_extra_progress (int progress) {
		double sp = 0;
		sp = progress / 100d;
		(get_widget ("progressbarExtra") as ProgressBar).fraction = sp;
	}

	private void run_installation () {
		assistant.commit ();
		Idle.add (run_installation_icb);
	}

	private bool run_installation_icb () {
		// Make sure testmode is set correctly
		if (testmode_enabled)
			liconf.testmode = true;

		inst.run_installation ();

		// Don't queue this again!
		return false;
	}

	public void setup_error_code (ErrorItem error) {
		Gtk.MessageDialog d = new Gtk.MessageDialog.with_markup(assistant, Gtk.DialogFlags.MODAL,
			Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, error.details, null);
		d.run();
		d.destroy();
		// Errors are always fatal, so quit the installer
		quit_wizard ();
	}

	public void setup_progress_changed (int progress, int sub_progress) {
		set_main_progress (progress);
		set_extra_progress (sub_progress);
		// Process interface changes
		Gtk.main_iteration ();
	}

	public void setup_status_changed (StatusItem status) {
		if (status.status == StatusEnum.INSTALLATION_FINISHED) {
			// Show setup complete message
			Gtk.MessageDialog d = new Gtk.MessageDialog.with_markup (assistant, Gtk.DialogFlags.MODAL,
										Gtk.MessageType.INFO, Gtk.ButtonsType.OK, status.info, null);
			d.run ();
			d.destroy ();
			assistant.next_page ();
		}
	}

	public void setup_message (MessageItem message) {
		stdout.printf (message.details + "\n");
	}

	private async void open_pkg_async () {
		bool ret = true;

		Gtk.main_iteration ();
		liconf = new Listaller.Settings ();
		inst = new Setup (ipkfname, liconf);
		inst.message.connect (setup_message);
		inst.status_changed.connect (setup_status_changed);
		inst.progress_changed.connect (setup_progress_changed);
		inst.error_code.connect (setup_error_code);

		ret = inst.initialize ();
		if (!ret)
			quit_wizard ();

		ipkmeta = inst.control;
		if (ipkmeta == null)
			quit_wizard ();

		appID = ipkmeta.get_application ();
		assistant.title = _("Installation of %s").printf (appID.full_name);
		format_label_text ("labelWelcome", appID.full_name);

		// Set description and license text
		(get_widget ("textviewDesc") as TextView).buffer.text = appID.description;
		(get_widget ("textviewLicense") as TextView).buffer.text = appID.license.text;

		// Add a list of dependencies
		add_dependency_info (ipkmeta.get_dependencies ());

		// Display security info
		IPK.PackSecurity sec = inst.get_security_info ();
		SecurityLevel secLev = sec.get_level ();
		set_label_text ("lbl_secinfo", secLev.to_string ());
		Image secImg = (get_widget ("img_security_status") as Image);
		secImg.stock = "gtk-dialog-warning";
		if (secLev == SecurityLevel.HIGH)
			secImg.stock = "gtk-apply";
		else if (secLev == SecurityLevel.MEDIUM)
			secImg.stock = "gtk-yes";
		else if (secLev == SecurityLevel.LOW)
			secImg.stock = "gtk-no";
	}

	public void sumode_checkbox_toggled (ToggleButton source) {
		if (source.get_active ()) {
			Gtk.MessageDialog d = new Gtk.MessageDialog.with_markup(assistant, Gtk.DialogFlags.MODAL,
								Gtk.MessageType.WARNING, Gtk.ButtonsType.YES_NO,
								_("You want to install this application as root!\nThis can damage your system or install malicious software for all users.\nPlease only proceed, if you really know what you're doing!\nContinue?"),
								  null);
			int i = d.run ();
			d.destroy ();

			if (i == ResponseType.YES) {
				liconf.sumode = true;
			} else {
				source.set_active (false);
			}
		} else {
			liconf.sumode = false;
		}
	}

	public void add_dependency_info (ArrayList<IPK.Dependency> deps) {
		// Build dependency info list
		TreeView twDeps = get_widget ("twDeps") as TreeView;
		var store = new TreeStore (1, typeof (string));
		twDeps.set_model (store);
		twDeps.insert_column_with_attributes (-1, _("Dependency"), new CellRendererText (), "markup", 0, null);
		twDeps.headers_visible = false;

		TreeIter dep_iter;
		TreeIter file_iter;

		foreach (IPK.Dependency d in deps) {
			store.append (out dep_iter, null);
			string text = "<b>%s</b>".printf (d.full_name);
			if (d.feed_url != "")
				text += "\n<i>%s</i>".printf (d.feed_url);
			store.set (dep_iter, 0, text, -1);

			foreach (string dc in d.raw_complist) {
				store.append (out file_iter, dep_iter);
				store.set (file_iter, 0, dc, -1);
			}

			debug (d.idname);
		}
	}

	private void quit_wizard () {
		Gtk.main_quit ();
	}

	private bool open_icb () {
		Spinner spin = get_widget ("spinnerPrepare") as Spinner;
		spin.active = true;

		open_pkg_async.begin( (obj, res) => {
			// We finished initializing this setup
			goto_welcome ();
		});

		// Never try to idle add this again
		return false;
	}

	public void run () {
		if (exit_code > 0)
			return;

		show ();

		Idle.add (open_icb);
		Gtk.main ();
	}

}

public class CmdLnOptions : Object {
	static string o_input_path = null;
	static bool o_show_version = false;
	static bool o_use_testmode = false;

	private OptionContext opt_context;

	private const OptionEntry[] options = {
		{ "version", 'v', 0, OptionArg.NONE, ref o_show_version,
		N_("Show the application's version"), null },
		{ "testmode", 'v', 0, OptionArg.NONE, ref o_use_testmode,
		N_("Run installation in testmode"), null },
		{ null }
	};

	public CmdLnOptions () {
		opt_context = new OptionContext ("- software installation wizard.");
	}

	public int process (string[] args) {

		opt_context.set_help_enabled (true);
		opt_context.add_main_entries (options, null);
		try {
			opt_context.parse (ref args);
		} catch (Error e) {
			stdout.printf (e.message + "\n");
			stdout.printf (_("Run '%s --help' to see a full list of available command line options.\n"), args[0]);
			return 1;
		}

		for (int i = 1; i < args.length; i++) {
			string arg = args[i];
			if (o_input_path == null) {
				o_input_path = arg;
			}
		}

		return 0;
	}

	public string get_help () {
		return opt_context.get_help (true, null);
	}

	static int main (string[] args) {
		Gtk.init (ref args);
		// Bind Listaller locale
		Intl.bindtextdomain("listaller", Config.LOCALEDIR);
		Intl.bind_textdomain_codeset("listaller", "UTF-8");
		Intl.textdomain("listaller");
		// Bind Listaller GTK UI locale
		Intl.setlocale(LocaleCategory.ALL,"");
		Intl.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
		Intl.bind_textdomain_codeset(Config.GETTEXT_PACKAGE, "UTF-8");
		Intl.textdomain(Config.GETTEXT_PACKAGE);

		var optn = new CmdLnOptions ();
		int i = optn.process (args);
		if (i > 0)
			return i;

		if (o_show_version) {
			stdout.printf ("Version: %s\n", Config.PROJECT_VERSION);
			return 0;
		}

		// Test if input IPK path is valid
		if (o_input_path == null) {
			stdout.printf (optn.get_help ());
			return 1;
		}

		if (!FileUtils.test (o_input_path, FileTest.EXISTS)) {
			stderr.printf (_("File %s does not exist!\n"), o_input_path);
			return 4;
		}

		// Find the data directory
		datadir = LiGtk.Utils.find_datadir (args, "install-wizard.ui");

		var wizard = new InstallWizard (o_input_path, o_use_testmode);
		wizard.run ();
		return wizard.exit_code;
	}

}