10#include <QAbstractTextDocumentLayout>
12#include <QApplication>
21#include <QTextDocumentFragment>
24#include <QtGui/private/qtextdocument_p.h>
28using namespace Qt::Literals::StringLiterals;
33 setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding));
35 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
36 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
38 QAbstractTextDocumentLayout *docLayout = document()->documentLayout();
39 connect(docLayout, &QAbstractTextDocumentLayout::documentSizeChanged,
40 this, &ExpandingTextEdit::updateHeight);
41 connect(
this, &QTextEdit::cursorPositionChanged,
42 this, &ExpandingTextEdit::reallyEnsureCursorVisible);
44 m_minimumHeight = qRound(docLayout->documentSize().height()) + frameWidth() * 2;
49 m_minimumHeight = qRound(documentSize.height()) + frameWidth() * 2;
55 return QSize(100, m_minimumHeight);
60 return QSize(100, m_minimumHeight);
65 QObject *ancestor = parent();
67 QScrollArea *scrollArea = qobject_cast<QScrollArea*>(ancestor);
69 (scrollArea->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff &&
70 scrollArea->horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff)) {
71 const QRect &r = cursorRect();
72 const QPoint &c = mapTo(scrollArea->widget(), r.center());
73 scrollArea->ensureVisible(c.x(), c.y());
76 ancestor = ancestor->parent();
83 setLineWrapMode(QTextEdit::WidgetWidth);
84 setAcceptRichText(
false);
85 m_highlighter =
new MessageHighlighter(
this);
88 QPalette p = palette();
89 p.setColor(QPalette::Disabled, QPalette::Base, p.color(QPalette::Active, QPalette::Base));
99 emit editorDestroyed();
105 static int framed = frameStyle();
106 static Qt::FocusPolicy defaultFocus = focusPolicy();
109 setFrameStyle(framed);
110 setFocusPolicy(defaultFocus);
112 setFrameStyle(QFrame::NoFrame | QFrame::Plain);
113 setFocusPolicy(Qt::NoFocus);
116 setReadOnly(!editable);
117 applyReadOnlySelectionPalette();
124 bool oldBlockState = blockSignals(
true);
125 document()->setUndoRedoEnabled(
false);
126 ExpandingTextEdit::setPlainText(text);
128 m_highlighter->rehighlight();
129 document()->setUndoRedoEnabled(
true);
130 blockSignals(oldBlockState);
132 ExpandingTextEdit::setPlainText(text);
138 QTextOption option = document()->defaultTextOption();
140 option.setFlags(option.flags()
141 | QTextOption::ShowLineAndParagraphSeparators
142 | QTextOption::ShowTabsAndSpaces);
144 option.setFlags(option.flags()
145 & ~QTextOption::ShowLineAndParagraphSeparators
146 & ~QTextOption::ShowTabsAndSpaces);
148 document()->setDefaultTextOption(option);
153 if ((event->type() == QEvent::ApplicationPaletteChange
154 || event->type() == QEvent::PaletteChange)) {
156 m_defaultPalette = palette();
157 applyReadOnlySelectionPalette();
159 return ExpandingTextEdit::event(event);
167 setPalette(m_defaultPalette);
171 QPalette pal = m_defaultPalette;
173 const QColor gray(100, 100, 100);
174 const QColor darkText = pal.color(QPalette::Text);
175 pal.setColor(QPalette::Inactive, QPalette::Highlight, gray);
176 pal.setColor(QPalette::Inactive, QPalette::HighlightedText, darkText);
177 pal.setColor(QPalette::Disabled, QPalette::Highlight, gray);
178 pal.setColor(QPalette::Disabled, QPalette::HighlightedText, darkText);
183FormWidget::FormWidget(
const QString &label,
bool isEditable, QWidget *parent)
185 m_hideWhenEmpty(
false)
187 QVBoxLayout *layout =
new QVBoxLayout;
188 layout->setContentsMargins(QMargins());
190 m_label =
new QLabel(
this);
193 m_label->setFont(fnt);
194 m_label->setText(label);
195 layout->addWidget(m_label);
197 m_editor =
new FormatTextEdit(
this);
200 layout->addWidget(m_editor);
204 connect(m_editor, &QTextEdit::textChanged,
205 this, &FormWidget::slotTextChanged);
206 connect(m_editor, &QTextEdit::selectionChanged,
207 this, &FormWidget::slotSelectionChanged);
208 connect(m_editor, &QTextEdit::cursorPositionChanged,
209 this, &FormWidget::cursorPositionChanged);
214 emit textChanged(m_editor);
219 emit selectionChanged(m_editor);
224 m_editor->setPlainText(text, userAction);
226 setHidden(text.isEmpty());
232 m_editor->setReadOnly(!enable);
233 m_label->setEnabled(enable);
244 QBoxLayout *box =
new QVBoxLayout;
245 box->setContentsMargins(QMargins());
247 box->addWidget(wrapee, 0, Qt::AlignBottom);
249 relator->installEventFilter(
this);
255 if (event->type() == QEvent::Resize) {
256 QWidget *relator =
static_cast<QWidget *>(object);
257 setFixedHeight(relator->height());
265 m_hideWhenEmpty(
false),
266 m_multiEnabled(
false)
269 m_label =
new QLabel(
this);
272 m_label->setFont(fnt);
273 m_label->setText(label);
275 m_plusButtons.append(
276 new ButtonWrapper(makeButton(m_plusIcon, &FormMultiWidget::plusButtonClicked), 0));
281 const QString prefix = isDarkMode() ?
":/images/darkicons"_L1:
":/images/lighticons"_L1;
282 m_plusIcon = QIcon(prefix +
"/plus-square-fill.png"_L1);
283 m_minusIcon = QIcon(prefix +
"/minus-square-fill.png"_L1);
284 for (QAbstractButton *button: std::as_const(m_minusButtons))
285 button->setIcon(m_minusIcon);
286 for (QWidget *button: std::as_const(m_plusButtons)) {
287 QWidget *w = button->layout()->itemAt(0)->widget();
288 if (
auto b = qobject_cast<QAbstractButton*>(w); b)
289 b->setIcon(m_plusIcon);
295 QAbstractButton *btn =
new QToolButton(
this);
297 btn->setFixedSize(icon.availableSizes().first() );
298 btn->setFocusPolicy(Qt::NoFocus);
299#ifndef QT_NO_STYLE_STYLESHEET
300 btn->setStyleSheet(
"border: none; background: transparent;"_L1);
308 m_editors.insert(idx, editor);
310 m_minusButtons.insert(idx, makeButton(m_minusIcon, &FormMultiWidget::minusButtonClicked));
311 m_plusButtons.insert(idx + 1,
312 new ButtonWrapper(makeButton(m_plusIcon, &FormMultiWidget::plusButtonClicked), editor));
314 connect(editor, &QTextEdit::textChanged,
315 this, &FormMultiWidget::slotTextChanged);
316 connect(editor, &QTextEdit::selectionChanged,
317 this, &FormMultiWidget::slotSelectionChanged);
318 connect(editor, &QTextEdit::cursorPositionChanged,
319 this, &FormMultiWidget::cursorPositionChanged);
320 editor->installEventFilter(
this);
322 emit editorCreated(editor);
328 while (m_editors.at(i) != watched)
329 if (++i >= m_editors.size())
331 if (event->type() == QEvent::FocusOut) {
332 m_minusButtons.at(i)->setToolTip(QString());
333 m_plusButtons.at(i)->setToolTip(QString());
334 m_plusButtons.at(i + 1)->setToolTip(QString());
335 }
else if (event->type() == QEvent::FocusIn) {
336 m_minusButtons.at(i)->setToolTip( tr(
"Alt+Delete"));
337 m_plusButtons.at(i)->setToolTip( tr(
"Shift+Alt+Insert"));
338 m_plusButtons.at(i + 1)->setToolTip( tr(
"Alt+Insert"));
339 }
else if (event->type() == QEvent::KeyPress) {
340 QKeyEvent *ke =
static_cast<QKeyEvent *>(event);
341 if (ke->modifiers() & Qt::AltModifier) {
342 if (ke->key() == Qt::Key_Delete) {
345 }
else if (ke->key() == Qt::Key_Insert) {
346 if (!(ke->modifiers() & Qt::ShiftModifier))
352 }
else if (event->type() == QEvent::ApplicationPaletteChange) {
362 QGridLayout *layout =
new QGridLayout;
363 layout->setContentsMargins(QMargins());
366 bool variants = m_multiEnabled && m_label->isEnabled();
368 layout->addWidget(m_label, 0, 0, 1, variants ? 2 : 1);
371 QVBoxLayout *layoutForPlusButtons =
new QVBoxLayout;
372 layoutForPlusButtons->setContentsMargins(QMargins());
373 for (
int i = 0; i < m_plusButtons.size(); ++i)
374 layoutForPlusButtons->addWidget(m_plusButtons.at(i), Qt::AlignTop);
375 layout->addLayout(layoutForPlusButtons, 1, 0, Qt::AlignTop);
377 const int minimumRowHeight = m_plusButtons.at(0)->sizeHint().height() / 2.0;
378 QGridLayout *layoutForLabels =
new QGridLayout;
379 layoutForLabels->setContentsMargins(QMargins());
380 layoutForLabels->setRowMinimumHeight(0, minimumRowHeight);
381 for (
int j = 0; j < m_editors.size(); ++j) {
382 layoutForLabels->addWidget(m_editors.at(j), 1 + j, 0, Qt::AlignVCenter);
383 layoutForLabels->addWidget(m_minusButtons.at(j), 1 + j, 1, Qt::AlignVCenter);
385 layoutForLabels->setRowMinimumHeight(m_editors.size() + 1, minimumRowHeight);
386 layout->addLayout(layoutForLabels, 1, 1, Qt::AlignTop);
388 for (
int k = 0; k < m_editors.size(); ++k)
389 layout->addWidget(m_editors.at(k), 1 + k, 0, Qt::AlignVCenter);
392 for (
int i = 0; i < m_plusButtons.size(); ++i)
393 m_plusButtons.at(i)->setVisible(variants);
394 for (
int j = 0; j < m_minusButtons.size(); ++j)
395 m_minusButtons.at(j)->setVisible(variants);
402 emit textChanged(
static_cast<QTextEdit *>(sender()));
407 emit selectionChanged(
static_cast<QTextEdit *>(sender()));
412 QStringList texts = text.split(QChar(Translator::BinaryVariantSeparator), Qt::KeepEmptyParts);
414 while (m_editors.size() > texts.size()) {
415 delete m_minusButtons.takeLast();
416 delete m_plusButtons.takeLast();
417 delete m_editors.takeLast();
419 while (m_editors.size() < texts.size())
420 addEditor(m_editors.size());
423 for (
int i = 0; i < texts.size(); ++i)
425 m_editors.at(i)->setPlainText(texts.at(i), userAction);
428 setHidden(text.isEmpty());
436 QChar *uc = txt.data();
437 QChar *e = uc + txt.size();
439 for (; uc != e; ++uc) {
440 switch (uc->unicode()) {
443 case QChar::ParagraphSeparator:
444 case QChar::LineSeparator:
455 for (
int i = 0; i < m_editors.size(); ++i) {
457 ret += QChar(Translator::BinaryVariantSeparator);
458 ret += toPlainText(m_editors.at(i)->document()->toRawText());
466 for (
int i = 0; i < m_editors.size(); ++i)
467 m_editors.at(i)->setReadOnly(!enable);
468 m_label->setEnabled(enable);
475 m_multiEnabled = enable;
476 if (m_label->isEnabled())
483 while (m_minusButtons.at(i) != sender())
490 QWidget *btn =
static_cast<QAbstractButton *>(sender())->parentWidget();
492 while (m_plusButtons.at(i) != btn)
499 if (m_editors.size() == 1) {
501 QTextCursor c = m_editors.first()->textCursor();
502 c.select(QTextCursor::Document);
503 c.removeSelectedText();
505 if (!m_editors.at(idx)->toPlainText().isEmpty()) {
506 if (QMessageBox::question(topLevelWidget(), tr(
"Confirmation - Qt Linguist"),
507 tr(
"Delete non-empty length variant?"),
508 QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes)
512 delete m_editors.takeAt(idx);
513 delete m_minusButtons.takeAt(idx);
514 delete m_plusButtons.takeAt(idx + 1);
516 emit textChanged(m_editors.at((m_editors.size() == idx) ? idx - 1 : idx));
524 emit textChanged(m_editors.at(idx));
QSize minimumSizeHint() const override
QSize sizeHint() const override
void setVisualizeWhitespace(bool value)
bool event(QEvent *event) override
void setEditable(bool editable)