UBGraphicsTextItemDelegate.cpp 23.4 KB
Newer Older
Claudio Valerio's avatar
Claudio Valerio committed
1
/*
Craig Watson's avatar
Craig Watson committed
2 3
 * Copyright (C) 2015-2016 Département de l'Instruction Publique (DIP-SEM)
 *
Claudio Valerio's avatar
Claudio Valerio committed
4
 * Copyright (C) 2013 Open Education Foundation
Claudio Valerio's avatar
Claudio Valerio committed
5
 *
Claudio Valerio's avatar
Claudio Valerio committed
6 7
 * Copyright (C) 2010-2013 Groupement d'Intérêt Public pour
 * l'Education Numérique en Afrique (GIP ENA)
8
 *
Claudio Valerio's avatar
Claudio Valerio committed
9 10 11
 * This file is part of OpenBoard.
 *
 * OpenBoard is free software: you can redistribute it and/or modify
Claudio Valerio's avatar
Claudio Valerio committed
12 13
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License,
14 15 16 17
 * with a specific linking exception for the OpenSSL project's
 * "OpenSSL" library (or with modified versions of it that use the
 * same license as the "OpenSSL" library).
 *
Claudio Valerio's avatar
Claudio Valerio committed
18
 * OpenBoard is distributed in the hope that it will be useful,
Claudio Valerio's avatar
Claudio Valerio committed
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Claudio Valerio's avatar
Claudio Valerio committed
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Claudio Valerio's avatar
Claudio Valerio committed
21
 * GNU General Public License for more details.
Claudio Valerio's avatar
Claudio Valerio committed
22
 *
Claudio Valerio's avatar
Claudio Valerio committed
23
 * You should have received a copy of the GNU General Public License
Claudio Valerio's avatar
Claudio Valerio committed
24
 * along with OpenBoard. If not, see <http://www.gnu.org/licenses/>.
Claudio Valerio's avatar
Claudio Valerio committed
25 26
 */

27

Claudio Valerio's avatar
Claudio Valerio committed
28

Claudio Valerio's avatar
Claudio Valerio committed
29

Claudio Valerio's avatar
Claudio Valerio committed
30 31 32
#include <QtGui>
#include <QtSvg>

Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
33
#include "core/UBApplication.h"
Claudio Valerio's avatar
Claudio Valerio committed
34
#include "UBGraphicsGroupContainerItem.h"
Claudio Valerio's avatar
Claudio Valerio committed
35 36
#include "UBGraphicsTextItemDelegate.h"
#include "UBGraphicsScene.h"
Claudio Valerio's avatar
Claudio Valerio committed
37 38
#include "gui/UBResources.h"

Claudio Valerio's avatar
Claudio Valerio committed
39 40 41 42
#include "domain/UBGraphicsTextItem.h"
#include "domain/UBGraphicsDelegateFrame.h"
#include "core/UBSettings.h"

43
#include "board/UBBoardController.h"
Clément Fauconnier's avatar
Clément Fauconnier committed
44
#include "board/UBBoardView.h"
Claudio Valerio's avatar
Claudio Valerio committed
45

46 47
#include "core/memcheck.h"

Claudio Valerio's avatar
Claudio Valerio committed
48
const int UBGraphicsTextItemDelegate::sMinPixelSize = 8;
49
const int UBGraphicsTextItemDelegate::sMinPointSize = 8;
Claudio Valerio's avatar
Claudio Valerio committed
50

51 52 53

AlignTextButton::AlignTextButton(const QString &fileName, QGraphicsItem *pDelegated, QGraphicsItem *parent, Qt::WindowFrameSection section)
    : DelegateButton(fileName, pDelegated, parent, section)
-f's avatar
-f committed
54 55 56 57
    , lft(new QSvgRenderer(QString(":/images/leftAligned.svg")))
    , cntr(new QSvgRenderer(QString(":/images/centerAligned.svg")))
    , rght(new QSvgRenderer(QString(":/images/rightAligned.svg")))
    , mxd(new QSvgRenderer(QString(":/images/notAligned.svg")))
