diff --git a/CMakeLists.txt b/CMakeLists.txt index 30288c2..64e622e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,74 +1,74 @@ project(kjots) cmake_minimum_required(VERSION 2.8.12) find_package(ECM 5.16.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ${ECM_MODULE_PATH}) set(CMAKE_CXX_STANDARD 14) include(ECMAddTests) include(CMakePackageConfigHelpers) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMInstallIcons) include(ECMQtDeclareLoggingCategory) include(ECMAddAppIcon) set(KJOTS_VERSION "5.0.2") -set(KF5_VERSION "5.69.0") +set(KF5_VERSION "5.70.0") # Only what is in Applications/15.12 set(KDEPIMLIBS_LIB_VERSION "5.1.0") set(KMIME_LIB_VERSION "4.87.0") set(PIMTEXTEDIT_LIB_VERSION "4.91.0") set(KONTACTINTERFACE_LIB_VERSION "4.82.0") #Qt Packages set(QT_REQUIRED_VERSION "5.6.0") find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED DBus PrintSupport) # KF5 Packages find_package(KF5KCMUtils ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5KIO ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5Config ${KF5_VERSION} CONFIG REQUIRED) find_packagE(KF5ConfigWidgets ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5Parts ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5Bookmarks ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5XmlGui ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5TextWidgets ${KF5_VERSION} CONFIG REQUIRED) # PIM packages find_package(KF5Akonadi ${KDEPIMLIBS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiNotes ${KDEPIMLIBS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5PimTextEdit ${PIMTEXTEDIT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5KontactInterface ${KONTACTINTERFACE_LIB_VERSION} CONFIG REQUIRED) find_package(Grantlee5 "5.0" CONFIG REQUIRED) find_package(Xsltproc) ##################### Definitions ##################### add_definitions(-DQT_NO_KEYWORDS) add_definitions(-DQT_NO_CAST_FROM_ASCII) ##################### Targets ####################### add_subdirectory(src) add_subdirectory(icons) ##################### Install ###################### install(DIRECTORY themes DESTINATION ${DATA_INSTALL_DIR}/kjots PATTERN *.svn EXCLUDE ) install(FILES data/org.kde.kjots.appdata.xml DESTINATION ${CMAKE_INSTALL_METAINFODIR} ) install(FILES data/org.kde.kjots.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) diff --git a/src/kjotsedit.cpp b/src/kjotsedit.cpp index 31cc136..545f4df 100644 --- a/src/kjotsedit.cpp +++ b/src/kjotsedit.cpp @@ -1,408 +1,409 @@ /* kjots Copyright (C) 1997 Christoph Neerfeld Copyright (C) 2002, 2003 Aaron J. Seigo Copyright (C) 2003 Stanislav Kljuhhin Copyright (C) 2005-2006 Jaison Lee Copyright (C) 2007-2008 Stephen Kelly This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //Own Header #include "kjotsedit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kjotsmodel.h" #include "kjotslinkdialog.h" #include "noteshared/notelockattribute.h" #include "noteshared/noteeditorutils.h" Q_DECLARE_METATYPE(QTextCursor) using namespace Akonadi; KJotsEdit::KJotsEdit(QWidget *parent) : KRichTextWidget(parent), actionCollection(nullptr), allowAutoDecimal(false) { setMouseTracking(true); setAcceptRichText(true); setWordWrapMode(QTextOption::WordWrap); setCheckSpellingEnabled(true); setRichTextSupport(FullTextFormattingSupport | FullListSupport | SupportAlignment | SupportRuleLine - | SupportFormatPainting); + | SupportFormatPainting + | SupportHeading); setFocusPolicy(Qt::StrongFocus); } void KJotsEdit::contextMenuEvent(QContextMenuEvent *event) { QMenu *popup = mousePopupMenu(); if (popup) { popup->addSeparator(); QAction *act = actionCollection->action(QStringLiteral("copyIntoTitle")); popup->addAction(act); act = actionCollection->action(QStringLiteral("insert_checkmark")); act->setEnabled(!isReadOnly()); popup->addAction(act); if (!qApp->clipboard()->text().isEmpty()) { act = actionCollection->action(QStringLiteral("paste_plain_text")); act->setEnabled(!isReadOnly()); popup->addAction(act); } if (!anchorAt(event->pos()).isNull()) { popup->addAction(actionCollection->action(QStringLiteral("manage_link"))); } aboutToShowContextMenu(popup); popup->exec(event->globalPos()); delete popup; } } void KJotsEdit::delayedInitialization(KActionCollection *collection) { actionCollection = collection; connect(actionCollection->action(QStringLiteral("auto_bullet")), &QAction::triggered, this, &KJotsEdit::onAutoBullet); connect(actionCollection->action(QStringLiteral("auto_decimal")), &QAction::triggered, this, &KJotsEdit::onAutoDecimal); connect(actionCollection->action(QStringLiteral("manage_link")), &QAction::triggered, this, &KJotsEdit::onLinkify); connect(actionCollection->action(QStringLiteral("insert_checkmark")), &QAction::triggered, this, &KJotsEdit::addCheckmark); connect(actionCollection->action(QStringLiteral("insert_date")), &QAction::triggered, this, &KJotsEdit::insertDate); connect(actionCollection->action(QStringLiteral("insert_image")), &QAction::triggered, this, &KJotsEdit::insertImage); } void KJotsEdit::insertDate() { NoteShared::NoteEditorUtils().insertDate(this); } void KJotsEdit::insertImage() { QTextCursor cursor = textCursor(); NoteShared::NoteEditorUtils().insertImage(document(), cursor, this); } bool KJotsEdit::setModelIndex(const QModelIndex &index) { bool newDocument = m_index && (*m_index != index); // Saving the old document, if it wa changed if (newDocument) { savePage(); } m_index = std::make_unique(index); // Loading document auto document = m_index->data(KJotsModel::DocumentRole).value(); if (!document) { setReadOnly(true); return false; } setDocument(document); // Setting cursor auto cursor = document->property("textCursor").value(); if (!cursor.isNull()) { setTextCursor(cursor); } else { // This is a work-around for QTextEdit bug. If the first letter of the document is formatted, // QTextCursor doesn't follow this format. One can either move the cursor 1 symbol to the right // and then 1 symbol to the left as a workaround, or just explicitly move it to the start. // Submitted to qt-bugs, id 192886. // -- (don't know the fate of this bug, as for April 2020 it is unaccessible) moveCursor(QTextCursor::Start); } // Setting focus if document was changed if (newDocument) { setFocus(); } // Setting ReadOnly auto item = m_index->data(EntityTreeModel::ItemRole).value(); if (!item.isValid()) { setReadOnly(true); return false; } else if (item.hasAttribute()) { setReadOnly(true); return true; } else { setReadOnly(false); return true; } } void KJotsEdit::onAutoBullet(void) { KTextEdit::AutoFormatting currentFormatting = autoFormatting(); //TODO: set line spacing properly. if (currentFormatting == KTextEdit::AutoBulletList) { setAutoFormatting(KTextEdit::AutoNone); actionCollection->action(QStringLiteral("auto_bullet"))->setChecked(false); } else { setAutoFormatting(KTextEdit::AutoBulletList); actionCollection->action(QStringLiteral("auto_bullet"))->setChecked(true); } } void KJotsEdit::createAutoDecimalList(void) { //this is an adaptation of Qt's createAutoBulletList() function for creating a bulleted list, except in this case I use it to create a decimal list. QTextCursor cursor = textCursor(); cursor.beginEditBlock(); QTextBlockFormat blockFmt = cursor.blockFormat(); QTextListFormat listFmt; listFmt.setStyle(QTextListFormat::ListDecimal); listFmt.setIndent(blockFmt.indent() + 1); blockFmt.setIndent(0); cursor.setBlockFormat(blockFmt); cursor.createList(listFmt); cursor.endEditBlock(); setTextCursor(cursor); } void KJotsEdit::DecimalList(void) { QTextCursor cursor = textCursor(); if (cursor.currentList()) { return; } QString blockText = cursor.block().text(); if (blockText.length() == 2 && blockText == QLatin1String("1.")) { cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); cursor.removeSelectedText(); createAutoDecimalList(); } } void KJotsEdit::onAutoDecimal(void) { if (allowAutoDecimal == true) { allowAutoDecimal = false; disconnect(this, &KJotsEdit::textChanged, this, &KJotsEdit::DecimalList); actionCollection->action(QStringLiteral("auto_decimal"))->setChecked(false); } else { allowAutoDecimal = true; connect(this, &KJotsEdit::textChanged, this, &KJotsEdit::DecimalList); actionCollection->action(QStringLiteral("auto_decimal"))->setChecked(true); } } void KJotsEdit::onLinkify(void) { // Nothing is yet opened, ignoring if (!m_index) { return; } selectLinkText(); auto linkDialog = std::make_unique(const_cast(m_index->model()), this); linkDialog->setLinkText(currentLinkText()); linkDialog->setLinkUrl(currentLinkUrl()); if (linkDialog->exec()) { updateLink(linkDialog->linkUrl(), linkDialog->linkText()); } } void KJotsEdit::addCheckmark(void) { QTextCursor cursor = textCursor(); NoteShared::NoteEditorUtils().addCheckmark(cursor); } bool KJotsEdit::canInsertFromMimeData(const QMimeData *source) const { if (source->hasUrls()) { return true; } else { return KTextEdit::canInsertFromMimeData(source); } } void KJotsEdit::insertFromMimeData(const QMimeData *source) { // Nothing is opened, ignoring if (!m_index) { return; } if (source->hasUrls()) { const QList urls = source->urls(); for (const QUrl &url : urls) { if (url.scheme() == QStringLiteral("akonadi")) { QModelIndex idx = KJotsModel::modelIndexForUrl(m_index->model(), url); if (idx.isValid()) { insertHtml(QStringLiteral("%2").arg(idx.data(KJotsModel::EntityUrlRole).toString(), idx.data().toString())); } } else { QString text = source->hasText() ? source->text() : url.toString(QUrl::RemovePassword); insertHtml(QStringLiteral("%2").arg(QString::fromUtf8(url.toEncoded()), text)); } } } else if (source->hasHtml()) { // Don't have an action to set top and bottom margins on paragraphs yet. // Remove the margins for all inserted html. QTextDocument dummy; dummy.setHtml(source->html()); QTextCursor c(&dummy); QTextBlockFormat fmt = c.blockFormat(); fmt.setTopMargin(0); fmt.setBottomMargin(0); fmt.setLeftMargin(0); fmt.setRightMargin(0); c.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); c.mergeBlockFormat(fmt); textCursor().insertFragment(QTextDocumentFragment(c)); ensureCursorVisible(); } else { KRichTextEdit::insertFromMimeData(source); } } void KJotsEdit::mouseMoveEvent(QMouseEvent *event) { if ((event->modifiers() & Qt::ControlModifier) && !anchorAt(event->pos()).isEmpty()) { if (!m_cursorChanged) { QApplication::setOverrideCursor(Qt::PointingHandCursor); m_cursorChanged = true; } } else { if (m_cursorChanged) { QApplication::restoreOverrideCursor(); m_cursorChanged = false; } } KRichTextEdit::mouseMoveEvent(event); } void KJotsEdit::leaveEvent(QEvent *event) { if (m_cursorChanged) { QApplication::restoreOverrideCursor(); m_cursorChanged = false; } KRichTextEdit::leaveEvent(event); } void KJotsEdit::mousePressEvent(QMouseEvent *event) { QUrl url = anchorAt(event->pos()); if ((event->modifiers() & Qt::ControlModifier) && (event->button() & Qt::LeftButton) && !url.isEmpty()) { Q_EMIT linkClicked(url); } else { KRichTextEdit::mousePressEvent(event); } } void KJotsEdit::pastePlainText() { QString text = qApp->clipboard()->text(); if (!text.isEmpty()) { insertPlainText(text); } } bool KJotsEdit::event(QEvent *event) { if (event->type() == QEvent::WindowDeactivate) { savePage(); } else if (event->type() == QEvent::ToolTip) { tooltipEvent(static_cast(event)); } return KRichTextWidget::event(event); } void KJotsEdit::tooltipEvent(QHelpEvent *event) { // Nothing is opened, ignoring if (!m_index) { return; } QUrl url(anchorAt(event->pos())); QString message; if (url.isValid()) { if (url.scheme() == QStringLiteral("akonadi")) { const QModelIndex idx = KJotsModel::modelIndexForUrl(m_index->model(), url); if (idx.data(EntityTreeModel::ItemRole).value().isValid()) { message = i18nc("@info:tooltip %1 is page name", "Ctrl+click to open page: %1", idx.data().toString()); } else if (idx.data(EntityTreeModel::CollectionRole).value().isValid()) { message = i18nc("@info:tooltip %1 is book name", "Ctrl+click to open book: %1", idx.data().toString()); } } else { message = i18nc("@info:tooltip %1 is hyperlink address", "Ctrl+click to follow the hyperlink: %1", url.toString(QUrl::RemovePassword)); } } if (!message.isEmpty()) { QToolTip::showText(event->globalPos(), message); } else { QToolTip::hideText(); } } void KJotsEdit::focusOutEvent(QFocusEvent *event) { savePage(); KRichTextWidget::focusOutEvent(event); } void KJotsEdit::savePage() { if (!document()->isModified() || !m_index) { return; } auto item = m_index->data(EntityTreeModel::ItemRole).value(); if (!item.isValid() || !item.hasPayload()) { return; } auto model = const_cast(m_index->model()); document()->setModified(false); document()->setProperty("textCursor", QVariant::fromValue(textCursor())); model->setData(*m_index, QVariant::fromValue(document()), KJotsModel::DocumentRole); } /* ex: set tabstop=4 softtabstop=4 shiftwidth=4 expandtab: */ diff --git a/src/kjotspartui.rc b/src/kjotspartui.rc index df34797..5d69766 100644 --- a/src/kjotspartui.rc +++ b/src/kjotspartui.rc @@ -1,113 +1,116 @@ F&ormat + + &Go &Tools &Settings Main Toolbar Text Toolbar Format Toolbar + diff --git a/src/kjotsui.rc b/src/kjotsui.rc index c015b3b..d8cb630 100644 --- a/src/kjotsui.rc +++ b/src/kjotsui.rc @@ -1,110 +1,113 @@ F&ormat + + Main Toolbar Text Toolbar Format Toolbar +