#include "support/lassert.h"
#include "support/limited_stack.h"
#include "support/lstrings.h"
+#include "support/lyxalgo.h"
+#include "support/TempFile.h"
#include "frontends/alert.h"
#include "frontends/Clipboard.h"
#include "frontends/Selection.h"
#include <boost/tuple/tuple.hpp>
-#include <boost/next_prior.hpp>
#include <string>
pit_type pit = cur.pit();
pos_type pos = cur.pos();
bool need_update = false;
+
+ if (parlist.empty())
+ return PasteReturnValue(pit, pos, need_update);
+
InsetText * target_inset = cur.inset().asInsetText();
if (!target_inset) {
InsetTabular * it = cur.inset().asInsetTabular();
- target_inset = it? it->cell(cur.idx())->asInsetText() : 0;
+ target_inset = it ? it->cell(cur.idx())->asInsetText() : 0;
}
LASSERT(target_inset, return PasteReturnValue(pit, pos, need_update));
- ParagraphList & pars = target_inset->paragraphs();
- if (parlist.empty())
- return PasteReturnValue(pit, pos, need_update);
-
- BOOST_ASSERT (pos <= pars[pit].size());
+ ParagraphList & pars = target_inset->paragraphs();
+ LASSERT(pos <= pars[pit].size(),
+ return PasteReturnValue(pit, pos, need_update));
// Make a copy of the CaP paragraphs.
ParagraphList insertion = parlist;
- DocumentClassConstPtr newDocClass = buffer.params().documentClassPtr();
// Now remove all out of the pars which is NOT allowed in the
// new environment and set also another font if that is required.
}
// set the paragraphs to plain layout if necessary
+ DocumentClassConstPtr newDocClass = buffer.params().documentClassPtr();
if (cur.inset().usePlainLayout()) {
bool forcePlainLayout = cur.inset().forcePlainLayout();
Layout const & plainLayout = newDocClass->plainLayout();
if (forcePlainLayout || parLayout == defaultLayout)
par->setLayout(plainLayout);
}
- } else { // check if we need to reset from plain layout
+ } else {
+ // check if we need to reset from plain layout
Layout const & defaultLayout = newDocClass->defaultLayout();
Layout const & plainLayout = newDocClass->plainLayout();
ParagraphList::iterator const end = insertion.end();
if (tmpbuf->params().depth() > max_depth)
tmpbuf->params().depth(max_depth);
- // Only set this from the 2nd on as the 2nd depends
- // for maxDepth still on pit.
- if (tmpbuf != insertion.begin())
- max_depth = tmpbuf->getMaxDepthAfter();
+ // Set max_depth for the next paragraph
+ max_depth = tmpbuf->getMaxDepthAfter();
// Set the inset owner of this paragraph.
tmpbuf->setInsetOwner(target_inset);
tmpbuf->eraseChar(i--, false);
}
- tmpbuf->setChange(Change(buffer.params().trackChanges ?
+ tmpbuf->setChange(Change(buffer.params().track_changes ?
Change::INSERTED : Change::UNCHANGED));
}
// Paste it!
if (empty) {
- pars.insert(boost::next(pars.begin(), pit),
+ pars.insert(next(pars.begin(), pit),
insertion.begin(),
insertion.end());
mergeParagraph(buffer.params(), pars,
pit + insertion.size() - 1);
} else {
- pars.insert(boost::next(pars.begin(), pit + 1),
+ pars.insert(next(pars.begin(), pit + 1),
insertion.begin(),
insertion.end());
pars[last_paste].makeSameLayout(pars[last_paste + 1]);
mergeParagraph(buffer.params(), pars, last_paste);
} else {
- pars[last_paste + 1].stripLeadingSpaces(buffer.params().trackChanges);
+ pars[last_paste + 1].stripLeadingSpaces(buffer.params().track_changes);
++last_paste;
}
}
// Start and end is inside same paragraph
if (endpit == pit_type(pars.size()) || startpit == endpit) {
- endpos -= pars[startpit].eraseChars(startpos, endpos, params.trackChanges);
+ endpos -= pars[startpit].eraseChars(startpos, endpos, params.track_changes);
return PitPosPair(endpit, endpos);
}
for (pit_type pit = startpit; pit != endpit + 1;) {
pos_type const left = (pit == startpit ? startpos : 0);
pos_type right = (pit == endpit ? endpos : pars[pit].size() + 1);
- bool const merge = pars[pit].isMergedOnEndOfParDeletion(params.trackChanges);
+ bool const merge = pars[pit].isMergedOnEndOfParDeletion(params.track_changes);
// Logically erase only, including the end-of-paragraph character
- pars[pit].eraseChars(left, right, params.trackChanges);
+ pars[pit].eraseChars(left, right, params.track_changes);
// Separate handling of paragraph break:
if (merge && pit != endpit &&
}
-void putClipboard(ParagraphList const & paragraphs,
- DocumentClassConstPtr docclass, docstring const & plaintext)
+Buffer * copyToTempBuffer(ParagraphList const & paragraphs, DocumentClassConstPtr docclass)
{
// This used to need to be static to avoid a memory leak. It no longer needs
// to be so, but the alternative is to construct a new one of these (with a
// new temporary directory, etc) every time, and then to destroy it. So maybe
// it's worth just keeping this one around.
+ // FIXME THREAD
+ static TempFile tempfile("clipboard.internal");
+ tempfile.setAutoRemove(false);
static Buffer * staticbuffer = theBufferList().newInternalBuffer(
- FileName::tempName("clipboard.internal").absFileName());
+ tempfile.name().absFileName());
// These two things only really need doing the first time.
staticbuffer->setUnnamed(true);
// Use a clone for the complicated stuff so that we do not need to clean
// up in order to avoid a crash.
Buffer * buffer = staticbuffer->cloneBufferOnly();
- LASSERT(buffer, return);
+ LASSERT(buffer, return 0);
// This needs doing every time.
+ // Since setDocumentClass() causes deletion of the old document class
+ // we need to reset all layout pointers in paragraphs (otherwise they
+ // would be dangling).
+ ParIterator const end = buffer->par_iterator_end();
+ for (ParIterator it = buffer->par_iterator_begin(); it != end; ++it) {
+ docstring const name = it->layout().name();
+ if (docclass->hasLayout(name))
+ it->setLayout((*docclass)[name]);
+ else
+ it->setPlainOrDefaultLayout(*docclass);
+ }
buffer->params().setDocumentClass(docclass);
// we will use pasteSelectionHelper to copy the paragraphs into the
ErrorList el;
pasteSelectionHelper(dit, paragraphs, docclass, buffer, el);
+ return buffer;
+}
+
+
+void putClipboard(ParagraphList const & paragraphs,
+ DocumentClassConstPtr docclass, docstring const & plaintext)
+{
+ Buffer * buffer = copyToTempBuffer(paragraphs, docclass);
+ if (!buffer) // already asserted in copyToTempBuffer()
+ return;
+
// We don't want to produce images that are not used. Therefore,
// output formulas as MathML. Even if this is not understood by all
// applications, the number that can parse it should go up in the future.
OutputParams runparams(encodings.fromLyXName("utf8"));
// We do not need to produce images, etc.
runparams.dryrun = true;
+ // We are not interested in errors (bug 8866)
+ runparams.silent = true;
buffer->writeLyXHTMLSource(oshtml, runparams, Buffer::FullSource);
theClipboard().put(lyx, oshtml.str(), plaintext);
LASSERT(startpit != endpit || start <= end, return);
// Clone the paragraphs within the selection.
- ParagraphList copy_pars(boost::next(pars.begin(), startpit),
- boost::next(pars.begin(), endpit + 1));
+ ParagraphList copy_pars(next(pars.begin(), startpit),
+ next(pars.begin(), endpit + 1));
// Remove the end of the last paragraph; afterwards, remove the
// beginning of the first paragraph. Keep this order - there may only
it->setLayout(newtc[name]);
}
- // character styles
+ // character styles and hidden table cells
InsetIterator const i_end = inset_iterator_end(in);
for (InsetIterator it = inset_iterator_begin(in); it != i_end; ++it) {
- if (it->lyxCode() != FLEX_CODE)
+ InsetCode const code = it->lyxCode();
+ if (code == FLEX_CODE) {
// FIXME: Should we verify all InsetCollapsable?
- continue;
-
- docstring const layoutName = it->layoutName();
- docstring const & n = newone->insetLayout(layoutName).name();
- bool const is_undefined = n.empty() ||
- n == DocumentClass::plainInsetLayout().name();
- if (!is_undefined)
- continue;
-
- // The flex inset is undefined in newtc
- docstring const oldname = from_utf8(oldtc.name());
- docstring const newname = from_utf8(newtc.name());
- docstring s;
- if (oldname == newname)
- s = bformat(_("Flex inset %1$s is undefined after "
- "reloading `%2$s' layout."), layoutName, oldname);
- else
- s = bformat(_("Flex inset %1$s is undefined because of "
- "conversion from `%2$s' layout to `%3$s'."),
- layoutName, oldname, newname);
- // To warn the user that something had to be done.
- errorlist.push_back(ErrorItem(
- _("Undefined flex inset"),
- s, it.paragraph().id(), it.pos(), it.pos() + 1));
+ docstring const layoutName = it->layoutName();
+ docstring const & n = newone->insetLayout(layoutName).name();
+ bool const is_undefined = n.empty() ||
+ n == DocumentClass::plainInsetLayout().name();
+ if (!is_undefined)
+ continue;
+
+ // The flex inset is undefined in newtc
+ docstring const oldname = from_utf8(oldtc.name());
+ docstring const newname = from_utf8(newtc.name());
+ docstring s;
+ if (oldname == newname)
+ s = bformat(_("Flex inset %1$s is undefined after "
+ "reloading `%2$s' layout."), layoutName, oldname);
+ else
+ s = bformat(_("Flex inset %1$s is undefined because of "
+ "conversion from `%2$s' layout to `%3$s'."),
+ layoutName, oldname, newname);
+ // To warn the user that something had to be done.
+ errorlist.push_back(ErrorItem(
+ _("Undefined flex inset"),
+ s, it.paragraph().id(), it.pos(), it.pos() + 1));
+ } else if (code == TABULAR_CODE) {
+ // The recursion above does not catch paragraphs in "hidden" cells,
+ // i.e., ones that are part of a multirow or multicolum. So we need
+ // to handle those separately.
+ // This is the cause of bug #9049.
+ InsetTabular * table = it->asInsetTabular();
+ table->setLayoutForHiddenCells(newtc);
+ }
}
}
// we do not use cit-> here because gcc 2.9x does not
// like it (JMarc)
ParagraphList const & pars = (*cit).first;
- docstring asciiSel;
+ docstring textSel;
ParagraphList::const_iterator pit = pars.begin();
ParagraphList::const_iterator pend = pars.end();
for (; pit != pend; ++pit) {
- Paragraph par(*pit, 0, 26);
+ Paragraph par(*pit, 0, 46);
// adapt paragraph to current buffer.
par.setBuffer(const_cast<Buffer &>(*buf));
- asciiSel += par.asString(AS_STR_INSETS);
- if (asciiSel.size() > 25) {
- asciiSel.replace(22, docstring::npos,
- from_ascii("..."));
+ textSel += par.asString(AS_STR_INSETS);
+ if (textSel.size() > 45) {
+ support::truncateWithEllipsis(textSel,45);
break;
}
}
-
- selList.push_back(asciiSel);
+ selList.push_back(textSel);
}
return selList;
// sometimes necessary
if (doclear
- && text->paragraphs()[begpit].stripLeadingSpaces(bp.trackChanges))
+ && text->paragraphs()[begpit].stripLeadingSpaces(bp.track_changes))
cur.fixIfBroken();
// need a valid cursor. (Lgb)
}
-docstring selection(size_t sel_index)
+docstring selection(size_t sel_index, DocumentClassConstPtr docclass)
{
- return sel_index < theCuts.size()
- ? theCuts[sel_index].first.back().asString(AS_STR_INSETS | AS_STR_NEWLINES)
- : docstring();
+ if (sel_index >= theCuts.size())
+ return docstring();
+
+ boost::scoped_ptr<Buffer> buffer(copyToTempBuffer(theCuts[sel_index].first, docclass));
+ if (!buffer)
+ return docstring();
+
+ return buffer->paragraphs().back().asString(AS_STR_INSETS | AS_STR_NEWLINES);
}
docstring::const_iterator cit = str.begin();
docstring::const_iterator end = str.end();
for (; cit != end; ++cit, ++pos)
- par.insertChar(pos, *cit, font, cur.buffer()->params().trackChanges);
+ par.insertChar(pos, *cit, font, cur.buffer()->params().track_changes);
// Cut the selection
cutSelection(cur, true, false);
//lyxerr << "cap::eraseSelection begin: " << cur << endl;
CursorSlice const & i1 = cur.selBegin();
CursorSlice const & i2 = cur.selEnd();
- if (i1.inset().asInsetMath()) {
- saveSelection(cur);
- cur.top() = i1;
- if (i1.idx() == i2.idx()) {
- i1.cell().erase(i1.pos(), i2.pos());
- // We may have deleted i1.cell(cur.pos()).
- // Make sure that pos is valid.
- if (cur.pos() > cur.lastpos())
- cur.pos() = cur.lastpos();
- } else {
- InsetMath * p = i1.asInsetMath();
- Inset::row_type r1, r2;
- Inset::col_type c1, c2;
- region(i1, i2, r1, r2, c1, c2);
- for (Inset::row_type row = r1; row <= r2; ++row)
- for (Inset::col_type col = c1; col <= c2; ++col)
- p->cell(p->index(row, col)).clear();
- // We've deleted the whole cell. Only pos 0 is valid.
- cur.pos() = 0;
- }
- // need a valid cursor. (Lgb)
- cur.clearSelection();
+ if (!i1.asInsetMath()) {
+ LYXERR0("Can't erase this selection");
+ return;
+ }
+
+ saveSelection(cur);
+ cur.top() = i1;
+ InsetMath * p = i1.asInsetMath();
+ if (i1.idx() == i2.idx()) {
+ i1.cell().erase(i1.pos(), i2.pos());
+ // We may have deleted i1.cell(cur.pos()).
+ // Make sure that pos is valid.
+ if (cur.pos() > cur.lastpos())
+ cur.pos() = cur.lastpos();
+ } else if (p->nrows() > 0 && p->ncols() > 0) {
+ // This is a grid, delete a nice square region
+ Inset::row_type r1, r2;
+ Inset::col_type c1, c2;
+ region(i1, i2, r1, r2, c1, c2);
+ for (Inset::row_type row = r1; row <= r2; ++row)
+ for (Inset::col_type col = c1; col <= c2; ++col)
+ p->cell(p->index(row, col)).clear();
+ // We've deleted the whole cell. Only pos 0 is valid.
+ cur.pos() = 0;
} else {
- lyxerr << "can't erase this selection 1" << endl;
+ Inset::idx_type idx1 = i1.idx();
+ Inset::idx_type idx2 = i2.idx();
+ if (idx1 > idx2)
+ swap(idx1, idx2);
+ for (Inset::idx_type idx = idx1 ; idx <= idx2; ++idx)
+ p->cell(idx).clear();
+ // We've deleted the whole cell. Only pos 0 is valid.
+ cur.pos() = 0;
}
+
+ // need a valid cursor. (Lgb)
+ cur.clearSelection();
//lyxerr << "cap::eraseSelection end: " << cur << endl;
}