kde-playground/kdepim/composereditor-ng/private/composerview_p.cpp

995 lines
37 KiB
C++
Raw Normal View History

/*
Copyright (c) 2013, 2014 Montel Laurent <montel@kde.org>
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This library 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 Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include "composerview_p.h"
#include "utils/composereditorutils_p.h"
#include "link/composerlinkdialog.h"
#include "link/composeranchordialog.h"
#include "list/composerlistdialog.h"
#include "image/composerimagedialog.h"
#include "table/composertabledialog.h"
#include "image/composerimageresizewidget.h"
#include "pagecolor/pagecolorbackgrounddialog.h"
#include "helper/listhelper_p.h"
#include "globalsettings_base.h"
#include <kpimtextedit/emoticontexteditaction.h>
#include <kpimtextedit/inserthtmldialog.h>
#include <kpimtextedit/selectspecialchar.h>
#include <Sonnet/Dialog>
#include <sonnet/backgroundchecker.h>
#include <KToolInvocation>
#include <KLocalizedString>
#include <KToggleAction>
#include <KAction>
#include <KSelectAction>
#include <KActionCollection>
#include <KColorDialog>
#include <KMessageBox>
#include <KStandardDirs>
#include <KDebug>
#include <KFontAction>
#include <KFileDialog>
#include <KPrintPreview>
#include <kdeprintdialog.h>
#include <KRun>
#include <QAction>
#include <QDBusInterface>
#include <QDBusConnectionInterface>
#include <QWebFrame>
#include <QWebElement>
#include <QContextMenuEvent>
#include <QDebug>
#include <QPointer>
#include <QPrinter>
#include <QPrintDialog>
#include <QClipboard>
namespace ComposerEditorNG {
#define FORWARD_ACTION(action1, action2) \
q->connect(action1, SIGNAL(triggered()), getAction(action2), SLOT(trigger()));\
q->connect(getAction(action2), SIGNAL(changed()), SLOT(_k_slotAdjustActions()));
#define FOLLOW_CHECK(a1, a2) a1->setChecked(getAction(a2)->isChecked())
void ComposerViewPrivate::createAction(ComposerView::ComposerViewAction type)
{
switch(type) {
case ComposerView::Bold: {
if (!action_text_bold) {
action_text_bold = new KToggleAction(KIcon(QLatin1String("format-text-bold")), i18nc("@action boldify selected text", "&Bold"), q);
QFont bold;
bold.setBold(true);
action_text_bold->setFont(bold);
action_text_bold->setShortcut(KShortcut(Qt::CTRL + Qt::Key_B));
FORWARD_ACTION(action_text_bold, QWebPage::ToggleBold);
htmlEditorActionList.append(action_text_bold);
}
break;
}
case ComposerView::Italic: {
if (!action_text_italic) {
action_text_italic = new KToggleAction(KIcon(QLatin1String("format-text-italic")), i18nc("@action italicize selected text", "&Italic"), q);
QFont italic;
italic.setItalic(true);
action_text_italic->setFont(italic);
action_text_italic->setShortcut(KShortcut(Qt::CTRL + Qt::Key_I));
FORWARD_ACTION(action_text_italic, QWebPage::ToggleItalic);
htmlEditorActionList.append(action_text_italic);
}
break;
}
case ComposerView::Underline: {
if (!action_text_underline) {
action_text_underline = new KToggleAction(KIcon(QLatin1String("format-text-underline")), i18nc("@action underline selected text", "&Underline"), q);
QFont underline;
underline.setUnderline(true);
action_text_underline->setFont(underline);
action_text_underline->setShortcut(KShortcut(Qt::CTRL + Qt::Key_U));
FORWARD_ACTION(action_text_underline, QWebPage::ToggleUnderline);
htmlEditorActionList.append(action_text_underline);
}
break;
}
case ComposerView::StrikeOut: {
if (!action_text_strikeout) {
action_text_strikeout = new KToggleAction(KIcon(QLatin1String("format-text-strikethrough")), i18nc("@action", "&Strike Out"), q);
action_text_strikeout->setShortcut(KShortcut(Qt::CTRL + Qt::Key_L));
FORWARD_ACTION(action_text_strikeout, QWebPage::ToggleStrikethrough);
htmlEditorActionList.append(action_text_strikeout);
}
break;
}
case ComposerView::AlignLeft: {
if (!action_align_left) {
action_align_left = new KToggleAction(KIcon(QLatin1String("format-justify-left")), i18nc("@action", "Align &Left"), q);
action_align_left->setIconText(i18nc("@label left justify", "Left"));
htmlEditorActionList.append((action_align_left));
FORWARD_ACTION(action_align_left, QWebPage::AlignLeft);
}
break;
}
case ComposerView::AlignCenter: {
if (!action_align_center) {
action_align_center = new KToggleAction(KIcon(QLatin1String("format-justify-center")), i18nc("@action", "Align &Center"), q);
action_align_center->setIconText(i18nc("@label center justify", "Center"));
htmlEditorActionList.append((action_align_center));
FORWARD_ACTION(action_align_center, QWebPage::AlignCenter);
}
break;
}
case ComposerView::AlignRight: {
if (!action_align_right) {
action_align_right = new KToggleAction(KIcon(QLatin1String("format-justify-right")), i18nc("@action", "Align &Right"), q);
action_align_right->setIconText(i18nc("@label right justify", "Right"));
htmlEditorActionList.append((action_align_right));
FORWARD_ACTION(action_align_right, QWebPage::AlignRight);
}
break;
}
case ComposerView::AlignJustify:
{
if (!action_align_justify) {
action_align_justify = new KToggleAction(KIcon(QLatin1String("format-justify-fill")), i18nc("@action", "&Justify"), q);
action_align_justify->setIconText(i18nc("@label justify fill", "Justify"));
htmlEditorActionList.append((action_align_justify));
FORWARD_ACTION(action_align_justify, QWebPage::AlignJustified);
}
break;
}
case ComposerView::DirectionLtr:
{
if (!action_direction_ltr) {
action_direction_ltr = new KToggleAction(KIcon(QLatin1String("format-text-direction-ltr")), i18nc("@action", "Left-to-Right"), q);
action_direction_ltr->setIconText(i18nc("@label left-to-right", "Left-to-Right"));
htmlEditorActionList.append(action_direction_ltr);
FORWARD_ACTION(action_direction_ltr, QWebPage::SetTextDirectionLeftToRight);
}
break;
}
case ComposerView::DirectionRtl:
{
if (!action_direction_rtl) {
action_direction_rtl = new KToggleAction(KIcon(QLatin1String("format-text-direction-rtl")), i18nc("@action", "Right-to-Left"), q);
action_direction_rtl->setIconText(i18nc("@label right-to-left", "Right-to-Left"));
htmlEditorActionList.append(action_direction_rtl);
FORWARD_ACTION(action_direction_rtl, QWebPage::SetTextDirectionRightToLeft);
}
break;
}
case ComposerView::SubScript:
{
if (!action_text_subscript) {
action_text_subscript = new KToggleAction(KIcon(QLatin1String("format-text-subscript")), i18nc("@action", "Subscript"), q);
htmlEditorActionList.append((action_text_subscript));
FORWARD_ACTION(action_text_subscript, QWebPage::ToggleSubscript);
}
break;
}
case ComposerView::SuperScript:
{
if (!action_text_superscript) {
action_text_superscript = new KToggleAction(KIcon(QLatin1String("format-text-superscript")), i18nc("@action", "Superscript"), q);
htmlEditorActionList.append((action_text_superscript));
FORWARD_ACTION(action_text_superscript, QWebPage::ToggleSuperscript);
}
break;
}
case ComposerView::HorizontalRule:
{
if (!action_insert_horizontal_rule) {
action_insert_horizontal_rule = new KAction(KIcon(QLatin1String("insert-horizontal-rule")), i18nc("@action", "Insert Rule Line"), q);
htmlEditorActionList.append((action_insert_horizontal_rule));
q->connect( action_insert_horizontal_rule, SIGNAL(triggered(bool)), SLOT(_k_slotInsertHorizontalRule()) );
}
break;
}
case ComposerView::ListIndent:
{
if (!action_list_indent) {
action_list_indent = new KAction(KIcon(QLatin1String("format-indent-more")), i18nc("@action", "Increase Indent"), q);
htmlEditorActionList.append((action_list_indent));
FORWARD_ACTION(action_list_indent, QWebPage::Indent);
}
break;
}
case ComposerView::ListDedent:
{
if (!action_list_dedent) {
action_list_dedent = new KAction(KIcon(QLatin1String("format-indent-less")), i18nc("@action", "Decrease Indent"), q);
htmlEditorActionList.append(action_list_dedent);
FORWARD_ACTION(action_list_dedent, QWebPage::Outdent);
}
break;
}
case ComposerView::OrderedList:
{
if (!action_ordered_list) {
action_ordered_list = new KToggleAction(KIcon(QLatin1String("format-list-ordered")), i18n("Ordered Style"), q);
htmlEditorActionList.append(action_ordered_list);
FORWARD_ACTION(action_ordered_list, QWebPage::InsertOrderedList);
}
break;
}
case ComposerView::UnorderedList:
{
if (!action_unordered_list) {
action_unordered_list = new KToggleAction( KIcon( QLatin1String("format-list-unordered" )), i18n( "Unordered List" ), q);
htmlEditorActionList.append(action_unordered_list);
FORWARD_ACTION(action_unordered_list, QWebPage::InsertUnorderedList);
}
break;
}
case ComposerView::FormatType:
{
if (!action_format_type) {
action_format_type = new KSelectAction(KIcon(QLatin1String("format-list-unordered")), i18nc("@title:menu", "List Style"), q);
KAction *act = action_format_type->addAction(i18n( "Paragraph" ));
act->setData(QVariant::fromValue(ComposerViewPrivate::Paragraph));
act = action_format_type->addAction(i18n( "Heading 1" ));
act->setData(QVariant::fromValue(ComposerViewPrivate::Header1));
act = action_format_type->addAction(i18n( "Heading 2" ));
act->setData(QVariant::fromValue(ComposerViewPrivate::Header2));
act = action_format_type->addAction(i18n( "Heading 3" ));
act->setData(QVariant::fromValue(ComposerViewPrivate::Header3));
act = action_format_type->addAction(i18n( "Heading 4" ));
act->setData(QVariant::fromValue(ComposerViewPrivate::Header4));
act = action_format_type->addAction(i18n( "Heading 5" ));
act->setData(QVariant::fromValue(ComposerViewPrivate::Header5));
act = action_format_type->addAction(i18n( "Heading 6" ));
act->setData(QVariant::fromValue(ComposerViewPrivate::Header6));
act = action_format_type->addAction(i18n( "Pre" ));
act->setData(QVariant::fromValue(ComposerViewPrivate::Pre));
act = action_format_type->addAction(i18n( "Address" ));
act->setData(QVariant::fromValue(ComposerViewPrivate::Address));
action_format_type->setCurrentItem(0);
htmlEditorActionList.append(action_format_type);
q->connect(action_format_type, SIGNAL(triggered(QAction*)),
q, SLOT(_k_setFormatType(QAction*)));
}
break;
}
case ComposerView::FontSize:
{
if (!action_font_size) {
action_font_size = new KSelectAction(i18nc("@action", "Font &Size"), q);
htmlEditorActionList.append(action_font_size);
QStringList sizes;
sizes << QLatin1String("xx-small");
sizes << QLatin1String("x-small");
sizes << QLatin1String("small");
sizes << QLatin1String("medium");
sizes << QLatin1String("large");
sizes << QLatin1String("x-large");
sizes << QLatin1String("xx-large");
action_font_size->setItems(sizes);
action_font_size->setCurrentItem(0);
q->connect(action_font_size, SIGNAL(triggered(int)), q, SLOT(_k_setFontSize(int)));
}
break;
}
case ComposerView::FontFamily:
{
if (!action_font_family) {
action_font_family = new KFontAction(i18nc("@action", "&Font"), q);
htmlEditorActionList.append((action_font_family));
q->connect(action_font_family, SIGNAL(triggered(QString)), q, SLOT(_k_setFontFamily(QString)));
}
break;
}
case ComposerView::Emoticon:
{
if (!action_add_emoticon) {
action_add_emoticon = new KPIMTextEdit::EmoticonTextEditAction(q);
q->connect( action_add_emoticon, SIGNAL(emoticonActivated(QString)),
q, SLOT(_k_slotAddEmoticon(QString)) );
}
break;
}
case ComposerView::InsertImage:
{
if (!action_insert_image) {
action_insert_image = new KAction( KIcon( QLatin1String( "insert-image" ) ), i18n( "Add Image" ), q);
q->connect( action_insert_image, SIGNAL(triggered(bool)), SLOT(_k_slotAddImage()) );
}
break;
}
case ComposerView::InsertHtml:
{
if (!action_insert_html) {
action_insert_html = new KAction( i18n( "Insert HTML" ), q);
q->connect( action_insert_html, SIGNAL(triggered(bool)), SLOT(_k_slotInsertHtml()) );
}
break;
}
case ComposerView::InsertTable:
{
if (!action_insert_table) {
action_insert_table = new KAction( KIcon( QLatin1String( "insert-table" ) ), i18n( "Table..." ), q);
htmlEditorActionList.append(action_insert_table);
q->connect( action_insert_table, SIGNAL(triggered(bool)), SLOT(_k_slotInsertTable()) );
}
break;
}
case ComposerView::InsertLink:
{
if (!action_insert_link) {
action_insert_link = new KAction(KIcon(QLatin1String("insert-link")), i18nc("@action", "Link"), q);
htmlEditorActionList.append(action_insert_link);
q->connect(action_insert_link, SIGNAL(triggered(bool)), q, SLOT(_k_insertLink()));
}
break;
}
case ComposerView::TextForegroundColor:
{
if (!action_text_foreground_color) {
action_text_foreground_color = new KAction(KIcon(QLatin1String("format-stroke-color")), i18nc("@action", "Text &Color..."), q);
action_text_foreground_color->setIconText(i18nc("@label stroke color", "Color"));
htmlEditorActionList.append((action_text_foreground_color));
q->connect(action_text_foreground_color, SIGNAL(triggered()), q, SLOT(_k_setTextForegroundColor()));
}
break;
}
case ComposerView::TextBackgroundColor:
{
if (!action_text_background_color) {
action_text_background_color = new KAction(KIcon(QLatin1String("format-fill-color")), i18nc("@action", "Text &Highlight..."), q);
htmlEditorActionList.append((action_text_background_color));
q->connect(action_text_background_color, SIGNAL(triggered()), q, SLOT(_k_setTextBackgroundColor()));
}
break;
}
case ComposerView::FormatReset:
{
if (!action_format_reset) {
action_format_reset = new KAction( KIcon( QLatin1String("draw-eraser") ), i18n("Reset Font Settings"), q);
FORWARD_ACTION(action_format_reset, QWebPage::RemoveFormat);
}
break;
}
case ComposerView::SpellCheck:
{
if (!action_spell_check) {
action_spell_check = new KAction(KIcon(QLatin1String("tools-check-spelling")), i18n("Check Spelling..."), q);
htmlEditorActionList.append(action_spell_check);
q->connect(action_spell_check, SIGNAL(triggered(bool)), q, SLOT(_k_slotSpellCheck()));
}
break;
}
case ComposerView::PageColor:
{
if (!action_page_color) {
action_page_color = new KAction( i18n( "Page Color and Background..." ), q);
htmlEditorActionList.append(action_page_color);
q->connect( action_page_color, SIGNAL(triggered(bool)), SLOT(_k_slotChangePageColorAndBackground()) );
}
break;
}
case ComposerView::BlockQuote:
{
if (!action_block_quote) {
action_block_quote = new KAction(KIcon(QLatin1String("format-text-blockquote")), i18n( "Blockquote" ), q);
htmlEditorActionList.append(action_block_quote);
q->connect( action_block_quote, SIGNAL(triggered()), q, SLOT(_k_slotToggleBlockQuote()) );
}
break;
}
case ComposerView::Find:
{
if (!action_find) {
action_find = new KAction(KIcon(QLatin1String("edit-find")), i18n( "&Find..." ), q);
action_find->setShortcut(KStandardShortcut::find());
htmlEditorActionList.append(action_find);
q->connect( action_find, SIGNAL(triggered()), q, SLOT(_k_slotFind()) );
}
break;
}
case ComposerView::Replace:
{
if (!action_replace) {
action_replace = new KAction(KIcon(QLatin1String("edit-replace")), i18n( "&Replace..." ), q);
htmlEditorActionList.append(action_replace);
action_replace->setShortcut(KStandardShortcut::replace());
q->connect( action_replace, SIGNAL(triggered()), q, SLOT(_k_slotReplace()) );
}
break;
}
case ComposerView::SaveAs:
{
if (!action_save_as) {
action_save_as = new KAction(KIcon(QLatin1String("file_save_as")), i18n( "Save &As..." ), q);
htmlEditorActionList.append(action_save_as);
action_replace->setShortcut(KStandardShortcut::save());
q->connect( action_save_as, SIGNAL(triggered()), q, SLOT(_k_slotSaveAs()) );
}
break;
}
case ComposerView::Print:
{
if (!action_print) {
action_print = new KAction(KIcon(QLatin1String("file_print")), i18n( "&Print..." ), q);
htmlEditorActionList.append(action_print);
action_replace->setShortcut(KStandardShortcut::print());
q->connect( action_print, SIGNAL(triggered()), q, SLOT(_k_slotPrint()) );
}
break;
}
case ComposerView::PrintPreview:
{
if (!action_print_preview) {
action_print_preview = new KAction(KIcon(QLatin1String("file_print_preview")), i18n( "Print Previe&w" ), q);
htmlEditorActionList.append(action_print_preview);
q->connect( action_print_preview, SIGNAL(triggered()), q, SLOT(_k_slotPrintPreview()) );
}
break;
}
case ComposerView::PasteWithoutFormatting:
{
if (!action_paste_withoutformatting) {
action_paste_withoutformatting = new KAction(i18n( "Paste Without Formatting" ), q);
htmlEditorActionList.append(action_paste_withoutformatting);
q->connect( action_paste_withoutformatting, SIGNAL(triggered()), q, SLOT(_k_slotPasteWithoutFormatting()) );
}
break;
}
case ComposerView::InsertSpecialChar:
{
if (!action_insert_specialchar) {
action_insert_specialchar = new KAction(i18n( "Insert Special Char..." ), q);
htmlEditorActionList.append(action_insert_specialchar);
q->connect( action_insert_specialchar, SIGNAL(triggered()), q, SLOT(_k_slotInsertSpecialChar()) );
}
break;
}
case ComposerView::InsertAnchor:
{
if (!action_insert_anchor) {
action_insert_anchor = new KAction(i18n( "Insert Anchor..." ), q);
htmlEditorActionList.append(action_insert_anchor);
q->connect( action_insert_anchor, SIGNAL(triggered()), q, SLOT(_k_slotInsertAnchor()) );
}
break;
}
case ComposerView::Separator:
//nothing
break;
case ComposerView::LastType:
//nothing
break;
}
}
void ComposerViewPrivate::connectActionGroup()
{
if (action_align_left || action_align_center || action_align_right || action_align_justify) {
QActionGroup *alignmentGroup = new QActionGroup(q);
if (action_align_left)
alignmentGroup->addAction(action_align_left);
if (action_align_center)
alignmentGroup->addAction(action_align_center);
if (action_align_right)
alignmentGroup->addAction(action_align_right);
if (action_align_justify)
alignmentGroup->addAction(action_align_justify);
}
if (action_direction_ltr && action_direction_rtl) {
QActionGroup *directionGroup = new QActionGroup(q);
directionGroup->addAction(action_direction_ltr);
directionGroup->addAction(action_direction_rtl);
}
}
#if QTWEBKIT_VERSION >= QTWEBKIT_VERSION_CHECK(2, 3, 0)
bool ComposerViewPrivate::checkSpellingEnabled()
{
return ComposerEditorNG::GlobalSettingsBase::autoSpellChecking();
}
#endif
void ComposerViewPrivate::_k_changeAutoSpellChecking(bool checked)
{
#if QTWEBKIT_VERSION >= QTWEBKIT_VERSION_CHECK(2, 3, 0)
ComposerEditorNG::GlobalSettingsBase::setAutoSpellChecking(checked);
#else
Q_UNUSED( checked );
#endif
}
QAction* ComposerViewPrivate::getAction ( QWebPage::WebAction action ) const
{
if ( action >= 0 && action <= 66 )
return q->page()->action( static_cast<QWebPage::WebAction>( action ));
else
return 0;
}
void ComposerViewPrivate::hideImageResizeWidget()
{
delete imageResizeWidget;
imageResizeWidget = 0;
}
void ComposerViewPrivate::showImageResizeWidget()
{
if (!imageResizeWidget) {
imageResizeWidget = new ComposerImageResizeWidget(contextMenuResult.element(),q);
imageResizeWidget->move(contextMenuResult.element().geometry().topLeft());
imageResizeWidget->show();
}
}
static QVariant execJScript(QWebElement element, const QString& script)
{
if (element.isNull())
return QVariant();
return element.evaluateJavaScript(script);
}
void ComposerViewPrivate::_k_setFormatType(QAction *act)
{
if (!act) {
return;
}
QString command;
switch(act->data().value<ComposerEditorNG::ComposerViewPrivate::FormatType>())
{
case Paragraph:
command = QLatin1String("p");
break;
case Header1:
command = QLatin1String("h1");
break;
case Header2:
command = QLatin1String("h2");
break;
case Header3:
command = QLatin1String("h3");
break;
case Header4:
command = QLatin1String("h4");
break;
case Header5:
command = QLatin1String("h5");
break;
case Header6:
command = QLatin1String("h6");
break;
case Pre:
command = QLatin1String("pre");
break;
case Address:
command = QLatin1String("address");
break;
}
execCommand ( QLatin1String("formatBlock"), command );
}
void ComposerViewPrivate::_k_slotToggleBlockQuote()
{
execCommand( QLatin1String("formatBlock"), QLatin1String("BLOCKQUOTE"));
}
void ComposerViewPrivate::_k_slotAddEmoticon(const QString& emoticon)
{
execCommand(QLatin1String("insertHTML"), emoticon);
}
void ComposerViewPrivate::_k_slotInsertHtml()
{
QPointer<KPIMTextEdit::InsertHtmlDialog> dialog = new KPIMTextEdit::InsertHtmlDialog( q );
if (dialog->exec()) {
const QString str = dialog->html().remove(QLatin1String("\n"));
if (!str.isEmpty()) {
execCommand(QLatin1String("insertHTML"), str);
}
}
delete dialog;
}
void ComposerViewPrivate::_k_setTextBackgroundColor()
{
QColor newColor = ComposerEditorNG::Utils::convertRgbToQColor(evaluateJavascript(QLatin1String("getTextBackgroundColor()")).toString());
const int result = KColorDialog::getColor(newColor, q);
if (result == QDialog::Accepted) {
execCommand(QLatin1String("hiliteColor"), newColor.name());
}
}
QVariant ComposerViewPrivate::evaluateJavascript(const QString& command)
{
return q->page()->mainFrame()->evaluateJavaScript( command );
}
void ComposerViewPrivate::_k_slotDeleteText()
{
evaluateJavascript(QLatin1String("setDeleteSelectedText()"));
}
void ComposerViewPrivate::_k_setTextForegroundColor()
{
QColor newColor = ComposerEditorNG::Utils::convertRgbToQColor(evaluateJavascript(QLatin1String("getTextForegroundColor()")).toString());
const int result = KColorDialog::getColor(newColor, q);
if (result == QDialog::Accepted) {
execCommand(QLatin1String("foreColor"), newColor.name());
}
}
void ComposerViewPrivate::_k_slotAddImage()
{
QPointer<ComposerImageDialog> dlg = new ComposerImageDialog( q );
if (dlg->exec() == KDialog::Accepted) {
execCommand(QLatin1String("insertHTML"), dlg->html());
}
delete dlg;
}
void ComposerViewPrivate::_k_slotEditImage()
{
showImageResizeWidget();
ComposerImageDialog dlg( contextMenuResult.element(),q );
dlg.exec();
}
void ComposerViewPrivate::_k_slotInsertTable()
{
QPointer<ComposerTableDialog> dlg = new ComposerTableDialog( q );
if (dlg->exec() == KDialog::Accepted) {
execCommand(QLatin1String("insertHTML"), dlg->html());
}
delete dlg;
}
void ComposerViewPrivate::_k_slotInsertHorizontalRule()
{
execCommand(QLatin1String("insertHTML"), QLatin1String("<hr>"));
}
void ComposerViewPrivate::_k_insertLink()
{
const QString selectedText = q->selectedText();
QPointer<ComposerEditorNG::ComposerLinkDialog> dlg = new ComposerEditorNG::ComposerLinkDialog( selectedText, q );
if (dlg->exec() == KDialog::Accepted) {
const QString html(dlg->html());
if (!html.isEmpty())
execCommand ( QLatin1String("insertHTML"), html );
}
delete dlg;
}
void ComposerViewPrivate::_k_slotEditLink()
{
ComposerEditorNG::ComposerLinkDialog dlg( contextMenuResult.linkElement(), q );
dlg.exec();
}
void ComposerViewPrivate::_k_slotOpenLink()
{
const QString href = contextMenuResult.linkElement().attribute(QLatin1String("href"));
if (!href.isEmpty()) {
new KRun( KUrl(href), 0 );
}
}
void ComposerViewPrivate::_k_setFontSize(int fontSize)
{
execCommand(QLatin1String("fontSize"), QString::number(fontSize+1)); //Verify
}
void ComposerViewPrivate::_k_setFontFamily(const QString& family)
{
execCommand(QLatin1String("fontName"), family);
}
void ComposerViewPrivate::_k_slotSpellCheck()
{
QString text(execJScript(contextMenuResult.element(), QLatin1String("this.value")).toString());
if (contextMenuResult.isContentSelected()) {
spellTextSelectionStart = qMax(0, execJScript(contextMenuResult.element(), QLatin1String("this.selectionStart")).toInt());
spellTextSelectionEnd = qMax(0, execJScript(contextMenuResult.element(), QLatin1String("this.selectionEnd")).toInt());
text = text.mid(spellTextSelectionStart, (spellTextSelectionEnd - spellTextSelectionStart));
} else {
spellTextSelectionStart = 0;
spellTextSelectionEnd = 0;
}
if (text.isEmpty())
return;
Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker;
Sonnet::Dialog* spellDialog = new Sonnet::Dialog(backgroundSpellCheck, q);
backgroundSpellCheck->setParent(spellDialog);
spellDialog->setAttribute(Qt::WA_DeleteOnClose, true);
q->connect(spellDialog, SIGNAL(replace(QString,int,QString)), q, SLOT(_k_spellCheckerCorrected(QString,int,QString)));
q->connect(spellDialog, SIGNAL(misspelling(QString,int)), q, SLOT(_k_spellCheckerMisspelling(QString,int)));
if (contextMenuResult.isContentSelected())
q->connect(spellDialog, SIGNAL(done(QString)), q, SLOT(_k_slotSpellCheckDone(QString)));
spellDialog->setBuffer(text);
spellDialog->show();
}
void ComposerViewPrivate::_k_spellCheckerCorrected(const QString& original, int pos, const QString& replacement)
{
// Adjust the selection end...
if (spellTextSelectionEnd > 0)
spellTextSelectionEnd += qMax(0, (replacement.length() - original.length()));
const int index = pos + spellTextSelectionStart;
QString script(QLatin1String("this.value=this.value.substring(0,"));
script += QString::number(index);
script += QLatin1String(") + \"");
QString w(replacement);
script += w.replace(QLatin1Char('\''), QLatin1String("\\\'")); // Escape any Quote marks in replacement word
script += QLatin1String("\" + this.value.substring(");
script += QString::number(index + original.length());
script += QLatin1String(")");
//kDebug() << "**** script:" << script;
execJScript(contextMenuResult.element(), script);
}
void ComposerViewPrivate::_k_spellCheckerMisspelling(const QString& text, int pos)
{
// kDebug() << text << pos;
QString selectionScript(QLatin1String("this.setSelectionRange("));
selectionScript += QString::number(pos + spellTextSelectionStart);
selectionScript += QLatin1Char(',');
selectionScript += QString::number(pos + text.length() + spellTextSelectionStart);
selectionScript += QLatin1Char(')');
execJScript(contextMenuResult.element(), selectionScript);
}
void ComposerViewPrivate::_k_slotSpellCheckDone(const QString&)
{
// Restore the text selection if one was present before we started the
// spell check.
if (spellTextSelectionStart > 0 || spellTextSelectionEnd > 0) {
QString script(QLatin1String("; this.setSelectionRange("));
script += QString::number(spellTextSelectionStart);
script += QLatin1Char(',');
script += QString::number(spellTextSelectionEnd);
script += QLatin1Char(')');
execJScript(contextMenuResult.element(), script);
}
}
void ComposerViewPrivate::_k_slotFind()
{
Q_EMIT q->showFindBar();
}
void ComposerViewPrivate::_k_slotReplace()
{
//TODO
}
void ComposerViewPrivate::_k_slotSaveAs()
{
QString fn = KFileDialog::getSaveFileName(QString(), i18n("HTML-Files (*.htm *.html);;All Files (*)") , q, i18n("Save as..."));
if (fn.isEmpty()) {
KMessageBox::error(q, i18n("Not file selected."), i18n("Save as"));
return;
}
if (!(fn.endsWith(QLatin1String(".htm"), Qt::CaseInsensitive) ||
fn.endsWith(QLatin1String(".html"), Qt::CaseInsensitive))) {
fn += QLatin1String(".htm");
}
QFile file(fn);
bool success = file.open(QIODevice::WriteOnly);
if (success) {
// FIXME: here we always use UTF-8 encoding
const QString content = q->page()->mainFrame()->toHtml();
QByteArray data = content.toUtf8();
const qint64 c = file.write(data);
success = (c >= data.length());
}
}
void ComposerViewPrivate::_k_slotPrint()
{
QPrinter printer;
QPointer<QPrintDialog> dlg(KdePrint::createPrintDialog(&printer));
if ( dlg->exec() == QDialog::Accepted ) {
q->print( &printer );
}
delete dlg;
}
void ComposerViewPrivate::_k_slotPrintPreview()
{
QPrinter printer;
KPrintPreview previewdlg( &printer, q );
q->print( &printer );
previewdlg.exec();
}
void ComposerViewPrivate::_k_slotChangePageColorAndBackground()
{
const QWebElement element = q->page()->mainFrame()->findFirstElement(QLatin1String("body"));
if (!element.isNull()) {
QPointer<PageColorBackgroundDialog> dlg = new PageColorBackgroundDialog(element, q);
dlg->exec();
delete dlg;
}
}
void ComposerViewPrivate::_k_slotEditList()
{
QWebElement listElement = ListHelper::listElement(contextMenuResult.element());
if (!listElement.isNull()) {
QPointer<ComposerListDialog> dlg = new ComposerListDialog(listElement,q);
if (dlg->exec()) {
//TODO
}
delete dlg;
}
}
void ComposerViewPrivate::_k_slotAdjustActions()
{
if (action_text_bold)
FOLLOW_CHECK(action_text_bold, QWebPage::ToggleBold);
if (action_text_italic)
FOLLOW_CHECK(action_text_italic, QWebPage::ToggleItalic);
if (action_text_strikeout)
FOLLOW_CHECK(action_text_strikeout, QWebPage::ToggleStrikethrough);
if (action_text_underline)
FOLLOW_CHECK(action_text_underline, QWebPage::ToggleUnderline);
if (action_text_subscript)
FOLLOW_CHECK(action_text_subscript, QWebPage::ToggleSubscript);
if (action_text_superscript)
FOLLOW_CHECK(action_text_superscript, QWebPage::ToggleSuperscript);
if (action_ordered_list)
FOLLOW_CHECK(action_ordered_list, QWebPage::InsertOrderedList);
if (action_unordered_list)
FOLLOW_CHECK(action_unordered_list, QWebPage::InsertUnorderedList);
if (action_direction_ltr)
FOLLOW_CHECK(action_direction_ltr, QWebPage::SetTextDirectionLeftToRight);
if (action_direction_rtl)
FOLLOW_CHECK(action_direction_rtl, QWebPage::SetTextDirectionRightToLeft);
const QString alignment = evaluateJavascript(QLatin1String("getAlignment()")).toString();
if (alignment == QLatin1String("left")) {
if (action_align_left)
action_align_left->setChecked(true);
} else if (alignment == QLatin1String("right")) {
if (action_align_right)
action_align_right->setChecked(true);
} else if (alignment == QLatin1String("center")) {
if (action_align_center)
action_align_center->setChecked(true);
} else if (alignment == QLatin1String("-webkit-auto")) {
if (action_align_justify)
action_align_justify->setChecked(true);
}
if (action_font_family) {
const QString font = evaluateJavascript(QLatin1String("getFontFamily()")).toString();
if (!font.isEmpty()) {
action_font_family->setFont(font);
}
}
}
void ComposerViewPrivate::execCommand(const QString &cmd)
{
QWebFrame *frame = q->page()->mainFrame();
const QString js = QString::fromLatin1("document.execCommand(\"%1\", false, null)").arg(cmd);
frame->evaluateJavaScript(js);
}
void ComposerViewPrivate::execCommand(const QString &cmd, const QString &arg)
{
QWebFrame *frame = q->page()->mainFrame();
const QString js = QString::fromLatin1("document.execCommand(\"%1\", false, \"%2\")").arg(cmd).arg(arg);
frame->evaluateJavaScript(js);
}
bool ComposerViewPrivate::queryCommandState(const QString &cmd)
{
QWebFrame *frame = q->page()->mainFrame();
QString js = QString::fromLatin1("document.queryCommandState(\"%1\", false, null)").arg(cmd);
const QVariant result = frame->evaluateJavaScript(js);
return result.toString().simplified().toLower() == QLatin1String("true");
}
void ComposerViewPrivate::_k_slotSpeakText()
{
// If KTTSD not running, start it.
if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.kttsd"))) {
QString error;
if (KToolInvocation::startServiceByDesktopName(QLatin1String("kttsd"), QStringList(), &error)) {
KMessageBox::error(q, i18n( "Starting Jovie Text-to-Speech Service Failed"), error );
return;
}
}
QDBusInterface ktts(QLatin1String("org.kde.kttsd"), QLatin1String("/KSpeech"), QLatin1String("org.kde.KSpeech"));
QString text = q->selectedText();
if (text.isEmpty())
text = q->page()->mainFrame()->toPlainText();
ktts.asyncCall(QLatin1String("say"), text, 0);
}
void ComposerViewPrivate::_k_slotPasteWithoutFormatting()
{
#ifndef QT_NO_CLIPBOARD
if ( q->hasFocus() ) {
QString s = QApplication::clipboard()->text();
if ( !s.isEmpty() ) {
s.replace(QLatin1String("\n"), QLatin1String("<BR>"));
execCommand(QLatin1String("insertHTML"), s);
}
}
#endif
}
void ComposerViewPrivate::_k_slotInsertSpecialChar()
{
KPIMTextEdit::SelectSpecialChar dlg(q);
dlg.showSelectButton(false);
dlg.autoInsertChar();
if (dlg.exec()) {
execCommand(QLatin1String("insertHTML"), dlg.currentChar());
}
}
void ComposerViewPrivate::_k_slotInsertAnchor()
{
QPointer<ComposerAnchorDialog> dlg = new ComposerAnchorDialog( q );
if (dlg->exec() == KDialog::Accepted) {
execCommand(QLatin1String("insertHTML"), dlg->html());
}
delete dlg;
}
QMap<QString, QString> ComposerViewPrivate::localImages() const
{
QMap<QString, QString> lst;
QWebElementCollection images = q->page()->mainFrame()->findAllElements(QLatin1String("img"));
Q_FOREACH (const QWebElement& elm, images){
if (elm.attribute(QLatin1String("src")).startsWith(QLatin1String("file://"))) {
KUrl url (elm.attribute(QLatin1String("src")));
lst.insert(url.fileName(), url.path());
}
}
return lst;
}
}