]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GMiniBuffer.C
Wrap most of the frontend code up inside namespace lyx::frontend.
[lyx.git] / src / frontends / gtk / GMiniBuffer.C
1 /**
2  * \file GMiniBuffer.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Huang Ying
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12 #include <gtkmm.h>
13
14 #include "GView.h"
15 #include "GMiniBuffer.h"
16 #include "debug.h"
17 #include "bufferview_funcs.h"
18
19 #include "frontends/controllers/ControlCommandBuffer.h"
20
21 #include <boost/bind.hpp>
22 #include <vector>
23
24 using std::string;
25
26 namespace lyx {
27 namespace frontend {
28
29 GMiniBuffer::GMiniBuffer(GView * view, ControlCommandBuffer & control) :
30         controller_(control), view_(view)
31 {
32         listCols_.add(listCol_);
33         listStore_ = Gtk::ListStore::create(listCols_);
34         listView_.set_model(listStore_);
35         listView_.append_column("Completions", listCol_);
36         listView_.signal_key_press_event().connect(
37                 SigC::slot(*this, &GMiniBuffer::onListKeyPress));
38         listView_.signal_focus_in_event().connect(
39                 SigC::slot(*this, &GMiniBuffer::onListFocusIn));
40         listView_.signal_focus_out_event().connect(
41                 SigC::slot(*this, &GMiniBuffer::onFocusOut));
42         listSel_ = listView_.get_selection();
43         listSel_->signal_changed().connect(
44                 SigC::slot(*this, &GMiniBuffer::onSelected));
45
46         listView_.show();
47         scrolledWindow_.set_policy(Gtk::POLICY_AUTOMATIC,
48                                    Gtk::POLICY_AUTOMATIC);
49         scrolledWindow_.set_size_request(300, 150);
50         scrolledWindow_.add(listView_);
51
52         view_->getBox(GView::Bottom).children().push_back(
53                 Gtk::Box_Helpers::Element(scrolledWindow_,Gtk::PACK_SHRINK));
54
55         entry_.signal_key_press_event().connect(
56                 SigC::slot(*this, &GMiniBuffer::onKeyPress));
57         entry_.signal_focus_in_event().connect(
58                 SigC::slot(*this, &GMiniBuffer::onFocusIn));
59         entry_.signal_focus_out_event().connect(
60                 SigC::slot(*this, &GMiniBuffer::onFocusOut));
61         entry_.signal_activate().connect(
62                 SigC::slot(*this, &GMiniBuffer::onCommit));
63         entry_.show();
64
65         view_->getBox(GView::Bottom).children().push_back(
66                 Gtk::Box_Helpers::Element(entry_, Gtk::PACK_SHRINK));
67
68         infoTimer_.reset(new Timeout(1500));
69         idleTimer_.reset(new Timeout(6000));
70         focusTimer_.reset(new Timeout(50));
71         infoCon_ = infoTimer_->timeout.connect(
72                 boost::bind(&GMiniBuffer::infoTimeout, this));
73         idleCon_ = idleTimer_->timeout.connect(
74                 boost::bind(&GMiniBuffer::idleTimeout, this));
75         focusTimer_->timeout.connect(
76                 boost::bind(&GMiniBuffer::focusTimeout, this));
77         idleTimer_->start();
78         messageMode();
79 }
80
81
82 GMiniBuffer::~GMiniBuffer()
83 {
84 }
85
86
87 void GMiniBuffer::message(string const & str)
88 {
89         if (!isEditMode())
90                 setInput(Glib::locale_to_utf8(str));
91 }
92
93
94 void GMiniBuffer::showInfo(Glib::ustring const & info, bool append)
95 {
96         storedInput_ = entry_.get_text();
97         entry_.set_editable(false);
98         infoShown_ = true;
99         if (append)
100                 setInput(storedInput_ + ' ' + info);
101         else
102                 setInput(info);
103         infoTimer_->start();
104 }
105
106
107 void GMiniBuffer::onSelected()
108 {
109         if (!listSel_->count_selected_rows())
110                 return;
111         Gtk::TreeModel::iterator it = listSel_->get_selected();
112         Glib::ustring sel = (*it)[listCol_];
113         setInput(sel + ' ');
114 }
115
116
117 void GMiniBuffer::onCommit()
118 {
119         controller_.dispatch(Glib::locale_from_utf8(entry_.get_text()));
120         messageMode();
121 }
122
123
124 bool GMiniBuffer::onListFocusIn(GdkEventFocus * /*event*/)
125 {
126         if (focusTimer_->running())
127                 focusTimer_->stop();
128         if (infoShown_) {
129                 infoTimer_->stop();
130                 infoTimeout();
131         }
132         return false;
133 }
134
135
136 bool GMiniBuffer::onFocusIn(GdkEventFocus * /*event*/)
137 {
138         if (infoShown_) {
139                 infoTimer_->stop();
140                 infoTimeout();
141         }
142         if (focusTimer_->running()) {
143                 focusTimer_->stop();
144                 return false;
145         }
146         setInput("");
147         idleTimer_->stop();
148         return false;
149 }
150
151
152 bool GMiniBuffer::onFocusOut(GdkEventFocus * /*event*/)
153 {
154         focusTimer_->start();
155         return false;
156 }
157
158
159 void GMiniBuffer::focusTimeout()
160 {
161         if (infoShown_) {
162                 infoTimer_->stop();
163                 infoTimeout();
164         }
165         focusTimer_->stop();
166         setInput("");
167         idleTimer_->start();
168         scrolledWindow_.hide();
169 }
170
171
172 bool GMiniBuffer::onListKeyPress(GdkEventKey * event)
173 {
174         if (infoShown_) {
175                 infoTimer_->stop();
176                 infoTimeout();
177         }
178         switch (event->keyval) {
179         case GDK_Escape:
180                 messageMode();
181                 break;
182         case GDK_Tab:
183                 entry_.grab_focus();
184                 setInput(entry_.get_text() + ' ');
185                 break;
186         }
187         return true;
188 }
189
190
191 bool GMiniBuffer::onKeyPress(GdkEventKey * event)
192 {
193         if (infoShown_) {
194                 infoTimer_->stop();
195                 infoTimeout();
196         }
197         switch (event->keyval) {
198         case GDK_Down:
199         {
200                 Glib::ustring const h =
201                         Glib::locale_to_utf8(controller_.historyDown());
202                 if (h.empty())
203                         showInfo("[End of history]", false);
204                 else
205                         setInput(h);
206                 break;
207         }
208         case GDK_Up:
209         {
210                 Glib::ustring const h =
211                         Glib::locale_to_utf8(controller_.historyUp());
212                 if (h.empty())
213                         showInfo("[Beginning of history]", false);
214                 else
215                         setInput(h);
216                 break;
217         }
218         case GDK_Escape:
219                 messageMode();
220                 break;
221         case GDK_Tab:
222         {
223                 Glib::ustring new_input, input;
224                 string new_input_locale;
225                 input = entry_.get_text();
226                 std::vector<string> comp =
227                         controller_.completions(Glib::locale_from_utf8(input),
228                                                 new_input_locale);
229                 new_input = Glib::locale_to_utf8(new_input_locale);
230                 if (comp.empty() && new_input == input) {
231                         showInfo("[no match]");
232                         break;
233                 }
234
235                 if (comp.empty()) {
236                         setInput(new_input + ' ');
237                         showInfo("[only completion]");
238                         break;
239                 }
240                 setInput(new_input);
241                 listStore_->clear();
242                 std::vector<string>::iterator it;
243                 for (it = comp.begin(); it != comp.end(); ++it)
244                         (*listStore_->append())[listCol_] =
245                                 Glib::locale_to_utf8(*it);
246                 scrolledWindow_.show();
247                 break;
248         }
249         }
250         return true;
251 }
252
253
254 bool GMiniBuffer::isEditMode() const
255 {
256         return entry_.has_focus() || listView_.has_focus();
257 }
258
259
260 void GMiniBuffer::infoTimeout()
261 {
262         infoShown_ = false;
263         setInput(storedInput_);
264         entry_.set_editable(true);
265 }
266
267
268 void GMiniBuffer::idleTimeout()
269 {
270         setInput(Glib::locale_to_utf8(controller_.getCurrentState()));
271 }
272
273
274 void GMiniBuffer::editMode()
275 {
276         entry_.grab_focus();
277 }
278
279
280 void GMiniBuffer::messageMode()
281 {
282         view_->focusWorkArea();
283 }
284
285
286 void GMiniBuffer::setInput(Glib::ustring const & input)
287 {
288         entry_.set_text(input);
289         entry_.set_position(-1);
290 }
291
292 } // namespace frontend
293 } // namespace lyx