/*! \fn QString QAbstractTextDocumentLayout::anchorAt(const QPointF &position) const Returns the reference of the anchor the given \a position, or an empty string if no anchor exists at that point. */ QString QAbstractTextDocumentLayout::anchorAt(const QPointF& pos) const { int cursorPos = hitTest(pos, Qt::ExactHit); if (cursorPos == -1) return QString(); // compensate for preedit in the hit text block QTextBlock block = document()->firstBlock(); while (block.isValid()) { QRectF blockBr = blockBoundingRect(block); if (blockBr.contains(pos)) { QTextLayout *layout = block.layout(); int relativeCursorPos = cursorPos - block.position(); const int preeditLength = layout ? layout->preeditAreaText().length() : 0; if (preeditLength > 0 && relativeCursorPos > layout->preeditAreaPosition()) cursorPos -= qMin(cursorPos - layout->preeditAreaPosition(), preeditLength); break; } block = block.next(); } QTextDocumentPrivate *pieceTable = qobject_cast<const QTextDocument *>(parent())->docHandle(); QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos); QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format); return fmt.anchorHref(); }
/*! \fn QString QAbstractTextDocumentLayout::anchorAt(const QPointF &position) const Returns the reference of the anchor the given \a position, or an empty string if no anchor exists at that point. */ QString QAbstractTextDocumentLayout::anchorAt(const QPointF& pos) const { int cursorPos = hitTest(pos, Qt::ExactHit); if (cursorPos == -1) return QString(); QTextDocumentPrivate *pieceTable = qobject_cast<const QTextDocument *>(parent())->docHandle(); QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos); QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format); return fmt.anchorHref(); }
void MoveViewController::selectAndMarkAnchor(const QString& link) { QTextBlock block = this->document->begin(); while(block != this->document->end()) { QTextBlock::iterator it; for(it = block.begin(); !it.atEnd(); ++it) { QTextFragment fragment = it.fragment(); if(!fragment.isValid()) { continue; } QTextCharFormat format = fragment.charFormat(); if(format.isAnchor() && format.anchorHref() == link) { QTextCursor cursor = this->textCursor(); cursor.setPosition(fragment.position()); int len = 0; bool finished = false; // we want to mark (highlight) everything from the // start of the anchor until the end of the move // the end of the move is indicated by an empty space // (there is always an empty space after a move) while(!finished && !it.atEnd()) { if(it.fragment().text().startsWith(" ") || len >= 6) { finished = true; } else { len+= it.fragment().text().length(); it++; } } cursor.setPosition(fragment.position() + len, QTextCursor::KeepAnchor); setTextCursor(cursor); ensureCursorVisible(); return; } } block = block.next(); } }
int TextCharFormat::anchorHref(lua_State * L) // const : QString { QTextCharFormat* lhs = ValueInstaller2<QTextCharFormat>::check( L, 1 ); lua_pushstring(L, lhs->anchorHref().toLatin1() ); return 1; }
void KoTextWriter::saveParagraph(const QTextBlock &block, int from, int to) { QString changeName = QString(); QTextBlockFormat blockFormat = block.blockFormat(); int outlineLevel = blockFormat.intProperty(KoParagraphStyle::OutlineLevel); if (outlineLevel > 0) { d->writer->startElement("text:h", false); d->writer->addAttribute("text:outline-level", outlineLevel); } else d->writer->startElement("text:p", false); QString styleName = saveParagraphStyle(block); if (!styleName.isEmpty()) d->writer->addAttribute("text:style-name", styleName); // Write the fragments and their formats QTextCursor cursor(block); QTextCharFormat blockCharFormat = cursor.blockCharFormat(); QTextCharFormat previousCharFormat; QTextBlock::iterator it; for (it = block.begin(); !(it.atEnd()); ++it) { QTextFragment currentFragment = it.fragment(); const int fragmentStart = currentFragment.position(); const int fragmentEnd = fragmentStart + currentFragment.length(); if (to != -1 && fragmentStart >= to) break; if (currentFragment.isValid()) { QTextCharFormat charFormat = currentFragment.charFormat(); QTextCharFormat compFormat = charFormat; bool identical; previousCharFormat.clearProperty(KoCharacterStyle::ChangeTrackerId); compFormat.clearProperty(KoCharacterStyle::ChangeTrackerId); if (previousCharFormat == compFormat) identical = true; else identical = false; if ( d->changeTracker && d->changeTracker->containsInlineChanges(charFormat) && d->changeTracker->elementById(charFormat.property(KoCharacterStyle::ChangeTrackerId).toInt())->isEnabled()) { KoGenChange change; d->changeTracker->saveInlineChange(charFormat.property(KoCharacterStyle::ChangeTrackerId).toInt(), change); changeName = d->sharedData->genChanges().insert(change); d->writer->startElement("text:change-start", false); d->writer->addAttribute("text:change-id", changeName); d->writer->endElement(); } KoInlineObject *inlineObject = d->layout->inlineTextObjectManager()->inlineTextObject(charFormat); if (currentFragment.length() == 1 && inlineObject && currentFragment.text()[0].unicode() == QChar::ObjectReplacementCharacter) { inlineObject->saveOdf(d->context); } else { QString styleName = saveCharacterStyle(charFormat, blockCharFormat); if (charFormat.isAnchor()) { d->writer->startElement("text:a", false); d->writer->addAttribute("xlink:type", "simple"); d->writer->addAttribute("xlink:href", charFormat.anchorHref()); } else if (!styleName.isEmpty() /*&& !identical*/) { d->writer->startElement("text:span", false); d->writer->addAttribute("text:style-name", styleName); } QString text = currentFragment.text(); int spanFrom = fragmentStart >= from ? 0 : from; int spanTo = to == -1 ? fragmentEnd : (fragmentEnd > to ? to : fragmentEnd); if (spanFrom != fragmentStart || spanTo != fragmentEnd) { // avoid mid, if possible d->writer->addTextSpan(text.mid(spanFrom - fragmentStart, spanTo - spanFrom)); } else { d->writer->addTextSpan(text); } if ((!styleName.isEmpty() /*&& !identical*/) || charFormat.isAnchor()) d->writer->endElement(); } // if (inlineObject) if (!changeName.isEmpty()) { d->writer->startElement("text:change-end", false); d->writer->addAttribute("text:change-id",changeName); d->writer->endElement(); changeName=QString(); } previousCharFormat = charFormat; } // if (fragment.valid()) } // foeach(fragment) d->writer->endElement(); }
QString Format::frameToString( QTextFrame *frame ) { QString out; QTextFrame::iterator it; for( it = frame->begin(); it != frame->end(); ++it ) { QTextBlock block = it.currentBlock(); if ( block.isValid() ) { out += "<block"; QTextCursor c( block ); QDateTime dt = TextFormats::lastModified( c ); if ( dt.isValid() ) { out += " lastmodified=\"" + dt.toString( Qt::ISODate ) + "\""; } if ( TextFormats::isTitle( c ) ) { out += " titlestyle=\"title\""; } else if ( TextFormats::isSubTitle( c ) ) { out += " titlestyle=\"subtitle\""; } QTextBlockFormat blockFormat = block.blockFormat(); if ( blockFormat.isValid() ) { QTextList *list = block.textList(); if ( list ) { QTextListFormat f = list->format(); out += " liststyle=\""; switch( f.style() ) { default: case QTextListFormat::ListDisc: out += "disc"; break; case QTextListFormat::ListDecimal: out += "decimal"; break; } out += "\""; out += " listindent=\"" + QString::number( f.indent() ) + "\""; } else { if ( blockFormat.indent() != 0 ) { out += " blockindent=\"" + QString::number( blockFormat.indent() ) + "\""; } } } out += ">\n"; QTextBlock::iterator it2; for( it2 = block.begin(); it2 != block.end(); ++it2 ) { QTextFragment fragment = it2.fragment(); if ( !fragment.isValid() ) continue; QString text = fragment.text(); QString outText; for( int i = 0; i < text.size(); ++i ) { if ( text.at( i ) == 0xfffc ) { outText += "<todo status=\""; QTextImageFormat imageFormat = fragment.charFormat().toImageFormat(); if ( imageFormat.isValid() ) { if ( imageFormat.name().contains( "done" ) ) outText += "done"; else outText += "todo"; } else { dbg() << "NO IMAGE FORMAT" << endl; } outText += "\"/>"; } else { outText += escape( QString( text.at( i ) ) ); } } out += " <fragment"; QTextCharFormat format = fragment.charFormat(); if ( !format.anchorHref().isEmpty() ) { out += " link=\"" + escape( format.anchorHref() ) + "\""; } if ( format.fontWeight() == QFont::Bold ) { out += " bold=\"true\""; } if ( format.fontItalic() ) { out += " italic=\"true\""; } if ( format.hasProperty( QTextFormat::FontPointSize ) && format.fontPointSize() != 10 ) { out += " fontsize=\"" + QString::number( format.fontPointSize() ) + "\""; } if ( outText.trimmed().isEmpty() ) outText.replace( " ", "[FIXME:space]" ); out += ">" + outText + "</fragment>\n"; } out += "</block>"; out += "\n"; } QTextFrame *f = it.currentFrame(); if ( f ) { QTextFrameFormat format = f->frameFormat(); out += "<frame"; if ( format.hasProperty( TextFormats::FrameType ) ) { out += " type="; if ( format.property( TextFormats::FrameType ) == TextFormats::CodeFrame ) { out += "\"code\""; } else { out += "\"undefined\""; } } out += ">\n"; out += frameToString( f ); out += "</frame>\n"; } } return out; }
QString validHtml(const QString &html, bool allowReplacement, QTextCursor *tc) { QDesktopWidget dw; ValidDocument oValidDocument(allowReplacement); QRectF qr = dw.availableGeometry(); oValidDocument.setTextWidth(qr.width() / 2); oValidDocument.setDefaultStyleSheet(qApp->styleSheet()); oValidDocument.setHtml(html); bool fIsValid = oValidDocument.isValid(); QStringList qslAllowed = allowedSchemes(); for (QTextBlock qtb = oValidDocument.begin(); qtb != oValidDocument.end(); qtb = qtb.next()) { for (QTextBlock::iterator qtbi = qtb.begin(); qtbi != qtb.end(); ++qtbi) { const QTextFragment &qtf = qtbi.fragment(); QTextCharFormat qcf = qtf.charFormat(); if (! qcf.anchorHref().isEmpty()) { QUrl url(qcf.anchorHref()); if (! url.isValid() || ! qslAllowed.contains(url.scheme())) { QTextCharFormat qcfn = QTextCharFormat(); QTextCursor qtc(&oValidDocument); qtc.setPosition(qtf.position(), QTextCursor::MoveAnchor); qtc.setPosition(qtf.position()+qtf.length(), QTextCursor::KeepAnchor); qtc.setCharFormat(qcfn); qtbi = qtb.begin(); } } if (qcf.isImageFormat()) { QTextImageFormat qtif = qcf.toImageFormat(); QUrl url(qtif.name()); if (! qtif.name().isEmpty() && ! url.isValid()) fIsValid = false; } } } oValidDocument.adjustSize(); QSizeF s = oValidDocument.size(); if (!fIsValid || (s.width() > qr.width()) || (s.height() > qr.height())) { oValidDocument.setPlainText(html); oValidDocument.adjustSize(); s = oValidDocument.size(); if ((s.width() > qr.width()) || (s.height() > qr.height())) { QString errorMessage = "[[ Text object too large to display ]]"; if (tc) { tc->insertText(errorMessage); return QString(); } else { return errorMessage; } } } if (tc) { QTextCursor tcNew(&oValidDocument); tcNew.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); tc->insertFragment(tcNew.selection()); return QString(); } else { return oValidDocument.toHtml(); } }
void HtmlExporter::emitFragment( const QTextFragment &fragment, const QTextBlockFormat &blockFormat ) { // kDebug() << "html" << html; const QTextCharFormat format = fragment.charFormat(); bool closeAnchor = false; bool anchorIsOpen = false; if ( format.isAnchor() ) { // const QStringList names = format.anchorNames(); // if (!names.isEmpty()) { // html += QLatin1String("<a name=\""); // html += names.at(0); // html += QLatin1String("\" "); // anchorIsOpen = true; // } const QString href = format.anchorHref(); if ( !href.isEmpty() ) { // if (!anchorIsOpen) { // html += QLatin1String("<a "); // anchorIsOpen = true; // } html += QLatin1String( "<a href=\"" ); html += href; html += QLatin1String( "\"" ); anchorIsOpen = true; // closeAnchor = true; // html += QLatin1String("\""); } if ( format.hasProperty( BilboTextFormat::AnchorTitle ) ) { const QString title = format.stringProperty( BilboTextFormat::AnchorTitle ); if ( !title.isEmpty() ) { html += QLatin1String( " title=\"" ); html += title; html += QLatin1String( "\"" ); } } if ( format.hasProperty( BilboTextFormat::AnchorTarget ) ) { const QString target = format.stringProperty( BilboTextFormat::AnchorTarget ); if ( !target.isEmpty() ) { html += QLatin1String( " target=\"" ); html += target; html += QLatin1String( "\"" ); } } if ( anchorIsOpen ) { html += QLatin1String( ">" ); closeAnchor = true; } } QList<tag> tags = emitCharFormatStyle( format, blockFormat ); // if ( !format.anchorHref().isNull() ) { // html += QLatin1String(">"); // closeAnchor = true; // } // kDebug() << "tags count" << tags.count() << endl; for ( int i = 0; i < tags.count(); ++i ) { switch ( tags.at( i ) ) { case span: break; //Jump // case h1: // html += QLatin1String( "<h1>" ); // break; // case h2: // html += QLatin1String( "<h2>" ); // break; // case h3: // html += QLatin1String( "<h3>" ); // break; // case h4: // html += QLatin1String( "<h4>" ); // break; // case h5: // html += QLatin1String( "<h5>" ); // break; case strong: html += QLatin1String( "<strong>" ); break; case em: html += QLatin1String( "<em>" ); break; case s: html += QLatin1String( "<s>" ); break; case u: if ( !closeAnchor ) html += QLatin1String( "<u>" ); break; case code: html += QLatin1String( "<code>" ); break; case sub: html += QLatin1String( "<sub>" ); break; case sup: html += QLatin1String( "<sup>" ); break; } } /* QLatin1String styleTag("<span style=\""); html += styleTag; const bool attributesEmitted = emitCharFormatStyle(format); if (attributesEmitted) html += QLatin1String("\">"); else html.chop(qstrlen(styleTag.latin1())); */ QString txt = fragment.text(); // kDebug() << txt ; if ( txt.count() == 1 && txt.at( 0 ) == QChar::ObjectReplacementCharacter ) { if ( format.isImageFormat() ) { QTextImageFormat imgFmt = format.toImageFormat(); html += QLatin1String( "<img" ); if ( imgFmt.hasProperty( QTextFormat::ImageName ) ) { emitAttribute( "src", imgFmt.name() ); } if ( imgFmt.hasProperty( BilboTextFormat::ImageTitle ) ) { const QString title = imgFmt.stringProperty( BilboTextFormat::ImageTitle ); if ( !title.isEmpty() ) { emitAttribute( "title", imgFmt.stringProperty( BilboTextFormat::ImageTitle ) ); } } if ( imgFmt.hasProperty( BilboTextFormat::ImageAlternateText ) ) { const QString alternate = imgFmt.stringProperty( BilboTextFormat::ImageAlternateText ); if ( !alternate.isEmpty() ) { emitAttribute( "alt", imgFmt.stringProperty( BilboTextFormat::ImageAlternateText ) ); } } if ( imgFmt.hasProperty( QTextFormat::ImageWidth ) ) { emitAttribute( "width", QString::number( imgFmt.width() ) ); } if ( imgFmt.hasProperty( QTextFormat::ImageHeight ) ) { emitAttribute( "height", QString::number( imgFmt.height() ) ); } if ( QTextFrame *imageFrame = qobject_cast<QTextFrame *>( doc->objectForFormat( imgFmt ) ) ) { emitFloatStyle( imageFrame->frameFormat().position() ); } html += QLatin1String( " />" ); } } else { // Q_ASSERT(!txt.contains(QChar::ObjectReplacementCharacter)); txt = Qt::escape( txt ); // split for [\n{LineSeparator}] QString forcedLineBreakRegExp = QString::fromLatin1( "[\\na]" ); forcedLineBreakRegExp[3] = QChar::LineSeparator; const QStringList lines = txt.split( QRegExp( forcedLineBreakRegExp ) ); for ( int i = 0; i < lines.count(); ++i ) { if ( i > 0 ) html += QLatin1String( "<br />" ); // space on purpose for compatibility with Netscape, Lynx & Co. //and to convert LineSeparators to <br /> tags. html += lines.at( i ); } } // kDebug() << html ; //Close Tags //if (!closeAnchor) for ( int i = tags.count(); i > 0; --i ) { switch ( tags.at( i - 1 ) ) { case span: html += QLatin1String( "</span>" ); break; //Jump // case h1: // html += QLatin1String( "</h1>" ); // break; // case h2: // html += QLatin1String( "</h2>" ); // break; // case h3: // html += QLatin1String( "</h3>" ); // break; // case h4: // html += QLatin1String( "</h4>" ); // break; // case h5: // html += QLatin1String( "</h5>" ); // break; case strong: html += QLatin1String( "</strong>" ); break; case em: html += QLatin1String( "</em>" ); break; case s: html += QLatin1String( "</s>" ); break; case u: if ( !closeAnchor ) html += QLatin1String( "</u>" ); break; case code: html += QLatin1String( "</code>" ); break; case sub: html += QLatin1String( "</sub>" ); break; case sup: html += QLatin1String( "</sup>" ); break; } } /* if (attributesEmitted) html += QLatin1String("</span>"); */ if ( closeAnchor ) { html += QLatin1String( "</a>" ); } // kDebug() << "html=>" << html; }