]> git.lyx.org Git - lyx.git/blob - src/frontends/LyXView.cpp
move font related stuff from bufferview_funcs to Font
[lyx.git] / src / frontends / LyXView.cpp
1 /**
2  * \file LyXView.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author John Levon
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "LyXView.h"
15
16 #include "Dialogs.h"
17 #include "Toolbars.h"
18 #include "WorkArea.h"
19 #include "Gui.h"
20
21 #include "Buffer.h"
22 #include "buffer_funcs.h"
23 #include "BufferList.h"
24 #include "BufferParams.h"
25 #include "BufferView.h"
26 #include "Cursor.h"
27 #include "debug.h"
28 #include "ErrorList.h"
29 #include "FuncRequest.h"
30 #include "gettext.h"
31 #include "Intl.h"
32 #include "callback.h"
33 #include "LyX.h"
34 #include "LyXFunc.h"
35 #include "LyXRC.h"
36 #include "Text.h"
37 #include "MenuBackend.h"
38 #include "Paragraph.h"
39
40 #include "support/lstrings.h"
41 #include "support/filetools.h" // OnlyFilename()
42 #include "support/Timeout.h"
43
44 #include <boost/bind.hpp>
45
46
47 #ifdef HAVE_SYS_TIME_H
48 # include <sys/time.h>
49 #endif
50 #ifdef HAVE_UNISTD_H
51 # include <unistd.h>
52 #endif
53
54 using std::endl;
55 using std::string;
56
57 namespace lyx {
58
59 using support::bformat;
60 using support::FileName;
61 using support::makeDisplayPath;
62 using support::onlyFilename;
63
64 namespace frontend {
65
66 docstring current_layout;
67
68 LyXView::LyXView(int id)
69         : toolbars_(new Toolbars(*this)),
70           autosave_timeout_(new Timeout(5000)),
71           dialogs_(new Dialogs(*this)),
72           id_(id)
73 {
74         // Start autosave timer
75         if (lyxrc.autosave) {
76                 autosave_timeout_->timeout.connect(boost::bind(&LyXView::autoSave, this));
77                 autosave_timeout_->setTimeout(lyxrc.autosave * 1000);
78                 autosave_timeout_->start();
79         }
80 }
81
82
83 LyXView::~LyXView()
84 {
85         disconnectBuffer();
86         disconnectBufferView();
87         delete dialogs_;
88         delete toolbars_;
89         delete autosave_timeout_;
90 }
91
92
93 Buffer * LyXView::buffer()
94 {
95         WorkArea * work_area = currentWorkArea();
96         if (work_area)
97                 return &work_area->bufferView().buffer();
98         return 0;
99 }
100
101
102 Buffer const * LyXView::buffer() const
103 {
104         WorkArea const * work_area = currentWorkArea();
105         if (work_area)
106                 return &work_area->bufferView().buffer();
107         return 0;
108 }
109
110
111 void LyXView::setBuffer(Buffer * newBuffer)
112 {
113         BOOST_ASSERT(newBuffer);
114         busy(true);
115
116         WorkArea * wa = workArea(*newBuffer);
117         if (wa == 0) {
118                 updateLabels(*newBuffer->getMasterBuffer());
119                 wa = addWorkArea(*newBuffer);
120         } else {
121                 //Disconnect the old buffer...there's no new one.
122                 disconnectBuffer();
123         }
124         connectBuffer(*newBuffer);
125         connectBufferView(wa->bufferView());
126         setCurrentWorkArea(wa);
127
128         busy(false);
129 }
130
131
132 Buffer * LyXView::loadLyXFile(FileName const & filename, bool tolastfiles)
133 {
134         busy(true);
135
136         Buffer * newBuffer = checkAndLoadLyXFile(filename);
137
138         if (!newBuffer) {
139                 message(_("Document not loaded."));
140                 updateStatusBar();
141                 busy(false);
142                 return 0;
143         }
144
145         WorkArea * wa = workArea(*newBuffer);
146         if (wa == 0)
147                 wa = addWorkArea(*newBuffer);
148
149         // scroll to the position when the file was last closed
150         if (lyxrc.use_lastfilepos) {
151                 pit_type pit;
152                 pos_type pos;
153                 boost::tie(pit, pos) = LyX::ref().session().lastFilePos().load(filename);
154                 // if successfully move to pit (returned par_id is not zero),
155                 // update metrics and reset font
156                 wa->bufferView().moveToPosition(pit, pos, 0, 0);
157         }
158
159         if (tolastfiles)
160                 LyX::ref().session().lastFiles().add(filename);
161
162         busy(false);
163         return newBuffer;
164 }
165
166
167 void LyXView::connectBuffer(Buffer & buf)
168 {
169         if (errorsConnection_.connected())
170                 disconnectBuffer();
171
172         bufferStructureChangedConnection_ =
173                 buf.getMasterBuffer()->structureChanged.connect(
174                         boost::bind(&LyXView::updateToc, this));
175
176         bufferEmbeddingChangedConnection_ =
177                 buf.embeddingChanged.connect(
178                         boost::bind(&LyXView::updateEmbeddedFiles, this));
179
180         errorsConnection_ =
181                 buf.errors.connect(
182                         boost::bind(&LyXView::showErrorList, this, _1));
183
184         messageConnection_ =
185                 buf.message.connect(
186                         boost::bind(&LyXView::message, this, _1));
187
188         busyConnection_ =
189                 buf.busy.connect(
190                         boost::bind(&LyXView::busy, this, _1));
191
192         titleConnection_ =
193                 buf.updateTitles.connect(
194                         boost::bind(&LyXView::updateWindowTitle, this));
195
196         timerConnection_ =
197                 buf.resetAutosaveTimers.connect(
198                         boost::bind(&LyXView::resetAutosaveTimer, this));
199
200         readonlyConnection_ =
201                 buf.readonly.connect(
202                         boost::bind(&LyXView::showReadonly, this, _1));
203 }
204
205
206 void LyXView::disconnectBuffer()
207 {
208         errorsConnection_.disconnect();
209         bufferStructureChangedConnection_.disconnect();
210         bufferEmbeddingChangedConnection_.disconnect();
211         messageConnection_.disconnect();
212         busyConnection_.disconnect();
213         titleConnection_.disconnect();
214         timerConnection_.disconnect();
215         readonlyConnection_.disconnect();
216         layout_changed_connection_.disconnect();
217 }
218
219
220 void LyXView::connectBufferView(BufferView & bv)
221 {
222         message_connection_ = bv.message.connect(
223                         boost::bind(&LyXView::message, this, _1));
224         show_dialog_connection_ = bv.showDialog.connect(
225                         boost::bind(&LyXView::showDialog, this, _1));
226         show_dialog_with_data_connection_ = bv.showDialogWithData.connect(
227                         boost::bind(&LyXView::showDialogWithData, this, _1, _2));
228         show_inset_dialog_connection_ = bv.showInsetDialog.connect(
229                         boost::bind(&LyXView::showInsetDialog, this, _1, _2, _3));
230         update_dialog_connection_ = bv.updateDialog.connect(
231                         boost::bind(&LyXView::updateDialog, this, _1, _2));
232         layout_changed_connection_ = bv.layoutChanged.connect(
233                         boost::bind(&Toolbars::setLayout, toolbars_, _1));
234 }
235
236
237 void LyXView::disconnectBufferView()
238 {
239         message_connection_.disconnect();
240         show_dialog_connection_.disconnect();
241         show_dialog_with_data_connection_.disconnect();
242         show_inset_dialog_connection_.disconnect();
243         update_dialog_connection_.disconnect();
244 }
245
246
247 void LyXView::showErrorList(string const & error_type)
248 {
249         ErrorList & el = buffer()->errorList(error_type);
250         if (!el.empty()) {
251                 getDialogs().show("errorlist", error_type);
252         }
253 }
254
255
256 void LyXView::showDialog(string const & name)
257 {
258         getDialogs().show(name);
259 }
260
261
262 void LyXView::showDialogWithData(string const & name, string const & data)
263 {
264         getDialogs().show(name, data);
265 }
266
267
268 void LyXView::showInsetDialog(string const & name, string const & data,
269                 Inset * inset)
270 {
271         getDialogs().show(name, data, inset);
272 }
273
274
275 void LyXView::updateDialog(string const & name, string const & data)
276 {
277         if (getDialogs().visible(name))
278                 getDialogs().update(name, data);
279 }
280
281
282 void LyXView::showReadonly(bool)
283 {
284         updateWindowTitle();
285         getDialogs().updateBufferDependent(false);
286 }
287
288
289 BufferView * LyXView::view()
290 {
291         WorkArea * wa = currentWorkArea();
292         return wa? &wa->bufferView() : 0;
293 }
294
295
296 void LyXView::updateToc()
297 {
298         updateDialog("toc", "");
299 }
300
301
302 void LyXView::updateEmbeddedFiles()
303 {
304         updateDialog("embedding", "");
305 }
306
307
308 void LyXView::updateToolbars()
309 {
310         WorkArea * wa = currentWorkArea();
311         if (wa) {
312                 bool const math =
313                         wa->bufferView().cursor().inMathed();
314                 bool const table =
315                         lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled();
316                 bool const review =
317                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() &&
318                         lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true);
319
320                 toolbars_->update(math, table, review);
321         } else
322                 toolbars_->update(false, false, false);
323
324         // update redaonly status of open dialogs.
325         getDialogs().checkStatus();
326 }
327
328
329 ToolbarInfo * LyXView::getToolbarInfo(string const & name)
330 {
331         return toolbars_->getToolbarInfo(name);
332 }
333
334
335 void LyXView::toggleToolbarState(string const & name, bool allowauto)
336 {
337         // it is possible to get current toolbar status like this,...
338         // but I decide to obey the order of ToolbarBackend::flags
339         // and disregard real toolbar status.
340         // toolbars_->saveToolbarInfo();
341         //
342         // toggle state on/off/auto
343         toolbars_->toggleToolbarState(name, allowauto);
344         // update toolbar
345         updateToolbars();
346 }
347
348
349 void LyXView::autoSave()
350 {
351         LYXERR(Debug::INFO) << "Running autoSave()" << endl;
352
353         if (buffer())
354                 lyx::autoSave(view());
355 }
356
357
358 void LyXView::resetAutosaveTimer()
359 {
360         if (lyxrc.autosave)
361                 autosave_timeout_->restart();
362 }
363
364
365 void LyXView::updateLayoutChoice()
366 {
367         // Don't show any layouts without a buffer
368         if (!buffer()) {
369                 toolbars_->clearLayoutList();
370                 return;
371         }
372
373         // Update the layout display
374         if (toolbars_->updateLayoutList(buffer()->params().getTextClassPtr())) {
375                 current_layout = buffer()->params().getTextClass().defaultLayoutName();
376         }
377
378         docstring const & layout = currentWorkArea()->bufferView().cursor().
379                 innerParagraph().layout()->name();
380
381         if (layout != current_layout) {
382                 toolbars_->setLayout(layout);
383                 current_layout = layout;
384         }
385 }
386
387
388 void LyXView::updateWindowTitle()
389 {
390         docstring maximize_title = from_ascii("LyX");
391         docstring minimize_title = from_ascii("LyX");
392
393         Buffer * buf = buffer();
394         if (buf) {
395                 string const cur_title = buf->fileName();
396                 if (!cur_title.empty()) {
397                         maximize_title += ": " + makeDisplayPath(cur_title, 30);
398                         minimize_title = lyx::from_utf8(onlyFilename(cur_title));
399                         if (!buf->isClean()) {
400                                 maximize_title += _(" (changed)");
401                                 minimize_title += char_type('*');
402                         }
403                         if (buf->isReadonly())
404                                 maximize_title += _(" (read only)");
405                 }
406         }
407
408         setWindowTitle(maximize_title, minimize_title);
409 }
410
411
412 void LyXView::dispatch(FuncRequest const & cmd)
413 {
414         string const argument = to_utf8(cmd.argument());
415         switch(cmd.action) {
416                 case LFUN_BUFFER_SWITCH:
417                         setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument())));
418                         break;
419                 default:
420                         theLyXFunc().setLyXView(this);
421                         lyx::dispatch(cmd);
422         }
423 }
424
425
426 Buffer const * LyXView::updateInset(Inset const * inset)
427 {
428         WorkArea * work_area = currentWorkArea();
429         if (!work_area)
430                 return 0;
431
432         if (inset) {
433                 BOOST_ASSERT(work_area);
434                 work_area->scheduleRedraw();
435         }
436         return &work_area->bufferView().buffer();
437 }
438
439
440 void LyXView::openLayoutList()
441 {
442         toolbars_->openLayoutList();
443 }
444
445
446 bool LyXView::isToolbarVisible(std::string const & id)
447 {
448         return toolbars_->visible(id);
449 }
450
451 } // namespace frontend
452 } // namespace lyx