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