예제 #1
0
void TextBuffer::insertText (const KTextEditor::Cursor &position, const QString &text)
{
  // only allowed if editing transaction running
  Q_ASSERT (m_editingTransactions > 0);

  // skip work, if no text to insert
  if (text.isEmpty())
    return;

  // get block, this will assert on invalid line
  int blockIndex = blockForLine (position.line());

  // let the block handle the insertText
  m_blocks.at(blockIndex)->insertText (position, text);

  // remember changes
  ++m_revision;

  // update changed line interval
  if (position.line () < m_editingMinimalLineChanged || m_editingMinimalLineChanged == -1)
    m_editingMinimalLineChanged = position.line ();

  if (position.line () > m_editingMaximalLineChanged)
    m_editingMaximalLineChanged = position.line ();

  // emit signal about done change
  emit textInserted (position, text);
}
예제 #2
0
void TextBuffer::wrapLine (const KTextEditor::Cursor &position)
{
  // only allowed if editing transaction running
  Q_ASSERT (m_editingTransactions > 0);

  // get block, this will assert on invalid line
  int blockIndex = blockForLine (position.line());

  // let the block handle the wrapLine
  // this can only lead to one more line in this block
  // no other blocks will change
  ++m_lines; // first alter the line counter, as functions called will need the valid one
  m_blocks.at(blockIndex)->wrapLine (position);

  // remember changes
  ++m_revision;

  // update changed line interval
  if (position.line() < m_editingMinimalLineChanged || m_editingMinimalLineChanged == -1)
    m_editingMinimalLineChanged = position.line();

  if (position.line() <= m_editingMaximalLineChanged)
    ++m_editingMaximalLineChanged;
  else
    m_editingMaximalLineChanged = position.line() + 1;

  // fixup all following blocks
  fixStartLines (blockIndex);

  // balance the changed block if needed
  balanceBlock (blockIndex);

  // emit signal about done change
  emit lineWrapped (position);
}
예제 #3
0
TextLine TextBuffer::line (int line) const
{
  // get block, this will assert on invalid line
  int blockIndex = blockForLine (line);

  // get line
  return m_blocks.at(blockIndex)->line (line);
}
예제 #4
0
void TextBuffer::unwrapLine (int line)
{
  // only allowed if editing transaction running
  Q_ASSERT (m_editingTransactions > 0);

  // line 0 can't be unwrapped
  Q_ASSERT (line > 0);

  // get block, this will assert on invalid line
  int blockIndex = blockForLine (line);

  // is this the first line in the block?
  bool firstLineInBlock = (line == m_blocks.at(blockIndex)->startLine());

  // let the block handle the unwrapLine
  // this can either lead to one line less in this block or the previous one
  // the previous one could even end up with zero lines
  m_blocks.at(blockIndex)->unwrapLine (line, (blockIndex > 0) ? m_blocks.at(blockIndex-1) : 0);
  --m_lines;

  // decrement index for later fixup, if we modified the block in front of the found one
  if (firstLineInBlock)
    --blockIndex;

  // remember changes
  ++m_revision;

  // update changed line interval
   if ((line - 1) < m_editingMinimalLineChanged || m_editingMinimalLineChanged == -1)
    m_editingMinimalLineChanged = line - 1;

  if (line <= m_editingMaximalLineChanged)
    --m_editingMaximalLineChanged;
  else
    m_editingMaximalLineChanged = line -1;

  // fixup all following blocks
  fixStartLines (blockIndex);

  // balance the changed block if needed
  balanceBlock (blockIndex);

  // emit signal about done change
  emit lineUnwrapped (line);
}
예제 #5
0
void QDocumentBuffer::insertLines(int after, const QVector<QDocumentLineHandle*>& l)
{
	int index = after + 1;
	int blockIndex = blockForLine(index);
	
	if ( blockIndex == -1 )
	{
		qWarning("cannot insert line at pos %i", index);
		return;
	}
	
	int n = l.count();
	Block *b = m_blocks.at(blockIndex);
	
	if ( (b->size() + 1) >= m_forkThresold )
	{
		// split block
		int bounds = b->start + m_optimalSize;
		
		Block *nb = new Block(bounds);
		nb->insert(bounds, b->lines.constData() + m_optimalSize, b->size() - m_optimalSize);
		nb->append(l.constData(), n);
		nb->end = bounds + nb->size();
		m_blocks.insert(blockIndex + 1, nb);
		
		b->lines.resize(m_optimalSize);
		b->end = bounds;
		
		blockIndex += 2;
	} else {
		b->insert(index, l.constData(), n);
	}
	
	// update block boundaries
	while ( blockIndex < m_blocks.count() )
	{
		b = m_blocks.at(blockIndex);
		b->start += n;
		b->end += n;
	}
}
예제 #6
0
QList<TextRange *> TextBuffer::rangesForLine (int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const
{
  // get block, this will assert on invalid line
  const int blockIndex = blockForLine (line);

  // get the ranges of the right block
  QList<TextRange *> rightRanges;
  foreach (const QSet<TextRange *> &ranges, m_blocks.at(blockIndex)->rangesForLine (line)) {
    foreach (TextRange * const range, ranges) {
        /**
        * we want only ranges with attributes, but this one has none
        */
        if (rangesWithAttributeOnly && !range->hasAttribute())
            continue;

        /**
        * we want ranges for no view, but this one's attribute is only valid for views
        */
        if (!view && range->attributeOnlyForViews())
            continue;

        /**
        * the range's attribute is not valid for this view
        */
        if (range->view() && range->view() != view)
            continue;

        /**
        * if line is in the range, ok
        */
        if (range->startInternal().lineInternal() <= line && line <= range->endInternal().lineInternal())
          rightRanges.append (range);
    }
  }

  // return right ranges
  return rightRanges;
}
예제 #7
0
void TextBuffer::removeText (const KTextEditor::Range &range)
{
  // only allowed if editing transaction running
  Q_ASSERT (m_editingTransactions > 0);

  // only ranges on one line are supported
  Q_ASSERT (range.start().line() == range.end().line());

  // start colum <= end column and >= 0
  Q_ASSERT (range.start().column() <= range.end().column());
  Q_ASSERT (range.start().column() >= 0);

  // skip work, if no text to remove
  if (range.isEmpty())
    return;

  // get block, this will assert on invalid line
  int blockIndex = blockForLine (range.start().line());

  // let the block handle the removeText, retrieve removed text
  QString text;
  m_blocks.at(blockIndex)->removeText (range, text);

  // remember changes
  ++m_revision;

  // update changed line interval
  if (range.start().line() < m_editingMinimalLineChanged || m_editingMinimalLineChanged == -1)
    m_editingMinimalLineChanged = range.start().line();

  if (range.start().line() > m_editingMaximalLineChanged)
    m_editingMaximalLineChanged = range.start().line();

  // emit signal about done change
  emit textRemoved (range, text);
}
예제 #8
0
QDocumentLineHandle* QDocumentBuffer::at(int index) const
{
	int blockIndex = blockForLine(index);
	
	return blockIndex != -1 ? m_blocks.at(blockIndex)->at(index) : 0;
}
예제 #9
0
void QDocumentBuffer::removeLines(int after, int n)
{
	int index = after + 1;
	int blockIndex = blockForLine(index);
	
	if ( blockIndex == -1 )
	{
		qWarning("cannot remove line at pos %i", index);
		return;
	}
	
	// update block boundaries
	int count = n;
	Block *b = m_blocks.at(blockIndex);
	
	while ( count > 0 )
	{
		int room = b->end - index;
		int toRem = qMin(room, count);
		
		b->remove(index, toRem);
		b->end -= toRem;
		count -= toRem;
		
		if ( !b->size() )
		{
			m_blocks.remove(blockIndex);
			delete b;
		} else {
			++blockIndex;
		}
		
		if ( blockIndex >= m_blocks.count() )
			break;
		
		b = m_blocks.at(blockIndex);
		b->start -= toRem;
	}
	
	if ( index )
	{
		qWarning("Troubles in line removal");
	}
	
	if ( b->size() < m_mergeThresold )
	{
		// "merge" block with its neighbors
		
		int sz = b->size();
		sz += qMin(1, sz / m_safetyRoom);
		
		int roomPrev = blockIndex ? m_forkThresold - m_blocks.at(blockIndex - 1)->size() : 0;
		int roomNext = blockIndex + 1 < m_blocks.count() ? m_forkThresold - m_blocks.at(blockIndex + 1)->size() : 0;
		
		bool maxPrev = false;
		int maxRoom = 0, minRoom = 0;
		Block *moreRoom = 0, *lessRoom = 0;
		
		if ( roomPrev > roomNext )
		{
			maxPrev = true;
			maxRoom = roomPrev;
			moreRoom = m_blocks.at(blockIndex - 1);
			
			minRoom = roomNext;
			
			if ( roomNext )
				lessRoom = m_blocks.at(blockIndex + 1);
		} else {
			maxRoom = roomNext;
			
			if ( roomNext )
				moreRoom = m_blocks.at(blockIndex + 1);
			
			minRoom = roomPrev;
			
			if ( roomPrev )
				lessRoom = m_blocks.at(blockIndex - 1);
		}
		
		if ( maxRoom > sz )
		{
			// put everything in one
			moreRoom->lines << b->lines;
			moreRoom->end += b->size();
			
			m_blocks.remove(blockIndex);
			delete b;
		} else if ( (maxRoom + minRoom) > sz ) {
			// try to alloc evenly
			int part = b->size() * maxRoom / (maxRoom + minRoom);
			
			moreRoom->append(b->lines.constData(), part);
			moreRoom->end += part;
			lessRoom->end += b->size() - part;
			lessRoom->append(b->lines.constData() + part, b->size() - part);
			
			m_blocks.remove(blockIndex);
			delete b;
		} else {
			// cannot merge simply... let's forget about it for now as it is not vital
			++blockIndex;
		}
	} else {
		++blockIndex;
	}
	
	// update block boundaries
	while ( blockIndex < m_blocks.count() )
	{
		b = m_blocks.at(blockIndex);
		b->start -= n;
		b->end -= n;
	}
}
예제 #10
0
void QDocumentBuffer::removeLine(int index)
{
	int blockIndex = blockForLine(index);
	
	if ( blockIndex == -1 )
	{
		qWarning("cannot remove line at pos %i", index);
		return;
	}
	
	Block *b = m_blocks.at(blockIndex);
	
	b->remove(index);
	--b->end;
	
	// if block too small, merge it with blocks around?
	
	if ( !b->size() )
	{
		// remove empty block
		m_blocks.remove(blockIndex);
		delete b;
	} else if ( b->size() < m_mergeThresold ) {
		// "merge" block with its neighbors
		
		int n = b->size();
		n += qMin(1, n / m_safetyRoom);
		
		int roomPrev = blockIndex ? m_forkThresold - m_blocks.at(blockIndex - 1)->size() : 0;
		int roomNext = blockIndex + 1 < m_blocks.count() ? m_forkThresold - m_blocks.at(blockIndex + 1)->size() : 0;
		
		bool maxPrev = false;
		int maxRoom = 0, minRoom = 0;
		Block *moreRoom = 0, *lessRoom = 0;
		
		if ( roomPrev > roomNext )
		{
			maxPrev = true;
			maxRoom = roomPrev;
			moreRoom = m_blocks.at(blockIndex - 1);
			
			minRoom = roomNext;
			
			if ( roomNext )
				lessRoom = m_blocks.at(blockIndex + 1);
		} else {
			maxRoom = roomNext;
			
			if ( roomNext )
				moreRoom = m_blocks.at(blockIndex + 1);
			
			minRoom = roomPrev;
			
			if ( roomPrev )
				lessRoom = m_blocks.at(blockIndex - 1);
		}
		
		if ( maxRoom > n )
		{
			// put everything in one
			moreRoom->lines << b->lines;
			moreRoom->end += b->size();
			
			m_blocks.remove(blockIndex);
			delete b;
		} else if ( (maxRoom + minRoom) > n ) {
			// try to alloc evenly
			int part = b->size() * maxRoom / (maxRoom + minRoom);
			
			if ( maxPrev )
			{
				moreRoom->append(b->lines.constData(), part);
				lessRoom->prepend(b->lines.constData() + part, b->size() - part);
			} else {
				moreRoom->prepend(b->lines.constData(), part);
				lessRoom->append(b->lines.constData() + part, b->size() - part);
			}
			
			moreRoom->end += part;
			lessRoom->end += b->size() - part;
			
			m_blocks.remove(blockIndex);
			delete b;
		} else {
			// cannot merge simply... let's forget about it for now as it is not vital
			++blockIndex;
		}
	} else {
		++blockIndex;
	}
	
	// update block boundaries
	while ( blockIndex < m_blocks.count() )
	{
		b = m_blocks.at(blockIndex);
		--b->start;
		--b->end;
	}
}