]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/xforms/XMiniBuffer.C
fix crash with "save as"
[lyx.git] / src / frontends / xforms / XMiniBuffer.C
index 790a16234e64bd534053ad9910b6ea7e1e0f6235..71c4380eb35d4c785c4d6b79ea4113d40dc3a9a9 100644 (file)
@@ -1,11 +1,13 @@
 // -*- C++ -*-
 /**
  * \file XMiniBuffer.C
- * Copyright 1995-2002 the LyX Team
- * Read the file COPYING
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
  *
  * \author Lars
  * \author Asger and Juergen
+ *
+ * Full author contact details are available in file CREDITS
  */
 
 #include <config.h>
 
 #include "frontends/xforms/DropDown.h"
 #include "frontends/xforms/XFormsView.h"
+#include "frontends/controllers/ControlCommandBuffer.h"
 #include "frontends/Timeout.h"
 
 #include "XMiniBuffer.h"
-#include "BufferView.h"
-#include "LyXAction.h"
 #include "gettext.h"
-#include "support/lyxalgo.h"
-#include "support/lstrings.h"
+#include "debug.h"
+#include "bufferview_funcs.h"
 
 #include <boost/bind.hpp>
 
 #include <vector>
-#include <cctype>
 
 #ifndef CXX_GLOBAL_CSTD
 using std::isprint;
 #endif
 
+using std::endl;
 using std::vector;
 
 
-namespace {
-
-struct prefix {
-       string p;
-       prefix(string const & s)
-               : p(s) {}
-       bool operator()(string const & s) const {
-               return prefixIs(s, p);
-       }
-};
-
-} // end of anon namespace
-
-
-XMiniBuffer::XMiniBuffer(LyXView * o, FL_Coord x, FL_Coord y,
-                        FL_Coord h, FL_Coord w)
-       : MiniBuffer(o)
+XMiniBuffer::XMiniBuffer(XFormsView * v, ControlCommandBuffer & control,
+       FL_Coord x, FL_Coord y, FL_Coord h, FL_Coord w)
+       : controller_(control), view_(v),
+       info_shown_(false)
 {
-       create_input_box(FL_NORMAL_INPUT, x, y, h, w);
+       input_obj_ = create_input_box(FL_NORMAL_INPUT, x, y, h, w);
+       info_timer_.reset(new Timeout(1500));
+       idle_timer_.reset(new Timeout(6000));
+       info_con = info_timer_->timeout.connect(boost::bind(&XMiniBuffer::info_timeout, this));
+       idle_con = idle_timer_->timeout.connect(boost::bind(&XMiniBuffer::idle_timeout, this));
+       idle_timer_->start();
        messageMode();
 }
 
 
