~ubuntu-branches/debian/sid/gnome-shell/sid

« back to all changes in this revision

Viewing changes to js/ui/shellMountOperation.js

  • Committer: Package Import Robot
  • Author(s): Emilio Pozuelo Monfort, Petr Salinger, Emilio Pozuelo Monfort
  • Date: 2013-10-13 17:47:35 UTC
  • mfrom: (1.2.17) (18.1.41 experimental)
  • Revision ID: package-import@ubuntu.com-20131013174735-2npsu0w5wk0e6vgb
Tags: 3.8.4-4
[ Petr Salinger ]
* Restrict dependency on gir1.2-nmgtk-1.0 to linux-any (Closes: #726099)

[ Emilio Pozuelo Monfort ]
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
2
2
 
 
3
const Clutter = imports.gi.Clutter;
3
4
const Lang = imports.lang;
4
5
const Signals = imports.signals;
5
6
const Gio = imports.gi.Gio;
 
7
const GLib = imports.gi.GLib;
6
8
const Gtk = imports.gi.Gtk;
7
9
const Pango = imports.gi.Pango;
8
10
const St = imports.gi.St;
9
11
const Shell = imports.gi.Shell;
10
12
 
 
13
const CheckBox = imports.ui.checkBox;
11
14
const Main = imports.ui.main;
12
15
const MessageTray = imports.ui.messageTray;
13
16
const ModalDialog = imports.ui.modalDialog;
14
17
const Params = imports.misc.params;
 
18
const ShellEntry = imports.ui.shellEntry;
15
19
 
16
20
const LIST_ITEM_ICON_SIZE = 48;
17
21
 
 
22
const REMEMBER_MOUNT_PASSWORD_KEY = 'remember-mount-password';
 
23
 
18
24
/* ------ Common Utils ------- */
19
25
function _setLabelText(label, text) {
20
26
    if (text) {
96
102
    Name: 'ShellMountOperation',
97
103
 
98
104
    _init: function(source, params) {
99
 
        params = Params.parse(params, { reaskPassword: false });
100
 
 
101
 
        this._reaskPassword = params.reaskPassword;
 
105
        params = Params.parse(params, { existingDialog: null });
102
106
 
103
107
        this._dialog = null;
 
108
        this._dialogId = 0;
 
109
        this._existingDialog = params.existingDialog;
104
110
        this._processesDialog = null;
105
111
 
106
112
        this.mountOp = new Shell.MountOperation();
112
118
        this.mountOp.connect('show-processes-2',
113
119
                             Lang.bind(this, this._onShowProcesses2));
114
120
        this.mountOp.connect('aborted',
115
 
                             Lang.bind(this, this._onAborted));
 
121
                             Lang.bind(this, this.close));
 
122
        this.mountOp.connect('show-unmount-progress',
 
123
                             Lang.bind(this, this._onShowUnmountProgress));
116
124
 
117
125
        this._gicon = source.get_icon();
118
126
    },
119
127
 
 
128
    _closeExistingDialog: function() {
 
129
        if (!this._existingDialog)
 
130
            return;
 
131
 
 
132
        this._existingDialog.close();
 
133
        this._existingDialog = null;
 
134
    },
 
135
 
120
136
    _onAskQuestion: function(op, message, choices) {
 
137
        this._closeExistingDialog();
121
138
        this._dialog = new ShellMountQuestionDialog(this._gicon);
122
139
 
123
 
        this._dialog.connect('response',
124
 
                               Lang.bind(this, function(object, choice) {
125
 
                                   this.mountOp.set_choice(choice);
126
 
                                   this.mountOp.reply(Gio.MountOperationResult.HANDLED);
 
140
        this._dialogId = this._dialog.connect('response', Lang.bind(this,
 
141
            function(object, choice) {
 
142
                this.mountOp.set_choice(choice);
 
143
                this.mountOp.reply(Gio.MountOperationResult.HANDLED);
127
144
 
128
 
                                   this._dialog.close(global.get_current_time());
129
 
                                   this._dialog = null;
130
 
                               }));
 
145
                this.close();
 
146
            }));
131
147
 
132
148
        this._dialog.update(message, choices);
133
 
        this._dialog.open(global.get_current_time());
134
 
    },
135
 
 
136
 
    _onAskPassword: function(op, message) {
137
 
        this._notificationShowing = true;
138
 
        this._source = new ShellMountPasswordSource(message, this._gicon, this._reaskPassword);
139
 
 
140
 
        this._source.connect('password-ready',
141
 
                             Lang.bind(this, function(source, password) {
142
 
                                 this.mountOp.set_password(password);
143
 
                                 this.mountOp.reply(Gio.MountOperationResult.HANDLED);
144
 
 
145
 
                                 this._notificationShowing = false;
146
 
                                 this._source.destroy();
147
 
                             }));
148
 
 
149
 
        this._source.connect('destroy',
150
 
                             Lang.bind(this, function() {
151
 
                                 if (!this._notificationShowing)
152
 
                                     return;
153
 
 
154
 
                                 this._notificationShowing = false;
155
 
                                 this.mountOp.reply(Gio.MountOperationResult.ABORTED);
156
 
                             }));
157
 
    },
158
 
 
159
 
    _onAborted: function(op) {
160
 
        if (!this._dialog)
161
 
            return;
162
 
 
163
 
        this._dialog.close(global.get_current_time());
164
 
        this._dialog = null;
 
149
        this._dialog.open();
 
150
    },
 
151
 
 
152
    _onAskPassword: function(op, message, defaultUser, defaultDomain, flags) {
 
153
        if (this._existingDialog) {
 
154
            this._dialog = this._existingDialog;
 
155
            this._dialog.reaskPassword();
 
156
        } else {
 
157
            this._dialog = new ShellMountPasswordDialog(message, this._gicon, flags);
 
158
        }
 
159
 
 
160
        this._dialogId = this._dialog.connect('response', Lang.bind(this,
 
161
            function(object, choice, password, remember) {
 
162
                if (choice == -1) {
 
163
                    this.mountOp.reply(Gio.MountOperationResult.ABORTED);
 
164
                } else {
 
165
                    if (remember)
 
166
                        this.mountOp.set_password_save(Gio.PasswordSave.PERMANENTLY);
 
167
                    else
 
168
                        this.mountOp.set_password_save(Gio.PasswordSave.NEVER);
 
169
 
 
170
                    this.mountOp.set_password(password);
 
171
                    this.mountOp.reply(Gio.MountOperationResult.HANDLED);
 
172
                }
 
173
            }));
 
174
        this._dialog.open();
 
175
    },
 
176
 
 
177
    close: function(op) {
 
178
        this._closeExistingDialog();
 
179
        this._processesDialog = null;
 
180
 
 
181
        if (this._dialog) {
 
182
            this._dialog.close();
 
183
            this._dialog = null;
 
184
        }
 
185
 
 
186
        if (this._notifier) {
 
187
            this._notifier.done();
 
188
            this._notifier = null;
 
189
        }
165
190
    },
166
191
 
167
192
    _onShowProcesses2: function(op) {
 
193
        this._closeExistingDialog();
 
194
 
168
195
        let processes = op.get_show_processes_pids();
169
196
        let choices = op.get_show_processes_choices();
170
197
        let message = op.get_show_processes_message();
173
200
            this._processesDialog = new ShellProcessesDialog(this._gicon);
174
201
            this._dialog = this._processesDialog;
175
202
 
176
 
            this._processesDialog.connect('response', 
177
 
                                          Lang.bind(this, function(object, choice) {
178
 
                                              if (choice == -1) {
179
 
                                                  this.mountOp.reply(Gio.MountOperationResult.ABORTED);
180
 
                                              } else {
181
 
                                                  this.mountOp.set_choice(choice);
182
 
                                                  this.mountOp.reply(Gio.MountOperationResult.HANDLED);
183
 
                                              }
 
203
            this._dialogId = this._processesDialog.connect('response', Lang.bind(this,
 
204
                function(object, choice) {
 
205
                    if (choice == -1) {
 
206
                        this.mountOp.reply(Gio.MountOperationResult.ABORTED);
 
207
                    } else {
 
208
                        this.mountOp.set_choice(choice);
 
209
                        this.mountOp.reply(Gio.MountOperationResult.HANDLED);
 
210
                    }
184
211
 
185
 
                                              this._processesDialog.close(global.get_current_time());
186
 
                                              this._dialog = null;
187
 
                                          }));
188
 
            this._processesDialog.open(global.get_current_time());
 
212
                    this.close();
 
213
                }));
 
214
            this._processesDialog.open();
189
215
        }
190
216
 
191
217
        this._processesDialog.update(message, processes, choices);
192
218
    },
 
219
 
 
220
    _onShowUnmountProgress: function(op, message, timeLeft, bytesLeft) {
 
221
        if (!this._notifier)
 
222
            this._notifier = new ShellUnmountNotifier();
 
223
            
 
224
        if (bytesLeft == 0)
 
225
            this._notifier.done(message);
 
226
        else
 
227
            this._notifier.show(message);
 
228
    },
 
229
 
 
230
    borrowDialog: function() {
 
231
        if (this._dialogId != 0) {
 
232
            this._dialog.disconnect(this._dialogId);
 
233
            this._dialogId = 0;
 
234
        }
 
235
 
 
236
        return this._dialog;
 
237
    }
 
238
});
 
