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