58
    , mHideMixed(true)
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
{
    setKind(k_left);
}

AlignTextButton::~AlignTextButton()
{
    if (lft) delete lft;
    if (cntr) delete cntr;
    if (rght) delete rght;
    if (mxd) delete mxd;
}

void AlignTextButton::setKind(int pKind)
{
    if (mHideMixed && pKind == k_mixed) {
        qDebug() << "Mixed button is hidden, can't process it";
        return;
    }
    mKind = pKind;
    QSvgRenderer *rndrer = rndFromKind(pKind);
    Q_ASSERT(rndrer);
    setSharedRenderer(rndrer);
}

void AlignTextButton::setNextKind()
{
    int mxKind = MAX_KIND;
    if (mHideMixed) {
        mxKind--;
    }
    setKind(mKind == mxKind ? 0 : ++mKind);
}

int AlignTextButton::nextKind() const
{
    int mxKind = MAX_KIND;
    if (mHideMixed) {
        mxKind--;
    }
    int result = mKind;
    return mKind == mxKind ? 0 : ++result;
}

102
UBGraphicsTextItemDelegate::UBGraphicsTextItemDelegate(UBGraphicsTextItem* pDelegated, QObject *)
103
    : UBGraphicsItemDelegate(pDelegated,0, GF_COMMON | GF_REVOLVABLE | GF_TITLE_BAR_USED)
104 105 106 107 108
    , mFontButton(0)
    , mColorButton(0)
    , mDecreaseSizeButton(0)
    , mIncreaseSizeButton(0)
    , mAlignButton(0)
Claudio Valerio's avatar
Claudio Valerio committed
109
    , mLastFontPixelSize(-1)
110
    , delta(5)
Claudio Valerio's avatar
Claudio Valerio committed
111
{
Ivan Ilin's avatar
Ivan Ilin committed
112 113 114 115 116 117 118 119 120 121 122
    delegated()->setData(UBGraphicsItemData::ItemEditable, QVariant(true));
    delegated()->setPlainText("");

    QTextCursor curCursor = delegated()->textCursor();
    QTextCharFormat format;
    QFont font(createDefaultFont());
    font.setPointSize(UBSettings::settings()->fontPointSize());

    format.setFont(font);
    curCursor.mergeCharFormat(format);
    delegated()->setTextCursor(curCursor);
123
    delegated()->setFont(font);
Ivan Ilin's avatar
Ivan Ilin committed
124 125 126 127

    delegated()->adjustSize();
    delegated()->contentsChanged();

128 129
    connect(delegated()->document(), SIGNAL(cursorPositionChanged(QTextCursor)), this, SLOT(onCursorPositionChanged(QTextCursor)));
    connect(delegated()->document(), SIGNAL(modificationChanged(bool)), this, SLOT(onModificationChanged(bool)));
Claudio Valerio's avatar
Claudio Valerio committed
130 131 132 133 134 135 136
}

UBGraphicsTextItemDelegate::~UBGraphicsTextItemDelegate()
{
    // NOOP
}

Ivan Ilin's avatar
Ivan Ilin committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
QFont UBGraphicsTextItemDelegate::createDefaultFont()
{
    QTextCharFormat textFormat;

    QString fFamily = UBSettings::settings()->fontFamily();
    if (!fFamily.isEmpty())
        textFormat.setFontFamily(fFamily);

    bool bold = UBSettings::settings()->isBoldFont();
    if (bold)
        textFormat.setFontWeight(QFont::Bold);

    bool italic = UBSettings::settings()->isItalicFont();
    if (italic)
        textFormat.setFontItalic(true);

    QFont font(fFamily, -1, bold ? QFont::Bold : -1, italic);
154 155 156
    int pointSize = UBSettings::settings()->fontPointSize();
    if (pointSize > 0) {
        font.setPointSize(pointSize);
Ivan Ilin's avatar
Ivan Ilin committed
157 158 159 160 161
    }

    return font;
}