239
 
 
240
const ShellUnmountNotifier = new Lang.Class({
 
241
    Name: 'ShellUnmountNotifier',
 
242
    Extends: MessageTray.Source,
 
243
 
 
244
    _init: function() {
 
245
        this.parent('', 'media-removable');
 
246
 
 
247
        this._notification = null;
 
248
        Main.messageTray.add(this);
 
249
    },
 
250
 
 
251
    show: function(message) {
 
252
        let [header, text] = message.split('\n', 2);
 
253
 
 
254
        if (!this._notification) {
 
255
            this._notification = new MessageTray.Notification(this, header, text);
 
256
            this._notification.setTransient(true);
 
257
            this._notification.setUrgency(MessageTray.Urgency.CRITICAL);
 
258
        } else {
 
259
            this._notification.update(header, text);
 
260
        }
 
261
 
 
262
        this.notify(this._notification);
 
263
    },
 
264
 
 
265
    done: function(message) {
 
266
        if (this._notification) {
 
267
            this._notification.destroy();
 
268
            this._notification = null;
 
269
        }
 
270
 
 
271
        if (message) {
 
272
            let notification = new MessageTray.Notification(this, message, null);
 
273
            notification.setTransient(true);
 
274
 
 
275
            this.notify(notification);
 
276
        }
 
277
    }
193
278
});
194
279
 