-// thanks for nothing, xforms (recursive creation not allowed)
-void XMiniBuffer::dd_init()
-{
-       dropdown_ = new DropDown(owner_, the_buffer);
-       dropdown_->result.connect(boost::bind(&XMiniBuffer::set_complete_input, this, _1));
-       dropdown_->keypress.connect(boost::bind(&XMiniBuffer::append_char, this, _1));
-}
+// This is here so that scoped ptr will not require a complete type.
+XMiniBuffer::~XMiniBuffer()
+{}
 
 
-XMiniBuffer::~XMiniBuffer()
+// thanks for nothing, xforms (recursive creation not allowed)
+void XMiniBuffer::dd_init()
 {
-       delete dropdown_;
+       dropdown_.reset(new DropDown(the_buffer_));
+       result_con = dropdown_->result.connect(boost::bind(&XMiniBuffer::set_complete_input, this, _1));
+       keypress_con = dropdown_->keypress.connect(boost::bind(&XMiniBuffer::append_char, this, _1));
 }
 
 
 int XMiniBuffer::peek_event(FL_OBJECT * ob, int event,
                            int key, XEvent * /*xev*/)
 {
-#if 0
-       if (dropdown_->isVisible()) {
-               return dropdown_->peek(xev);
-       }
-#endif
-
        switch (event) {
+       case FL_FOCUS:
+               messageMode(false);
+               break;
        case FL_UNFOCUS:
                messageMode();
                break;
        case FL_KEYBOARD:
        {
                string input;
-               if (information_displayed_) {
-                       information_timer_->stop();
-                       input = stored_input;
-                       restore_input();
-               } else {
-                       char const * tmp = fl_get_input(ob);
-                       input = tmp ? tmp : "";
+               if (info_shown_) {
+                       info_timer_->stop();
+                       info_timeout();
                }
 
+               char const * tmp = fl_get_input(ob);
+               input = tmp ? tmp : "";
 
                switch (key) {
                case XK_Down:
 #ifdef XK_KP_Down
                case XK_KP_Down:
 #endif
-                       if (hist_iter != history_->end()) {
-                               ++hist_iter;
-                       }
-                       if (hist_iter == history_->end()) {
-                               // no further history
-                               show_information(_("[End of history]"), input);
+               {
+                       string const h(controller_.historyDown());
+                       if (h.empty()) {
+                               show_info(_("[End of history]"), input, false);
                        } else {
-                               set_input((*hist_iter));
+                               set_input(h);
                        }
                        return 1;
+               }
+
                case XK_Up:
 #ifdef XK_KP_Up
                case XK_KP_Up:
 #endif
-                       if (hist_iter == history_->begin()) {
-                               // no further history
-                               show_information(_("[Beginning of history]"),
-                                                input);
+               {
+                       string const h(controller_.historyUp());
+                       if (h.empty()) {
+                               show_info(_("[Beginning of history]"), input, false);
                        } else {
-                               --hist_iter;
-                               set_input((*hist_iter));
+                               set_input(h);
                        }
                        return 1;
+               }
+
                case 9:
                case XK_Tab:
                {
-                       // Completion handling.
+                       string new_input;
+                       vector<string> comp = controller_.completions(input, new_input);
 
-                       vector<string> comp;
-                       lyx::copy_if(completion_.begin(),
-                                    completion_.end(),
-                                    back_inserter(comp), prefix(input));
+                       if (comp.empty() && new_input == input) {
+                               show_info(_("[no match]"), input);
+                               break;
+                       }
 
                        if (comp.empty()) {
-                               // No matches
-                               string const tmp = input + _(" [no match]");
-                               show_information(tmp, input);
-                       } else if (comp.size() == 1) {
-                               // Perfect match
-                               string const tmp =
-                                       comp[0] + _(" [sole completion]");
-                               show_information(tmp, comp[0] + " ");
-                       } else {
-                               // More that one match
-                               // Find maximal avaliable prefix
-                               string const tmp = comp[0];
-                               string test(input);
-                               if (tmp.length() > test.length())
-                                       test += tmp[test.length()];
-                               while (test.length() < tmp.length()) {
-                                       vector<string> vtmp;
-                                       lyx::copy_if(comp.begin(),
-                                                    comp.end(),
-                                                    back_inserter(vtmp),
-                                                    prefix(test));
-                                       if (vtmp.size() != comp.size()) {
-                                               test.erase(test.length() - 1);
-                                               break;
-                                       }
-                                       test += tmp[test.length()];
-                               }
-                               set_input(test);
-
-                               int x,y,w,h;
-                               fl_get_wingeometry(fl_get_real_object_window(the_buffer),
-                                                  &x, &y, &w, &h);
-
-                               // asynchronous completion
-                               int const air = the_buffer->x;
-                               x += air;
-                               y += h - (the_buffer->h + air);
-                               w = the_buffer->w;
-                               dropdown_->select(comp, x, y, w);
+                               set_input(new_input);
+                               show_info(("[only completion]"), new_input + " ");
+                               break;
                        }
+
+                       set_input(new_input);
+
+                       int x,y,w,h;
+                       fl_get_wingeometry(fl_get_real_object_window(the_buffer_),
+                                          &x, &y, &w, &h);
+
+                       // asynchronous completion
+                       int const air = the_buffer_->x;
+                       x += air;
+                       y += h - (the_buffer_->h + air);
+                       w = the_buffer_->w;
+                       dropdown_->select(comp, x, y, w);
                        return 1;
                }
                case 27:
                case XK_Escape:
-                       // Abort
-#if 0
-                       owner_->view()->focus(true);
-#endif
-                       message_timeout();
                        messageMode();
-                       //escape.emit();
                        return 1;
                case 13:
                case XK_Return:
@@ -198,33 +158,9 @@ int XMiniBuffer::peek_event(FL_OBJECT * ob, int event,
                case XK_KP_Enter:
 #endif
                {
-#if 0
-                       // This will go in again in a little while
-                       // we need to be able to declare what types
-                       // of argumetns LFUN's should have first. (Lgb)
-                       // First check for match
-                       vector<string>::const_iterator cit =
-                               find(completion_.begin(),
-                                    completion_.end(),
-                                    input);
-                       if (cit == completion_.end()) {
-                               // no such func/item
-                               string const tmp = input + _(" [no match]");
-                               show_information(tmp, input);
-                       } else {
-#endif
-                               // Return the inputted string
-                               messageMode();
-#if 0
-                               owner_->view()->focus(true);
-#endif
-                               if (!input.empty()) {
-                                       history_->push_back(input);
-                               }
-                               inputReady(input);
-# if 0
-                       }
-#endif
+                       messageMode();
+                       redraw();
+                       controller_.dispatch(input);
                        return 1;
                }
                default:
@@ -232,7 +168,6 @@ int XMiniBuffer::peek_event(FL_OBJECT * ob, int event,
                }
        }
        default:
-               //lyxerr << "Unhandled minibuffer event!" << endl;
                break;
        }
 
@@ -251,7 +186,6 @@ extern "C" {
                return mini->peek_event(ob, event, key,
                                        static_cast<XEvent *>(xev));
        }
-
 }
 
 
@@ -260,7 +194,7 @@ FL_OBJECT * XMiniBuffer::create_input_box(int type, FL_Coord x, FL_Coord y,
 {
        FL_OBJECT * obj;
 
-       the_buffer = obj = fl_add_input(type, x, y, w, h, text.c_str());
+       the_buffer_ = obj = fl_add_input(type, x, y, w, h, "");
        fl_set_object_boxtype(obj, FL_DOWN_BOX);
        fl_set_object_resize(obj, FL_RESIZE_ALL);
        fl_set_object_gravity(obj, SouthWestGravity, SouthEastGravity);
@@ -272,37 +206,70 @@ FL_OBJECT * XMiniBuffer::create_input_box(int type, FL_Coord x, FL_Coord y,
        obj->u_vdata = this;
        obj->wantkey = FL_KEY_TAB;
 
-       set_input(text);
-
        return obj;
 }
 
 
-bool XMiniBuffer::isEditingMode() const
+void XMiniBuffer::freeze()
+{
+       // we must prevent peek_event, or we get an unfocus() when the
+       // containing form gets destroyed
+       fl_set_object_prehandler(input_obj_, 0);
+}
+
+
+void XMiniBuffer::show_info(string const & info, string const & input, bool append)
+{
+       stored_input_ = input;
+       info_shown_ = true;
+       if (append)
+               set_input(input + " " + info);
+       else
+               set_input(info);
+       info_timer_->start();
+}
+
+
+void XMiniBuffer::idle_timeout()
 {
-       return the_buffer->focus;
+       set_input(currentState(view_->view().get()));
 }
 
 
-void XMiniBuffer::editingMode()
+void XMiniBuffer::info_timeout()
 {
-       fl_activate_object(the_buffer);
-       fl_set_focus_object(static_cast<XFormsView *>(owner_)->getForm(),
-                           the_buffer);
-       redraw();
+       info_shown_ = false;
+       set_input(stored_input_);
 }
 
 
-void XMiniBuffer::messageMode()
+bool XMiniBuffer::isEditingMode() const
+{
+       return the_buffer_->focus;
+}
+
+
+void XMiniBuffer::messageMode(bool on)
 {
-       fl_deactivate_object(the_buffer);
-       redraw();
+       set_input("");
+       if (!on) {
+               fl_activate_object(the_buffer_);
+               fl_set_focus_object(view_->getForm(), the_buffer_);
+               redraw();
+               idle_timer_->stop();
+       } else {
+               if (isEditingMode()) {
+                       // focus back to the workarea
+                       fl_set_focus_object(view_->getForm(), 0);
+                       idle_timer_->start();
+               }
+       }
 }
 
 
 void XMiniBuffer::redraw()
 {
-       fl_redraw_object(the_buffer);
+       fl_redraw_object(the_buffer_);
        XFlush(fl_display);
 }
 
@@ -312,16 +279,33 @@ void XMiniBuffer::append_char(char c)
        if (!c || !isprint(c))
                return;
 
-       char const * tmp = fl_get_input(the_buffer);
+       char const * tmp = fl_get_input(the_buffer_);
        string str = tmp ? tmp : "";
 
        str += c;
 
-       fl_set_input(the_buffer, str.c_str());
+       fl_set_input(the_buffer_, str.c_str());
+}
+
+
+void XMiniBuffer::set_complete_input(string const & str)
+{
+       if (!str.empty()) {
+               // add a space so the user can type
+               // an argument immediately
+               set_input(str + " ");
+       }
+}
+
+
+void XMiniBuffer::message(string const & str)
+{
+       if (!isEditingMode())
+               set_input(str);
 }
 
 
 void XMiniBuffer::set_input(string const & str)
 {
-       fl_set_input(the_buffer, str.c_str());
+       fl_set_input(the_buffer_, str.c_str());
 }