]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormForks.C
fix crash with "save as"
[lyx.git] / src / frontends / xforms / FormForks.C
1 /**
2  * \file FormForks.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming 
7  *
8  * Full author contact details are available in file CREDITS
9  * \date 2001-10-22
10  */
11
12 #include <config.h>
13
14 #ifdef __GNUG__
15 #pragma implementation
16 #endif
17
18 #include "xformsBC.h"
19 #include "FormForks.h"
20 #include "ControlForks.h"
21 #include "forms/form_forks.h"
22 #include "Tooltips.h"
23 #include "helper_funcs.h"
24 #include "xforms_helpers.h"
25 #include "gettext.h"
26 #include "support/lstrings.h"
27 #include FORMS_H_LOCATION
28
29 using std::vector;
30 using std::find;
31 using std::find_if;
32
33 typedef FormCB<ControlForks, FormDB<FD_forks> > base_class;
34
35 FormForks::FormForks()
36         : base_class(_("Child processes"))
37 {}
38
39
40 void FormForks::build() {
41         dialog_.reset(build_forks(this));
42
43         // It appears that the browsers aren't initialised properly.
44         // This fudge fixes tings.
45         fl_add_browser_line(dialog_->browser_children, " ");
46         fl_add_browser_line(dialog_->browser_kill, " ");
47         fl_clear_browser(dialog_->browser_children);
48         fl_clear_browser(dialog_->browser_kill);
49
50         // Manage the ok, apply, restore and cancel/close buttons
51         bc().setOK(dialog_->button_ok);
52         bc().setApply(dialog_->button_apply);
53         bc().setCancel(dialog_->button_close);
54         bc().invalid();
55
56         // Set up the tooltip mechanism
57         string str = _("All currently running child processes forked by LyX.");
58         tooltips().init(dialog_->browser_children, str);
59         // Work-around xforms' bug; enable tooltips for browser widgets.
60         setPrehandler(dialog_->browser_children);
61
62         str = _("A list of all child processes to kill.");
63         tooltips().init(dialog_->browser_kill, str);
64         // Work-around xforms' bug; enable tooltips for browser widgets.
65         setPrehandler(dialog_->browser_kill);
66
67         str = _("Add all processes to the list of processes to kill.");
68         tooltips().init(dialog_->button_all, str);
69
70         str = _("Add the currently selected child process to the list of processes to kill.");
71         tooltips().init(dialog_->button_add, str);
72
73         str = _("Remove the currently selected item from the list of processes to kill.");
74         tooltips().init(dialog_->button_remove, str);
75 }
76
77
78 void FormForks::update()
79 {
80         if (!form())
81                 return;
82
83         string const current_pid_str =
84                 getString(dialog_->browser_kill);
85         pid_t const current_pid = strToInt(current_pid_str);
86
87         vector<pid_t> pids = controller().getPIDs();
88
89         // No child processes.
90         if (pids.empty()) {
91                 if (fl_get_browser_maxline(dialog_->browser_kill) > 0)
92                         fl_clear_browser(dialog_->browser_kill);
93                 if (fl_get_browser_maxline(dialog_->browser_children) > 0)
94                         fl_clear_browser(dialog_->browser_children);
95
96                 setEnabled(dialog_->browser_children, false);
97                 setEnabled(dialog_->browser_kill,     false);
98                 setEnabled(dialog_->button_all,       false);
99                 setEnabled(dialog_->button_add,       false);
100                 setEnabled(dialog_->button_remove,    false);
101
102                 return;
103         }
104
105         // Remove any processes from the kill browser that aren't in the
106         // vector of existing PIDs.
107         for (int i = 1; i <= fl_get_browser_maxline(dialog_->browser_kill);
108              ++i) {
109                 string const pid_str =
110                         getString(dialog_->browser_kill, i);
111                 pid_t const pid = strToInt(pid_str);
112                 vector<pid_t>::const_iterator it =
113                         find(pids.begin(), pids.end(), pid);
114                 if (it == pids.end())
115                         fl_delete_browser_line(dialog_->browser_kill, i);
116         }
117
118         // Build the children browser from scratch.
119         if (fl_get_browser_maxline(dialog_->browser_children) > 0)
120                 fl_clear_browser(dialog_->browser_children);
121         int i = 1;
122         for (vector<pid_t>::const_iterator it = pids.begin();
123              it != pids.end(); ++it) {
124                 string const pid_str = tostr(*it);
125                 string const command = controller().getCommand(*it);
126                 string const line = pid_str + '\t' + command;
127
128                 fl_add_browser_line(dialog_->browser_children, line.c_str());
129
130                 if (*it == current_pid)
131                         fl_select_browser_line(dialog_->browser_children, i);
132                 ++i;
133         }
134
135         setEnabled(dialog_->browser_children, true);
136         setEnabled(dialog_->button_all,       true);
137         setEnabled(dialog_->button_add,       true);
138 }
139
140
141 void FormForks::apply()
142 {
143         // Get the list of all processes to kill.
144         vector<string> const kill_vec =
145                 getVector(dialog_->browser_kill);
146
147         if (kill_vec.empty())
148                 return;
149
150         // Remove these items from the vector of child processes.
151         for (int i = 1; i <= fl_get_browser_maxline(dialog_->browser_children);
152              ++i) {
153                 string const selection =
154                         getString(dialog_->browser_children, i);
155                 string pid_str;
156                 split(selection, pid_str, '\t');
157
158                 vector<string>::const_iterator it =
159                         find(kill_vec.begin(), kill_vec.end(), pid_str);
160
161                 if (it != kill_vec.end())
162                         fl_delete_browser_line(dialog_->browser_children, i);
163         }
164
165         // Clear the kill browser and deactivate appropriately.
166         fl_clear_browser(dialog_->browser_kill);
167         setEnabled(dialog_->browser_kill,  false);
168         setEnabled(dialog_->button_remove, false);
169
170         // Pass these pids to the controller for destruction.
171         for (vector<string>::const_iterator it = kill_vec.begin();
172              it != kill_vec.end(); ++it) {
173                 pid_t const pid = strToInt(*it);
174                 controller().kill(pid);
175         }
176
177 }
178
179
180 ButtonPolicy::SMInput FormForks::input(FL_OBJECT * ob, long)
181 {
182         ButtonPolicy::SMInput activate = ButtonPolicy::SMI_NOOP;
183
184         if (ob == dialog_->browser_children) {
185                 activate = input_browser_children();
186
187         } else if (ob == dialog_->browser_kill) {
188                 activate = input_browser_kill();
189
190         } else if (ob == dialog_->button_all) {
191                 activate = input_button_all();
192
193         } else if (ob == dialog_->button_add) {
194                 activate = input_button_add();
195
196         } else if (ob == dialog_->button_remove) {
197                 activate = input_button_remove();
198         }
199
200         return activate;
201 }
202
203 ButtonPolicy::SMInput FormForks::input_browser_children()
204 {
205         // Selected an item in the browser containing a list of all child
206         // processes.
207
208         // 1. Highlight this item in the browser of processes to kill
209         //    if it is already there.
210
211         // 2. If it is there, enable the remove button so that it can
212         //    be removed from this list, if so desired.
213
214         // 3. If it isn't there, activate the add button so that it can
215         //    be added to this list if so desired.
216
217         string const selection =
218                 getString(dialog_->browser_children);
219         string pid_str;
220         split(selection, pid_str, '\t');
221
222         vector<string> const kill_vec =
223                 getVector(dialog_->browser_kill);
224
225         vector<string>::const_iterator it =
226                 find(kill_vec.begin(), kill_vec.end(), pid_str);
227
228         fl_deselect_browser(dialog_->browser_kill);
229         if (it != kill_vec.end()) {
230                 int const n = int(it - kill_vec.begin());
231                 fl_select_browser_line(dialog_->browser_kill, n+1);
232                 fl_set_browser_topline(dialog_->browser_kill, n+1);
233         }
234
235         setEnabled(dialog_->button_remove, it != kill_vec.end());
236         setEnabled(dialog_->button_add,    it == kill_vec.end());
237
238         return ButtonPolicy::SMI_NOOP;
239 }
240
241
242 namespace {
243
244 class FindPID {
245 public:
246         FindPID(string const & pid) : pid_(pid) {}
247         bool operator()(string const & line)
248         {
249                 if (line.empty())
250                         return false;
251
252                 string pid_str;
253                 split(line, pid_str, '\t');
254                 return pid_str == pid_;
255         }
256
257 private:
258         string pid_;
259 };
260
261 } // namespace anon
262
263
264 ButtonPolicy::SMInput FormForks::input_browser_kill()
265 {
266         // Selected an item in the browser containing a list of processes
267         // to kill.
268
269         // 1. Highlight this item in the browser of all child processes.
270
271         // 2. Enable the remove button so that it can removed from this list,
272         //    if so desired.
273
274         // 3. Disable the add button.
275
276         string const pid_str =
277                 getString(dialog_->browser_kill);
278
279         // Find this string in the list of all child processes
280         vector<string> const child_vec =
281                 getVector(dialog_->browser_children);
282
283         vector<string>::const_iterator it =
284                 find_if(child_vec.begin(), child_vec.end(), FindPID(pid_str));
285
286         fl_deselect_browser(dialog_->browser_children);
287         if (it != child_vec.end()) {
288                 int const n = int(it - child_vec.begin());
289                 fl_select_browser_line(dialog_->browser_children, n+1);
290                 fl_set_browser_topline(dialog_->browser_children, n+1);
291         }
292
293         setEnabled(dialog_->button_remove, true);
294         setEnabled(dialog_->button_add,    false);
295
296         return ButtonPolicy::SMI_NOOP;
297 }
298
299
300 namespace {
301
302 vector<string> const getPIDvector(FL_OBJECT * ob)
303 {
304         vector<string> vec = getVector(ob);
305         if (vec.empty())
306                 return vec;
307
308         for (vector<string>::iterator it = vec.begin(); it != vec.end(); ++it) {
309                 string pid_str;
310                 split(*it, pid_str, '\t');
311                 *it = pid_str;
312         }
313
314         return vec;
315 }
316
317 } // namespace anon
318
319
320 ButtonPolicy::SMInput FormForks::input_button_all()
321 {
322         // Pressed the "All" button.
323
324         // 1. Check that the browser of processes to kill doesn't already
325         //    contain the entire list.
326
327         // 2. If it doesn't, copy the PIDs of all child processes into the
328         //    browser of processes to kill.
329
330         // 3. Deactivate the "children" browser and the "add" and "all" buttons
331
332         // 4. Activate the "kill" browser and the "remove" button"
333
334         ButtonPolicy::SMInput activate = ButtonPolicy::SMI_NOOP;
335
336         vector<string> const pid_vec = getPIDvector(dialog_->browser_children);
337
338         // to resolve a warning about comparison between signed and unsigned.
339         int const pid_vec_size = int(pid_vec.size());
340
341         if (fl_get_browser_maxline(dialog_->browser_kill) != pid_vec_size) {
342                 activate = ButtonPolicy::SMI_VALID;
343
344                 fl_clear_browser(dialog_->browser_kill);
345                 for (vector<string>::const_iterator it = pid_vec.begin();
346                      it != pid_vec.end(); ++it) {
347                         fl_add_browser_line(dialog_->browser_kill, it->c_str());
348                 }
349
350                 if (fl_get_browser_maxline(dialog_->browser_kill) >= 1)
351                         fl_set_browser_topline(dialog_->browser_kill, 1);
352         }
353
354         setEnabled(dialog_->browser_children, false);
355         setEnabled(dialog_->button_add,       false);
356         setEnabled(dialog_->button_all,       false);
357         setEnabled(dialog_->browser_kill,     true);
358         setEnabled(dialog_->button_remove,    true);
359
360         return activate;
361 }
362
363
364 ButtonPolicy::SMInput FormForks::input_button_add()
365 {
366         // Pressed the "Add" button.
367
368         // 1. Copy the PID of the selected item in the browser of all child
369         //    processes over into the browser of processes to kill.
370
371         // 2. Activate the "kill" browser and the "remove" button.
372
373         // 3. Deactivate the "add" button.
374
375         string const selection = getString(dialog_->browser_children);
376         string pid_str;
377         split(selection, pid_str, '\t');
378
379         vector<string> const kill_vec =
380                 getVector(dialog_->browser_kill);
381
382         vector<string>::const_iterator it =
383                 find(kill_vec.begin(), kill_vec.end(), pid_str);
384
385         if (it == kill_vec.end()) {
386                 fl_add_browser_line(dialog_->browser_kill, pid_str.c_str());
387                 int const n = fl_get_browser_maxline(dialog_->browser_kill);
388                 fl_select_browser_line(dialog_->browser_kill, n);
389         }
390
391         setEnabled(dialog_->browser_kill,  true);
392         setEnabled(dialog_->button_remove, true);
393         setEnabled(dialog_->button_add,    false);
394
395         return ButtonPolicy::SMI_VALID;
396 }
397
398
399 ButtonPolicy::SMInput FormForks::input_button_remove()
400 {
401         // Pressed the "Remove" button.
402
403         // 1. Remove the selected item in the browser of processes to kill.
404
405         // 2. Activate the "add" button and "all" buttons.
406
407         // 3. Deactivate the "remove" button.
408
409         int const sel = fl_get_browser(dialog_->browser_kill);
410         fl_delete_browser_line(dialog_->browser_kill, sel);
411
412         setEnabled(dialog_->button_add,    true);
413         setEnabled(dialog_->button_all,    true);
414         setEnabled(dialog_->button_remove, false);
415
416         return ButtonPolicy::SMI_VALID;
417 }