195
280
const ShellMountQuestionDialog = new Lang.Class({
238
323
});
239
324
Signals.addSignalMethods(ShellMountQuestionDialog.prototype);
240
325
 
241
 
const ShellMountPasswordSource = new Lang.Class({
242
 
    Name: 'ShellMountPasswordSource',
243
 
    Extends: MessageTray.Source,
244
 
 
245
 
    _init: function(message, gicon, reaskPassword) {
246
 
        this._gicon = gicon;
247
 
 
 
326
const ShellMountPasswordDialog = new Lang.Class({
 
327
    Name: 'ShellMountPasswordDialog',
 
328
    Extends: ModalDialog.ModalDialog,
 
329
 
 
330
    _init: function(message, gicon, flags) {
248
331
        let strings = message.split('\n');
249
 
        this.parent(strings[0]);
250
 
        this._notification = new ShellMountPasswordNotification(this, strings, reaskPassword);
251
 
 
252
 
        // add ourselves as a source, and popup the notification
253
 
        Main.messageTray.add(this);
254
 
        this.notify(this._notification);
255
 
    },
256
 
 
257
 
    createNotificationIcon: function() {
258
 
        return _createIcon(this._gicon);
259
 
    },
260
 
});
261
 
Signals.addSignalMethods(ShellMountPasswordSource.prototype);
262
 
 
263
 
const ShellMountPasswordNotification = new Lang.Class({
264
 
    Name: 'ShellMountPasswordNotification',
265
 
    Extends: MessageTray.Notification,
266
 
 
267
 
    _init: function(source, strings, reaskPassword) {
268
 
        this.parent(source, strings[0], null, { customContent: true });
269
 
 
270
 
        // set the notification to transient and urgent, so that it
271
 
        // expands out
272
 
        this.setTransient(true);
273
 
        this.setUrgency(MessageTray.Urgency.CRITICAL);
274
 
 
 
332
        this.parent({ styleClass: 'prompt-dialog' });
 
333
 
 
334
        let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
 
335
                                                vertical: false });
 
336
        this.contentLayout.add(mainContentBox);
 
337
 
 
338
        let icon = _createIcon(gicon);
 
339
        mainContentBox.add(icon,
 
340
                           { x_fill:  true,
 
341
                             y_fill:  false,
 
342
                             x_align: St.Align.END,
 
343
                             y_align: St.Align.START });
 
344
 
 
345
        this._messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
 
346
                                              vertical: true });
 
347
        mainContentBox.add(this._messageBox,
 
348
                           { y_align: St.Align.START, expand: true, x_fill: true, y_fill: true });
 
349
 
 
350
        let subject = new St.Label({ style_class: 'prompt-dialog-headline' });
 
351
        this._messageBox.add(subject,
 
352
                             { y_fill:  false,
 
353
                               y_align: St.Align.START });
 
354
        if (strings[0])
 
355
            subject.set_text(strings[0]);
 
356
 
 
357
        let description = new St.Label({ style_class: 'prompt-dialog-description' });
 
358
        description.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 
359
        description.clutter_text.line_wrap = true;
 
360
        this._messageBox.add(description,
 
361
                            { y_fill:  true,
 
362
                              y_align: St.Align.START });
275
363
        if (strings[1])
276
 
            this.addBody(strings[1]);
277
 
 
278
 
        if (reaskPassword) {
279
 
            let label = new St.Label({ style_class: 'mount-password-reask',
280
 
                                       text: _("Wrong password, please try again") });
281
 
 
282
 
            this.addActor(label);
 
364
            description.set_text(strings[1]);
 
365
 
 
366
        this._passwordBox = new St.BoxLayout({ vertical: false, style_class: 'prompt-dialog-password-box' });
 
367
        this._messageBox.add(this._passwordBox);
 
368
 
 
369
        this._passwordLabel = new St.Label(({ style_class: 'prompt-dialog-password-label',
 
370
                                              text: _("Password") }));
 
371
        this._passwordBox.add(this._passwordLabel, { y_fill: false, y_align: St.Align.MIDDLE });
 
372
 
 
373
        this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
 
374
                                             text: "",
 
375
                                             can_focus: true});
 
376
        ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
 
377
        this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivate));
 
