]> git.lyx.org Git - lyx.git/blob - src/minibuffer.C
insetquote fix; getStatus tweaks
[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                 fl_set_input(the_buffer, stored_input.c_str());
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                         fl_set_input(ob, input.c_str());
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                                 fl_set_input(ob, _("[End of history]"));
106                         } else {
107                                 fl_set_input(ob, hist_iter->c_str());
108                         }
109                         return 1; 
110                 case XK_Up:
111                         if (hist_iter == history_->begin()) {
112                                 // no further history
113                                 stored_set(input);
114                                 fl_set_input(ob, _("[Beginning of history]"));
115                         } else {
116                                 --hist_iter;
117                                 fl_set_input(ob, hist_iter->c_str());
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                                 fl_set_input(ob, tmp.c_str());
135                         } else if (comp.size() == 1) {
136                                 // Perfect match
137                                 string const tmp =
138                                         comp[0] + _(" [sole completion]");
139                                 stored_set(comp[0]);
140                                 fl_set_input(ob, tmp.c_str());
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                                 fl_set_input(ob, test.c_str());
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                                 fl_set_input(ob, tmp.c_str());
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                                 fl_set_input(ob, tmp.c_str());
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 int C_MiniBuffer_peek_event(FL_OBJECT * ob, int event, 
238                             FL_Coord, FL_Coord,
239                             int key, void * /*xev*/)
240 {
241         MiniBuffer * mini = static_cast<MiniBuffer*>(ob->u_vdata);
242         return mini->peek_event(ob, event, key);
243 }
244
245
246 void MiniBuffer::prepare()
247 {
248         text.erase();
249         fl_set_input(the_buffer, "");
250         activate();
251         fl_set_focus_object(static_cast<XFormsView *>(owner_)->getForm(),
252                             the_buffer);
253 }
254
255
256 FL_OBJECT * MiniBuffer::add(int type, FL_Coord x, FL_Coord y,
257                            FL_Coord w, FL_Coord h)
258 {
259         FL_OBJECT * obj;
260         
261         the_buffer = obj = fl_add_input(type, x, y, w, h, text.c_str());
262         fl_set_object_boxtype(obj, FL_DOWN_BOX);
263         fl_set_object_resize(obj, FL_RESIZE_ALL);
264         fl_set_object_gravity(obj, SouthWestGravity, SouthEastGravity);
265         fl_set_object_color(obj, FL_MCOL, FL_MCOL);
266         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
267         
268         // To intercept Up, Down, Table for history
269         fl_set_object_prehandler(obj, C_MiniBuffer_peek_event);
270         obj->u_vdata = this;
271         obj->wantkey = FL_KEY_TAB;
272
273         fl_set_input(the_buffer, text.c_str());
274         
275         return obj;
276 }
277
278
279 void MiniBuffer::message(string const & str) 
280 {
281         timer.restart();
282         string const ntext = strip(str);
283         if (!the_buffer->focus) {
284                 fl_set_input(the_buffer, ntext.c_str());
285                 text = ntext;
286         }
287 }
288
289
290 void MiniBuffer::messagePush(string const & str) 
291 {
292         text_stored = text;
293         message(str);
294 }
295
296
297 void MiniBuffer::messagePop()
298 {
299         if (!text_stored.empty()) {
300                 message(text_stored);
301                 text_stored.erase();
302         }
303 }
304
305
306 void MiniBuffer::addSet(string const & s1, string const & s2)
307 {
308         string const str = text + ' ' +  s1 + ' ' + s2;
309         message(str);
310 }
311
312
313 void MiniBuffer::getString(State spaces,
314                            vector<string> const & completion,
315                            vector<string> & history)
316 {
317         state_ = spaces;
318         completion_ = completion;
319         history_ = &history;
320         hist_iter = history_->end();
321         prepare();
322 }
323
324
325 void MiniBuffer::init()
326 {
327         // If we have focus, we don't want to change anything.
328         if (the_buffer->focus)
329                 return;
330
331         timeout.emit();
332         timer.stop();
333 }
334
335
336 void MiniBuffer::activate()
337 {
338         fl_activate_object(the_buffer);
339         fl_redraw_object(the_buffer);
340 }
341
342
343 void MiniBuffer::deactivate()
344 {
345         fl_redraw_object(the_buffer);
346         fl_deactivate_object(the_buffer);
347 }
348
349
350 void MiniBuffer::redraw() 
351 {
352         fl_redraw_object(the_buffer);
353 }