162
void UBGraphicsTextItemDelegate::createControls()
Claudio Valerio's avatar
Claudio Valerio committed
163
{
164
    UBGraphicsItemDelegate::createControls();
Claudio Valerio's avatar
Claudio Valerio committed
165

166
    if (!mFontButton) {
167
        mFontButton = new DelegateButton(":/images/font.svg", mDelegated, mFrame, Qt::TitleBarArea);
168
        connect(mFontButton, SIGNAL(clicked(bool)), this, SLOT(pickFont()));
169
        mButtons << mFontButton;
170 171
    }
    if (!mColorButton) {
172
        mColorButton = new DelegateButton(":/images/color.svg", mDelegated, mFrame, Qt::TitleBarArea);
173
        connect(mColorButton, SIGNAL(clicked(bool)), this, SLOT(pickColor()));
174
        mButtons << mColorButton;
175
    }
Claudio Valerio's avatar
Claudio Valerio committed
176

177
    if (!mDecreaseSizeButton) {
178
        mDecreaseSizeButton = new DelegateButton(":/images/minus.svg", mDelegated, mFrame, Qt::TitleBarArea);
179
        connect(mDecreaseSizeButton, SIGNAL(clicked(bool)), this, SLOT(decreaseSize()));
180
        mButtons << mDecreaseSizeButton;
181 182 183
    }

    if (!mIncreaseSizeButton) {
184
        mIncreaseSizeButton = new DelegateButton(":/images/plus.svg", mDelegated, mFrame, Qt::TitleBarArea);
185
        connect(mIncreaseSizeButton, SIGNAL(clicked(bool)), this, SLOT(increaseSize()));
186
        mButtons << mIncreaseSizeButton;
187 188 189
    }

    if (!mAlignButton) {
190
        mAlignButton = new AlignTextButton(":/images/plus.svg", mDelegated, mFrame, Qt::TitleBarArea);
191
        connect(mAlignButton, SIGNAL(clicked()), this, SLOT(alignButtonProcess()));
192
        mButtons << mAlignButton;
193
    }
194

195 196 197 198 199 200
    foreach(DelegateButton* button, mButtons)
    {
        button->hide();
        button->setFlag(QGraphicsItem::ItemIsSelectable, true);
    }

201 202 203 204 205
    // Claudio: on changing the zvlaue the frame is updated updateSelectionFrame and
    // the default value for the operation mode is set (scaling). This isn't the right
    // mode for text so we call that here.
    frame()->setOperationMode(UBGraphicsDelegateFrame::Resizing);

206 207
}

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
/**
 * @brief Calculate the width of the toolbar containing the text item-related buttons
 * @return The space between the left-most and right-most buttons in pixels
 */
qreal UBGraphicsTextItemDelegate::titleBarWidth()
{
    if (!mFontButton)
        return 0;

    // refresh the frame and buttons' positions
    positionHandles();

    qreal titleBarWidth(0);
    qreal frameLeftCoordinate = mFontButton->pos().x();
    qreal frameRightCoordinate = frameLeftCoordinate;

    foreach(DelegateButton* button, mButtons) {
        if (button->getSection() == Qt::TitleBarArea) {
            frameLeftCoordinate = qMin(button->pos().x(), frameLeftCoordinate);
            frameRightCoordinate = qMax(button->pos().x() + button->boundingRect().width(), frameRightCoordinate);
        }
    }

    return frameRightCoordinate - frameLeftCoordinate;
}
Claudio Valerio's avatar
Claudio Valerio committed
233

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
void UBGraphicsTextItemDelegate::freeButtons()
{
    mButtons.removeOne(mFontButton);
    delete mFontButton;
    mFontButton = 0;

    mButtons.removeOne(mColorButton);
    delete mColorButton;
    mColorButton = 0;

    mButtons.removeOne(mDecreaseSizeButton);
    delete mDecreaseSizeButton;
    mDecreaseSizeButton = 0;

    mButtons.removeOne(mIncreaseSizeButton);
    delete mIncreaseSizeButton;
    mIncreaseSizeButton = 0;

252 253 254
    mButtons.removeOne(mAlignButton);
    delete mAlignButton;
    mAlignButton = 0;
255 256

    UBGraphicsItemDelegate::freeButtons();
Claudio Valerio's avatar
Claudio Valerio committed
257 258
}

