/** * \file GMiniBuffer.C * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * * \author Huang Ying * * Full author contact details are available in file CREDITS. */ #include // Too hard to make concept checks work with this file #ifdef _GLIBCPP_CONCEPT_CHECKS #undef _GLIBCPP_CONCEPT_CHECKS #endif #include "GView.h" #include "GMiniBuffer.h" #include "debug.h" #include "bufferview_funcs.h" #include "frontends/controllers/ControlCommandBuffer.h" #include #include using std::string; namespace lyx { namespace frontend { GMiniBuffer::GMiniBuffer(GView * view, ControlCommandBuffer & control) : controller_(control), view_(view) { listCols_.add(listCol_); listStore_ = Gtk::ListStore::create(listCols_); listView_.set_model(listStore_); listView_.append_column("Completions", listCol_); listView_.signal_key_press_event().connect( sigc::mem_fun(*this, &GMiniBuffer::onListKeyPress)); listView_.signal_focus_in_event().connect( sigc::mem_fun(*this, &GMiniBuffer::onListFocusIn)); listView_.signal_focus_out_event().connect( sigc::mem_fun(*this, &GMiniBuffer::onFocusOut)); listSel_ = listView_.get_selection(); listSel_->signal_changed().connect( sigc::mem_fun(*this, &GMiniBuffer::onSelected)); listView_.show(); scrolledWindow_.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); scrolledWindow_.set_size_request(300, 150); scrolledWindow_.add(listView_); view_->getBox(GView::Bottom).children().push_back( Gtk::Box_Helpers::Element(scrolledWindow_,Gtk::PACK_SHRINK)); entry_.signal_key_press_event().connect( sigc::mem_fun(*this, &GMiniBuffer::onKeyPress)); entry_.signal_focus_in_event().connect( sigc::mem_fun(*this, &GMiniBuffer::onFocusIn)); entry_.signal_focus_out_event().connect( sigc::mem_fun(*this, &GMiniBuffer::onFocusOut)); entry_.signal_activate().connect( sigc::mem_fun(*this, &GMiniBuffer::onCommit)); entry_.show(); view_->getBox(GView::Bottom).children().push_back( Gtk::Box_Helpers::Element(entry_, Gtk::PACK_SHRINK)); infoTimer_.reset(new Timeout(1500)); idleTimer_.reset(new Timeout(6000)); focusTimer_.reset(new Timeout(50)); infoCon_ = infoTimer_->timeout.connect( boost::bind(&GMiniBuffer::infoTimeout, this)); idleCon_ = idleTimer_->timeout.connect( boost::bind(&GMiniBuffer::idleTimeout, this)); focusTimer_->timeout.connect( boost::bind(&GMiniBuffer::focusTimeout, this)); idleTimer_->start(); messageMode(); } GMiniBuffer::~GMiniBuffer() { } void GMiniBuffer::message(string const & str) { if (!isEditMode()) setInput(Glib::locale_to_utf8(str)); } void GMiniBuffer::showInfo(Glib::ustring const & info, bool append) { storedInput_ = entry_.get_text(); entry_.set_editable(false); infoShown_ = true; if (append) setInput(storedInput_ + ' ' + info); else setInput(info); infoTimer_->start(); } void GMiniBuffer::onSelected() { if (!listSel_->count_selected_rows()) return; Gtk::TreeModel::iterator it = listSel_->get_selected(); Glib::ustring sel = (*it)[listCol_]; setInput(sel + ' '); } void GMiniBuffer::onCommit() { controller_.dispatch(Glib::locale_from_utf8(entry_.get_text())); messageMode(); } bool GMiniBuffer::onListFocusIn(GdkEventFocus * /*event*/) { if (focusTimer_->running()) focusTimer_->stop(); if (infoShown_) { infoTimer_->stop(); infoTimeout(); } return false; } bool GMiniBuffer::onFocusIn(GdkEventFocus * /*event*/) { if (infoShown_) { infoTimer_->stop(); infoTimeout(); } if (focusTimer_->running()) { focusTimer_->stop(); return false; } setInput(""); idleTimer_->stop(); return false; } bool GMiniBuffer::onFocusOut(GdkEventFocus * /*event*/) { focusTimer_->start(); return false; } void GMiniBuffer::focusTimeout() { if (infoShown_) { infoTimer_->stop(); infoTimeout(); } focusTimer_->stop(); setInput(""); idleTimer_->start(); scrolledWindow_.hide(); } bool GMiniBuffer::onListKeyPress(GdkEventKey * event) { if (infoShown_) { infoTimer_->stop(); infoTimeout(); } switch (event->keyval) { case GDK_Escape: messageMode(); break; case GDK_Tab: entry_.grab_focus(); setInput(entry_.get_text() + ' '); break; } return true; } bool GMiniBuffer::onKeyPress(GdkEventKey * event) { if (infoShown_) { infoTimer_->stop(); infoTimeout(); } switch (event->keyval) { case GDK_Down: { Glib::ustring const h = Glib::locale_to_utf8(controller_.historyDown()); if (h.empty()) showInfo("[End of history]", false); else setInput(h); break; } case GDK_Up: { Glib::ustring const h = Glib::locale_to_utf8(controller_.historyUp()); if (h.empty()) showInfo("[Beginning of history]", false); else setInput(h); break; } case GDK_Escape: messageMode(); break; case GDK_Tab: { string new_input_locale; Glib::ustring input = entry_.get_text(); std::vector comp = controller_.completions(Glib::locale_from_utf8(input), new_input_locale); Glib::ustring new_input = Glib::locale_to_utf8(new_input_locale); if (comp.empty() && new_input == input) { showInfo("[no match]"); break; } if (comp.empty()) { setInput(new_input + ' '); showInfo("[only completion]"); break; } setInput(new_input); listStore_->clear(); std::vector::iterator it; for (it = comp.begin(); it != comp.end(); ++it) (*listStore_->append())[listCol_] = Glib::locale_to_utf8(*it); scrolledWindow_.show(); break; } } return true; } bool GMiniBuffer::isEditMode() const { return entry_.has_focus() || listView_.has_focus(); } void GMiniBuffer::infoTimeout() { infoShown_ = false; setInput(storedInput_); entry_.set_editable(true); } void GMiniBuffer::idleTimeout() { setInput(Glib::locale_to_utf8(controller_.getCurrentState())); } void GMiniBuffer::editMode() { entry_.grab_focus(); } void GMiniBuffer::messageMode() { view_->focusWorkArea(); } void GMiniBuffer::setInput(Glib::ustring const & input) { entry_.set_text(input); entry_.set_position(-1); } } // namespace frontend } // namespace lyx