2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2009-05-14 16:37:17 +02:00
|
|
|
**
|
2013-01-28 17:12:19 +01:00
|
|
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
2012-10-02 09:12:39 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2009-05-14 16:37:17 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2009-05-14 16:37:17 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
2009-05-14 16:37:17 +02:00
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
|
**
|
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2009-05-14 16:37:17 +02:00
|
|
|
|
|
|
|
|
#include "uncommentselection.h"
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QPlainTextEdit>
|
|
|
|
|
#include <QTextBlock>
|
2009-05-14 16:37:17 +02:00
|
|
|
|
2010-04-30 13:08:06 +02:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
|
|
|
|
CommentDefinition::CommentDefinition() :
|
|
|
|
|
m_afterWhiteSpaces(false),
|
|
|
|
|
m_singleLine(QLatin1String("//")),
|
|
|
|
|
m_multiLineStart(QLatin1String("/*")),
|
|
|
|
|
m_multiLineEnd(QLatin1String("*/"))
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
CommentDefinition &CommentDefinition::setAfterWhiteSpaces(const bool afterWhiteSpaces)
|
|
|
|
|
{
|
|
|
|
|
m_afterWhiteSpaces = afterWhiteSpaces;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CommentDefinition &CommentDefinition::setSingleLine(const QString &singleLine)
|
|
|
|
|
{
|
|
|
|
|
m_singleLine = singleLine;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CommentDefinition &CommentDefinition::setMultiLineStart(const QString &multiLineStart)
|
|
|
|
|
{
|
|
|
|
|
m_multiLineStart = multiLineStart;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CommentDefinition &CommentDefinition::setMultiLineEnd(const QString &multiLineEnd)
|
|
|
|
|
{
|
|
|
|
|
m_multiLineEnd = multiLineEnd;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CommentDefinition::isAfterWhiteSpaces() const
|
|
|
|
|
{ return m_afterWhiteSpaces; }
|
|
|
|
|
|
|
|
|
|
const QString &CommentDefinition::singleLine() const
|
|
|
|
|
{ return m_singleLine; }
|
|
|
|
|
|
|
|
|
|
const QString &CommentDefinition::multiLineStart() const
|
|
|
|
|
{ return m_multiLineStart; }
|
|
|
|
|
|
|
|
|
|
const QString &CommentDefinition::multiLineEnd() const
|
|
|
|
|
{ return m_multiLineEnd; }
|
|
|
|
|
|
|
|
|
|
bool CommentDefinition::hasSingleLineStyle() const
|
|
|
|
|
{ return !m_singleLine.isEmpty(); }
|
|
|
|
|
|
|
|
|
|
bool CommentDefinition::hasMultiLineStyle() const
|
|
|
|
|
{ return !m_multiLineStart.isEmpty() && !m_multiLineEnd.isEmpty(); }
|
|
|
|
|
|
2010-05-20 13:56:11 +02:00
|
|
|
void CommentDefinition::clearCommentStyles()
|
|
|
|
|
{
|
|
|
|
|
m_singleLine.clear();
|
|
|
|
|
m_multiLineStart.clear();
|
|
|
|
|
m_multiLineEnd.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-30 13:08:06 +02:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
bool isComment(const QString &text,
|
|
|
|
|
int index,
|
|
|
|
|
const CommentDefinition &definition,
|
|
|
|
|
const QString & (CommentDefinition::* comment) () const)
|
|
|
|
|
{
|
|
|
|
|
const QString &commentType = ((definition).*(comment))();
|
|
|
|
|
const int length = commentType.length();
|
|
|
|
|
|
|
|
|
|
Q_ASSERT(text.length() - index >= length);
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
while (i < length) {
|
|
|
|
|
if (text.at(index + i) != commentType.at(i))
|
|
|
|
|
return false;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace anynomous
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Utils::unCommentSelection(QPlainTextEdit *edit, const CommentDefinition &definition)
|
2009-05-14 16:37:17 +02:00
|
|
|
{
|
2010-04-30 13:08:06 +02:00
|
|
|
if (!definition.hasSingleLineStyle() && !definition.hasMultiLineStyle())
|
|
|
|
|
return;
|
|
|
|
|
|
2009-05-14 16:37:17 +02:00
|
|
|
QTextCursor cursor = edit->textCursor();
|
|
|
|
|
QTextDocument *doc = cursor.document();
|
|
|
|
|
cursor.beginEditBlock();
|
|
|
|
|
|
|
|
|
|
int pos = cursor.position();
|
|
|
|
|
int anchor = cursor.anchor();
|
|
|
|
|
int start = qMin(anchor, pos);
|
|
|
|
|
int end = qMax(anchor, pos);
|
|
|
|
|
bool anchorIsStart = (anchor == start);
|
|
|
|
|
|
|
|
|
|
QTextBlock startBlock = doc->findBlock(start);
|
|
|
|
|
QTextBlock endBlock = doc->findBlock(end);
|
|
|
|
|
|
|
|
|
|
if (end > start && endBlock.position() == end) {
|
|
|
|
|
--end;
|
|
|
|
|
endBlock = endBlock.previous();
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-30 13:08:06 +02:00
|
|
|
bool doMultiLineStyleUncomment = false;
|
|
|
|
|
bool doMultiLineStyleComment = false;
|
|
|
|
|
bool doSingleLineStyleUncomment = false;
|
2009-05-14 16:37:17 +02:00
|
|
|
|
|
|
|
|
bool hasSelection = cursor.hasSelection();
|
|
|
|
|
|
2010-04-30 13:08:06 +02:00
|
|
|
if (hasSelection && definition.hasMultiLineStyle()) {
|
|
|
|
|
|
2009-05-14 16:37:17 +02:00
|
|
|
QString startText = startBlock.text();
|
|
|
|
|
int startPos = start - startBlock.position();
|
2010-04-30 13:08:06 +02:00
|
|
|
const int multiLineStartLength = definition.multiLineStart().length();
|
2009-05-14 16:37:17 +02:00
|
|
|
bool hasLeadingCharacters = !startText.left(startPos).trimmed().isEmpty();
|
|
|
|
|
|
2010-04-30 13:08:06 +02:00
|
|
|
if (startPos >= multiLineStartLength
|
|
|
|
|
&& isComment(startText,
|
|
|
|
|
startPos - multiLineStartLength,
|
|
|
|
|
definition,
|
|
|
|
|
&CommentDefinition::multiLineStart)) {
|
|
|
|
|
startPos -= multiLineStartLength;
|
|
|
|
|
start -= multiLineStartLength;
|
|
|
|
|
}
|
2009-05-14 16:37:17 +02:00
|
|
|
|
2010-05-06 11:34:11 +02:00
|
|
|
bool hasSelStart = (startPos <= startText.length() - multiLineStartLength
|
2010-04-30 13:08:06 +02:00
|
|
|
&& isComment(startText,
|
|
|
|
|
startPos,
|
|
|
|
|
definition,
|
|
|
|
|
&CommentDefinition::multiLineStart));
|
2009-05-14 16:37:17 +02:00
|
|
|
|
|
|
|
|
QString endText = endBlock.text();
|
|
|
|
|
int endPos = end - endBlock.position();
|
2010-04-30 13:08:06 +02:00
|
|
|
const int multiLineEndLength = definition.multiLineEnd().length();
|
|
|
|
|
bool hasTrailingCharacters =
|
|
|
|
|
!endText.left(endPos).remove(definition.singleLine()).trimmed().isEmpty()
|
|
|
|
|
&& !endText.mid(endPos).trimmed().isEmpty();
|
|
|
|
|
|
|
|
|
|
if (endPos <= endText.length() - multiLineEndLength
|
|
|
|
|
&& isComment(endText, endPos, definition, &CommentDefinition::multiLineEnd)) {
|
|
|
|
|
endPos += multiLineEndLength;
|
|
|
|
|
end += multiLineEndLength;
|
2009-05-14 16:37:17 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-30 13:08:06 +02:00
|
|
|
bool hasSelEnd = (endPos >= multiLineEndLength
|
|
|
|
|
&& isComment(endText,
|
|
|
|
|
endPos - multiLineEndLength,
|
|
|
|
|
definition,
|
|
|
|
|
&CommentDefinition::multiLineEnd));
|
2009-05-14 16:37:17 +02:00
|
|
|
|
2010-04-30 13:08:06 +02:00
|
|
|
doMultiLineStyleUncomment = hasSelStart && hasSelEnd;
|
|
|
|
|
doMultiLineStyleComment = !doMultiLineStyleUncomment
|
|
|
|
|
&& (hasLeadingCharacters
|
|
|
|
|
|| hasTrailingCharacters
|
|
|
|
|
|| !definition.hasSingleLineStyle());
|
|
|
|
|
} else if (!hasSelection && !definition.hasSingleLineStyle()) {
|
|
|
|
|
|
|
|
|
|
QString text = startBlock.text().trimmed();
|
|
|
|
|
doMultiLineStyleUncomment = text.startsWith(definition.multiLineStart())
|
|
|
|
|
&& text.endsWith(definition.multiLineEnd());
|
|
|
|
|
doMultiLineStyleComment = !doMultiLineStyleUncomment && !text.isEmpty();
|
|
|
|
|
|
|
|
|
|
start = startBlock.position();
|
|
|
|
|
end = endBlock.position() + endBlock.length() - 1;
|
2010-05-07 14:17:48 +02:00
|
|
|
|
|
|
|
|
if (doMultiLineStyleUncomment) {
|
|
|
|
|
int offset = 0;
|
|
|
|
|
text = startBlock.text();
|
|
|
|
|
const int length = text.length();
|
|
|
|
|
while (offset < length && text.at(offset).isSpace())
|
|
|
|
|
++offset;
|
|
|
|
|
start += offset;
|
|
|
|
|
}
|
2009-05-14 16:37:17 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-30 13:08:06 +02:00
|
|
|
if (doMultiLineStyleUncomment) {
|
2009-05-14 16:37:17 +02:00
|
|
|
cursor.setPosition(end);
|
2010-04-30 13:08:06 +02:00
|
|
|
cursor.movePosition(QTextCursor::PreviousCharacter,
|
|
|
|
|
QTextCursor::KeepAnchor,
|
|
|
|
|
definition.multiLineEnd().length());
|
2009-05-14 16:37:17 +02:00
|
|
|
cursor.removeSelectedText();
|
|
|
|
|
cursor.setPosition(start);
|
2010-04-30 13:08:06 +02:00
|
|
|
cursor.movePosition(QTextCursor::NextCharacter,
|
|
|
|
|
QTextCursor::KeepAnchor,
|
|
|
|
|
definition.multiLineStart().length());
|
2009-05-14 16:37:17 +02:00
|
|
|
cursor.removeSelectedText();
|
2010-04-30 13:08:06 +02:00
|
|
|
} else if (doMultiLineStyleComment) {
|
2009-05-14 16:37:17 +02:00
|
|
|
cursor.setPosition(end);
|
2010-04-30 13:08:06 +02:00
|
|
|
cursor.insertText(definition.multiLineEnd());
|
2009-05-14 16:37:17 +02:00
|
|
|
cursor.setPosition(start);
|
2010-04-30 13:08:06 +02:00
|
|
|
cursor.insertText(definition.multiLineStart());
|
2009-05-14 16:37:17 +02:00
|
|
|
} else {
|
|
|
|
|
endBlock = endBlock.next();
|
2010-04-30 13:08:06 +02:00
|
|
|
doSingleLineStyleUncomment = true;
|
2009-05-14 16:37:17 +02:00
|
|
|
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
|
2010-03-26 14:28:26 +01:00
|
|
|
QString text = block.text().trimmed();
|
2010-04-30 13:08:06 +02:00
|
|
|
if (!text.isEmpty() && !text.startsWith(definition.singleLine())) {
|
|
|
|
|
doSingleLineStyleUncomment = false;
|
2009-05-14 16:37:17 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-30 13:08:06 +02:00
|
|
|
|
|
|
|
|
const int singleLineLength = definition.singleLine().length();
|
2009-05-14 16:37:17 +02:00
|
|
|
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
|
2010-04-30 13:08:06 +02:00
|
|
|
if (doSingleLineStyleUncomment) {
|
2009-05-14 16:37:17 +02:00
|
|
|
QString text = block.text();
|
|
|
|
|
int i = 0;
|
2010-04-30 13:08:06 +02:00
|
|
|
while (i <= text.size() - singleLineLength) {
|
|
|
|
|
if (isComment(text, i, definition, &CommentDefinition::singleLine)) {
|
2009-05-14 16:37:17 +02:00
|
|
|
cursor.setPosition(block.position() + i);
|
2010-04-30 13:08:06 +02:00
|
|
|
cursor.movePosition(QTextCursor::NextCharacter,
|
|
|
|
|
QTextCursor::KeepAnchor,
|
|
|
|
|
singleLineLength);
|
2009-05-14 16:37:17 +02:00
|
|
|
cursor.removeSelectedText();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!text.at(i).isSpace())
|
|
|
|
|
break;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2010-03-26 14:28:26 +01:00
|
|
|
QString text = block.text();
|
2012-11-28 20:44:03 +02:00
|
|
|
foreach (QChar c, text) {
|
2010-03-26 14:28:26 +01:00
|
|
|
if (!c.isSpace()) {
|
2010-04-30 13:08:06 +02:00
|
|
|
if (definition.isAfterWhiteSpaces())
|
|
|
|
|
cursor.setPosition(block.position() + text.indexOf(c));
|
|
|
|
|
else
|
|
|
|
|
cursor.setPosition(block.position());
|
|
|
|
|
cursor.insertText(definition.singleLine());
|
2010-03-26 14:28:26 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-05-14 16:37:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// adjust selection when commenting out
|
2010-04-30 13:08:06 +02:00
|
|
|
if (hasSelection && !doMultiLineStyleUncomment && !doSingleLineStyleUncomment) {
|
2009-05-14 16:37:17 +02:00
|
|
|
cursor = edit->textCursor();
|
2010-04-30 13:08:06 +02:00
|
|
|
if (!doMultiLineStyleComment)
|
|
|
|
|
start = startBlock.position(); // move the comment into the selection
|
2009-05-14 16:37:17 +02:00
|
|
|
int lastSelPos = anchorIsStart ? cursor.position() : cursor.anchor();
|
|
|
|
|
if (anchorIsStart) {
|
|
|
|
|
cursor.setPosition(start);
|
|
|
|
|
cursor.setPosition(lastSelPos, QTextCursor::KeepAnchor);
|
|
|
|
|
} else {
|
|
|
|
|
cursor.setPosition(lastSelPos);
|
|
|
|
|
cursor.setPosition(start, QTextCursor::KeepAnchor);
|
|
|
|
|
}
|
|
|
|
|
edit->setTextCursor(cursor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cursor.endEditBlock();
|
|
|
|
|
}
|