]> git.lyx.org Git - lyx.git/blob - src/minibuffer.C
Fix the WorkArea problems.
[lyx.git] / src / minibuffer.C
1 /* ###########################################################################
2  *
3  *                 The MiniBuffer Class
4  *                 read minibuffer.h for more
5  *                 information.
6  * 
7  *           Copyright 1995 Matthias Ettrich
8  *           Copyright 1995-2001 The LyX Team.  
9  * 
10  * ###########################################################################
11  */
12
13 #include <config.h>
14
15 #include <iostream>
16
17 #ifdef __GNUG__
18 #pragma implementation
19 #endif
20
21 #include "minibuffer.h"
22
23 #include "support/lyxalgo.h"
24 #include "support/filetools.h"
25 #include "support/lstrings.h"
26 #include "LyXView.h"
27 #include "XFormsView.h"
28 #include "gettext.h"
29 #include "LyXAction.h"
30 #include "BufferView.h"
31
32
33 using SigC::slot;
34 using std::vector;
35
36 extern LyXAction lyxaction;
37
38
39 namespace {
40
41 struct prefix {
42         string p;
43         prefix(string const & s) 
44                 : p(s) {}
45         bool operator()(string const & s) const {
46                 return prefixIs(s, p);
47         }
48 };
49
50 } // end of anon namespace
51
52
53 MiniBuffer::MiniBuffer(LyXView * o, FL_Coord x, FL_Coord y,
54                        FL_Coord h, FL_Coord w)
55         : stored_(false), owner_(o), state_(spaces)
56 {
57         add(FL_NORMAL_INPUT, x, y, h, w);
58         timer.setTimeout(6000);
59         timer.timeout.connect(slot(this, &MiniBuffer::init));
60         stored_timer.setTimeout(1500);
61         stored_timer.timeout.connect(slot(this, &MiniBuffer::stored_slot));
62         deactivate();
63 }
64
65
66 void MiniBuffer::stored_slot() 
67 {
68         if (stored_) {
69                 stored_ = false;
70                 set_input(stored_input);
71         }
72 }
73
74
75 void MiniBuffer::stored_set(string const & str) 
76 {
77         stored_input = str;
78         stored_ = true;
79         stored_timer.start();
80 }
81
82
83 int MiniBuffer::peek_event(FL_OBJECT * ob, int event, int key)
84 {
85         switch (event) {
86         case FL_KEYBOARD:
87         {
88                 char const * tmp = fl_get_input(ob);
89                 string input = tmp ? tmp : "";
90                 if (stored_) {
91                         stored_timer.stop();
92                         input = stored_input;
93                         set_input(input);
94                         stored_ = false;
95                 }
96                 
97                 switch (key) {
98                 case XK_Down:
99                         if (hist_iter != history_->end()) {
100                                 ++hist_iter;
101                         }
102                         if (hist_iter == history_->end()) {
103                                 // no further history
104                                 stored_set(input);
105                                 set_input(_("[End of history]"));
106                         } else {
107                                 set_input((*hist_iter));
108                         }
109                         return 1; 
110                 case XK_Up:
111                         if (hist_iter == history_->begin()) {
112                                 // no further history
113                                 stored_set(input);
114                                 set_input(_("[Beginning of history]"));
115                         } else {
116                                 --hist_iter;
117                                 set_input((*hist_iter));
118                         }
119                         return 1; 
120                 case 9:
121                 case XK_Tab:
122                 {
123                         // Completion handling.
124                         
125                         vector<string> comp;
126                         lyx::copy_if(completion_.begin(),
127                                      completion_.end(),
128                                      std::back_inserter(comp), prefix(input));
129
130                         if (comp.empty()) {
131                                 // No matches
132                                 string const tmp = input + _(" [no match]");
133                                 stored_set(input);
134                                 set_input(tmp);
135                         } else if (comp.size() == 1) {
136                                 // Perfect match
137                                 string const tmp =
138                                         comp[0] + _(" [sole completion]");
139                                 stored_set(comp[0]);
140                                 set_input(tmp);
141                         } else {
142                                 // More that one match
143                                 // Find maximal avaliable prefix
144                                 string const tmp = comp[0];
145                                 string test(input);
146                                 test += tmp[test.length()];
147                                 while (test.length() < tmp.length()) {
148                                         vector<string> vtmp;
149                                         lyx::copy_if(comp.begin(),
150                                                      comp.end(),
151                                                      std::back_inserter(vtmp),
152                                                      prefix(test));
153                                         if (vtmp.size() != comp.size()) {
154                                                 test.erase(test.length() - 1);
155                                                 break;
156                                         }
157                                         test += tmp[test.length()];
158                                 }
159                                 set_input(test);
160                                 
161                                 // How should the possible matches
162                                 // be visualized?
163                                 std::copy(comp.begin(), comp.end(),
164                                           std::ostream_iterator<string>(std::cerr, "\n"));
165                         }
166                         return 1; 
167                 }
168                 case 27:
169                 case XK_Escape:
170                         // Abort
171                         owner_->view()->focus(true);
172                         init();
173                         deactivate();
174                         //escape.emit();
175                         return 1; 
176                 case 13:
177                 case XK_Return:
178                 {
179 #if 0
180                         // This will go in again in a little while
181                         // we need to be able to declare what types
182                         // of argumetns LFUN's should have first. (Lgb)
183                         // First check for match
184                         vector<string>::const_iterator cit =
185                                 std::find(completion_.begin(),
186                                           completion_.end(),
187                                           input);
188                         if (cit == completion_.end()) {
189                                 // no such func/item
190                                 stored_set(input);
191                                 string const tmp = input + _(" [no match]");
192                                 set_input(tmp);
193                         } else {
194 #endif
195                                 // Return the inputted string
196                                 deactivate();
197                                 owner_->view()->focus(true);
198                                 history_->push_back(input);
199                                 stringReady.emit(input);
200 # if 0
201                         }
202 #endif
203                         return 1;
204                 }
205                 case XK_space:
206                 {
207                         // Depending on the input state spaces might not
208                         // be allowed.
209                         switch (state_) {
210                         case spaces:
211                                 return 0;
212                         case nospaces:
213                         {
214                                 stored_set(input);
215                                 string const tmp = input + _(" [no match]");
216                                 set_input(tmp);
217                                 return 1;
218                         }
219                         }
220                         
221                 }
222                 
223                 default:
224                         return 0;
225                 }
226         }
227         default:
228                 //lyxerr << "Unhandled minibuffer event!" << endl;
229                 break;
230         }
231         
232         return 0;
233 }
234
235
236 extern "C" {
237         
238         static
239         int C_MiniBuffer_peek_event(FL_OBJECT * ob, int event, 
240                                     FL_Coord, FL_Coord,
241                                     int key, void * /*xev*/)
242         {
243                 MiniBuffer * mini = static_cast<MiniBuffer*>(ob->u_vdata);
244                 return mini->peek_event(ob, event, key);
245         }
246         
247 }
248
249
250 void MiniBuffer::prepare()
251 {
252         text.erase();
253         set_input("");
254         activate();
255         fl_set_focus_object(static_cast<XFormsView *>(owner_)->getForm(),
256                             the_buffer);
257 }
258
259
260 FL_OBJECT * MiniBuffer::add(int type, FL_Coord x, FL_Coord y,
261                            FL_Coord w, FL_Coord h)
262 {
263         FL_OBJECT * obj;
264         
265         the_buffer = obj = fl_add_input(type, x, y, w, h, text.c_str());
266         fl_set_object_boxtype(obj, FL_DOWN_BOX);
267         fl_set_object_resize(obj, FL_RESIZE_ALL);
268         fl_set_object_gravity(obj, SouthWestGravity, SouthEastGravity);
269         fl_set_object_color(obj, FL_MCOL, FL_MCOL);
270         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
271         
272         // To intercept Up, Down, Table for history
273         fl_set_object_prehandler(obj, C_MiniBuffer_peek_event);
274         obj->u_vdata = this;
275         obj->wantkey = FL_KEY_TAB;
276
277         set_input(text);
278         
279         return obj;
280 }
281
282
283 void MiniBuffer::message(string const & str) 
284 {
285         timer.restart();
286         string const ntext = strip(str);
287         if (!the_buffer->focus) {
288                 set_input(ntext);
289                 text = ntext;
290         }
291 }
292
293
294 void MiniBuffer::messagePush(string const & str) 
295 {
296         text_stored = text;
297         message(str);
298 }
299
300
301 void MiniBuffer::messagePop()
302 {
303         if (!text_stored.empty()) {
304                 message(text_stored);
305                 text_stored.erase();
306         }
307 }
308
309
310 void MiniBuffer::addSet(string const & s1, string const & s2)
311 {
312         string const str = text + ' ' +  s1 + ' ' + s2;
313         message(str);
314 }
315
316
317 void MiniBuffer::getString(State spaces,
318                            vector<string> const & completion,
319                            vector<string> & history)
320 {
321         state_ = spaces;
322         completion_ = completion;
323         history_ = &history;
324         hist_iter = history_->end();
325         prepare();
326 }
327
328
329 void MiniBuffer::init()
330 {
331         // If we have focus, we don't want to change anything.
332         if (the_buffer->focus)
333                 return;
334
335         timeout.emit();
336         timer.stop();
337 }
338
339
340 void MiniBuffer::activate()
341 {
342         fl_activate_object(the_buffer);
343         redraw();
344 }
345
346
347 void MiniBuffer::deactivate()
348 {
349         redraw();
350         fl_deactivate_object(the_buffer);
351         XFlush(fl_display);
352 }
353
354
355 void MiniBuffer::redraw() 
356 {
357         fl_redraw_object(the_buffer);
358         XFlush(fl_display);
359 }
360
361
362 void MiniBuffer::set_input(string const & str)
363 {
364         fl_set_input(the_buffer, str.c_str());
365         XFlush(fl_display);
366 }