]> git.lyx.org Git - lyx.git/blob - src/BufferView.C
0517a129fae4c5b1a4378a2cf8c1de45ab106acd
[lyx.git] / src / BufferView.C
1 /**
2  * \file BufferView.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braustein
7  * \author Lars Gullik Bjønnes
8  * \author John Levon
9  * \author André Pönitz
10  * \author Jürgen Vigna
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "BufferView.h"
18 #include "buffer.h"
19 #include "bufferlist.h"
20 #include "BufferView_pimpl.h"
21 #include "funcrequest.h"
22 #include "gettext.h"
23 #include "iterators.h"
24 #include "language.h"
25 #include "lyxlayout.h"
26 #include "lyxtext.h"
27 #include "paragraph.h"
28 #include "paragraph_funcs.h"
29 #include "texrow.h"
30 #include "undo_funcs.h"
31 #include "WordLangTuple.h"
32
33 #include "frontends/Alert.h"
34 #include "frontends/Dialogs.h"
35 #include "frontends/LyXView.h"
36 #include "frontends/screen.h"
37 #include "frontends/WorkArea.h"
38
39 #include "insets/insetcommand.h" // ChangeRefs
40 #include "insets/updatableinset.h"
41
42 #include "support/filetools.h"
43 #include "support/lyxalgo.h" // lyx_count
44
45
46 extern BufferList bufferlist;
47
48 using namespace lyx::support;
49
50 using std::find;
51 using std::vector;
52
53
54 BufferView::BufferView(LyXView * owner, int xpos, int ypos,
55                        int width, int height)
56         : pimpl_(new Pimpl(this, owner, xpos, ypos, width, height))
57 {
58         text = 0;
59 }
60
61
62 BufferView::~BufferView()
63 {
64         delete text;
65         delete pimpl_;
66 }
67
68
69 Buffer * BufferView::buffer() const
70 {
71         return pimpl_->buffer_;
72 }
73
74
75 LyXScreen & BufferView::screen() const
76 {
77         return pimpl_->screen();
78 }
79
80
81 LyXView * BufferView::owner() const
82 {
83         return pimpl_->owner_;
84 }
85
86
87 Painter & BufferView::painter() const
88 {
89         return pimpl_->painter();
90 }
91
92
93 void BufferView::buffer(Buffer * b)
94 {
95         pimpl_->buffer(b);
96 }
97
98
99 bool BufferView::newFile(string const & fn, string const & tn, bool named)
100 {
101         return pimpl_->newFile(fn, tn, named);
102 }
103
104
105 bool BufferView::loadLyXFile(string const & fn, bool tl)
106 {
107         return pimpl_->loadLyXFile(fn, tl);
108 }
109
110
111 void BufferView::reload()
112 {
113         string const fn = buffer()->fileName();
114         if (bufferlist.close(buffer(), false))
115                 loadLyXFile(fn);
116 }
117
118
119 void BufferView::resize()
120 {
121         if (pimpl_->buffer_)
122                 pimpl_->resizeCurrentBuffer();
123 }
124
125
126 bool BufferView::fitCursor()
127 {
128         return pimpl_->fitCursor();
129 }
130
131
132 void BufferView::update()
133 {
134         pimpl_->update();
135 }
136
137
138 void BufferView::updateScrollbar()
139 {
140         pimpl_->updateScrollbar();
141 }
142
143
144 void BufferView::scrollDocView(int value)
145 {
146         pimpl_->scrollDocView(value);
147 }
148
149
150 void BufferView::redoCurrentBuffer()
151 {
152         pimpl_->redoCurrentBuffer();
153 }
154
155
156 bool BufferView::available() const
157 {
158         return pimpl_->available();
159 }
160
161
162 Change const BufferView::getCurrentChange()
163 {
164         return pimpl_->getCurrentChange();
165 }
166
167
168 void BufferView::beforeChange(LyXText * text)
169 {
170         pimpl_->beforeChange(text);
171 }
172
173
174 void BufferView::savePosition(unsigned int i)
175 {
176         pimpl_->savePosition(i);
177 }
178
179
180 void BufferView::restorePosition(unsigned int i)
181 {
182         pimpl_->restorePosition(i);
183 }
184
185
186 bool BufferView::isSavedPosition(unsigned int i)
187 {
188         return pimpl_->isSavedPosition(i);
189 }
190
191
192 void BufferView::switchKeyMap()
193 {
194         pimpl_->switchKeyMap();
195 }
196
197
198 void BufferView::insetUnlock()
199 {
200         pimpl_->insetUnlock();
201 }
202
203
204 int BufferView::workWidth() const
205 {
206         return pimpl_->workarea().workWidth();
207 }
208
209
210 void BufferView::center()
211 {
212         pimpl_->center();
213 }
214
215
216 int BufferView::top_y() const
217 {
218         return pimpl_->top_y();
219 }
220
221
222 void BufferView::top_y(int y)
223 {
224         pimpl_->top_y(y);
225 }
226
227
228 string const BufferView::getClipboard() const
229 {
230         return pimpl_->workarea().getClipboard();
231 }
232
233
234 void BufferView::stuffClipboard(string const & stuff) const
235 {
236         pimpl_->stuffClipboard(stuff);
237 }
238
239
240 bool BufferView::dispatch(FuncRequest const & ev)
241 {
242         return pimpl_->dispatch(ev);
243 }
244
245
246 void BufferView::scroll(int lines)
247 {
248         pimpl_->scroll(lines);
249 }
250
251
252 // Inserts a file into current document
253 bool BufferView::insertLyXFile(string const & filen)
254         //
255         // Copyright CHT Software Service GmbH
256         // Uwe C. Schroeder
257         //
258         // Insert a LyXformat - file into current buffer
259         //
260         // Moved from lyx_cb.C (Lgb)
261 {
262         BOOST_ASSERT(!filen.empty());
263
264         string const fname = MakeAbsPath(filen);
265
266         beforeChange(text);
267
268         text->breakParagraph(buffer()->paragraphs());
269
270         bool res = buffer()->readFile(fname, text->cursor.par());
271
272         resize();
273         return res;
274 }
275
276
277 void BufferView::showErrorList(string const & action) const
278 {
279         if (getErrorList().size()) {
280                 string const title = bformat(_("LyX: %1$s errors (%2$s)"), action, buffer()->fileName());
281                 owner()->getDialogs().show("errorlist", title);
282                 pimpl_->errorlist_.clear();
283         }
284 }
285
286
287 ErrorList const &
288 BufferView::getErrorList() const
289 {
290         return pimpl_->errorlist_;
291 }
292
293
294 void BufferView::setCursorFromRow(int row)
295 {
296         int tmpid = -1;
297         int tmppos = -1;
298
299         buffer()->texrow().getIdFromRow(row, tmpid, tmppos);
300
301         ParagraphList::iterator texrowpar;
302
303         if (tmpid == -1) {
304                 texrowpar = text->ownerParagraphs().begin();
305                 tmppos = 0;
306         } else {
307                 texrowpar = buffer()->getParFromID(tmpid).pit();
308         }
309         text->setCursor(texrowpar, tmppos);
310 }
311
312
313 bool BufferView::insertInset(InsetOld * inset, string const & lout)
314 {
315         return pimpl_->insertInset(inset, lout);
316 }
317
318
319 void BufferView::gotoLabel(string const & label)
320 {
321         for (Buffer::inset_iterator it = buffer()->inset_iterator_begin();
322              it != buffer()->inset_iterator_end(); ++it) {
323                 vector<string> labels;
324                 it->getLabelList(labels);
325                 if (find(labels.begin(),labels.end(),label) != labels.end()) {
326                         beforeChange(text);
327                         text->setCursor(it.getPar(), it.getPos());
328                         text->selection.cursor = text->cursor;
329                         update();
330                         return;
331                 }
332         }
333 }
334
335
336 void BufferView::undo()
337 {
338         if (!available())
339                 return;
340
341         owner()->message(_("Undo"));
342         beforeChange(text);
343         if (!textUndo(this))
344                 owner()->message(_("No further undo information"));
345         update();
346         switchKeyMap();
347 }
348
349
350 void BufferView::redo()
351 {
352         if (!available())
353                 return;
354
355         owner()->message(_("Redo"));
356         beforeChange(text);
357         if (!textRedo(this))
358                 owner()->message(_("No further redo information"));
359         update();
360         switchKeyMap();
361 }
362
363
364 // these functions are for the spellchecker
365 WordLangTuple const BufferView::nextWord(float & value)
366 {
367         if (!available()) {
368                 value = 1;
369                 return WordLangTuple();
370         }
371
372         return text->selectNextWordToSpellcheck(value);
373 }
374
375
376 void BufferView::selectLastWord()
377 {
378         if (!available())
379                 return;
380
381         LyXCursor cur = text->selection.cursor;
382         beforeChange(text);
383         text->selection.cursor = cur;
384         text->selectSelectedWord();
385         update();
386 }
387
388
389 void BufferView::endOfSpellCheck()
390 {
391         if (!available()) return;
392
393         beforeChange(text);
394         text->selectSelectedWord();
395         text->clearSelection();
396         update();
397 }
398
399
400 void BufferView::replaceWord(string const & replacestring)
401 {
402         if (!available())
403                 return;
404
405         LyXText * tt = getLyXText();
406
407         tt->replaceSelectionWithString(replacestring);
408         tt->setSelectionRange(replacestring.length());
409
410         // Go back so that replacement string is also spellchecked
411         for (string::size_type i = 0; i < replacestring.length() + 1; ++i)
412                 tt->cursorLeft(this);
413
414         // FIXME: should be done through LFUN
415         buffer()->markDirty();
416         update();
417 }
418
419
420 bool BufferView::lockInset(UpdatableInset * inset)
421 {
422         if (!inset)
423                 return false;
424         // don't relock if we're already locked
425         if (theLockingInset() == inset)
426                 return true;
427         if (!theLockingInset()) {
428                 // first check if it's the inset under the cursor we want lock
429                 // should be most of the time
430                 if (text->cursor.pos() < text->cursor.par()->size()
431                     && text->cursor.par()->getChar(text->cursor.pos()) ==
432                     Paragraph::META_INSET) {
433                         InsetOld * in = text->cursor.par()->getInset(text->cursor.pos());
434                         if (inset == in) {
435                                 theLockingInset(inset);
436                                 return true;
437                         }
438                 }
439                 // Then do a deep look of the inset and lock the right one
440                 int const id = inset->id();
441                 ParagraphList::iterator pit = buffer()->paragraphs().begin();
442                 ParagraphList::iterator pend = buffer()->paragraphs().end();
443                 for (; pit != pend; ++pit) {
444                         InsetList::iterator it = pit->insetlist.begin();
445                         InsetList::iterator end = pit->insetlist.end();
446                         for (; it != end; ++it) {
447                                 if (it->inset == inset) {
448                                         text->setCursorIntern(pit, it->pos);
449                                         theLockingInset(inset);
450                                         return true;
451                                 }
452                                 if (it->inset->getInsetFromID(id)) {
453                                         text->setCursorIntern(pit, it->pos);
454                                         FuncRequest cmd(this, LFUN_INSET_EDIT, "left");
455                                         it->inset->localDispatch(cmd);
456                                         return theLockingInset()->lockInsetInInset(this, inset);
457                                 }
458                         }
459                 }
460                 return false;
461         }
462         return theLockingInset()->lockInsetInInset(this, inset);
463 }
464
465
466 bool BufferView::fitLockedInsetCursor(int x, int y, int asc, int desc)
467 {
468         if (theLockingInset() && available()) {
469                 y += text->cursor.y() + theLockingInset()->insetInInsetY();
470                 if (screen().fitManualCursor(this, text, x, y, asc, desc)) {
471                         updateScrollbar();
472                         return true;
473                 }
474         }
475         return false;
476 }
477
478
479 void BufferView::hideCursor()
480 {
481         screen().hideCursor();
482 }
483
484
485 int BufferView::unlockInset(UpdatableInset * inset)
486 {
487         if (!inset)
488                 return 0;
489         if (inset && theLockingInset() == inset) {
490                 inset->insetUnlock(this);
491                 theLockingInset(0);
492                 // make sure we update the combo !
493                 owner()->setLayout(getLyXText()->cursor.par()->layout()->name());
494                 // Tell the paragraph dialog that we changed paragraph
495                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
496                 finishUndo();
497                 return 0;
498         } else if (inset && theLockingInset() &&
499                    theLockingInset()->unlockInsetInInset(this, inset)) {
500                 // Tell the paragraph dialog that we changed paragraph
501                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
502                 // owner inset has updated the layout combo
503                 finishUndo();
504                 return 0;
505         }
506         return 1;
507 }
508
509
510 void BufferView::updateInset(InsetOld const * inset)
511 {
512         pimpl_->updateInset(inset);
513 }
514
515
516 bool BufferView::ChangeRefsIfUnique(string const & from, string const & to)
517 {
518         // Check if the label 'from' appears more than once
519         vector<string> labels;
520         buffer()->getLabelList(labels);
521
522         if (lyx::count(labels.begin(), labels.end(), from) > 1)
523                 return false;
524
525         return pimpl_->ChangeInsets(InsetOld::REF_CODE, from, to);
526 }
527
528
529 UpdatableInset * BufferView::theLockingInset() const
530 {
531         // If NULL is not allowed we should put an Assert here. (Lgb)
532         if (text)
533                 return text->the_locking_inset;
534         return 0;
535 }
536
537
538 void BufferView::theLockingInset(UpdatableInset * inset)
539 {
540         text->the_locking_inset = inset;
541 }
542
543
544 LyXText * BufferView::getLyXText() const
545 {
546         if (theLockingInset()) {
547                 LyXText * txt = theLockingInset()->getLyXText(this, true);
548                 if (txt)
549                         return txt;
550         }
551         return text;
552 }
553
554
555 Language const * BufferView::getParentLanguage(InsetOld * inset) const
556 {
557         Paragraph const & par = ownerPar(*buffer(), inset);
558         return par.getFontSettings(buffer()->params(),
559                                    par.getPositionOfInset(inset)).language();
560 }
561
562
563 Encoding const * BufferView::getEncoding() const
564 {
565         LyXText * t = getLyXText();
566         if (!t)
567                 return 0;
568
569         LyXCursor const & c = t->cursor;
570         LyXFont const font = c.par()->getFont(buffer()->params(), c.pos(),
571                                               outerFont(c.par(), t->ownerParagraphs()));
572         return font.language()->encoding();
573 }
574
575
576 void BufferView::haveSelection(bool sel)
577 {
578         pimpl_->workarea().haveSelection(sel);
579 }
580
581
582 int BufferView::workHeight() const
583 {
584         return pimpl_->workarea().workHeight();
585 }