259 260 261



Claudio Valerio's avatar
Claudio Valerio committed
262 263 264 265 266
void UBGraphicsTextItemDelegate::contentsChanged()
{
    delegated()->contentsChanged();
}

267 268
// This method is used to filter the available fonts. Only the web-compliant fonts
// will remain in the font list.
Claudio Valerio's avatar
Claudio Valerio committed
269 270 271 272
void UBGraphicsTextItemDelegate::customize(QFontDialog &fontDialog)
{
    fontDialog.setOption(QFontDialog::DontUseNativeDialog);

273
    if (UBSettings::settings()->isDarkBackground()) {
Claudio Valerio's avatar
Claudio Valerio committed
274 275 276
        fontDialog.setStyleSheet("background-color: white;");
    }

277
    QListView *fontNameListView = NULL;
Claudio Valerio's avatar
Claudio Valerio committed
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
    QList<QListView*> listViews = fontDialog.findChildren<QListView*>();
    if (listViews.count() > 0)
    {
        fontNameListView = listViews.at(0);
        foreach (QListView* listView, listViews)
        {
            if (listView->pos().x() < fontNameListView->pos().x())
                fontNameListView = listView;
        }
    }
    if (fontNameListView)
    {
        QStringListModel *stringListModel = dynamic_cast<QStringListModel*>(fontNameListView->model());
        if (stringListModel)
        {
            QStringList dialogFontNames = stringListModel->stringList();
            QStringList safeWebFontNames;
            safeWebFontNames.append("Arial");
            safeWebFontNames.append("Arial Black");
            safeWebFontNames.append("Comic Sans MS");
            safeWebFontNames.append("Courier New");
            safeWebFontNames.append("Georgia");
            safeWebFontNames.append("Impact");
            safeWebFontNames.append("Times New Roman");
            safeWebFontNames.append("Trebuchet MS");
            safeWebFontNames.append("Verdana");
Claudio Valerio's avatar
Claudio Valerio committed
304 305

            QStringList customFontList =  UBResources::resources()->customFontList();
Claudio Valerio's avatar
Claudio Valerio committed
306
            int index = 0;
Claudio Valerio's avatar
Claudio Valerio committed
307 308
            foreach (QString dialogFontName, dialogFontNames){
                if (safeWebFontNames.contains(dialogFontName, Qt::CaseInsensitive) || customFontList.contains(dialogFontName, Qt::CaseSensitive))
Claudio Valerio's avatar
Claudio Valerio committed
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
                    index++;
                else
                    stringListModel->removeRow(index);
            }
        }
    }
    QList<QComboBox*> comboBoxes = fontDialog.findChildren<QComboBox*>();
    if (comboBoxes.count() > 0)
        comboBoxes.at(0)->setEnabled(false);
}


void UBGraphicsTextItemDelegate::pickFont()
{
    if (mDelegated && mDelegated->scene() && mDelegated->scene()->views().size() > 0)
    {
325
        QFontDialog fontDialog(delegated()->textCursor().charFormat().font(), static_cast<QGraphicsView*>(UBApplication::boardController->controlView()));
Claudio Valerio's avatar
Claudio Valerio committed
326 327 328 329 330 331 332 333
        customize(fontDialog);

        if (fontDialog.exec())
        {
            QFont selectedFont = fontDialog.selectedFont();
            UBSettings::settings()->setFontFamily(selectedFont.family());
            UBSettings::settings()->setBoldFont(selectedFont.bold());
            UBSettings::settings()->setItalicFont(selectedFont.italic());
Ivan Ilin's avatar
Ivan Ilin committed
334
            UBSettings::settings()->setFontPointSize(selectedFont.pointSize());
Claudio Valerio's avatar
Claudio Valerio committed
335

336 337 338 339 340 341
            //setting format for selected item
            QTextCursor curCursor = delegated()->textCursor();
            QTextCharFormat format;
            format.setFont(selectedFont);
            curCursor.mergeCharFormat(format);

342
            delegated()->setTextCursor(curCursor);
343 344 345 346

            if (curCursor.selectedText().length() == 0)
                delegated()->setFont(selectedFont);

347
            delegated()->setSelected(true);
Claudio Valerio's avatar
Claudio Valerio committed
348 349 350 351 352 353 354 355 356 357
            delegated()->document()->adjustSize();
            delegated()->contentsChanged();
        }
    }
}