378
        this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
 
379
        this._passwordBox.add(this._passwordEntry, {expand: true });
 
380
        this.setInitialKeyFocus(this._passwordEntry);
 
381
 
 
382
        this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label',
 
383
                                                 text: _("Sorry, that didn\'t work. Please try again.") });
 
384
        this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
 
385
        this._errorMessageLabel.clutter_text.line_wrap = true;
 
386
        this._errorMessageLabel.hide();
 
387
        this._messageBox.add(this._errorMessageLabel);
 
388
 
 
389
        if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
 
390
            this._rememberChoice = new CheckBox.CheckBox();
 
391
            this._rememberChoice.getLabelActor().text = _("Remember Password");
 
392
            this._rememberChoice.actor.checked =
 
393
                global.settings.get_boolean(REMEMBER_MOUNT_PASSWORD_KEY);
 
394
            this._messageBox.add(this._rememberChoice.actor);
 
395
        } else {
 
396
            this._rememberChoice = null;
283
397
        }
284
398
 
285
 
        this._responseEntry = new St.Entry({ style_class: 'mount-password-entry',
286
 
                                             can_focus: true });
287
 
        this.setActionArea(this._responseEntry);
288
 
 
289
 
        this._responseEntry.clutter_text.connect('activate',
290
 
                                                 Lang.bind(this, this._onEntryActivated));
291
 
        this._responseEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
292
 
 
293
 
        this._responseEntry.grab_key_focus();
294
 
    },
295
 
 
296
 
    _onEntryActivated: function() {
297
 
        let text = this._responseEntry.get_text();
298
 
        if (text == '')
299
 
            return;
300
 
 
301
 
        this.source.emit('password-ready', text);
 
399
        let buttons = [{ label: _("Cancel"),
 
400
                         action: Lang.bind(this, this._onCancelButton),
 
401
                         key:    Clutter.Escape
 
402
                       },
 
403
                       { label: _("Unlock"),
 
404
                         action: Lang.bind(this, this._onUnlockButton),
 
405
                         default: true
 
406
                       }];
 
407
 
 
408
        this.setButtons(buttons);
 
409
    },
 
410
 
 
411
    reaskPassword: function() {
 
412
        this._passwordEntry.set_text('');
 
413
        this._errorMessageLabel.show();
 
414
    },
 
415
 
 
416
    _onCancelButton: function() {
 
417
        this.emit('response', -1, '', false);
 
418
    },
 
