- string fmt = appendix ?
- layout->labelstring_appendix() : layout->labelstring();
-
- // handle 'inherited level parts' in 'fmt',
- // i.e. the stuff between '@' in '@Section@.\arabic{subsection}'
- size_t const i = fmt.find('@', 0);
- if (i != string::npos) {
- size_t const j = fmt.find('@', i + 1);
- if (j != string::npos) {
- string parent(fmt, i + 1, j - i - 1);
- string label = expandLabel(textclass, textclass[parent], appendix);
- fmt = string(fmt, 0, i) + label + string(fmt, j + 1, string::npos);
- }
- }
-
- return textclass.counters().counterLabel(fmt);
-}
-
-
-namespace {
-
-void incrementItemDepth(ParagraphList::iterator pit,
- ParagraphList::iterator first_pit)
-{
- int const cur_labeltype = pit->layout()->labeltype;
-
- if (cur_labeltype != LABEL_ENUMERATE && cur_labeltype != LABEL_ITEMIZE)
- return;
-
- int const cur_depth = pit->getDepth();
-
- ParagraphList::iterator prev_pit = boost::prior(pit);
- while (true) {
- int const prev_depth = prev_pit->getDepth();
- int const prev_labeltype = prev_pit->layout()->labeltype;
- if (prev_depth == 0 && cur_depth > 0) {
- if (prev_labeltype == cur_labeltype) {
- pit->itemdepth = prev_pit->itemdepth + 1;
- }
- break;
- } else if (prev_depth < cur_depth) {
- if (prev_labeltype == cur_labeltype) {
- pit->itemdepth = prev_pit->itemdepth + 1;
- break;
- }
- } else if (prev_depth == cur_depth) {
- if (prev_labeltype == cur_labeltype) {
- pit->itemdepth = prev_pit->itemdepth;
- break;
- }
- }
- if (prev_pit == first_pit)
- break;
-
- --prev_pit;
- }
-}
-
-
-void resetEnumCounterIfNeeded(ParagraphList::iterator pit,
- ParagraphList::iterator firstpit,
- Counters & counters)
-{
- if (pit == firstpit)
- return;
-
- int const cur_depth = pit->getDepth();
- ParagraphList::iterator prev_pit = boost::prior(pit);
- while (true) {
- int const prev_depth = prev_pit->getDepth();
- int const prev_labeltype = prev_pit->layout()->labeltype;
- if (prev_depth <= cur_depth) {
- if (prev_labeltype != LABEL_ENUMERATE) {
- switch (pit->itemdepth) {
- case 0:
- counters.reset("enumi");
- case 1:
- counters.reset("enumii");
- case 2:
- counters.reset("enumiii");
- case 3:
- counters.reset("enumiv");
- }
- }
- break;
- }
-
- if (prev_pit == firstpit)
- break;
-
- --prev_pit;
- }
-}
-
-} // anon namespace
-
-
-// set the counter of a paragraph. This includes the labels
-void LyXText::setCounter(Buffer const & buf, ParagraphList::iterator pit)
-{
- BufferParams const & bufparams = buf.params();
- LyXTextClass const & textclass = bufparams.getLyXTextClass();
- LyXLayout_ptr const & layout = pit->layout();
- ParagraphList::iterator first_pit = paragraphs().begin();
- Counters & counters = textclass.counters();
-
- // Always reset
- pit->itemdepth = 0;
-
- if (pit == first_pit) {
- pit->params().appendix(pit->params().startOfAppendix());
- } else {
- pit->params().appendix(boost::prior(pit)->params().appendix());
- if (!pit->params().appendix() &&
- pit->params().startOfAppendix()) {
- pit->params().appendix(true);
- textclass.counters().reset();
- }
-
- // Maybe we have to increment the item depth.
- incrementItemDepth(pit, first_pit);
- }
-
- // erase what was there before
- pit->params().labelString(string());
-
- if (layout->margintype == MARGIN_MANUAL) {
- if (pit->params().labelWidthString().empty())
- pit->setLabelWidthString(layout->labelstring());
- } else {
- pit->setLabelWidthString(string());
- }
-
- // is it a layout that has an automatic label?
- if (layout->labeltype == LABEL_COUNTER) {
- BufferParams const & bufparams = buf.params();
- LyXTextClass const & textclass = bufparams.getLyXTextClass();
- counters.step(layout->counter);
- string label = expandLabel(textclass, layout, pit->params().appendix());
- pit->params().labelString(label);
- } else if (layout->labeltype == LABEL_ITEMIZE) {
- // At some point of time we should do something more
- // clever here, like:
- // pit->params().labelString(
- // bufparams.user_defined_bullet(pit->itemdepth).getText());
- // for now, use a simple hardcoded label
- string itemlabel;
- switch (pit->itemdepth) {
- case 0:
- itemlabel = "*";
- break;
- case 1:
- itemlabel = "-";
- break;
- case 2:
- itemlabel = "@";
- break;
- case 3:
- itemlabel = "·";
- break;
- }
-
- pit->params().labelString(itemlabel);
- } else if (layout->labeltype == LABEL_ENUMERATE) {
- // Maybe we have to reset the enumeration counter.
- resetEnumCounterIfNeeded(pit, first_pit, counters);
-
- // FIXME
- // Yes I know this is a really, really! bad solution
- // (Lgb)
- string enumcounter = "enum";
-
- switch (pit->itemdepth) {
- case 2:
- enumcounter += 'i';
- case 1:
- enumcounter += 'i';
- case 0:
- enumcounter += 'i';
- break;
- case 3:
- enumcounter += "iv";
- break;
- default:
- // not a valid enumdepth...
- break;
- }
-
- counters.step(enumcounter);
-
- pit->params().labelString(counters.enumLabel(enumcounter));
- } else if (layout->labeltype == LABEL_BIBLIO) {// ale970302
- counters.step("bibitem");
- int number = counters.value("bibitem");
- if (pit->bibitem()) {
- pit->bibitem()->setCounter(number);
- pit->params().labelString(layout->labelstring());
- }
- // In biblio should't be following counters but...
- } else {
- string s = buf.B_(layout->labelstring());
-
- // the caption hack:
- if (layout->labeltype == LABEL_SENSITIVE) {
- ParagraphList::iterator end = paragraphs().end();
- ParagraphList::iterator tmppit = pit;
- InsetOld * in = 0;
- bool isOK = false;
- while (tmppit != end && tmppit->inInset()
- // the single '=' is intended below
- && (in = tmppit->inInset()->owner()))
- {
- if (in->lyxCode() == InsetOld::FLOAT_CODE ||
- in->lyxCode() == InsetOld::WRAP_CODE) {
- isOK = true;
- break;
- } else {
- Paragraph const * owner = &ownerPar(buf, in);
- tmppit = first_pit;
- for ( ; tmppit != end; ++tmppit)
- if (&*tmppit == owner)
- break;
- }
- }
-
- if (isOK) {
- string type;
-
- if (in->lyxCode() == InsetOld::FLOAT_CODE)
- type = static_cast<InsetFloat*>(in)->params().type;
- else if (in->lyxCode() == InsetOld::WRAP_CODE)
- type = static_cast<InsetWrap*>(in)->params().type;
- else
- BOOST_ASSERT(false);
-
- Floating const & fl = textclass.floats().getType(type);
-
- counters.step(fl.type());
-
- // Doesn't work... yet.
- s = bformat(_("%1$s #:"), buf.B_(fl.name()));
- } else {
- // par->SetLayout(0);
- // s = layout->labelstring;
- s = _("Senseless: ");
- }
- }
- pit->params().labelString(s);
-
- }
-}
-
-
-// Updates all counters.
-void LyXText::updateCounters()
-{
- // start over
- bv()->buffer()->params().getLyXTextClass().counters().reset();
-
- bool update_pos = false;
-
- ParagraphList::iterator beg = paragraphs().begin();
- ParagraphList::iterator end = paragraphs().end();
- for (ParagraphList::iterator pit = beg; pit != end; ++pit) {
- string const oldLabel = pit->params().labelString();
- size_t maxdepth = 0;
- if (pit != beg)
- maxdepth = boost::prior(pit)->getMaxDepthAfter();
-
- if (pit->params().depth() > maxdepth)
- pit->params().depth(maxdepth);
-
- // setCounter can potentially change the labelString.
- setCounter(*bv()->buffer(), pit);
- string const & newLabel = pit->params().labelString();
- if (oldLabel != newLabel) {
- redoParagraphInternal(pit);
- update_pos = true;
- }
-
- }
- if (update_pos)
- updateParPositions();
-}
-
-
-void LyXText::insertInset(InsetOld * inset)
-{
- if (!cursorPar()->insetAllowed(inset->lyxCode()))
- return;
-
- recUndo(cursor().par());
- freezeUndo();
- cursorPar()->insertInset(cursor().pos(), inset);
- // Just to rebreak and refresh correctly.
- // The character will not be inserted a second time
- insertChar(Paragraph::META_INSET);
- // If we enter a highly editable inset the cursor should be before
- // the inset. After an undo LyX tries to call inset->edit(...)
- // and fails if the cursor is behind the inset and getInset
- // does not return the inset!
- if (isHighlyEditableInset(inset))
- cursorLeft(true);
-
- unFreezeUndo();
-}
-
-
-void LyXText::cutSelection(bool doclear, bool realcut)
-{
- // Stuff what we got on the clipboard. Even if there is no selection.
-
- // There is a problem with having the stuffing here in that the
- // larger the selection the slower LyX will get. This can be
- // solved by running the line below only when the selection has
- // finished. The solution used currently just works, to make it
- // faster we need to be more clever and probably also have more
- // calls to stuffClipboard. (Lgb)
- bv()->stuffClipboard(selectionAsString(*bv()->buffer(), true));
-
- // This doesn't make sense, if there is no selection
- if (!bv()->selection().set())
- return;
-
- // OK, we have a selection. This is always between bv()->selStart()
- // and bv()->selEnd()
-
- // make sure that the depth behind the selection are restored, too
- ParagraphList::iterator begpit = getPar(bv()->selStart().par());
- ParagraphList::iterator endpit = getPar(bv()->selEnd().par());
- ParagraphList::iterator undopit = undoSpan(endpit);
- recUndo(bv()->selStart().par(), parOffset(undopit) - 1);
-
- int endpos = bv()->selEnd().pos();
-
- BufferParams const & bufparams = bv()->buffer()->params();
- boost::tie(endpit, endpos) = realcut ?
- CutAndPaste::cutSelection(bufparams,
- paragraphs(),
- begpit , endpit,
- bv()->selStart().pos(), endpos,
- bufparams.textclass,
- doclear)
- : CutAndPaste::eraseSelection(bufparams,
- paragraphs(),
- begpit, endpit,
- bv()->selStart().pos(), endpos,
- doclear);
- // sometimes necessary
- if (doclear)
- begpit->stripLeadingSpaces();
-
- redoParagraphs(begpit, undopit);
- // cutSelection can invalidate the cursor so we need to set
- // it anew. (Lgb)
- // we prefer the end for when tracking changes
- cursor().pos(endpos);
- cursor().par(parOffset(endpit));
-
- // need a valid cursor. (Lgb)
- clearSelection();
- updateCounters();
-}
-
-
-void LyXText::copySelection()
-{
- // stuff the selection onto the X clipboard, from an explicit copy request
- bv()->stuffClipboard(selectionAsString(*bv()->buffer(), true));
-
- // this doesnt make sense, if there is no selection
- if (!bv()->selection().set())
- return;
-
- // ok we have a selection. This is always between bv()->selStart()
- // and sel_end cursor
-
- // copy behind a space if there is one
- while (getPar(bv()->selStart())->size() > bv()->selStart().pos()
- && getPar(bv()->selStart())->isLineSeparator(bv()->selStart().pos())
- && (bv()->selStart().par() != bv()->selEnd().par()
- || bv()->selStart().pos() < bv()->selEnd().pos()))
- bv()->selStart().pos(bv()->selStart().pos() + 1);
-
- CutAndPaste::copySelection(getPar(bv()->selStart().par()),
- getPar(bv()->selEnd().par()),
- bv()->selStart().pos(),
- bv()->selEnd().pos(),
- bv()->buffer()->params().textclass);
-}
-
-
-void LyXText::pasteSelection(size_t sel_index)
-{
- // this does not make sense, if there is nothing to paste
- if (!CutAndPaste::checkPastePossible())
- return;
-
- recUndo(cursor().par());
-
- ParagraphList::iterator endpit;
- PitPosPair ppp;
-
- ErrorList el;
-
- boost::tie(ppp, endpit) =
- CutAndPaste::pasteSelection(*bv()->buffer(),
- paragraphs(),
- cursorPar(), cursor().pos(),
- bv()->buffer()->params().textclass,
- sel_index, el);
- bufferErrors(*bv()->buffer(), el);
- bv()->showErrorList(_("Paste"));
-
- redoParagraphs(cursorPar(), endpit);
-
- clearSelection();
-
- bv()->resetAnchor();
- setCursor(ppp.first, ppp.second);
- setSelection();
- updateCounters();
-}
-
-
-void LyXText::setSelectionRange(lyx::pos_type length)
-{
- if (!length)
- return;
-
- bv()->resetAnchor();
- while (length--)
- cursorRight(true);
- setSelection();
-}
-
-
-// simple replacing. The font of the first selected character is used
-void LyXText::replaceSelectionWithString(string const & str)
-{
- recUndo(cursor().par());
- freezeUndo();
-
- // Get font setting before we cut
- pos_type pos = bv()->selEnd().pos();
- LyXFont const font = getPar(bv()->selStart())
- ->getFontSettings(bv()->buffer()->params(),
- bv()->selStart().pos());
-
- // Insert the new string
- string::const_iterator cit = str.begin();
- string::const_iterator end = str.end();
- for (; cit != end; ++cit) {
- getPar(bv()->selEnd())->insertChar(pos, (*cit), font);
- ++pos;
- }
-
- // Cut the selection
- cutSelection(true, false);
-
- unFreezeUndo();