void UBGraphicsTextItemDelegate::pickColor()
{
    if (mDelegated && mDelegated->scene() && mDelegated->scene()->views().size() > 0)
    {
358
        QColorDialog colorDialog(delegated()->defaultTextColor(), static_cast<QGraphicsView*>(UBApplication::boardController->controlView()));
Claudio Valerio's avatar
Claudio Valerio committed
359
        colorDialog.setWindowTitle(tr("Text Color"));
360
        colorDialog.setOption(QColorDialog::DontUseNativeDialog);
Claudio Valerio's avatar
Claudio Valerio committed
361 362 363 364 365 366 367 368 369
        if (UBSettings::settings()->isDarkBackground())
        {
            colorDialog.setStyleSheet("background-color: white;");
        }

        if (colorDialog.exec())
        {
            QColor selectedColor = colorDialog.selectedColor();
            delegated()->setDefaultTextColor(selectedColor);
370 371 372 373 374
            QTextCursor curCursor = delegated()->textCursor();
            QTextCharFormat format;
            format.setForeground(QBrush(selectedColor));
            curCursor.mergeCharFormat(format);
            delegated()->setTextCursor(curCursor);
Claudio Valerio's avatar
Claudio Valerio committed
375 376 377 378 379 380 381 382 383 384 385

            UBGraphicsTextItem::lastUsedTextColor = selectedColor;

            delegated()->setSelected(true);
            delegated()->contentsChanged();
        }
    }
}

void UBGraphicsTextItemDelegate::decreaseSize()
{
Aleksei Kanash's avatar
Aleksei Kanash committed
386
    ChangeTextSize(-delta, changeSize);
Claudio Valerio's avatar
Claudio Valerio committed
387 388 389 390
}

void UBGraphicsTextItemDelegate::increaseSize()
{
Aleksei Kanash's avatar
Aleksei Kanash committed
391
   ChangeTextSize(delta, changeSize);
Claudio Valerio's avatar
Claudio Valerio committed
392 393
}

394 395 396 397 398 399 400 401 402 403
void UBGraphicsTextItemDelegate::alignButtonProcess()
{
    qDebug() << "alignButtonProcess() clicked";
    QObject *sndr = sender();

    if (sndr == mAlignButton) {
        qDebug() << "Align button";
        AlignTextButton *asAlText = static_cast<AlignTextButton*>(mAlignButton);
        if (asAlText->nextKind() == AlignTextButton::k_mixed) {
            restoreTextCursorFormats();
404 405
            asAlText->setNextKind();
            return;
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
        }
        asAlText->setNextKind();

        QTextCursor cur = delegated()->textCursor();
        QTextBlockFormat fmt = cur.blockFormat();
        switch (asAlText->kind()) {
        case AlignTextButton::k_left:
            fmt.setAlignment(Qt::AlignLeft);
            break;
        case AlignTextButton::k_center:
            fmt.setAlignment(Qt::AlignCenter);
            break;
        case AlignTextButton::k_right:
            fmt.setAlignment(Qt::AlignRight);
            break;
        case AlignTextButton::k_mixed:
            break;
        }

        delegated()->setTextCursor(cur);
        cur.setBlockFormat(fmt);
427
        delegated()->setFocus();
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
    }

    qDebug() << "sender process" << sndr;
}

void UBGraphicsTextItemDelegate::onCursorPositionChanged(const QTextCursor &cursor)
{
    qDebug() << "cursor position changed";
    qDebug() << "-----------------------";
    qDebug() << "we have a selection!" << cursor.selectionStart();
    qDebug() << "-----------------------";
}

