#include "qt_helpers.h"
-#include "support/filetools.h"
-#include "support/convert.h"
-#include "support/lstrings.h"
-#include "support/os.h"
-
#include "buffer_funcs.h"
#include "Buffer.h"
#include "BufferList.h"
#include "gettext.h"
#include "Intl.h"
#include "Layout.h"
+#include "Lexer.h"
#include "LyXFunc.h"
#include "LyX.h"
#include "LyXRC.h"
+#include "LyXVC.h"
#include "MenuBackend.h"
#include "Paragraph.h"
#include "TextClass.h"
#include "ToolbarBackend.h"
#include "version.h"
+#include "support/convert.h"
+#include "support/FileName.h"
#include "support/lstrings.h"
-#include "support/filetools.h" // OnlyFilename()
+#include "support/os.h"
#include "support/Timeout.h"
#include <QAction>
#include <QSplitter>
#include <QStackedWidget>
#include <QStatusBar>
+#include <QTimer>
#include <QToolBar>
#include <QUrl>
using support::bformat;
using support::FileName;
-using support::makeDisplayPath;
-using support::onlyFilename;
+using support::trim;
namespace {
struct GuiView::GuiViewPrivate
{
GuiViewPrivate()
- : current_work_area_(0), posx_offset(0), posy_offset(0)
- {}
+ : current_work_area_(0), layout_(0),
+ autosave_timeout_(new Timeout(5000)), quitting_by_menu_(false),
+ in_show_(false)
+ {
+ // hardcode here the platform specific icon size
+ smallIconSize = 14; // scaling problems
+ normalIconSize = 20; // ok, default
+ bigIconSize = 26; // better for some math icons
+
+ splitter_ = new QSplitter;
+ initBackground();
+ stack_widget_ = new QStackedWidget;
+ stack_widget_->addWidget(bg_widget_);
+ stack_widget_->addWidget(splitter_);
+ setBackground();
+ }
~GuiViewPrivate()
{
delete stack_widget_;
delete menubar_;
delete toolbars_;
+ delete autosave_timeout_;
}
- unsigned int smallIconSize;
- unsigned int normalIconSize;
- unsigned int bigIconSize;
- // static needed by "New Window"
- static unsigned int lastIconSize;
-
QMenu * toolBarPopup(GuiView * parent)
{
// FIXME: translation
string cur_title;
GuiWorkArea * current_work_area_;
- int posx_offset;
- int posy_offset;
-
QSplitter * splitter_;
QStackedWidget * stack_widget_;
BackgroundWidget * bg_widget_;
GuiMenubar * menubar_;
/// view's toolbars
GuiToolbars * toolbars_;
- ///
- docstring current_layout;
+ /// The main layout box.
+ /**
+ * \warning Don't Delete! The layout box is actually owned by
+ * whichever toolbar contains it. All the GuiView class needs is a
+ * means of accessing it.
+ *
+ * FIXME: replace that with a proper model so that we are not limited
+ * to only one dialog.
+ */
+ GuiLayoutBox * layout_;
///
std::map<std::string, Inset *> open_insets_;
///
std::map<std::string, DialogPtr> dialogs_;
+
+ unsigned int smallIconSize;
+ unsigned int normalIconSize;
+ unsigned int bigIconSize;
+ ///
+ QTimer statusbar_timer_;
+ /// are we quitting by the menu?
+ bool quitting_by_menu_;
+ /// auto-saving of buffers
+ Timeout * const autosave_timeout_;
///
- /// flag against a race condition due to multiclicks
+ /// flag against a race condition due to multiclicks in Qt frontend,
/// see bug #1119
bool in_show_;
};
-unsigned int GuiView::GuiViewPrivate::lastIconSize = 0;
-
-
GuiView::GuiView(int id)
- : QMainWindow(), LyXView(id),
- d(*new GuiViewPrivate),
- quitting_by_menu_(false),
- autosave_timeout_(new Timeout(5000)),
- in_show_(false)
+ : d(*new GuiViewPrivate), id_(id)
{
+ // GuiToolbars *must* be initialised before GuiMenubar.
+ d.toolbars_ = new GuiToolbars(*this);
+ d.menubar_ = new GuiMenubar(this, menubackend);
+
+ setCentralWidget(d.stack_widget_);
+
// Start autosave timer
if (lyxrc.autosave) {
- autosave_timeout_->timeout.connect(boost::bind(&GuiView::autoSave, this));
- autosave_timeout_->setTimeout(lyxrc.autosave * 1000);
- autosave_timeout_->start();
+ d.autosave_timeout_->timeout.connect(boost::bind(&GuiView::autoSave, this));
+ d.autosave_timeout_->setTimeout(lyxrc.autosave * 1000);
+ d.autosave_timeout_->start();
}
+ QObject::connect(&d.statusbar_timer_, SIGNAL(timeout()),
+ this, SLOT(clearMessage()));
// Qt bug? signal lastWindowClosed does not work
setAttribute(Qt::WA_QuitOnClose, false);
setAttribute(Qt::WA_DeleteOnClose, true);
-
- // hardcode here the platform specific icon size
- d.smallIconSize = 14; // scaling problems
- d.normalIconSize = 20; // ok, default
- d.bigIconSize = 26; // better for some math icons
-
#ifndef Q_WS_MACX
// assign an icon to main form. We do not do it under Qt/Mac,
// since the icon is provided in the application bundle.
setWindowIcon(QPixmap(":/images/lyx.png"));
#endif
- d.splitter_ = new QSplitter;
-
- d.initBackground();
- LYXERR(Debug::GUI, "stack widget!");
- d.stack_widget_ = new QStackedWidget;
- d.stack_widget_->addWidget(d.bg_widget_);
- d.stack_widget_->addWidget(d.splitter_);
- setCentralWidget(d.stack_widget_);
-
// For Drag&Drop.
setAcceptDrops(true);
- setMinimumSize(300, 200);
- // GuiToolbars *must* be initialised before GuiMenubar.
- d.toolbars_ = new GuiToolbars(*this);
- d.toolbars_->init();
- d.menubar_ = new GuiMenubar(this, menubackend);
-
statusBar()->setSizeGripEnabled(true);
- QObject::connect(&statusbar_timer_, SIGNAL(timeout()),
- this, SLOT(clearMessage()));
-
- d.setBackground();
+ // Forbid too small unresizable window because it can happen
+ // with some window manager under X11.
+ setMinimumSize(300, 200);
if (!lyxrc.allow_geometry_session)
+ // No session handling, default to a sane size.
setGeometry(50, 50, 690, 510);
// Now take care of session management.
QSettings settings;
- QString const key = "view-" + QString::number(id);
+ QString const key = "view-" + QString::number(id_);
#ifdef Q_WS_X11
QPoint pos = settings.value(key + "/pos", QPoint(50, 50)).toPoint();
QSize size = settings.value(key + "/size", QSize(690, 510)).toSize();
GuiView::~GuiView()
{
- delete autosave_timeout_;
delete &d;
}
void GuiView::close()
{
- quitting_by_menu_ = true;
+ d.quitting_by_menu_ = true;
d.current_work_area_ = 0;
for (int i = 0; i != d.splitter_->count(); ++i) {
TabWorkArea * twa = d.tabWorkArea(i);
twa->closeAll();
}
QMainWindow::close();
- quitting_by_menu_ = false;
+ d.quitting_by_menu_ = false;
}
{
// we may have been called through the close window button
// which bypasses the LFUN machinery.
- if (!quitting_by_menu_ && guiApp->viewCount() == 1) {
+ if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
if (!theBufferList().quitWriteAll()) {
close_event->ignore();
return;
// Make sure that no LFUN use this close to be closed View.
theLyXFunc().setLyXView(0);
// Make sure the timer time out will not trigger a statusbar update.
- statusbar_timer_.stop();
+ d.statusbar_timer_.stop();
if (lyxrc.allow_geometry_session) {
QSettings settings;
- QString const key = "view-" + QString::number(id());
+ QString const key = "view-" + QString::number(id_);
#ifdef Q_WS_X11
settings.setValue(key + "/pos", pos());
settings.setValue(key + "/size", size());
d.toolbars_->saveToolbarInfo();
}
- guiApp->unregisterView(id());
+ guiApp->unregisterView(id_);
if (guiApp->viewCount() > 0) {
// Just close the window and do nothing else if this is not the
// last window.
void GuiView::message(docstring const & str)
{
statusBar()->showMessage(toqstr(str));
- statusbar_timer_.stop();
- statusbar_timer_.start(statusbar_timer_value);
+ d.statusbar_timer_.stop();
+ d.statusbar_timer_.start(statusbar_timer_value);
}
return;
theLyXFunc().setLyXView(this);
statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
- statusbar_timer_.stop();
+ d.statusbar_timer_.stop();
}
// require bv_->text.
updateBufferDependent(true);
updateToolbars();
- updateLayoutChoice(false);
+ updateLayoutList();
updateStatusBar();
}
void GuiView::updateStatusBar()
{
// let the user see the explicit message
- if (statusbar_timer_.isActive())
+ if (d.statusbar_timer_.isActive())
return;
statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
GuiWorkArea * GuiView::addWorkArea(Buffer & buffer)
{
- GuiWorkArea * wa = new GuiWorkArea(buffer, *this);
- wa->setUpdatesEnabled(false);
// Automatically create a TabWorkArea if there are none yet.
if (!d.splitter_->count())
addTabWorkArea();
TabWorkArea * tab_widget = d.currentTabWorkArea();
- tab_widget->addTab(wa, wa->windowTitle());
- QObject::connect(wa, SIGNAL(titleChanged(GuiWorkArea *)),
- tab_widget, SLOT(updateTabText(GuiWorkArea *)));
-
- wa->bufferView().updateMetrics();
-
- // Hide tabbar if there's only one tab.
- tab_widget->showBar(tab_widget->count() > 1);
- return wa;
+ return tab_widget->addWorkArea(buffer, *this);
}
}
-void GuiView::updateLayoutChoice(bool force)
+void GuiView::setLayoutDialog(GuiLayoutBox * layout)
{
- // Don't show any layouts without a buffer
- if (!buffer()) {
- d.toolbars_->clearLayoutList();
- return;
- }
-
- // Update the layout display
- if (d.toolbars_->updateLayoutList(buffer()->params().getTextClassPtr(), force)) {
- d.current_layout = buffer()->params().getTextClass().defaultLayoutName();
- }
-
- docstring const & layout = d.current_work_area_->bufferView().cursor().
- innerParagraph().layout()->name();
-
- if (layout != d.current_layout) {
- d.toolbars_->setLayout(layout);
- d.current_layout = layout;
- }
+ d.layout_ = layout;
}
-bool GuiView::isToolbarVisible(std::string const & id)
+void GuiView::updateLayoutList()
{
- return d.toolbars_->visible(id);
+ if (d.layout_)
+ d.layout_->updateContents(false);
}
+
void GuiView::updateToolbars()
{
if (d.current_work_area_) {
}
-Buffer * GuiView::loadLyXFile(FileName const & filename, bool tolastfiles)
-{
- setBusy(true);
-
- Buffer * newBuffer = checkAndLoadLyXFile(filename);
-
- if (!newBuffer) {
- message(_("Document not loaded."));
- updateStatusBar();
- setBusy(false);
- return 0;
- }
-
- GuiWorkArea * wa = workArea(*newBuffer);
- if (wa == 0)
- wa = addWorkArea(*newBuffer);
-
- // scroll to the position when the file was last closed
- if (lyxrc.use_lastfilepos) {
- LastFilePosSection::FilePos filepos =
- LyX::ref().session().lastFilePos().load(filename);
- // if successfully move to pit (returned par_id is not zero),
- // update metrics and reset font
- wa->bufferView().moveToPosition(filepos.pit, filepos.pos, 0, 0);
- }
-
- if (tolastfiles)
- LyX::ref().session().lastFiles().add(filename);
-
- setBusy(false);
- return newBuffer;
-}
-
-
void GuiView::connectBuffer(Buffer & buf)
{
buf.setGuiDelegate(this);
void GuiView::resetAutosaveTimers()
{
if (lyxrc.autosave)
- autosave_timeout_->restart();
+ d.autosave_timeout_->restart();
+}
+
+
+FuncStatus GuiView::getStatus(FuncRequest const & cmd)
+{
+ FuncStatus flag;
+ bool enable = true;
+ Buffer * buf = buffer();
+
+ /* In LyX/Mac, when a dialog is open, the menus of the
+ application can still be accessed without giving focus to
+ the main window. In this case, we want to disable the menu
+ entries that are buffer-related.
+
+ Note that this code is not perfect, as bug 1941 attests:
+ http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
+ */
+ if (cmd.origin == FuncRequest::MENU && !hasFocus())
+ buf = 0;
+
+ switch(cmd.action) {
+ case LFUN_TOOLBAR_TOGGLE:
+ flag.setOnOff(d.toolbars_->visible(cmd.getArg(0)));
+ break;
+
+ case LFUN_DIALOG_TOGGLE:
+ flag.setOnOff(isDialogVisible(cmd.getArg(0)));
+ // fall through to set "enable"
+ case LFUN_DIALOG_SHOW: {
+ string const name = cmd.getArg(0);
+ if (!buf)
+ enable = name == "aboutlyx"
+ || name == "file" //FIXME: should be removed.
+ || name == "prefs"
+ || name == "texinfo";
+ else if (name == "print")
+ enable = buf->isExportable("dvi")
+ && lyxrc.print_command != "none";
+ else if (name == "character") {
+ if (!view())
+ enable = false;
+ else {
+ InsetCode ic = view()->cursor().inset().lyxCode();
+ enable = ic != ERT_CODE && ic != LISTINGS_CODE;
+ }
+ }
+ else if (name == "latexlog")
+ enable = FileName(buf->logName()).isFileReadable();
+ else if (name == "spellchecker")
+#if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
+ enable = !buf->isReadonly();
+#else
+ enable = false;
+#endif
+ else if (name == "vclog")
+ enable = buf->lyxvc().inUse();
+ break;
+ }
+
+ case LFUN_DIALOG_UPDATE: {
+ string const name = cmd.getArg(0);
+ if (!buf)
+ enable = name == "prefs";
+ break;
+ }
+
+ default:
+ if (!view()) {
+ enable = false;
+ break;
+ }
+ }
+
+ if (!enable)
+ flag.enabled(false);
+
+ return flag;
}
void GuiView::dispatch(FuncRequest const & cmd)
{
+ Buffer * buf = buffer();
switch(cmd.action) {
case LFUN_BUFFER_SWITCH:
setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
break;
}
case LFUN_DROP_LAYOUTS_CHOICE:
- d.toolbars_->openLayoutList();
+ if (d.layout_)
+ d.layout_->showPopup();
break;
case LFUN_MENU_OPEN:
break;
}
+ case LFUN_DIALOG_UPDATE: {
+ string const name = to_utf8(cmd.argument());
+ // Can only update a dialog connected to an existing inset
+ Inset * inset = getOpenInset(name);
+ if (inset) {
+ FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
+ inset->dispatch(view()->cursor(), fr);
+ } else if (name == "paragraph") {
+ lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
+ } else if (name == "prefs") {
+ updateDialog(name, string());
+ }
+ break;
+ }
+
+ case LFUN_DIALOG_TOGGLE: {
+ if (isDialogVisible(cmd.getArg(0)))
+ dispatch(FuncRequest(LFUN_DIALOG_HIDE, cmd.argument()));
+ else
+ dispatch(FuncRequest(LFUN_DIALOG_SHOW, cmd.argument()));
+ break;
+ }
+
+ case LFUN_DIALOG_DISCONNECT_INSET:
+ disconnectDialog(to_utf8(cmd.argument()));
+ break;
+
+ case LFUN_DIALOG_HIDE: {
+ if (quitting)
+ break;
+ guiApp->hideDialogs(to_utf8(cmd.argument()), 0);
+ break;
+ }
+
+ case LFUN_DIALOG_SHOW: {
+ string const name = cmd.getArg(0);
+ string data = trim(to_utf8(cmd.argument()).substr(name.size()));
+
+ if (name == "character") {
+ data = freefont2string();
+ if (!data.empty())
+ showDialog("character", data);
+ } else if (name == "latexlog") {
+ Buffer::LogType type;
+ string const logfile = buf->logName(&type);
+ switch (type) {
+ case Buffer::latexlog:
+ data = "latex ";
+ break;
+ case Buffer::buildlog:
+ data = "literate ";
+ break;
+ }
+ data += Lexer::quoteString(logfile);
+ showDialog("log", data);
+ } else if (name == "vclog") {
+ string const data = "vc " +
+ Lexer::quoteString(buf->lyxvc().getLogFile());
+ showDialog("log", data);
+ } else
+ showDialog(name, data);
+ break;
+ }
+
default:
theLyXFunc().setLyXView(this);
lyx::dispatch(cmd);
*/
if (d.current_work_area_)
d.current_work_area_->startBlinkingCursor();
+
+ // Take this occasion to update the toobars and layout list.
+ updateLayoutList();
+ updateToolbars();
+}
+
+namespace {
+
+// This list should be kept in sync with the list of insets in
+// src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
+// dialog should have the same name as the inset.
+
+char const * const dialognames[] = {
+"aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
+"citation", "document", "embedding", "errorlist", "ert", "external", "file",
+"findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
+"mathdelimiter", "mathmatrix", "note", "paragraph",
+"prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
+
+#ifdef HAVE_LIBAIKSAURUS
+"thesaurus",
+#endif
+
+"texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
+
+char const * const * const end_dialognames =
+ dialognames + (sizeof(dialognames) / sizeof(char *));
+
+class cmpCStr {
+public:
+ cmpCStr(char const * name) : name_(name) {}
+ bool operator()(char const * other) {
+ return strcmp(other, name_) == 0;
+ }
+private:
+ char const * name_;
+};
+
+
+bool isValidName(string const & name)
+{
+ return std::find_if(dialognames, end_dialognames,
+ cmpCStr(name.c_str())) != end_dialognames;
+}
+
+} // namespace anon
+
+
+void GuiView::resetDialogs()
+{
+ // Make sure that no LFUN uses any LyXView.
+ theLyXFunc().setLyXView(0);
+ d.toolbars_->init();
+ d.menubar_->init();
+ if (d.layout_)
+ d.layout_->updateContents(true);
}
void GuiView::showDialog(string const & name, string const & data,
Inset * inset)
{
- if (in_show_)
+ if (d.in_show_)
return;
- in_show_ = true;
+ d.in_show_ = true;
Dialog * dialog = find_or_build(name);
if (dialog) {
dialog->showData(data);
if (inset)
d.open_insets_[name] = inset;
}
- in_show_ = false;
+ d.in_show_ = false;
}
}
-void GuiView::redrawDialog() const
-{
- std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
- std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
-
- for(; it != end; ++it)
- it->second->redraw();
-}
-
-
void GuiView::checkStatus()
{
std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
}
-namespace {
-
-// This list should be kept in sync with the list of insets in
-// src/insets/Inset.cpp. I.e., if a dialog goes with an inset, the
-// dialog should have the same name as the inset.
-
-char const * const dialognames[] = {
-"aboutlyx", "bibitem", "bibtex", "box", "branch", "changes", "character",
-"citation", "document", "embedding", "errorlist", "ert", "external", "file",
-"findreplace", "float", "graphics", "include", "index", "nomenclature", "label", "log",
-"mathdelimiter", "mathmatrix", "note", "paragraph",
-"prefs", "print", "ref", "sendto", "spellchecker","tabular", "tabularcreate",
-
-#ifdef HAVE_LIBAIKSAURUS
-"thesaurus",
-#endif
-
-"texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" };
-
-char const * const * const end_dialognames =
- dialognames + (sizeof(dialognames) / sizeof(char *));
-
-class cmpCStr {
-public:
- cmpCStr(char const * name) : name_(name) {}
- bool operator()(char const * other) {
- return strcmp(other, name_) == 0;
- }
-private:
- char const * name_;
-};
-
-
-} // namespace anon
// will be replaced by a proper factory...
Dialog * createGuiAbout(LyXView & lv);
Dialog * createGuiWrap(LyXView & lv);
-bool GuiView::isValidName(string const & name) const
-{
- return std::find_if(dialognames, end_dialognames,
- cmpCStr(name.c_str())) != end_dialognames;
-}
-
-
Dialog * GuiView::build(string const & name)
{
BOOST_ASSERT(isValidName(name));