00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <KoTextTool.h>
00021 #include <KoCanvasBase.h>
00022 #include <KoSelection.h>
00023 #include <KoShapeManager.h>
00024 #include <KoPointerEvent.h>
00025
00026 #include <kdebug.h>
00027 #include <QKeyEvent>
00028 #include <QTextBlock>
00029 #include <QTextLayout>
00030 #include <QAbstractTextDocumentLayout>
00031
00032 KoTextTool::KoTextTool(KoCanvasBase *canvas)
00033 : KoTool(canvas)
00034 , m_textShape(0)
00035 , m_textShapeData(0)
00036 {
00037 }
00038
00039 KoTextTool::~KoTextTool() {
00040 }
00041
00042 void KoTextTool::paint( QPainter &painter, KoViewConverter &converter) {
00043 if(painter.hasClipping()) {
00044 QRect shape = converter.documentToView(m_textShape->boundingRect()).toRect();
00045 if(painter.clipRegion().intersect( QRegion(shape) ).isEmpty())
00046 return;
00047 }
00048
00049 painter.setMatrix( painter.matrix() * m_textShape->transformationMatrix(&converter) );
00050 double zoomX, zoomY;
00051 converter.zoom(&zoomX, &zoomY);
00052 painter.scale(zoomX, zoomY);
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 QTextBlock block = m_caret.block();
00066 if(! block.layout())
00067 return;
00068
00069 #if 0
00070 Hmm, not useful right now due to the implementation of QAbstractTextDocumentLayout
00071 if(m_caret.selectionStart() != m_caret.selectionEnd()) {
00072
00073 bool first = true;
00074 QList<QTextLine> lines;
00075 QTextBlock block = document->findBlock(m_caret.selectionStart());
00076 do {
00077 QTextLayout *layout = block.layout();
00078 if(!block.isValid() || block.position() > m_caret.selectionEnd())
00079 break;
00080 if(layout == 0)
00081 continue;
00082 layout->setCacheEnabled(true);
00083 kDebug() << " block '" << block.text() << "'" << endl;
00084 for(int i=0; i < layout->lineCount(); i++) {
00085 QTextLine line = layout->lineAt(i);
00086 kDebug() << " line: " << line.textStart() << "-" << (line.textStart() + line.textLength()) << endl;
00087 if(first && line.textStart() + line.textLength() < m_caret.selectionStart())
00088 continue;
00089 lines.append(line);
00090 kDebug() << " appending" << endl;
00091 if(line.textStart() + line.textLength() > m_caret.selectionEnd())
00092 break;
00093 }
00094 first = false;
00095 block = block.next();
00096 } while(block.position() + block.length() < m_caret.selectionEnd());
00097
00098 kDebug(32500) << "found " << lines.count() << " lines that contain the selection" << endl;
00099 foreach(QTextLine line, lines) {
00100 if(! line.isValid())
00101 continue;
00102 if(painter.clipRegion().intersect(QRegion(line.rect().toRect())).isEmpty())
00103 continue;
00104 painter.fillRect(line.rect(), QBrush(Qt::yellow));
00105 }
00106 }
00107 #endif
00108
00109
00110 QPen pen(Qt::black);
00111 if(! m_textShape->hasTransparency()) {
00112 QColor bg = m_textShape->background().color();
00113 QColor invert = QColor(255 - bg.red(), 255 - bg.green(), 255 - bg.blue());
00114 pen.setColor(invert);
00115 }
00116 painter.setPen(pen);
00117 painter.translate(0, -m_textShapeData->documentOffset());
00118 block.layout()->drawCursor(&painter, QPointF(0,0), m_caret.position() - block.position());
00119 }
00120
00121 void KoTextTool::mousePressEvent( KoPointerEvent *event ) {
00122 if(! m_textShape->boundingRect().contains(event->point)) {
00123 QRectF area(event->point, QSizeF(1,1));
00124 foreach(KoShape *shape, m_canvas->shapeManager()->shapesAt(area, true)) {
00125 KoTextShape *textShape = dynamic_cast<KoTextShape*> (shape);
00126 if(textShape) {
00127 m_textShape = textShape;
00128 KoTextShapeData *d = static_cast<KoTextShapeData*> (textShape->userData());
00129 if(d->document() == m_textShapeData->document())
00130 break;
00131 }
00132 }
00133 m_textShapeData = static_cast<KoTextShapeData*> (m_textShape->userData());
00134
00135 m_caret = QTextCursor(m_textShapeData->document());
00136 }
00137
00138 int position = pointToPosition(event->point);
00139 repaint();
00140 m_caret.setPosition(position);
00141 repaint();
00142 }
00143
00144 int KoTextTool::pointToPosition(const QPointF & point) const {
00145 QPointF p = m_textShape->convertScreenPos(point);
00146 int caretPos = m_caret.block().document()->documentLayout()->hitTest(p, Qt::FuzzyHit);
00147 caretPos = qMax(caretPos, m_textShapeData->position());
00148 if(m_textShapeData->endPosition() == -1)
00149 kWarning() << "Clicking in not fully laid-out textframe\n";
00150 caretPos = qMin(caretPos, m_textShapeData->endPosition());
00151 return caretPos;
00152 }
00153
00154 void KoTextTool::mouseDoubleClickEvent( KoPointerEvent *event ) {
00155
00156 }
00157
00158 void KoTextTool::mouseMoveEvent( KoPointerEvent *event ) {
00159 useCursor(Qt::IBeamCursor);
00160 if(event->buttons() == Qt::NoButton)
00161 return;
00162 int position = pointToPosition(event->point);
00163 if(position >= 0) {
00164 repaint();
00165 m_caret.setPosition(position, QTextCursor::KeepAnchor);
00166 repaint();
00167 }
00168 }
00169
00170 void KoTextTool::mouseReleaseEvent( KoPointerEvent *event ) {
00171
00172 }
00173
00174 void KoTextTool::keyPressEvent(QKeyEvent *event) {
00175 QTextCursor::MoveOperation moveOperation = QTextCursor::NoMove;
00176 switch(event->key()) {
00177
00178
00179
00180
00181 case Qt::Key_Backspace:
00182 useCursor(Qt::BlankCursor);
00183 m_caret.deletePreviousChar();
00184 break;
00185 case Qt::Key_Tab:
00186 kDebug(32500) << "Tab key pressed";
00187 break;
00188 case Qt::Key_Delete:
00189 useCursor(Qt::BlankCursor);
00190 m_caret.deleteChar();
00191 break;
00192 case Qt::Key_Left:
00193 if(event->modifiers() & Qt::ControlModifier)
00194 moveOperation = QTextCursor::WordLeft;
00195 else
00196 moveOperation = QTextCursor::Left;
00197 break;
00198 case Qt::Key_Up:
00199 moveOperation = QTextCursor::Up;
00200 break;
00201 case Qt::Key_Right:
00202 if(event->modifiers() & Qt::ControlModifier)
00203 moveOperation = QTextCursor::NextWord;
00204 else
00205 moveOperation = QTextCursor::Right;
00206 break;
00207 case Qt::Key_Down:
00208 moveOperation = QTextCursor::Down;
00209 break;
00210 case Qt::Key_PageUp:
00211
00212 break;
00213 case Qt::Key_PageDown:
00214
00215 break;
00216 case Qt::Key_End:
00217 moveOperation = QTextCursor::EndOfLine;
00218 break;
00219 case Qt::Key_Home:
00220 moveOperation = QTextCursor::StartOfLine;
00221 break;
00222 default:
00223 if(event->text().length() == 0)
00224 return;
00225 useCursor(Qt::BlankCursor);
00226 m_caret.insertText(event->text());
00227 }
00228 if(moveOperation != QTextCursor::NoMove) {
00229 repaint();
00230 m_caret.movePosition(moveOperation,
00231 (event->modifiers() & Qt::ShiftModifier)?QTextCursor::KeepAnchor:QTextCursor::MoveAnchor);
00232 repaint();
00233 }
00234 event->accept();
00235 }
00236
00237 void KoTextTool::keyReleaseEvent(QKeyEvent *event) {
00238 event->accept();
00239 }
00240
00241 void KoTextTool::activate (bool temporary) {
00242 Q_UNUSED(temporary);
00243 KoSelection *selection = m_canvas->shapeManager()->selection();
00244 foreach(KoShape *shape, selection->selectedShapes().toList()) {
00245 m_textShape = dynamic_cast<KoTextShape*> (shape);
00246 if(m_textShape)
00247 break;
00248 }
00249 if(m_textShape == 0) {
00250 emit sigDone();
00251 return;
00252 }
00253 foreach(KoShape *shape, selection->selectedShapes().toList()) {
00254
00255 if(m_textShape == shape) continue;
00256 selection->deselect(shape);
00257 }
00258 m_textShapeData = static_cast<KoTextShapeData*> (m_textShape->userData());
00259 m_textShapeData->document()->setUndoRedoEnabled(true);
00260 m_caret = QTextCursor(m_textShapeData->document());
00261 useCursor(Qt::IBeamCursor, true);
00262 m_textShape->repaint();
00263 }
00264
00265 void KoTextTool::deactivate() {
00266 m_textShape = 0;
00267 if(m_textShapeData)
00268 m_textShapeData->document()->setUndoRedoEnabled(false);
00269 m_textShapeData = 0;
00270 }
00271
00272 void KoTextTool::repaint() {
00273 QTextBlock block = m_caret.block();
00274 if(block.isValid()) {
00275 QTextLine tl = block.layout()->lineForTextPosition(m_caret.position() - block.position());
00276 QRectF repaintRect;
00277 if(tl.isValid())
00278 repaintRect = tl.rect();
00279 else
00280 repaintRect = block.layout()->boundingRect();
00281 repaintRect.moveTop(repaintRect.y() - m_textShapeData->documentOffset());
00282 repaintRect.moveTopLeft(repaintRect.topLeft() + m_textShape->position());
00283 m_canvas->updateCanvas(repaintRect);
00284 }
00285 }