void UBGraphicsTextItemDelegate::onModificationChanged(bool ch)
{
    Q_UNUSED(ch);
    qDebug() << "modification changed";
445 446 447 448 449
}

void UBGraphicsTextItemDelegate::onContentChanged()
{
    qDebug() << "onContentChanged";
450 451
}

Claudio Valerio's avatar
Claudio Valerio committed
452 453 454 455
UBGraphicsTextItem* UBGraphicsTextItemDelegate::delegated()
{
    return static_cast<UBGraphicsTextItem*>(mDelegated);
}
456

457 458 459 460 461 462 463 464 465 466 467 468 469 470
void UBGraphicsTextItemDelegate::setEditable(bool editable)
{
    if (editable) {
        delegated()->setTextInteractionFlags(Qt::TextEditorInteraction);
        mDelegated->setData(UBGraphicsItemData::ItemEditable, QVariant(true));
    } else {
        QTextCursor cursor(delegated()->document());
        cursor.clearSelection();
        delegated()->setTextCursor(cursor);

        delegated()->setTextInteractionFlags(Qt::NoTextInteraction);
        mDelegated->setData(UBGraphicsItemData::ItemEditable, QVariant(false));
    }
}
471

Ilia Ryabokon's avatar
Ilia Ryabokon committed
472 473 474 475 476
void UBGraphicsTextItemDelegate::remove(bool canUndo)
{
    UBGraphicsItemDelegate::remove(canUndo);
}

477 478 479 480
bool UBGraphicsTextItemDelegate::isEditable()
{
    return mDelegated->data(UBGraphicsItemData::ItemEditable).toBool();
}
481

482 483 484 485 486 487
void UBGraphicsTextItemDelegate::decorateMenu(QMenu *menu)
{
    UBGraphicsItemDelegate::decorateMenu(menu);

    mEditableAction = menu->addAction(tr("Editable"), this, SLOT(setEditable(bool)));
    mEditableAction->setCheckable(true);
Ivan Ilin's avatar
Ivan Ilin committed
488
    mEditableAction->setChecked(isEditable());
489 490

}
491

492 493 494 495
void UBGraphicsTextItemDelegate::updateMenuActionState()
{
    UBGraphicsItemDelegate::updateMenuActionState();
}
496

497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
bool UBGraphicsTextItemDelegate::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    mSelectionData.mButtonIsPressed = true;
    qDebug() << "Reporting selection  of the cursor (mouse press)" << delegated()->textCursor().selection().isEmpty();
    qDebug() << QString("Anchor: %1\nposition: %2 (mouse press)").arg(delegated()->textCursor().anchor()).arg(delegated()->textCursor().position());

    if (!UBGraphicsItemDelegate::mousePressEvent(event)) {
        return false;
    }

    return true;
}

bool UBGraphicsTextItemDelegate::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if (mSelectionData.mButtonIsPressed) {
        qDebug() << "Reporting selection of the cursor (mouse move)" << delegated()->textCursor().selection().isEmpty();
        qDebug() << QString("Anchor: %1\nposition: %2 (mouse mouse move)").arg(delegated()->textCursor().anchor()).arg(delegated()->textCursor().position());
    }

    if (!UBGraphicsItemDelegate::mouseMoveEvent(event)) {
        return false;
    }

    return true;
}

bool UBGraphicsTextItemDelegate::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    mSelectionData.mButtonIsPressed = false;
    qDebug() << "Reporting selection of the cursor (mouse release)" << delegated()->textCursor().selection().isEmpty();
    qDebug() << QString("Anchor: %1\nposition: %2 (mouse mouse release)").arg(delegated()->textCursor().anchor()).arg(delegated()->textCursor().position());
    updateAlighButtonState();

    if (!UBGraphicsItemDelegate::mouseReleaseEvent(event)) {
        return false;
    }

    return true;
}

538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
bool UBGraphicsTextItemDelegate::keyPressEvent(QKeyEvent *event)
{
    Q_UNUSED(event);
    return true;
}

