#include <config.h>
-#include "GuiView.h"
-#include "Dialog.h"
-
-#include <boost/assert.hpp>
-
-using std::string;
-
#include "GuiView.h"
+#include "Dialog.h"
+#include "FileDialog.h"
#include "GuiApplication.h"
#include "GuiWorkArea.h"
#include "GuiKeySymbol.h"
-#include "GuiMenubar.h"
#include "GuiToolbar.h"
#include "GuiToolbars.h"
+#include "Menus.h"
#include "qt_helpers.h"
-#include "support/filetools.h"
-#include "support/convert.h"
-#include "support/lstrings.h"
-#include "support/os.h"
+#include "frontends/alert.h"
#include "buffer_funcs.h"
#include "Buffer.h"
#include "BufferList.h"
#include "BufferParams.h"
#include "BufferView.h"
+#include "Converter.h"
#include "Cursor.h"
-#include "debug.h"
#include "ErrorList.h"
+#include "Format.h"
#include "FuncRequest.h"
-#include "gettext.h"
+#include "support/gettext.h"
#include "Intl.h"
#include "Layout.h"
+#include "Lexer.h"
#include "LyXFunc.h"
#include "LyX.h"
#include "LyXRC.h"
-#include "MenuBackend.h"
+#include "LyXVC.h"
#include "Paragraph.h"
#include "TextClass.h"
#include "Text.h"
#include "ToolbarBackend.h"
#include "version.h"
+#include "support/debug.h"
+#include "support/FileFilterList.h"
+#include "support/FileName.h"
+#include "support/filetools.h"
+#include "support/ForkedCalls.h"
#include "support/lstrings.h"
-#include "support/filetools.h" // OnlyFilename()
+#include "support/os.h"
+#include "support/Package.h"
#include "support/Timeout.h"
#include <QAction>
#include <QApplication>
#include <QCloseEvent>
+#include <QDebug>
#include <QDesktopWidget>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QList>
#include <QMenu>
+#include <QMenuBar>
#include <QPainter>
#include <QPixmap>
#include <QPoint>
#include <QSplitter>
#include <QStackedWidget>
#include <QStatusBar>
+#include <QTimer>
#include <QToolBar>
#include <QUrl>
+#include <QScrollBar>
+#include <boost/assert.hpp>
#include <boost/bind.hpp>
-#include <boost/current_function.hpp>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# include <unistd.h>
#endif
-using std::endl;
-using std::string;
-using std::vector;
+using namespace std;
+using namespace lyx::support;
namespace lyx {
-
-extern bool quitting;
-
namespace frontend {
-using support::bformat;
-using support::FileName;
-using support::makeDisplayPath;
-using support::onlyFilename;
-
namespace {
-int const statusbar_timer_value = 3000;
-
class BackgroundWidget : public QWidget
{
public:
- BackgroundWidget(QString const & file, QString const & text)
+ BackgroundWidget()
{
- splash_ = new QPixmap(file);
- if (!splash_) {
- lyxerr << "could not load splash screen: '" << fromqstr(file) << "'" << endl;
- return;
- }
+ LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
+ /// The text to be written on top of the pixmap
+ QString const text = lyx_version ? lyx_version : qt_("unknown version");
+ splash_ = QPixmap(":/images/banner.png");
- QPainter pain(splash_);
+ QPainter pain(&splash_);
pain.setPen(QColor(255, 255, 0));
QFont font;
// The font used to display the version info
font.setStyleHint(QFont::SansSerif);
font.setWeight(QFont::Bold);
- font.setPointSize(convert<int>(lyxrc.font_sizes[FONT_SIZE_LARGE]));
+ font.setPointSize(int(toqstr(lyxrc.font_sizes[FONT_SIZE_LARGE]).toDouble()));
pain.setFont(font);
pain.drawText(260, 270, text);
}
void paintEvent(QPaintEvent *)
{
- if (!splash_)
- return;
-
- int x = (width() - splash_->width()) / 2;
- int y = (height() - splash_->height()) / 2;
+ int x = (width() - splash_.width()) / 2;
+ int y = (height() - splash_.height()) / 2;
QPainter pain(this);
- pain.drawPixmap(x, y, *splash_);
+ pain.drawPixmap(x, y, splash_);
}
private:
- QPixmap * splash_;
+ QPixmap splash_;
};
} // namespace anon
struct GuiView::GuiViewPrivate
{
GuiViewPrivate()
- : current_work_area_(0), posx_offset(0), posy_offset(0)
- {}
+ : current_work_area_(0), layout_(0),
+ quitting_by_menu_(false), autosave_timeout_(5000), 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;
+ bg_widget_ = new BackgroundWidget;
+ stack_widget_ = new QStackedWidget;
+ stack_widget_->addWidget(bg_widget_);
+ stack_widget_->addWidget(splitter_);
+ setBackground();
+ }
~GuiViewPrivate()
{
delete splitter_;
delete bg_widget_;
delete stack_widget_;
- delete menubar_;
delete toolbars_;
}
- unsigned int smallIconSize;
- unsigned int normalIconSize;
- unsigned int bigIconSize;
- // static needed by "New Window"
- static unsigned int lastIconSize;
-
QMenu * toolBarPopup(GuiView * parent)
{
// FIXME: translation
return menu;
}
- void initBackground()
- {
- LYXERR(Debug::GUI, "show banner: " << lyxrc.show_banner);
- /// The text to be written on top of the pixmap
- QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version");
- bg_widget_ = new BackgroundWidget(":/images/banner.png", text);
- }
-
void setBackground()
{
stack_widget_->setCurrentWidget(bg_widget_);
// The first TabWorkArea is always the first one, if any.
return tabWorkArea(0);
- TabWorkArea * tab_widget = 0;
for (int i = 0; i != splitter_->count(); ++i) {
- QWidget * w = splitter_->widget(i);
- if (!w->hasFocus())
- continue;
- tab_widget = dynamic_cast<TabWorkArea *>(w);
- if (tab_widget)
- break;
+ TabWorkArea * twa = tabWorkArea(i);
+ if (current_work_area_ == twa->currentWorkArea())
+ return twa;
}
- return tab_widget;
+ // None has the focus so we just take the first one.
+ return tabWorkArea(0);
}
public:
- ///
- string cur_title;
-
GuiWorkArea * current_work_area_;
- int posx_offset;
- int posy_offset;
-
QSplitter * splitter_;
QStackedWidget * stack_widget_;
BackgroundWidget * bg_widget_;
- /// view's menubar
- 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_;
+ map<string, Inset *> open_insets_;
///
- std::map<std::string, DialogPtr> dialogs_;
+ map<string, DialogPtr> dialogs_;
+
+ unsigned int smallIconSize;
+ unsigned int normalIconSize;
+ unsigned int bigIconSize;
///
- /// flag against a race condition due to multiclicks
- /// see bug #1119
+ QTimer statusbar_timer_;
+ /// are we quitting by the menu?
+ bool quitting_by_menu_;
+ /// auto-saving of buffers
+ Timeout autosave_timeout_;
+ /// flag against a race condition due to multiclicks, 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 the menu bar.
+ d.toolbars_ = new GuiToolbars(*this);
+
+ // Fill up the menu bar.
+ guiApp->menus().fillMenuBar(this);
+
+ 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();
}
+ 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;
}
}
-QMenu* GuiView::createPopupMenu()
+QMenu * GuiView::createPopupMenu()
{
return d.toolBarPopup(this);
}
{
// we may have been called through the close window button
// which bypasses the LFUN machinery.
- if (!quitting_by_menu_ && guiApp->viewCount() == 1) {
- if (!theBufferList().quitWriteAll()) {
+ if (!d.quitting_by_menu_ && guiApp->viewCount() == 1) {
+ if (!quitWriteAll()) {
close_event->ignore();
return;
}
// Make sure that no LFUN use this close to be closed View.
theLyXFunc().setLyXView(0);
+
+ // Save toolbars configuration
+ if (isFullScreen()) {
+ d.toolbars_->toggleFullScreen(!isFullScreen());
+ updateToolbars();
+ }
+
// Make sure the timer time out will not trigger a statusbar update.
- statusbar_timer_.stop();
+ d.statusbar_timer_.stop();
- if (lyxrc.allow_geometry_session) {
+ // Saving fullscreen requires additional tweaks in the toolbar code.
+ // It wouldn't also work under linux natively.
+ if (lyxrc.allow_geometry_session && !isFullScreen()) {
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());
#endif
settings.setValue(key + "/icon_size", iconSize());
d.toolbars_->saveToolbarInfo();
+ // Now take care of all other dialogs:
+ map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
+ for (; it!= d.dialogs_.end(); ++it)
+ it->second->saveSession();
}
- 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.
if (files.isEmpty())
return;
- LYXERR(Debug::GUI, BOOST_CURRENT_FUNCTION << " got URLs!");
+ LYXERR(Debug::GUI, "GuiView::dropEvent: got URLs!");
for (int i = 0; i != files.size(); ++i) {
- string const file = support::os::internal_path(fromqstr(
+ string const file = os::internal_path(fromqstr(
files.at(i).toLocalFile()));
if (!file.empty())
- dispatch(FuncRequest(LFUN_FILE_OPEN, file));
+ lyx::dispatch(FuncRequest(LFUN_FILE_OPEN, file));
}
}
void GuiView::message(docstring const & str)
{
+ if (ForkedProcess::iAmAChild())
+ return;
+
statusBar()->showMessage(toqstr(str));
- statusbar_timer_.stop();
- statusbar_timer_.start(statusbar_timer_value);
+ d.statusbar_timer_.stop();
+ d.statusbar_timer_.start(3000);
}
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;
+ theLyXFunc().setLyXView(this);
statusBar()->showMessage(toqstr(theLyXFunc().viewStatusMessage()));
}
// The document structure, name and dialogs might have
// changed in another view.
updateBufferDependent(true);
+ updateToolbars();
+ updateLayoutList();
+ updateStatusBar();
} else {
setWindowTitle(qt_("LyX"));
setWindowIconText(qt_("LyX"));
}
+ setFocus();
return QMainWindow::event(e);
}
+
case QEvent::ShortcutOverride: {
+ if (d.current_work_area_)
+ // Nothing special to do.
+ return QMainWindow::event(e);
+
QKeyEvent * ke = static_cast<QKeyEvent*>(e);
- if (!d.current_work_area_) {
- theLyXFunc().setLyXView(this);
- KeySymbol sym;
- setKeySymbol(&sym, ke);
- theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
- e->accept();
- return true;
- }
- if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) {
- KeySymbol sym;
- setKeySymbol(&sym, ke);
- d.current_work_area_->processKeySym(sym, NoModifier);
- e->accept();
- return true;
- }
+
+ // Let Qt handle menu access and the Tab keys to navigate keys to navigate
+ // between controls.
+ if (ke->modifiers() & Qt::AltModifier || ke->key() == Qt::Key_Tab
+ || ke->key() == Qt::Key_Backtab)
+ return QMainWindow::event(e);
+
+ // Allow processing of shortcuts that are allowed even when no Buffer
+ // is viewed.
+ theLyXFunc().setLyXView(this);
+ KeySymbol sym;
+ setKeySymbol(&sym, ke);
+ theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
+ e->accept();
+ return true;
}
+
default:
return QMainWindow::event(e);
}
}
-void GuiView::setBusy(bool yes)
+void GuiView::setBusy(bool busy)
{
if (d.current_work_area_) {
- d.current_work_area_->setUpdatesEnabled(!yes);
- if (yes)
+ d.current_work_area_->setUpdatesEnabled(!busy);
+ if (busy)
d.current_work_area_->stopBlinkingCursor();
else
d.current_work_area_->startBlinkingCursor();
}
- if (yes)
+ if (busy)
QApplication::setOverrideCursor(Qt::WaitCursor);
else
QApplication::restoreOverrideCursor();
GuiWorkArea * GuiView::workArea(Buffer & buffer)
{
- for (int i = 0; i != d.splitter_->count(); ++i) {
- GuiWorkArea * wa = d.tabWorkArea(i)->workArea(buffer);
- if (wa)
- return wa;
- }
+ if (TabWorkArea * twa = d.currentTabWorkArea())
+ return twa->workArea(buffer);
return 0;
}
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;
+ TabWorkArea * tab_widget = d.splitter_->count()
+ ? d.currentTabWorkArea() : addTabWorkArea();
+ return tab_widget->addWorkArea(buffer, *this);
}
-void GuiView::addTabWorkArea()
+TabWorkArea * GuiView::addTabWorkArea()
{
TabWorkArea * twa = new TabWorkArea;
QObject::connect(twa, SIGNAL(currentWorkAreaChanged(GuiWorkArea *)),
this, SLOT(on_currentWorkAreaChanged(GuiWorkArea *)));
d.splitter_->addWidget(twa);
d.stack_widget_->setCurrentWidget(d.splitter_);
+ return twa;
}
}
-void GuiView::setCurrentWorkArea(GuiWorkArea * work_area)
+void GuiView::setCurrentWorkArea(GuiWorkArea * wa)
{
- BOOST_ASSERT(work_area);
+ BOOST_ASSERT(wa);
// Changing work area can result from opening a file so
// update the toc in any case.
updateToc();
- GuiWorkArea * wa = static_cast<GuiWorkArea *>(work_area);
d.current_work_area_ = wa;
for (int i = 0; i != d.splitter_->count(); ++i) {
if (d.tabWorkArea(i)->setCurrentWorkArea(wa))
}
-void GuiView::removeWorkArea(GuiWorkArea * work_area)
+void GuiView::removeWorkArea(GuiWorkArea * wa)
{
- BOOST_ASSERT(work_area);
- GuiWorkArea * gwa = static_cast<GuiWorkArea *>(work_area);
- if (gwa == d.current_work_area_) {
+ BOOST_ASSERT(wa);
+ if (wa == d.current_work_area_) {
disconnectBuffer();
disconnectBufferView();
hideBufferDependent();
d.current_work_area_ = 0;
}
- // removing a work area often results from closing a file so
- // update the toc in any case.
- updateToc();
-
for (int i = 0; i != d.splitter_->count(); ++i) {
TabWorkArea * twa = d.tabWorkArea(i);
- if (!twa->removeWorkArea(gwa))
+ if (!twa->removeWorkArea(wa))
// Not found in this tab group.
continue;
}
-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_) {
bool const review =
lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
+ bool const mathmacrotemplate =
+ lyx::getStatus(FuncRequest(LFUN_IN_MATHMACROTEMPLATE)).enabled();
- d.toolbars_->update(math, table, review);
+ d.toolbars_->update(math, table, review, mathmacrotemplate);
} else
- d.toolbars_->update(false, false, false);
+ d.toolbars_->update(false, false, false, false);
// update read-only status of open dialogs.
checkStatus();
}
-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);
if (!isDialogVisible(name))
return;
- std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+ map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
if (it == d.dialogs_.end())
return;
void GuiView::resetAutosaveTimers()
{
if (lyxrc.autosave)
- autosave_timeout_->restart();
+ d.autosave_timeout_.restart();
}
-void GuiView::dispatch(FuncRequest const & cmd)
+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_BUFFER_SWITCH:
- setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
- break;
+ case LFUN_BUFFER_WRITE:
+ enable = buf && (buf->isUnnamed() || !buf->isClean());
+ break;
- case LFUN_COMMAND_EXECUTE: {
- bool const show_it = cmd.argument() != "off";
- d.toolbars_->showCommandBuffer(show_it);
- break;
- }
- case LFUN_DROP_LAYOUTS_CHOICE:
- d.toolbars_->openLayoutList();
- break;
+ case LFUN_BUFFER_WRITE_AS:
+ enable = buf;
+ break;
- case LFUN_MENU_OPEN:
- d.menubar_->openByName(toqstr(cmd.argument()));
- break;
+ case LFUN_SPLIT_VIEW:
+ enable = buf;
+ break;
- case LFUN_TOOLBAR_TOGGLE: {
- string const name = cmd.getArg(0);
- bool const allowauto = cmd.getArg(1) == "allowauto";
- // it is possible to get current toolbar status like this,...
- // but I decide to obey the order of ToolbarBackend::flags
- // and disregard real toolbar status.
- // toolbars_->saveToolbarInfo();
- //
- // toggle state on/off/auto
- d.toolbars_->toggleToolbarState(name, allowauto);
- // update toolbar
- updateToolbars();
+ case LFUN_CLOSE_TAB_GROUP:
+ enable = d.currentTabWorkArea();
+ break;
- ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
- if (!tbi) {
- message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
- break;
+ 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;
}
- docstring state;
- if (tbi->flags & ToolbarInfo::ON)
- state = _("on");
- else if (tbi->flags & ToolbarInfo::OFF)
- state = _("off");
- else if (tbi->flags & ToolbarInfo::AUTO)
- state = _("auto");
+ }
+ else if (name == "symbols") {
+ if (!view() || view()->cursor().inMathed())
+ enable = false;
+ else {
+ InsetCode ic = view()->cursor().inset().lyxCode();
+ enable = ic != ERT_CODE && ic != LISTINGS_CODE;
+ }
+ }
+ else if (name == "latexlog")
+ enable = FileName(buf->logName()).isReadableFile();
+ 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;
+ }
- message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
- _(tbi->gui_name), state));
+ case LFUN_DIALOG_UPDATE: {
+ string const name = cmd.getArg(0);
+ if (!buf)
+ enable = name == "prefs";
+ break;
+ }
+
+ case LFUN_INSET_APPLY: {
+ if (!buf) {
+ enable = false;
break;
}
+ string const name = cmd.getArg(0);
+ Inset * inset = getOpenInset(name);
+ if (inset) {
+ FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
+ FuncStatus fs;
+ if (!inset->getStatus(view()->cursor(), fr, fs)) {
+ // Every inset is supposed to handle this
+ BOOST_ASSERT(false);
+ }
+ flag |= fs;
+ } else {
+ FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
+ flag |= getStatus(fr);
+ }
+ enable = flag.enabled();
+ break;
+ }
- default:
- theLyXFunc().setLyXView(this);
- lyx::dispatch(cmd);
+ default:
+ if (!view()) {
+ enable = false;
+ break;
+ }
}
+
+ if (!enable)
+ flag.enabled(false);
+
+ return flag;
}
-Buffer const * GuiView::updateInset(Inset const * inset)
+static FileName selectTemplateFile()
{
- if (!d.current_work_area_)
- return 0;
+ FileDialog dlg(_("Select template file"));
+ dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
+ dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
- if (inset)
- d.current_work_area_->scheduleRedraw();
+ FileDialog::Result result =
+ dlg.open(from_utf8(lyxrc.template_path),
+ FileFilterList(_("LyX Documents (*.lyx)")),
+ docstring());
- return &d.current_work_area_->bufferView().buffer();
+ if (result.first == FileDialog::Later)
+ return FileName();
+ if (result.second.empty())
+ return FileName();
+ return FileName(to_utf8(result.second));
}
-void GuiView::restartCursor()
+Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles)
{
- /* When we move around, or type, it's nice to be able to see
- * the cursor immediately after the keypress.
- */
- if (d.current_work_area_)
- d.current_work_area_->startBlinkingCursor();
-}
+ setBusy(true);
+ Buffer * newBuffer = checkAndLoadLyXFile(filename);
-Dialog * GuiView::find_or_build(string const & name)
-{
- if (!isValidName(name))
+ if (!newBuffer) {
+ message(_("Document not loaded."));
+ setBusy(false);
return 0;
+ }
- std::map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
+ setBuffer(newBuffer);
- if (it != d.dialogs_.end())
- return it->second.get();
+ // scroll to the position when the file was last closed
+ if (lyxrc.use_lastfilepos) {
+ LastFilePosSection::FilePos filepos =
+ LyX::ref().session().lastFilePos().load(filename);
+ view()->moveToPosition(filepos.pit, filepos.pos, 0, 0);
+ }
+
+ if (tolastfiles)
+ LyX::ref().session().lastFiles().add(filename);
- d.dialogs_[name].reset(build(name));
- return d.dialogs_[name].get();
+ setBusy(false);
+ return newBuffer;
}
-void GuiView::showDialog(string const & name, string const & data,
- Inset * inset)
+void GuiView::openDocument(string const & fname)
{
- if (in_show_)
- return;
+ string initpath = lyxrc.document_path;
- in_show_ = true;
- Dialog * dialog = find_or_build(name);
- if (dialog) {
- dialog->showData(data);
- if (inset)
- d.open_insets_[name] = inset;
+ if (buffer()) {
+ string const trypath = buffer()->filePath();
+ // If directory is writeable, use this as default.
+ if (FileName(trypath).isDirWritable())
+ initpath = trypath;
}
- in_show_ = false;
-}
+ string filename;
-bool GuiView::isDialogVisible(string const & name) const
-{
- std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
- if (it == d.dialogs_.end())
- return false;
- return it->second.get()->isVisibleView();
-}
+ if (fname.empty()) {
+ FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
+ dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
+ dlg.setButton2(_("Examples|#E#e"),
+ from_utf8(addPath(package().system_support().absFilename(), "examples")));
+ FileDialog::Result result =
+ dlg.open(from_utf8(initpath),
+ FileFilterList(_("LyX Documents (*.lyx)")),
+ docstring());
-void GuiView::hideDialog(string const & name, Inset * inset)
-{
- // Don't send the signal if we are quitting, because on MSVC it is
- // destructed before the cut stack in CutAndPaste.cpp, and this method
- // is called from some inset destructor if the cut stack is not empty
- // on exit.
- if (quitting)
- return;
+ if (result.first == FileDialog::Later)
+ return;
- std::map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
- if (it == d.dialogs_.end())
- return;
+ filename = to_utf8(result.second);
- if (inset && inset != getOpenInset(name))
+ // check selected filename
+ if (filename.empty()) {
+ message(_("Canceled."));
+ return;
+ }
+ } else
+ filename = fname;
+
+ // get absolute path of file and add ".lyx" to the filename if
+ // necessary.
+ FileName const fullname =
+ fileSearch(string(), filename, "lyx", support::may_not_exist);
+ if (!fullname.empty())
+ filename = fullname.absFilename();
+
+ // if the file doesn't exist, let the user create one
+ if (!fullname.exists()) {
+ // the user specifically chose this name. Believe him.
+ Buffer * const b = newFile(filename, string(), true);
+ if (b)
+ setBuffer(b);
return;
+ }
- Dialog * const dialog = it->second.get();
- if (dialog->isVisibleView())
- dialog->hide();
- d.open_insets_[name] = 0;
+ docstring const disp_fn = makeDisplayPath(filename);
+ message(bformat(_("Opening document %1$s..."), disp_fn));
+
+ docstring str2;
+ Buffer * buf = loadDocument(fullname);
+ if (buf) {
+ updateLabels(*buf);
+ setBuffer(buf);
+ buf->errors("Parse");
+ str2 = bformat(_("Document %1$s opened."), disp_fn);
+ } else {
+ str2 = bformat(_("Could not open document %1$s"), disp_fn);
+ }
+ message(str2);
}
+// FIXME: clean that
+static bool import(GuiView * lv, FileName const & filename,
+ string const & format, ErrorList & errorList)
+{
+ FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
-void GuiView::disconnectDialog(string const & name)
+ string loader_format;
+ vector<string> loaders = theConverters().loaders();
+ if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
+ for (vector<string>::const_iterator it = loaders.begin();
+ it != loaders.end(); ++it) {
+ if (!theConverters().isReachable(format, *it))
+ continue;
+
+ string const tofile =
+ changeExtension(filename.absFilename(),
+ formats.extension(*it));
+ if (!theConverters().convert(0, filename, FileName(tofile),
+ filename, format, *it, errorList))
+ return false;
+ loader_format = *it;
+ break;
+ }
+ if (loader_format.empty()) {
+ frontend::Alert::error(_("Couldn't import file"),
+ bformat(_("No information for importing the format %1$s."),
+ formats.prettyName(format)));
+ return false;
+ }
+ } else
+ loader_format = format;
+
+ if (loader_format == "lyx") {
+ Buffer * buf = lv->loadDocument(lyxfile);
+ if (!buf)
+ return false;
+ updateLabels(*buf);
+ lv->setBuffer(buf);
+ buf->errors("Parse");
+ } else {
+ Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
+ if (!b)
+ return false;
+ lv->setBuffer(b);
+ bool as_paragraphs = loader_format == "textparagraph";
+ string filename2 = (loader_format == format) ? filename.absFilename()
+ : changeExtension(filename.absFilename(),
+ formats.extension(loader_format));
+ lv->view()->insertPlaintextFile(FileName(filename2), as_paragraphs);
+ theLyXFunc().setLyXView(lv);
+ lyx::dispatch(FuncRequest(LFUN_MARK_OFF));
+ }
+
+ return true;
+}
+
+
+void GuiView::importDocument(string const & argument)
{
- if (!isValidName(name))
+ string format;
+ string filename = split(argument, format, ' ');
+
+ LYXERR(Debug::INFO, format << " file: " << filename);
+
+ // need user interaction
+ if (filename.empty()) {
+ string initpath = lyxrc.document_path;
+
+ Buffer const * buf = buffer();
+ if (buf) {
+ string const trypath = buf->filePath();
+ // If directory is writeable, use this as default.
+ if (FileName(trypath).isDirWritable())
+ initpath = trypath;
+ }
+
+ docstring const text = bformat(_("Select %1$s file to import"),
+ formats.prettyName(format));
+
+ FileDialog dlg(text, LFUN_BUFFER_IMPORT);
+ dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
+ dlg.setButton2(_("Examples|#E#e"),
+ from_utf8(addPath(package().system_support().absFilename(), "examples")));
+
+ docstring filter = formats.prettyName(format);
+ filter += " (*.";
+ // FIXME UNICODE
+ filter += from_utf8(formats.extension(format));
+ filter += ')';
+
+ FileDialog::Result result =
+ dlg.open(from_utf8(initpath),
+ FileFilterList(filter),
+ docstring());
+
+ if (result.first == FileDialog::Later)
+ return;
+
+ filename = to_utf8(result.second);
+
+ // check selected filename
+ if (filename.empty())
+ message(_("Canceled."));
+ }
+
+ if (filename.empty())
return;
- if (d.open_insets_.find(name) != d.open_insets_.end())
- d.open_insets_[name] = 0;
+ // get absolute path of file
+ FileName const fullname(makeAbsPath(filename));
+
+ FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
+
+ // Check if the document already is open
+ Buffer * buf = theBufferList().getBuffer(lyxfile.absFilename());
+ if (buf) {
+ setBuffer(buf);
+ if (!closeBuffer()) {
+ message(_("Canceled."));
+ return;
+ }
+ }
+
+ docstring const displaypath = makeDisplayPath(lyxfile.absFilename(), 30);
+
+ // if the file exists already, and we didn't do
+ // -i lyx thefile.lyx, warn
+ if (lyxfile.exists() && fullname != lyxfile) {
+
+ docstring text = bformat(_("The document %1$s already exists.\n\n"
+ "Do you want to overwrite that document?"), displaypath);
+ int const ret = Alert::prompt(_("Overwrite document?"),
+ text, 0, 1, _("&Overwrite"), _("&Cancel"));
+
+ if (ret == 1) {
+ message(_("Canceled."));
+ return;
+ }
+ }
+
+ message(bformat(_("Importing %1$s..."), displaypath));
+ ErrorList errorList;
+ if (import(this, fullname, format, errorList))
+ message(_("imported."));
+ else
+ message(_("file not imported!"));
+
+ // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
}
-Inset * GuiView::getOpenInset(string const & name) const
+void GuiView::newDocument(string const & filename, bool from_template)
{
- if (!isValidName(name))
- return 0;
+ FileName initpath(lyxrc.document_path);
+ Buffer * buf = buffer();
+ if (buf) {
+ FileName const trypath(buf->filePath());
+ // If directory is writeable, use this as default.
+ if (trypath.isDirWritable())
+ initpath = trypath;
+ }
- std::map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
- return it == d.open_insets_.end() ? 0 : it->second;
+ string templatefile = from_template ?
+ selectTemplateFile().absFilename() : string();
+ Buffer * b;
+ if (filename.empty())
+ b = newUnnamedFile(templatefile, initpath);
+ else
+ b = newFile(filename, templatefile, true);
+
+ if (b)
+ setBuffer(b);
+ // Ensure the cursor is correctly positionned on screen.
+ view()->showCursor();
}
-void GuiView::hideAll() const
+void GuiView::insertLyXFile(docstring const & fname)
{
- std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
- std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+ BufferView * bv = view();
+ if (!bv)
+ return;
- for(; it != end; ++it)
- it->second->hide();
+ // FIXME UNICODE
+ FileName filename(to_utf8(fname));
+
+ if (!filename.empty()) {
+ bv->insertLyXFile(filename);
+ return;
+ }
+
+ // Launch a file browser
+ // FIXME UNICODE
+ string initpath = lyxrc.document_path;
+ string const trypath = bv->buffer().filePath();
+ // If directory is writeable, use this as default.
+ if (FileName(trypath).isDirWritable())
+ initpath = trypath;
+
+ // FIXME UNICODE
+ FileDialog dlg(_("Select LyX document to insert"), LFUN_FILE_INSERT);
+ dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
+ dlg.setButton2(_("Examples|#E#e"),
+ from_utf8(addPath(package().system_support().absFilename(),
+ "examples")));
+
+ FileDialog::Result result =
+ dlg.open(from_utf8(initpath),
+ FileFilterList(_("LyX Documents (*.lyx)")),
+ docstring());
+
+ if (result.first == FileDialog::Later)
+ return;
+
+ // FIXME UNICODE
+ filename.set(to_utf8(result.second));
+
+ // check selected filename
+ if (filename.empty()) {
+ // emit message signal.
+ message(_("Canceled."));
+ return;
+ }
+
+ bv->insertLyXFile(filename);
}
-void GuiView::hideBufferDependent() const
+void GuiView::insertPlaintextFile(docstring const & fname,
+ bool asParagraph)
{
- std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
- std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+ BufferView * bv = view();
+ if (!bv)
+ return;
- for(; it != end; ++it) {
- Dialog * dialog = it->second.get();
- if (dialog->isBufferDependent())
- dialog->hide();
+ // FIXME UNICODE
+ FileName filename(to_utf8(fname));
+
+ if (!filename.empty()) {
+ bv->insertPlaintextFile(filename, asParagraph);
+ return;
}
+
+ FileDialog dlg(_("Select file to insert"), (asParagraph ?
+ LFUN_FILE_INSERT_PLAINTEXT_PARA : LFUN_FILE_INSERT_PLAINTEXT));
+
+ FileDialog::Result result = dlg.open(from_utf8(bv->buffer().filePath()),
+ FileFilterList(), docstring());
+
+ if (result.first == FileDialog::Later)
+ return;
+
+ // FIXME UNICODE
+ filename.set(to_utf8(result.second));
+
+ // check selected filename
+ if (filename.empty()) {
+ // emit message signal.
+ message(_("Canceled."));
+ return;
+ }
+
+ bv->insertPlaintextFile(filename, asParagraph);
}
-void GuiView::updateBufferDependent(bool switched) const
+bool GuiView::renameBuffer(Buffer & b, docstring const & newname)
{
- std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
- std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+ FileName fname = b.fileName();
+ FileName const oldname = fname;
- for(; it != end; ++it) {
- Dialog * dialog = it->second.get();
- if (switched && dialog->isBufferDependent()) {
- if (dialog->isVisibleView() && dialog->initialiseParams(""))
- dialog->updateView();
- else
- dialog->hide();
- } else {
- // A bit clunky, but the dialog will request
- // that the kernel provides it with the necessary
- // data.
- dialog->slotRestore();
+ if (!newname.empty()) {
+ // FIXME UNICODE
+ fname = makeAbsPath(to_utf8(newname), oldname.onlyPath().absFilename());
+ } else {
+ // Switch to this Buffer.
+ setBuffer(&b);
+
+ /// No argument? Ask user through dialog.
+ // FIXME UNICODE
+ FileDialog dlg(_("Choose a filename to save document as"),
+ LFUN_BUFFER_WRITE_AS);
+ dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
+ dlg.setButton2(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
+
+ if (!isLyXFilename(fname.absFilename()))
+ fname.changeExtension(".lyx");
+
+ FileFilterList const filter(_("LyX Documents (*.lyx)"));
+
+ FileDialog::Result result =
+ dlg.save(from_utf8(fname.onlyPath().absFilename()),
+ filter,
+ from_utf8(fname.onlyFileName()));
+
+ if (result.first == FileDialog::Later)
+ return false;
+
+ fname.set(to_utf8(result.second));
+
+ if (fname.empty())
+ return false;
+
+ if (!isLyXFilename(fname.absFilename()))
+ fname.changeExtension(".lyx");
+ }
+
+ if (FileName(fname).exists()) {
+ docstring const file = makeDisplayPath(fname.absFilename(), 30);
+ docstring text = bformat(_("The document %1$s already "
+ "exists.\n\nDo you want to "
+ "overwrite that document?"),
+ file);
+ int const ret = Alert::prompt(_("Overwrite document?"),
+ text, 0, 2, _("&Overwrite"), _("&Rename"), _("&Cancel"));
+ switch (ret) {
+ case 0: break;
+ case 1: return renameBuffer(b, docstring());
+ case 2: return false;
}
}
+
+ // Ok, change the name of the buffer
+ b.setFileName(fname.absFilename());
+ b.markDirty();
+ bool unnamed = b.isUnnamed();
+ b.setUnnamed(false);
+ b.saveCheckSum(fname);
+
+ if (!saveBuffer(b)) {
+ b.setFileName(oldname.absFilename());
+ b.setUnnamed(unnamed);
+ b.saveCheckSum(oldname);
+ return false;
+ }
+
+ return true;
}
-void GuiView::redrawDialog() const
+bool GuiView::saveBuffer(Buffer & b)
{
- std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
- std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+ if (b.isUnnamed())
+ return renameBuffer(b, docstring());
- for(; it != end; ++it)
- it->second->redraw();
+ if (b.save()) {
+ LyX::ref().session().lastFiles().add(b.fileName());
+ return true;
+ }
+
+ // Switch to this Buffer.
+ setBuffer(&b);
+
+ // FIXME: we don't tell the user *WHY* the save failed !!
+ docstring const file = makeDisplayPath(b.absFileName(), 30);
+ docstring text = bformat(_("The document %1$s could not be saved.\n\n"
+ "Do you want to rename the document and "
+ "try again?"), file);
+ int const ret = Alert::prompt(_("Rename and save?"),
+ text, 0, 2, _("&Rename"), _("&Retry"), _("&Cancel"));
+ switch (ret) {
+ case 0:
+ if (!renameBuffer(b, docstring()))
+ return false;
+ break;
+ case 1:
+ break;
+ case 2:
+ return false;
+ }
+
+ return saveBuffer(b);
}
-void GuiView::checkStatus()
+bool GuiView::closeBuffer()
+{
+ Buffer * buf = buffer();
+ return buf && closeBuffer(*buf);
+}
+
+
+bool GuiView::closeBuffer(Buffer & buf)
{
- std::map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
- std::map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+ if (buf.isClean() || buf.paragraphs().empty()) {
+ theBufferList().release(&buf);
+ return true;
+ }
+ // Switch to this Buffer.
+ setBuffer(&buf);
- for(; it != end; ++it) {
- Dialog * const dialog = it->second.get();
- if (dialog && dialog->isVisibleView())
- dialog->checkStatus();
+ docstring file;
+ // FIXME: Unicode?
+ if (buf.isUnnamed())
+ file = from_utf8(buf.fileName().onlyFileName());
+ else
+ file = buf.fileName().displayName(30);
+
+ docstring const text = bformat(_("The document %1$s has unsaved changes."
+ "\n\nDo you want to save the document or discard the changes?"), file);
+ int const ret = Alert::prompt(_("Save changed document?"),
+ text, 0, 2, _("&Save"), _("&Discard"), _("&Cancel"));
+
+ switch (ret) {
+ case 0:
+ if (!saveBuffer(buf))
+ return false;
+ break;
+ case 1:
+ // if we crash after this we could
+ // have no autosave file but I guess
+ // this is really improbable (Jug)
+ removeAutosaveFile(buf.absFileName());
+ break;
+ case 2:
+ return false;
}
+
+ // save file names to .lyx/session
+ // if master/slave are both open, do not save slave since it
+ // will be automatically loaded when the master is loaded
+ if (buf.masterBuffer() == &buf)
+ LyX::ref().session().lastOpened().add(buf.fileName());
+
+ theBufferList().release(&buf);
+ return true;
+}
+
+
+bool GuiView::quitWriteAll()
+{
+ while (!theBufferList().empty()) {
+ Buffer * b = theBufferList().first();
+ if (!closeBuffer(*b))
+ return false;
+ }
+ return true;
}
+bool GuiView::dispatch(FuncRequest const & cmd)
+{
+ BufferView * bv = view();
+ // By default we won't need any update.
+ if (bv)
+ bv->cursor().updateFlags(Update::None);
+
+ switch(cmd.action) {
+ case LFUN_FILE_OPEN:
+ openDocument(to_utf8(cmd.argument()));
+ break;
+
+ case LFUN_BUFFER_IMPORT:
+ importDocument(to_utf8(cmd.argument()));
+ break;
+
+ case LFUN_BUFFER_SWITCH:
+ setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
+ break;
+
+ case LFUN_BUFFER_NEXT:
+ setBuffer(theBufferList().next(buffer()));
+ break;
+
+ case LFUN_BUFFER_PREVIOUS:
+ setBuffer(theBufferList().previous(buffer()));
+ break;
+
+ case LFUN_COMMAND_EXECUTE: {
+ bool const show_it = cmd.argument() != "off";
+ d.toolbars_->showCommandBuffer(show_it);
+ break;
+ }
+ case LFUN_DROP_LAYOUTS_CHOICE:
+ if (d.layout_)
+ d.layout_->showPopup();
+ break;
+
+ case LFUN_MENU_OPEN:
+ if (QMenu * menu = guiApp->menus().menu(toqstr(cmd.argument())))
+ menu->exec(QCursor::pos());
+ break;
+
+ case LFUN_FILE_INSERT:
+ insertLyXFile(cmd.argument());
+ break;
+ case LFUN_FILE_INSERT_PLAINTEXT_PARA:
+ insertPlaintextFile(cmd.argument(), true);
+ break;
+
+ case LFUN_FILE_INSERT_PLAINTEXT:
+ insertPlaintextFile(cmd.argument(), false);
+ break;
+
+ case LFUN_BUFFER_WRITE:
+ if (bv)
+ saveBuffer(bv->buffer());
+ break;
+
+ case LFUN_BUFFER_WRITE_AS:
+ if (bv)
+ renameBuffer(bv->buffer(), cmd.argument());
+ break;
+
+ case LFUN_BUFFER_WRITE_ALL: {
+ Buffer * first = theBufferList().first();
+ if (!first)
+ break;
+ message(_("Saving all documents..."));
+ // We cannot use a for loop as the buffer list cycles.
+ Buffer * b = first;
+ do {
+ if (b->isClean())
+ continue;
+ saveBuffer(*b);
+ LYXERR(Debug::ACTION, "Saved " << b->absFileName());
+ b = theBufferList().next(b);
+ } while (b != first);
+ message(_("All documents saved."));
+ break;
+ }
+
+ case LFUN_TOOLBAR_TOGGLE: {
+ string const name = cmd.getArg(0);
+ bool const allowauto = cmd.getArg(1) == "allowauto";
+ // it is possible to get current toolbar status like this,...
+ // but I decide to obey the order of ToolbarBackend::flags
+ // and disregard real toolbar status.
+ // toolbars_->saveToolbarInfo();
+ //
+ // toggle state on/off/auto
+ d.toolbars_->toggleToolbarState(name, allowauto);
+ // update toolbar
+ updateToolbars();
+
+ ToolbarInfo * tbi = d.toolbars_->getToolbarInfo(name);
+ if (!tbi) {
+ message(bformat(_("Unknown toolbar \"%1$s\""), from_utf8(name)));
+ break;
+ }
+ docstring state;
+ if (tbi->flags & ToolbarInfo::ON)
+ state = _("on");
+ else if (tbi->flags & ToolbarInfo::OFF)
+ state = _("off");
+ else if (tbi->flags & ToolbarInfo::AUTO)
+ state = _("auto");
+
+ message(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
+ _(tbi->gui_name), state));
+ 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 = buffer()->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(buffer()->lyxvc().getLogFile());
+ showDialog("log", data);
+ } else if (name == "symbols") {
+ data = bv->cursor().getEncoding()->name();
+ if (!data.empty())
+ showDialog("symbols", data);
+ } else
+ showDialog(name, data);
+ break;
+ }
+
+ case LFUN_INSET_APPLY: {
+ string const name = cmd.getArg(0);
+ Inset * inset = getOpenInset(name);
+ if (inset) {
+ FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
+ inset->dispatch(view()->cursor(), fr);
+ } else {
+ FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
+ lyx::dispatch(fr);
+ }
+ break;
+ }
+
+ case LFUN_UI_TOGGLE:
+ lfunUiToggle(cmd);
+ // Make sure the keyboard focus stays in the work area.
+ setFocus();
+ break;
+
+ case LFUN_SPLIT_VIEW:
+ if (Buffer * buf = buffer()) {
+ string const orientation = cmd.getArg(0);
+ d.splitter_->setOrientation(orientation == "vertical"
+ ? Qt::Vertical : Qt::Horizontal);
+ TabWorkArea * twa = addTabWorkArea();
+ GuiWorkArea * wa = twa->addWorkArea(*buf, *this);
+ setCurrentWorkArea(wa);
+ }
+ break;
+
+ case LFUN_CLOSE_TAB_GROUP:
+ if (TabWorkArea * twa = d.currentTabWorkArea()) {
+ delete twa;
+ twa = d.currentTabWorkArea();
+ // Switch to the next GuiWorkArea in the found TabWorkArea.
+ d.current_work_area_ = twa? twa->currentWorkArea() : 0;
+ if (d.splitter_->count() == 0)
+ // No more work area, switch to the background widget.
+ d.setBackground();
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+
+void GuiView::lfunUiToggle(FuncRequest const & cmd)
+{
+ string const arg = cmd.getArg(0);
+ if (arg == "scrollbar") {
+ // hide() is of no help
+ if (d.current_work_area_->verticalScrollBarPolicy() ==
+ Qt::ScrollBarAlwaysOff)
+
+ d.current_work_area_->setVerticalScrollBarPolicy(
+ Qt::ScrollBarAsNeeded);
+ else
+ d.current_work_area_->setVerticalScrollBarPolicy(
+ Qt::ScrollBarAlwaysOff);
+ return;
+ }
+ if (arg == "statusbar") {
+ statusBar()->setVisible(!statusBar()->isVisible());
+ return;
+ }
+ if (arg == "menubar") {
+ menuBar()->setVisible(!menuBar()->isVisible());
+ return;
+ }
+#if QT_VERSION >= 0x040300
+ if (arg == "frame") {
+ int l, t, r, b;
+ getContentsMargins(&l, &t, &r, &b);
+ //are the frames in default state?
+ if (l == 0) {
+ d.current_work_area_->setFrameStyle(QFrame::NoFrame);
+ setContentsMargins(-2, -2, -2, -2);
+ } else {
+ d.current_work_area_->setFrameStyle(QFrame::NoFrame);
+ setContentsMargins(0, 0, 0, 0);
+ }
+ return;
+ }
+#endif
+ if (arg != "fullscreen") {
+ message(bformat(_("LFUN_UI_TOGGLE %1$s unknown command!"), from_utf8(arg)));
+ return;
+ }
+
+ if (lyxrc.full_screen_toolbars)
+ d.toolbars_->toggleFullScreen(!isFullScreen());
+
+ if (isFullScreen()) {
+ for (int i = 0; i != d.splitter_->count(); ++i)
+ d.tabWorkArea(i)->setFullScreen(false);
+#if QT_VERSION >= 0x040300
+ setContentsMargins(0, 0, 0, 0);
+#endif
+ showNormal();
+ menuBar()->show();
+ statusBar()->show();
+ } else {
+ for (int i = 0; i != d.splitter_->count(); ++i)
+ d.tabWorkArea(i)->setFullScreen(true);
+#if QT_VERSION >= 0x040300
+ setContentsMargins(-2, -2, -2, -2);
+#endif
+ showFullScreen();
+ statusBar()->hide();
+ menuBar()->hide();
+ }
+}
+
+
+Buffer const * GuiView::updateInset(Inset const * inset)
+{
+ if (!d.current_work_area_)
+ return 0;
+
+ if (inset)
+ d.current_work_area_->scheduleRedraw();
+
+ return &d.current_work_area_->bufferView().buffer();
+}
+
+
+void GuiView::restartCursor()
+{
+ /* When we move around, or type, it's nice to be able to see
+ * the cursor immediately after the keypress.
+ */
+ 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
"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",
+"mathdelimiter", "mathmatrix", "note", "paragraph", "prefs", "print",
+"ref", "sendto", "spellchecker", "symbols", "tabular", "tabularcreate",
#ifdef HAVE_LIBAIKSAURUS
"thesaurus",
};
+bool isValidName(string const & name)
+{
+ return find_if(dialognames, end_dialognames,
+ cmpCStr(name.c_str())) != end_dialognames;
+}
+
} // namespace anon
-// will be replaced by a proper factory...
-Dialog * createGuiAbout(LyXView & lv);
-Dialog * createGuiBibitem(LyXView & lv);
-Dialog * createGuiBibtex(LyXView & lv);
-Dialog * createGuiBox(LyXView & lv);
-Dialog * createGuiBranch(LyXView & lv);
-Dialog * createGuiChanges(LyXView & lv);
-Dialog * createGuiCharacter(LyXView & lv);
-Dialog * createGuiCitation(LyXView & lv);
-Dialog * createGuiDelimiter(LyXView & lv);
-Dialog * createGuiDocument(LyXView & lv);
-Dialog * createGuiErrorList(LyXView & lv);
-Dialog * createGuiERT(LyXView & lv);
-Dialog * createGuiExternal(LyXView & lv);
-Dialog * createGuiFloat(LyXView & lv);
-Dialog * createGuiGraphics(LyXView & lv);
-Dialog * createGuiInclude(LyXView & lv);
-Dialog * createGuiIndex(LyXView & lv);
-Dialog * createGuiLabel(LyXView & lv);
-Dialog * createGuiListings(LyXView & lv);
-Dialog * createGuiLog(LyXView & lv);
-Dialog * createGuiMathMatrix(LyXView & lv);
-Dialog * createGuiNomenclature(LyXView & lv);
-Dialog * createGuiNote(LyXView & lv);
-Dialog * createGuiParagraph(LyXView & lv);
-Dialog * createGuiPreferences(LyXView & lv);
-Dialog * createGuiPrint(LyXView & lv);
-Dialog * createGuiRef(LyXView & lv);
-Dialog * createGuiSearch(LyXView & lv);
-Dialog * createGuiSendTo(LyXView & lv);
-Dialog * createGuiShowFile(LyXView & lv);
-Dialog * createGuiSpellchecker(LyXView & lv);
-Dialog * createGuiTabularCreate(LyXView & lv);
-Dialog * createGuiTabular(LyXView & lv);
-Dialog * createGuiTexInfo(LyXView & lv);
-Dialog * createGuiToc(LyXView & lv);
-Dialog * createGuiThesaurus(LyXView & lv);
-Dialog * createGuiHyperlink(LyXView & lv);
-Dialog * createGuiVSpace(LyXView & lv);
-Dialog * createGuiViewSource(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;
+
+void GuiView::resetDialogs()
+{
+ // Make sure that no LFUN uses any LyXView.
+ theLyXFunc().setLyXView(0);
+ // FIXME: the "math panels" toolbar takes an awful lot of time to
+ // initialise so we don't do that for the time being.
+ //d.toolbars_->init();
+ guiApp->menus().fillMenuBar(this);
+ if (d.layout_)
+ d.layout_->updateContents(true);
+ // Now update controls with current buffer.
+ theLyXFunc().setLyXView(this);
+ restartCursor();
+}
+
+
+Dialog * GuiView::find_or_build(string const & name)
+{
+ if (!isValidName(name))
+ return 0;
+
+ map<string, DialogPtr>::iterator it = d.dialogs_.find(name);
+
+ if (it != d.dialogs_.end())
+ return it->second.get();
+
+ Dialog * dialog = build(name);
+ d.dialogs_[name].reset(dialog);
+ if (lyxrc.allow_geometry_session)
+ dialog->restoreSession();
+ return dialog;
+}
+
+
+void GuiView::showDialog(string const & name, string const & data,
+ Inset * inset)
+{
+ if (d.in_show_)
+ return;
+
+ d.in_show_ = true;
+ Dialog * dialog = find_or_build(name);
+ if (dialog) {
+ dialog->showData(data);
+ if (inset)
+ d.open_insets_[name] = inset;
+ }
+ d.in_show_ = false;
+}
+
+
+bool GuiView::isDialogVisible(string const & name) const
+{
+ map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+ if (it == d.dialogs_.end())
+ return false;
+ return it->second.get()->isVisibleView();
}
+void GuiView::hideDialog(string const & name, Inset * inset)
+{
+ // Don't send the signal if we are quitting, because on MSVC it is
+ // destructed before the cut stack in CutAndPaste.cpp, and this method
+ // is called from some inset destructor if the cut stack is not empty
+ // on exit.
+ if (quitting)
+ return;
+
+ map<string, DialogPtr>::const_iterator it = d.dialogs_.find(name);
+ if (it == d.dialogs_.end())
+ return;
+
+ if (inset && inset != getOpenInset(name))
+ return;
+
+ Dialog * const dialog = it->second.get();
+ if (dialog->isVisibleView())
+ dialog->hideView();
+ d.open_insets_[name] = 0;
+}
+
+
+void GuiView::disconnectDialog(string const & name)
+{
+ if (!isValidName(name))
+ return;
+
+ if (d.open_insets_.find(name) != d.open_insets_.end())
+ d.open_insets_[name] = 0;
+}
+
+
+Inset * GuiView::getOpenInset(string const & name) const
+{
+ if (!isValidName(name))
+ return 0;
+
+ map<string, Inset *>::const_iterator it = d.open_insets_.find(name);
+ return it == d.open_insets_.end() ? 0 : it->second;
+}
+
+
+void GuiView::hideAll() const
+{
+ map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
+ map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+
+ for(; it != end; ++it)
+ it->second->hideView();
+}
+
+
+void GuiView::hideBufferDependent() const
+{
+ map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
+ map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+
+ for(; it != end; ++it) {
+ Dialog * dialog = it->second.get();
+ if (dialog->isBufferDependent())
+ dialog->hideView();
+ }
+}
+
+
+void GuiView::updateBufferDependent(bool switched) const
+{
+ map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
+ map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+
+ for(; it != end; ++it) {
+ Dialog * dialog = it->second.get();
+ if (!dialog->isVisibleView())
+ continue;
+ if (switched && dialog->isBufferDependent()) {
+ if (dialog->initialiseParams(""))
+ dialog->updateView();
+ else
+ dialog->hideView();
+ } else {
+ // A bit clunky, but the dialog will request
+ // that the kernel provides it with the necessary
+ // data.
+ dialog->updateDialog();
+ }
+ }
+}
+
+
+void GuiView::checkStatus()
+{
+ map<string, DialogPtr>::const_iterator it = d.dialogs_.begin();
+ map<string, DialogPtr>::const_iterator end = d.dialogs_.end();
+
+ for(; it != end; ++it) {
+ Dialog * const dialog = it->second.get();
+ if (dialog && dialog->isVisibleView())
+ dialog->checkStatus();
+ }
+}
+
+
+
+// will be replaced by a proper factory...
+Dialog * createGuiAbout(GuiView & lv);
+Dialog * createGuiBibitem(GuiView & lv);
+Dialog * createGuiBibtex(GuiView & lv);
+Dialog * createGuiBox(GuiView & lv);
+Dialog * createGuiBranch(GuiView & lv);
+Dialog * createGuiChanges(GuiView & lv);
+Dialog * createGuiCharacter(GuiView & lv);
+Dialog * createGuiCitation(GuiView & lv);
+Dialog * createGuiDelimiter(GuiView & lv);
+Dialog * createGuiDocument(GuiView & lv);
+Dialog * createGuiErrorList(GuiView & lv);
+Dialog * createGuiERT(GuiView & lv);
+Dialog * createGuiExternal(GuiView & lv);
+Dialog * createGuiFloat(GuiView & lv);
+Dialog * createGuiGraphics(GuiView & lv);
+Dialog * createGuiInclude(GuiView & lv);
+Dialog * createGuiLabel(GuiView & lv);
+Dialog * createGuiListings(GuiView & lv);
+Dialog * createGuiLog(GuiView & lv);
+Dialog * createGuiMathMatrix(GuiView & lv);
+Dialog * createGuiNomenclature(GuiView & lv);
+Dialog * createGuiNote(GuiView & lv);
+Dialog * createGuiParagraph(GuiView & lv);
+Dialog * createGuiPreferences(GuiView & lv);
+Dialog * createGuiPrint(GuiView & lv);
+Dialog * createGuiRef(GuiView & lv);
+Dialog * createGuiSearch(GuiView & lv);
+Dialog * createGuiSendTo(GuiView & lv);
+Dialog * createGuiShowFile(GuiView & lv);
+Dialog * createGuiSpellchecker(GuiView & lv);
+Dialog * createGuiSymbols(GuiView & lv);
+Dialog * createGuiTabularCreate(GuiView & lv);
+Dialog * createGuiTabular(GuiView & lv);
+Dialog * createGuiTexInfo(GuiView & lv);
+Dialog * createGuiToc(GuiView & lv);
+Dialog * createGuiThesaurus(GuiView & lv);
+Dialog * createGuiHyperlink(GuiView & lv);
+Dialog * createGuiVSpace(GuiView & lv);
+Dialog * createGuiViewSource(GuiView & lv);
+Dialog * createGuiWrap(GuiView & lv);
+
+
Dialog * GuiView::build(string const & name)
{
BOOST_ASSERT(isValidName(name));
return createGuiGraphics(*this);
if (name == "include")
return createGuiInclude(*this);
- if (name == "index")
- return createGuiIndex(*this);
if (name == "nomenclature")
return createGuiNomenclature(*this);
if (name == "label")
return createGuiSendTo(*this);
if (name == "spellchecker")
return createGuiSpellchecker(*this);
+ if (name == "symbols")
+ return createGuiSymbols(*this);
if (name == "tabular")
return createGuiTabular(*this);
if (name == "tabularcreate")