void OutputWindowPlainTextEdit::appendLines(QString const& s, const QString &repository) { if (s.isEmpty()) return; const int previousLineCount = document()->lineCount(); const QChar newLine(QLatin1Char('\n')); const QChar lastChar = s.at(s.size() - 1); const bool appendNewline = (lastChar != QLatin1Char('\r') && lastChar != newLine); m_formatter->appendMessage(appendNewline ? s + newLine : s, currentCharFormat()); // Scroll down moveCursor(QTextCursor::End); ensureCursorVisible(); if (!repository.isEmpty()) { // Associate repository with new data. QTextBlock block = document()->findBlockByLineNumber(previousLineCount); for ( ; block.isValid(); block = block.next()) block.setUserData(new RepositoryUserData(repository)); } }
void WChatLog::ChatLog_EventsDisplay(const CArrayPtrEvents & arraypEvents, int iEventStart) { Assert(iEventStart >= 0); Assert(m_oTextBlockComposing.isValid()); // CSocketXmpp * pSocket = m_pContactOrGroup->Xmpp_PGetSocketOnlyIfReady(); OCursorSelectBlock oCursor(m_oTextBlockComposing); QTextBlock oTextBlockEvent; // Text block for each event to insert IEvent ** ppEventStop; IEvent ** ppEventFirst = arraypEvents.PrgpGetEventsStop(OUT &ppEventStop) + iEventStart; IEvent ** ppEvent = ppEventFirst; if (!m_fDisplayAllMessages) { // For performance, limit the display to the last 100 events if (ppEventStop != NULL) { IEvent ** ppEventStart = ppEventStop - 100; if (ppEventStart > ppEvent) { ppEvent = ppEventStart; QTextBlockFormat oFormat; oFormat.setAlignment(Qt::AlignHCenter); oFormat.setBackground(c_brushSilver); // Use a silver color oCursor.setBlockFormat(oFormat); g_strScratchBufferStatusBar.Format("<a href='" d_SzMakeCambrianAction(d_szCambrianAction_DisplayAllHistory) "'>Display complete history ($I messages)</a>", arraypEvents.GetSize()); oCursor.insertHtml(g_strScratchBufferStatusBar); oCursor.AppendBlockBlank(); } } } while (ppEvent < ppEventStop) { IEvent * pEvent = *ppEvent++; AssertValidEvent(pEvent); if (pEvent->m_tsEventID >= m_tsMidnightNext) { QDateTime dtl = QDateTime::fromMSecsSinceEpoch(pEvent->m_tsEventID).toLocalTime(); QDate date = dtl.date(); // Strip the time of the day m_tsMidnightNext = QDateTime(date).toMSecsSinceEpoch() + d_ts_cDays; // I am sure there is a more elegant way to strip the time from a date, however at the moment I don't have time to investigate a better solution (and this code works) QTextBlockFormat oFormatBlock; oFormatBlock.setAlignment(Qt::AlignHCenter); oFormatBlock.setBackground(c_brushSilver); oCursor.setBlockFormat(oFormatBlock); QTextCharFormat oFormatChar; // = oCursor.charFormat(); oFormatChar.setFontWeight(QFont::Bold); //oFormatChar.setFontItalic(true); //oCursor.setCharFormat(oFormatChar); oCursor.insertText(date.toString("dddd MMMM d, yyyy"), oFormatChar); oCursor.AppendBlockBlank(); } oTextBlockEvent = oCursor.block(); // Get the current block under the cursor Endorse(oTextBlockEvent.userData() == NULL); if (pEvent->m_uFlagsEvent & IEvent::FE_kfReplacing) { MessageLog_AppendTextFormatSev(eSeverityComment, "Attempting to replace Event ID $t\n", pEvent->m_tsEventID); QTextBlock oTextBlockUpdate; QTextBlock oTextBlockTemp = document()->lastBlock(); IEvent * pEventOld = pEvent; const EEventClass eEventClassUpdater = pEvent->Event_FIsEventTypeSent() ? CEventUpdaterSent::c_eEventClass : CEventUpdaterReceived::c_eEventClass; // Which updater to search for // The event is replacing an older event. This code is a bit complex because the Chat Log may not display all events and therefore we need to find the most recent block displaying the most recent event. IEvent ** ppEventStop; IEvent ** ppEventFirst = pEvent->m_pVaultParent_NZ->m_arraypaEvents.PrgpGetEventsStop(OUT &ppEventStop); IEvent ** ppEventCompare = ppEventStop; // Search the array from the end, as the event to search is likely to be a recent one while (ppEventFirst < ppEventCompare) { // Find the updater which should be right before the replacing event IEvent * pEventTemp = *--ppEventCompare; TryAgain: if (pEventTemp == pEventOld && ppEventFirst < ppEventCompare) { CEventUpdaterSent * pEventUpdater = (CEventUpdaterSent *)*--ppEventCompare; // Get the updater which is just before the event if (pEventUpdater->EGetEventClass() != eEventClassUpdater) { MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "\t Missing Updater for Event ID $t ({tL}); instead found class '$U' with Event ID $t.\n", pEventTemp->m_tsEventID, pEventTemp->m_tsEventID, pEventUpdater->EGetEventClass(), pEventUpdater->m_tsEventID); pEvent->m_uFlagsEvent &= ~IEvent::FE_kfReplacing; // Remove the bit to avoid displaying the error again and again pEvent->m_pVaultParent_NZ->SetModified(); // Save the change continue; } const TIMESTAMP tsEventIdOld = pEventUpdater->m_tsEventIdOld; MessageLog_AppendTextFormatSev(eSeverityNoise, "\t [$i] Found updater: $t -> $t\n", ppEventCompare - ppEventFirst, pEventUpdater->m_tsEventIdNew, tsEventIdOld); // Now, search for the block containing the replacement event while (oTextBlockTemp.isValid()) { OTextBlockUserDataEvent * pUserData = (OTextBlockUserDataEvent *)oTextBlockTemp.userData(); if (pUserData != NULL) { TIMESTAMP_DELTA dtsEvent = (pUserData->m_pEvent->m_tsEventID - tsEventIdOld); MessageLog_AppendTextFormatCo(d_coPurple, "Comparing block Event ID $t with $t: dtsEvent = $T\n", pUserData->m_pEvent->m_tsEventID, tsEventIdOld, dtsEvent); if (dtsEvent <= 0) { if (dtsEvent == 0) { MessageLog_AppendTextFormatSev(eSeverityNoise, "\t Found matching textblock for replacement: Event ID $t -> $t\n", pEventOld->m_tsEventID, tsEventIdOld); oTextBlockUpdate = oTextBlockTemp; } break; } } oTextBlockTemp = oTextBlockTemp.previous(); } // while // Keep searching in case there are chained updated events while (ppEventFirst < ppEventCompare) { pEventTemp = *--ppEventCompare; if (pEventTemp->m_tsEventID == tsEventIdOld) { MessageLog_AppendTextFormatSev(eSeverityNoise, "\t [$i] Found chained replacement: Event ID $t -> $t\n", ppEventCompare - ppEventFirst, pEvent->m_tsEventID, tsEventIdOld); pEventTemp->m_uFlagsEvent |= IEvent::FE_kfReplaced; pEventOld = pEventTemp; goto TryAgain; } } // while } // if } // while if (oTextBlockUpdate.isValid()) { MessageLog_AppendTextFormatSev(eSeverityNoise, "\t Event ID $t is updating its old Event ID $t\n", pEvent->m_tsEventID, pEventOld->m_tsEventID); OCursorSelectBlock oCursorEventOld(oTextBlockUpdate); pEvent->ChatLogUpdateTextBlock(INOUT &oCursorEventOld); continue; } MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "Event ID $t is replacing another event which cannot be found\n", pEvent->m_tsEventID); } // if (replacing) oTextBlockEvent.setUserData(PA_CHILD new OTextBlockUserDataEvent(pEvent)); // Assign an event for each text block pEvent->ChatLogUpdateTextBlock(INOUT &oCursor); if ((pEvent->m_uFlagsEvent & IEvent::FE_kfEventHidden) == 0) oCursor.AppendBlockBlank(); // If the event is visible, then add a new text block (otherwise it will reuse the same old block) else oTextBlockEvent.setUserData(NULL); // Since we are reusing the same block, delete its userdata so we may assing another OTextBlockUserDataEvent } // while m_oTextBlockComposing = oCursor.block(); ChatLog_ChatStateTextAppend(INOUT oCursor); Widget_ScrollToEnd(INOUT this); } // ChatLog_EventsDisplay()
KoTextBlockData::KoTextBlockData(QTextBlock &block) : d(block.userData() ? dynamic_cast<KoTextBlockData::Private *>(block.userData()) : new Private()) { block.setUserData(d); }
void ListItemsHelper::recalculate() { //kDebug(32500); const QTextListFormat format = m_textList->format(); const KoListStyle::Style listStyle = static_cast<KoListStyle::Style>(m_textList->format().style()); const QString prefix = format.stringProperty(KoListStyle::ListItemPrefix); const QString suffix = format.stringProperty(KoListStyle::ListItemSuffix); const int level = format.intProperty(KoListStyle::Level); int dp = format.intProperty(KoListStyle::DisplayLevel); if (dp > level) dp = level; const int displayLevel = dp ? dp : 1; int startValue = 1; if (format.hasProperty(KoListStyle::StartValue)) startValue = format.intProperty(KoListStyle::StartValue); if (format.boolProperty(KoListStyle::ContinueNumbering)) { // Look for the index of a previous list of the same numbering style and level for (QTextBlock tb = m_textList->item(0).previous(); tb.isValid(); tb = tb.previous()) { if (!tb.textList() || tb.textList() == m_textList) continue; // no list here or it's the same list; keep looking QTextListFormat otherFormat = tb.textList()->format(); if (otherFormat.intProperty(KoListStyle::Level) != level) break; // found a different list but of a different level if (otherFormat.style() == format.style()) { if (KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(tb.userData())) startValue = data->counterIndex() + 1; // Start from previous list value + 1 } break; } } int index = startValue; QList<QTextList*> sublistsToRecalculate; qreal width = format.doubleProperty(KoListStyle::MinimumWidth); for (int i = 0; i < m_textList->count(); i++) { QTextBlock tb = m_textList->item(i); //kDebug(32500) <<" *" << tb.text(); KoTextBlockData *data = dynamic_cast<KoTextBlockData*>(tb.userData()); if (!data) { data = new KoTextBlockData(); tb.setUserData(data); } QTextBlockFormat blockFormat = tb.blockFormat(); if (blockFormat.boolProperty(KoParagraphStyle::UnnumberedListItem) || blockFormat.boolProperty(KoParagraphStyle::IsListHeader)) { data->setCounterText(QString()); data->setPartialCounterText(QString()); continue; } if (blockFormat.boolProperty(KoParagraphStyle::RestartListNumbering)) index = format.intProperty(KoListStyle::StartValue); const int paragIndex = blockFormat.intProperty(KoParagraphStyle::ListStartValue); if (paragIndex > 0) index = paragIndex; //check if this is the first of this level meaning we should start from startvalue QTextBlock b = tb.previous(); for (;b.isValid(); b = b.previous()) { if (b.textList() == m_textList) break; // all fine if (b.textList() == 0) continue; QTextListFormat otherFormat = b.textList()->format(); if (otherFormat.style() != format.style()) continue; // uninteresting for us if (b.textList()->format().intProperty(KoListStyle::Level) < level) { index = startValue; break; } } QString item; if (displayLevel > 1) { int checkLevel = level; int tmpDisplayLevel = displayLevel; for (QTextBlock b = tb.previous(); tmpDisplayLevel > 1 && b.isValid(); b = b.previous()) { if (b.textList() == 0) continue; QTextListFormat lf = b.textList()->format(); if (lf.style() != format.style()) continue; // uninteresting for us const int otherLevel = lf.intProperty(KoListStyle::Level); if (checkLevel <= otherLevel) continue; /*if(needsRecalc(b->textList())) { TODO } */ KoTextBlockData *otherData = dynamic_cast<KoTextBlockData*>(b.userData()); if (! otherData) { kWarning(32500) << "Missing KoTextBlockData, Skipping textblock"; continue; } if (tmpDisplayLevel - 1 < otherLevel) { // can't just copy it fully since we are // displaying less then the full counter item += otherData->partialCounterText(); tmpDisplayLevel--; checkLevel--; for (int i = otherLevel + 1; i < level; i++) { tmpDisplayLevel--; item += ".1"; // add missing counters. } } else { // just copy previous counter as prefix QString otherPrefix = lf.stringProperty(KoListStyle::ListItemPrefix); QString otherSuffix = lf.stringProperty(KoListStyle::ListItemSuffix); QString pureCounter = otherData->counterText().mid(otherPrefix.size()); pureCounter = pureCounter.left(pureCounter.size() - otherSuffix.size()); item += pureCounter; for (int i = otherLevel + 1; i < level; i++) item += ".1"; // add missing counters. tmpDisplayLevel = 0; break; } } for (int i = 1; i < tmpDisplayLevel; i++) item = "1." + item; // add missing counters. } if ((listStyle == KoListStyle::DecimalItem || listStyle == KoListStyle::AlphaLowerItem || listStyle == KoListStyle::UpperAlphaItem || listStyle == KoListStyle::RomanLowerItem || listStyle == KoListStyle::UpperRomanItem) && !(item.isEmpty() || item.endsWith('.') || item.endsWith(' '))) { item += '.'; } bool calcWidth = true; QString partialCounterText; switch (listStyle) { case KoListStyle::DecimalItem: partialCounterText = QString::number(index); break; case KoListStyle::AlphaLowerItem: partialCounterText = intToAlpha(index, Lowercase, m_textList->format().boolProperty(KoListStyle::LetterSynchronization)); break; case KoListStyle::UpperAlphaItem: partialCounterText = intToAlpha(index, Uppercase, m_textList->format().boolProperty(KoListStyle::LetterSynchronization)); break; case KoListStyle::RomanLowerItem: partialCounterText = intToRoman(index); break; case KoListStyle::UpperRomanItem: partialCounterText = intToRoman(index).toUpper(); break; case KoListStyle::SquareItem: case KoListStyle::DiscItem: case KoListStyle::CircleItem: case KoListStyle::HeavyCheckMarkItem: case KoListStyle::BallotXItem: case KoListStyle::RightArrowItem: case KoListStyle::RightArrowHeadItem: case KoListStyle::RhombusItem: case KoListStyle::BoxItem: { calcWidth = false; item = ' '; width = m_displayFont.pointSizeF(); int percent = format.intProperty(KoListStyle::BulletSize); if (percent > 0) width = width * (percent / 100.0); break; } case KoListStyle::CustomCharItem: calcWidth = false; if (format.intProperty(KoListStyle::BulletCharacter)) item = QString(QChar(format.intProperty(KoListStyle::BulletCharacter))); width = m_fm.width(item); break; case KoListStyle::None: calcWidth = false; width = 10.0; // simple indenting break; case KoListStyle::Bengali: case KoListStyle::Gujarati: case KoListStyle::Gurumukhi: case KoListStyle::Kannada: case KoListStyle::Malayalam: case KoListStyle::Oriya: case KoListStyle::Tamil: case KoListStyle::Telugu: case KoListStyle::Tibetan: case KoListStyle::Thai: partialCounterText = intToScript(index, listStyle); break; case KoListStyle::Abjad: case KoListStyle::ArabicAlphabet: case KoListStyle::AbjadMinor: partialCounterText = intToScriptList(index, listStyle); break; case KoListStyle::ImageItem: calcWidth = false; width = qMax(format.doubleProperty(KoListStyle::Width), (qreal)1.0); break; default: // others we ignore. calcWidth = false; } data->setCounterIsImage(listStyle == KoListStyle::ImageItem); data->setPartialCounterText(partialCounterText); data->setCounterIndex(index); item += partialCounterText; if (calcWidth) width = qMax(width, m_fm.width(item)); data->setCounterText(prefix + item + suffix); index++; // have to recalculate any sublists under this element too QTextBlock nb = tb.next(); while (nb.isValid() && nb.textList() == 0) nb = nb.next(); if (nb.isValid()) { QTextListFormat lf = nb.textList()->format(); if ((lf.style() == format.style()) && nb.textList()->format().intProperty(KoListStyle::Level) > level) { // this is a sublist // have to remember to recalculate this list after the current level is done // cant do it right away since the sublist's prefix text is dependant on this level sublistsToRecalculate.append(nb.textList()); } } } for (int i = 0; i < sublistsToRecalculate.count(); i++) { ListItemsHelper lih(sublistsToRecalculate.at(i), m_displayFont); lih.recalculate(); } qreal counterSpacing = m_fm.width(' '); counterSpacing = qMax(format.doubleProperty(KoListStyle::MinimumDistance), counterSpacing); width += m_fm.width(prefix + suffix); // same for all width = qMax(format.doubleProperty(KoListStyle::MinimumWidth), width); for (int i = 0; i < m_textList->count(); i++) { QTextBlock tb = m_textList->item(i); KoTextBlockData *data = dynamic_cast<KoTextBlockData*>(tb.userData()); Q_ASSERT(data); data->setCounterWidth(width); data->setCounterSpacing(counterSpacing); //kDebug(32500) << data->counterText() <<"" << tb.text(); //kDebug(32500) <<" setCounterWidth:" << width; } //kDebug(32500); }