419
 
 
420
    _onUnlockButton: function() {
 
421
        this._onEntryActivate();
 
422
    },
 
423
 
 
424
    _onEntryActivate: function() {
 
425
        global.settings.set_boolean(REMEMBER_MOUNT_PASSWORD_KEY,
 
426
            this._rememberChoice && this._rememberChoice.actor.checked);
 
427
        this.emit('response', 1,
 
428
            this._passwordEntry.get_text(),
 
429
            this._rememberChoice &&
 
430
            this._rememberChoice.actor.checked);
302
431
    }
303
432
});
304
433
 
347
476
        scrollView.hide();
348
477
 
349
478
        this._applicationList = new St.BoxLayout({ vertical: true });
350
 
        scrollView.add_actor(this._applicationList,
351
 
                             { x_fill:  true,
352
 
                               y_fill:  true,
353
 
                               x_align: St.Align.START,
354
 
                               y_align: St.Align.MIDDLE });
 
479
        scrollView.add_actor(this._applicationList);
355
480
 
356
481
        this._applicationList.connect('actor-added',
357
482
                                      Lang.bind(this, function() {
358
 
                                          if (this._applicationList.get_children().length == 1)
 
483
                                          if (this._applicationList.get_n_children() == 1)
359
484
                                              scrollView.show();
360
485
                                      }));
361
486
 
362
487
        this._applicationList.connect('actor-removed',
363
488
                                      Lang.bind(this, function() {
364
 
                                          if (this._applicationList.get_children().length == 0)
 
489
                                          if (this._applicationList.get_n_children() == 0)
365
490
                                              scrollView.hide();
366
491
                                      }));
367
492
    },
395
520
    }
396
521
});
397
522
Signals.addSignalMethods(ShellProcessesDialog.prototype);
 
523
 
 
524
const GnomeShellMountOpIface = <interface name="org.Gtk.MountOperationHandler">
 
525
<method name="AskPassword">
 
526
    <arg type="s" direction="in" name="object_id"/>
 
527
    <arg type="s" direction="in" name="message"/>
 
528
    <arg type="s" direction="in" name="icon_name"/>
 
529
    <arg type="s" direction="in" name="default_user"/>
 
530
    <arg type="s" direction="in" name="default_domain"/>
 
531
    <arg type="u" direction="in" name="flags"/>
 
532
    <arg type="u" direction="out" name="response"/>
 
533
    <arg type="a{sv}" direction="out" name="response_details"/>
 
534
</method>
 
535
<method name="AskQuestion">
 
536
    <arg type="s" direction="in" name="object_id"/>
 
537
    <arg type="s" direction="in" name="message"/>
 
538
    <arg type="s" direction="in" name="icon_name"/>
 
539
    <arg type="as" direction="in" name="choices"/>
 
540
    <arg type="u" direction="out" name="response"/>
 
541
    <arg type="a{sv}" direction="out" name="response_details"/>
 
542
</method>
 
543
<method name="ShowProcesses">
 
544
    <arg type="s" direction="in" name="object_id"/>
 
545
    <arg type="s" direction="in" name="message"/>
 
546
    <arg type="s" direction="in" name="icon_name"/>
 
547
    <arg type="ai" direction="in" name="application_pids"/>
 
548
    <arg type="as" direction="in" name="choices"/>
 
549
    <arg type="u" direction="out" name="response"/>
 
550
    <arg type="a{sv}" direction="out" name="response_details"/>
 
551
</method>
 
552
<method name="Close"/>
 
553
</interface>;
 
554
 
 
555
const ShellMountOperationType = {
 
556
    NONE: 0,
 
557
    ASK_PASSWORD: 1,
 
558
    ASK_QUESTION: 2,
 
559
    SHOW_PROCESSES: 3
 
560
};
 