bool UBGraphicsTextItemDelegate::keyReleaseEvent(QKeyEvent *event)
{
    if (!delegated()->hasFocus()) {
        return true;
    }

    switch (event->key()) {
    case Qt::Key_Left:
    case Qt::Key_Right:
    case Qt::Key_Up:
    case Qt::Key_Down:
        updateAlighButtonState();
        break;
    }

    qDebug() << "Key has been released" << QString::number(event->key(), 16);
    return true;
}

Aleksei Kanash's avatar
Aleksei Kanash committed
563
void UBGraphicsTextItemDelegate::ChangeTextSize(qreal factor, textChangeMode changeMode)
564
{
565 566 567
    // round it to the nearest hundredth
    factor = floor(factor*100+0.5)/100.;

568 569 570 571 572 573
    if (scaleSize == changeMode)
    {
        if (1 == factor)
            return;
    }
    else
574 575
        if (0 == factor)
            return;
576

Aleksei Kanash's avatar
Aleksei Kanash committed
577 578 579 580 581
    UBGraphicsTextItem *item = dynamic_cast<UBGraphicsTextItem*>(delegated());

    if (item && (QString() == item->toPlainText()))
        return;

582 583 584 585 586 587 588 589
    QTextCursor cursor = delegated()->textCursor();
    QTextCharFormat textFormat;

    int anchorPos = cursor.anchor();
    int cursorPos = cursor.position();

    if (0 == anchorPos-cursorPos)
    {
590
        // If nothing is selected, then we select all the text
591 592 593 594
        cursor.setPosition (0, QTextCursor::MoveAnchor);
        cursor.setPosition (cursor.document()->characterCount()-1, QTextCursor::KeepAnchor);
    }

595
    // Now we got the real start and stop positions
596 597 598
    int startPos = qMin(cursor.anchor(), cursor.position());
    int endPos = qMax(cursor.anchor(), cursor.position());

599
    QFont curFont;
600
    QFont nextCharFont;
601 602 603
    bool bEndofTheSameBlock;
    int iBlockLen;
    int iPointSize;
604
    int iNextPointSize;
605
    int iCursorPos = startPos;
606 607
    QBrush curBrush;
    QBrush nextCharBrush;
608

609
   // we search continuous blocks of the text with the same PointSize and allpy new settings for them.
Aleksei Kanash's avatar
Aleksei Kanash committed
610
    cursor.setPosition (startPos, QTextCursor::MoveAnchor);
611
    while(iCursorPos < endPos)
612
    {
613
        bEndofTheSameBlock = false;
614
        iBlockLen = 0;
615

616
        // Here we get the point size of the first character
617
        cursor.setPosition (iCursorPos+1, QTextCursor::KeepAnchor);
618
        curFont = cursor.charFormat().font();
619
        curBrush = cursor.charFormat().foreground();
620
        iPointSize = curFont.pointSize();
621

622
        // Then we position the end cursor to the start cursor position
623 624 625 626
        cursor.setPosition (iCursorPos, QTextCursor::KeepAnchor);

        do
        {
627
            // Get the next character font size
628
            cursor.setPosition (iCursorPos+iBlockLen+1, QTextCursor::KeepAnchor);
629
            nextCharFont = cursor.charFormat().font();
630
            nextCharBrush = cursor.charFormat().foreground();
631
            iNextPointSize = nextCharFont.pointSize();
632

633
            if ((iPointSize != iNextPointSize)||(iCursorPos+iBlockLen >= endPos)||(0 != curFont.family().compare(nextCharFont.family()))||(curBrush != nextCharBrush)){
634
                bEndofTheSameBlock = true;
635 636 637 638
                break;
            }

            iBlockLen++;
639

640
        }while(!bEndofTheSameBlock);
641

642

643
        //setting new parameters
644
        QFont tmpFont = curFont;
Aleksei Kanash's avatar
Aleksei Kanash committed
645
        int iNewPointSize = (changeSize == changeMode) ? (iPointSize + factor) : (iPointSize * factor);
646 647
        tmpFont.setPointSize( (iNewPointSize > 0)?iNewPointSize:1);
        textFormat.setFont(tmpFont);
648
        textFormat.setForeground(curBrush);
649 650
        cursor.setPosition (iCursorPos+iBlockLen, QTextCursor::KeepAnchor);
        cursor.setCharFormat(textFormat);
651

652 653
        iCursorPos += iBlockLen;
        cursor.setPosition (iCursorPos, QTextCursor::MoveAnchor);
654 655

        curFont = nextCharFont;
656 657
    }

658 659
    delegated()->setFont(curFont);
    UBSettings::settings()->setFontPointSize(iPointSize);
660 661 662 663 664 665
    //returning initial selection
    cursor.setPosition (anchorPos, QTextCursor::MoveAnchor);
    cursor.setPosition (cursorPos, QTextCursor::KeepAnchor);

    delegated()->setTextCursor(cursor);
}
Aleksei Kanash's avatar
Aleksei Kanash committed
666