561
 
 
562
const GnomeShellMountOpHandler = new Lang.Class({
 
563
    Name: 'GnomeShellMountOpHandler',
 
564
 
 
565
    _init: function() {
 
566
        this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellMountOpIface, this);
 
567
        this._dbusImpl.export(Gio.DBus.session, '/org/gtk/MountOperationHandler');
 
568
        Gio.bus_own_name_on_connection(Gio.DBus.session, 'org.gtk.MountOperationHandler',
 
569
                                       Gio.BusNameOwnerFlags.REPLACE, null, null);
 
570
 
 
571
        this._dialog = null;
 
572
        this._volumeMonitor = Gio.VolumeMonitor.get();
 
573
 
 
574
        this._ensureEmptyRequest();
 
575
    },
 
576
 
 
577
    _ensureEmptyRequest: function() {
 
578
        this._currentId = null;
 
579
        this._currentInvocation = null;
 
580
        this._currentType = ShellMountOperationType.NONE;
 
581
    },
 
582
 
 
583
    _clearCurrentRequest: function(response, details) {
 
584
        if (this._currentInvocation) {
 
585
            this._currentInvocation.return_value(
 
586
                GLib.Variant.new('(ua{sv})', [response, details]));
 
587
        }
 
588
 
 
589
        this._ensureEmptyRequest();
 
590
    },
 
591
 
 
592
    _setCurrentRequest: function(invocation, id, type) {
 
593
        let oldId = this._currentId;
 
594
        let oldType = this._currentType;
 
595
        let requestId = id + '@' + invocation.get_sender();
 
596
 
 
597
        this._clearCurrentRequest(Gio.MountOperationResult.UNHANDLED, {});
 
598
 
 
599
        this._currentInvocation = invocation;
 
600
        this._currentId = requestId;
 
601
        this._currentType = type;
 
602
 
 
603
        if (this._dialog && (oldId == requestId) && (oldType == type))
 
604
            return true;
 
605
 
 
606
        return false;
 
607
    },
 
608
 
 
609
    _closeDialog: function() {
 
610
        if (this._dialog) {
 
611
            this._dialog.close();
 
612
            this._dialog = null;
 
613
        }
 
614
    },
 
615
 
 
616
    _createGIcon: function(iconName) {
 
617
        let realIconName = iconName ? iconName : 'drive-harddisk';
 
618
        return new Gio.ThemedIcon({ name: realIconName,
 
619
                                    use_default_fallbacks: true });
 
620
    },
 
621
 
 
622
    /**
 
623
     * AskPassword:
 
624
     * @id: an opaque ID identifying the object for which the operation is requested
 
625
     *      The ID must be unique in the context of the calling process.
 
626
     * @message: the message to display
 
627
     * @icon_name: the name of an icon to display
 
628
     * @default_user: the default username for display
 
629
     * @default_domain: the default domain for display
 
630
     * @flags: a set of GAskPasswordFlags
 
631
     * @response: a GMountOperationResult
 
632
     * @response_details: a dictionary containing the response details as
 
633
     * entered by the user. The dictionary MAY contain the following properties:
 
634
     *   - "password" -> (s): a password to be used to complete the mount operation
 
635
     *   - "password_save" -> (u): a GPasswordSave
 
636
     *
 
637
     * The dialog will stay visible until clients call the Close() method, or
 
638
     * another dialog becomes visible.
 
639
     * Calling AskPassword again for the same id will have the effect to clear
 
640
     * the existing dialog and update it with a message indicating the previous
 
641
     * attempt went wrong.
 
642
     */
 
643
    AskPasswordAsync: function(params, invocation) {
 
644
        let [id, message, iconName, defaultUser, defaultDomain, flags] = params;
 
645
 
 
646
        if (this._setCurrentRequest(invocation, id, ShellMountOperationType.ASK_PASSWORD)) {
 
647
            this._dialog.reaskPassword();
 
648
            return;
 
649
        }
 
650
 
 
651
        this._closeDialog();
 
652
 
 
653
        this._dialog = new ShellMountPasswordDialog(message, this._createGIcon(iconName), flags);
 
654
        this._dialog.connect('response', Lang.bind(this,
 
655
            function(object, choice, password, remember) {
 
656
                let details = {};
 
657
                let response;
 
658
 
 
659
                if (choice == -1) {
 
660
                    response = Gio.MountOperationResult.ABORTED;
 
661
                } else {
 
662
                    response = Gio.MountOperationResult.HANDLED;
 
663
 
 
664
                    let passSave = remember ? Gio.PasswordSave.PERMANENTLY : Gio.PasswordSave.NEVER;
 
665
                    details['password_save'] = GLib.Variant.new('u', passSave);
 
666
                    details['password'] = GLib.Variant.new('s', password);
 
667
                }
 
668
 
 
669
                this._clearCurrentRequest(response, details);
 
670
            }));
 
671
        this._dialog.open();
 
672
    },
 
673
 
 
674
    /**
 
675
     * AskQuestion:
 
676
     * @id: an opaque ID identifying the object for which the operation is requested
 
677
     *      The ID must be unique in the context of the calling process.
 
678
     * @message: the message to display
 
679
     * @icon_name: the name of an icon to display
 
680
     * @choices: an array of choice strings
 
681
     * GetResponse:
 
682
     * @response: a GMountOperationResult
 
683
     * @response_details: a dictionary containing the response details as
 
684
     * entered by the user. The dictionary MAY contain the following properties:
 
685
     *   - "choice" -> (i): the chosen answer among the array of strings passed in
 
686
     *
 
687
     * The dialog will stay visible until clients call the Close() method, or
 
688
     * another dialog becomes visible.
 
689
     * Calling AskQuestion again for the same id will have the effect to clear
 
690
     * update the dialog with the new question.
 
691
     */
 
692
    AskQuestionAsync: function(params, invocation) {
 
693
        let [id, message, iconName, choices] = params;
 
694
 
 
695
        if (this._setCurrentRequest(invocation, id, ShellMountOperationType.ASK_QUESTION)) {
 
696
            this._dialog.update(message, choices);
 
697
            return;
 
698
        }
 
699
 
 
700
        this._closeDialog();
 
701
 
 
702
        this._dialog = new ShellMountQuestionDialog(this._createGIcon(iconName), message);
 
703
        this._dialog.connect('response', Lang.bind(this,
 
704
            function(object, choice) {
 
705
                this._clearCurrentRequest(Gio.MountOperationResult.HANDLED,
 
706
                                          { choice: GLib.Variant.new('i', choice) });
 
707
            }));
 
708
 
 
709
        this._dialog.update(message, choices);
 
710
        this._dialog.open();
 
711
    },
 
712
 
 
713
    /**
 
714
     * ShowProcesses:
 
715
     * @id: an opaque ID identifying the object for which the operation is requested
 
716
     *      The ID must be unique in the context of the calling process.
 
717
     * @message: the message to display
 
718
     * @icon_name: the name of an icon to display
 
719
     * @application_pids: the PIDs of the applications to display
 
720
     * @choices: an array of choice strings
 
721
     * @response: a GMountOperationResult
 
722
     * @response_details: a dictionary containing the response details as
 
723
     * entered by the user. The dictionary MAY contain the following properties:
 
724
     *   - "choice" -> (i): the chosen answer among the array of strings passed in
 
725
     *
 
726
     * The dialog will stay visible until clients call the Close() method, or
 
727
     * another dialog becomes visible.
 
728
     * Calling ShowProcesses again for the same id will have the effect to clear
 
729
     * the existing dialog and update it with the new message and the new list
 
730
     * of processes.
 
731
     */
 
732
    ShowProcessesAsync: function(params, invocation) {
 
733
        let [id, message, iconName, applicationPids, choices] = params;
 
734
 
 
735
        if (this._setCurrentRequest(invocation, id, ShellMountOperationType.SHOW_PROCESSES)) {
 
736
            this._dialog.update(message, applicationPids, choices);
 
737
            return;
 
738
        }
 
739
 
 
740
        this._closeDialog();
 
741
 
 
742
        this._dialog = new ShellProcessesDialog(this._createGIcon(iconName));
 
743
        this._dialog.connect('response', Lang.bind(this,
 
744
            function(object, choice) {
 
745
                let response;
 
746
                let details = {};
 
747
 
 
748
                if (choice == -1) {
 
749
                    response = Gio.MountOperationResult.ABORTED;
 
750
                } else {
 
751
                    response = Gio.MountOperationResult.HANDLED;
 
752
                    details['choice'] = GLib.Variant.new('i', choice);
 
753
                }
 
754
 
 
755
                this._clearCurrentRequest(response, details);
 
756
            }));
 
757
 
 
758
        this._dialog.update(message, applicationPids, choices);
 
759
        this._dialog.open();
 
760
    },
 
761
 
 
762
    /**
 
763
     * Close:
 
764
     *
 
765
     * Closes a dialog previously opened by AskPassword, AskQuestion or ShowProcesses.
 
766
     * If no dialog is open, does nothing.
 
767
     */
 
768
    Close: function(params, invocation) {
 
769
        this._clearCurrentRequest(Gio.MountOperationResult.UNHANDLED, {});
 
770
        this._closeDialog();
 
771
    }
 
772
});