667 668 669 670 671 672
void UBGraphicsTextItemDelegate::updateAlighButtonState()
{
    if (!mAlignButton) {
        return;
    }

673
    qDebug() << "new cursor position" << delegated()->textCursor().position();
674 675 676 677 678 679 680 681 682 683
    AlignTextButton *asAlBtn = static_cast<AlignTextButton*>(mAlignButton);

    if (!oneBlockSelection()) {
        asAlBtn->setMixedButtonVisible(true);
        asAlBtn->setKind(AlignTextButton::k_mixed);
        saveTextCursorFormats();
        return;
    }

    asAlBtn->setMixedButtonVisible(false);
684 685 686 687 688

    Qt::Alignment cf = delegated()->textCursor().blockFormat().alignment();
    qDebug() << "getting alignment" << cf;

    if (cf & Qt::AlignCenter) {
689
        asAlBtn->setKind(AlignTextButton::k_center);
690
    } else if (cf & Qt::AlignRight) {
691
        asAlBtn->setKind(AlignTextButton::k_right);
692
    } else {
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
        asAlBtn->setKind(AlignTextButton::k_left);
    }
}

bool UBGraphicsTextItemDelegate::oneBlockSelection()
{
    const QTextCursor cursor = delegated()->textCursor();
    int pos = cursor.position();
    int anchor = cursor.anchor();

    // no selection
    if (pos == anchor) {
        return true;
    }

    //selecton within one text block
    QTextBlock blck = cursor.block();
    if (blck.contains(pos) && blck.contains(anchor)) {
        return true;
    }

    //otherwise
    return false;
}

void UBGraphicsTextItemDelegate::saveTextCursorFormats()
{
    mSelectionData.anchor = delegated()->textCursor().anchor();
    mSelectionData.position = delegated()->textCursor().position();
    mSelectionData.html = delegated()->document()->toHtml();
}

void UBGraphicsTextItemDelegate::restoreTextCursorFormats()
{
    delegated()->document()->setHtml(mSelectionData.html);

    int min = qMin(mSelectionData.position, mSelectionData.anchor);
    int max = qMax(mSelectionData.position, mSelectionData.anchor);
    int steps = max - min;

    QTextCursor tcrsr = delegated()->textCursor();
    tcrsr.setPosition(mSelectionData.position);
    tcrsr.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, steps);
    delegated()->setTextCursor(tcrsr);
}

Aleksei Kanash's avatar
Aleksei Kanash committed
739 740 741
void UBGraphicsTextItemDelegate::scaleTextSize(qreal multiplyer)
{
    ChangeTextSize(multiplyer, scaleSize);
742
}
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
743 744 745 746 747 748 749 750 751 752

QVariant UBGraphicsTextItemDelegate::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
    if (change == QGraphicsItem::ItemSelectedChange)
    {
        if (delegated()->isSelected())
        {
            QTextCursor c = delegated()->textCursor();
            if (c.hasSelection())
            {
Ilia Ryabokon's avatar
Ilia Ryabokon committed
753 754
                c.clearSelection();
                delegated()->setTextCursor(c);
Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
755 756 757
            }
        }
    }
758

Anatoly Mihalchenko's avatar
Anatoly Mihalchenko committed
759
    return UBGraphicsItemDelegate::itemChange(change, value);
760
}