Logo Search packages:      
Sourcecode: kblogger-kde4 version File versions  Download package

composereditor.cpp

/***************************************************************************

   Copyright (C) 2007 Antonio Aloisio <gnuton@gnuton.org>

   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.
 ***************************************************************************/

#include "composereditor.h"

#include <kurl.h>
#include <ktoolbar.h>
#include <kaction.h>
#include <ktoggleaction.h>
#include <kactioncollection.h>
#include <kactionmenu.h>
#include <ktextbrowser.h>
#include <khtml_part.h>
#include <khtmlview.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kinputdialog.h>
#include <kcolorscheme.h>

#include <QLayout>

#include "linkdialog.h"
#include "uploadmediadialog.h"
#include "htmlexporter.h"
#include "composer.h"
#include "kbloggermedia.h"
#include "visualeditor.h"
#include "medialistview.h"
#include "weblogstylegetter.h"

namespace KBlogger
{

ComposerEditor::ComposerEditor(Composer *composer, QWidget *parent) :
        QWidget(parent),
        mComposer(composer),
        visualTextEditor(0),
        prevPage(0),
        mMediaEnabled(false),
        weblogStyleGetter(0)
{
    setupUi( this );

    mLinkDialog = new KBloggerLinkDialog( this );

    kDebug();

    //Add a VisualEditor ActionCollection and Toolbar.
    mActionCollection = new KActionCollection ( this );
    mToolBar = new KToolBar ( VisualPageWidget );
    mToolBar->setIconDimensions(16);
    mToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
    VisualPageWidget->layout()->addWidget ( mToolBar );
    createActions();

    //Add VisualEditor
    visualTextEditor = new VisualEditor(VisualPageWidget);
    VisualPageWidget->layout()->addWidget ( visualTextEditor );
    visualTextEditor->setStyleSheet("background-color: #FFFF7F");

    connect( visualTextEditor, SIGNAL( currentFontChanged( const QFont & ) ),
             this, SLOT( updateCharFmt() ) );
    connect( visualTextEditor, SIGNAL( droppedMedia( const QString & ) ),
             this, SLOT( showUploadMediaDialog( const QString& ) ) );

    updateCharFmt();

    //KHTML, Posts Preview Widget
    previewBrowser = new KHTMLPart(PreviewPageWidget);
    PreviewPageWidget->layout()->addWidget(previewBrowser->view());
    mToolBarPreview = new KToolBar ( PreviewPageWidget );
    PreviewPageWidget->layout()->addWidget ( mToolBarPreview );

    previewBrowser->view()->show();
    previewBrowser->setJScriptEnabled(true);
    previewBrowser->setJavaEnabled(false);
    previewBrowser->setMetaRefreshEnabled(false);
    previewBrowser->setPluginsEnabled(true);
    visualTextEditor->setCheckSpellingEnabled ( true );

    connect ( mLinkDialog, SIGNAL ( addLink ( const QString&, const QString& ) ),
              this, SLOT ( addLink ( const QString&, const QString& ) ) );
    connect ( ComposerTabWidget, SIGNAL ( currentChanged ( int) ),
              this, SLOT ( syncEditors (int) ) );
    connect ( getStyleButton, SIGNAL( clicked() ),
              this, SLOT( getStyle() ) );

}

ComposerEditor::~ComposerEditor()
{
    kDebug();
}

void ComposerEditor::enableMedia( bool enabled )
{
    kDebug();
    mMediaEnabled = enabled;
}

void ComposerEditor::createActions()
{
    kDebug();
    //Add Bold Action
    KLocalizedString boldKLS = ki18nc("a button to make the text in the editor bold or make bold text non-bold.", "bold" );
    boldAction = new KToggleAction (KIcon("format-text-bold"), boldKLS.toString(), this);
    mActionCollection->addAction("bold", boldAction);
    connect(boldAction, SIGNAL(triggered()), this, SLOT(toggleBold()));
    mToolBar->addAction(boldAction);

    //Add Italic Action
    KLocalizedString italicKLS = ki18nc( "a button to make the text in the editor italic or make italic text non-italic.", "italic");
    italicAction = new KToggleAction (KIcon("format-text-italic"), italicKLS.toString(), this);
    mActionCollection->addAction("italic", italicAction);
    connect(italicAction, SIGNAL(triggered()), this, SLOT(toggleItalic()));
    mToolBar->addAction(italicAction);

    //Add Underline Action
    underlineAction = new KToggleAction (KIcon("format-text-underline"), i18n("underline"), this);
    mActionCollection->addAction("underline", underlineAction);
    connect(underlineAction, SIGNAL(triggered()), this, SLOT(toggleUnderline()));
    mToolBar->addAction(underlineAction);

    //Add Strikeout Tag Action
    strikeoutAction = new KToggleAction (KIcon("format-text-strikethrough"), i18n("strikeout"), this);
    mActionCollection->addAction("strikeout", strikeoutAction);
    connect(strikeoutAction, SIGNAL(triggered()), this, SLOT(toggleStrikeout()));
    mToolBar->addAction(strikeoutAction);

    //FontWeight Menu & Actions
    fontSizeMoreAction = new KAction (KIcon("format-font-size-more"),
                                      i18n("font size more"), this);
    mActionCollection->addAction("format-font-size-more", fontSizeMoreAction);
    connect(fontSizeMoreAction, SIGNAL( triggered()), this, SLOT( fontSizeMore() ));
    mToolBar->addAction(fontSizeMoreAction);

    fontSizeLessAction = new KAction (KIcon("format-font-size-less"),
                                      i18n("font size less"), this);
    mActionCollection->addAction("format-font-size-less", fontSizeLessAction);
    connect(fontSizeLessAction, SIGNAL(triggered()), this, SLOT( fontSizeLess() ));
    mToolBar->addAction(fontSizeLessAction);

    //Add HTML TAG <Code> Action
    codeAction = new KAction (KIcon("text-x-generic"), i18n("code"), this);
    mActionCollection->addAction("code", codeAction);
    connect(codeAction, SIGNAL(triggered()), this, SLOT(toggleCode()));
    mToolBar->addAction(codeAction);

    //Add Link Action
    addLinkAction = new KAction (KIcon("bookmark-new"), i18n("add link"), this);
    mActionCollection->addAction("add_link", addLinkAction);
    connect(addLinkAction, SIGNAL(triggered()), this, SLOT(showLinkDialog()));
    mToolBar->addAction(addLinkAction);

    //Add Media Actions
    insertMediaMenu = new KActionMenu (KIcon("insert-image"), i18n("insert media"), this);
    insertMediaMenu->setDelayed( false );
    mToolBar->addAction(insertMediaMenu);

    newMediaAction = new KAction (KIcon("document-new"), i18n("New media from file..."), this);
    mActionCollection->addAction("addMedia", newMediaAction);
    connect(newMediaAction, SIGNAL(triggered()), this, SLOT(showUploadMediaDialog()));
    insertMediaMenu->addAction(newMediaAction);

    addMediaAction = new KAction (KIcon("view-preview"), i18n("Media"), this);
    mActionCollection->addAction("addMedia", addMediaAction);
    connect(addMediaAction, SIGNAL(triggered()), this, SLOT( showMediaList()));
    insertMediaMenu->addAction(addMediaAction);

    //Add Html Tag Action
    addHtmlAction = new KAction (KIcon("text-html"), i18n("add HTML code"), this);
    mActionCollection->addAction("addHtmlCode", addHtmlAction);
    connect(addHtmlAction, SIGNAL(triggered()), this, SLOT(showHtmlDialog()));
    mToolBar->addAction(addHtmlAction);

    //Visual Editor Spell Checker Action
    spellCheckAction = new KAction (KIcon("tools-check-spelling"), i18n("check spell"), this);
    mActionCollection->addAction("checkSpell", addLinkAction);
    connect(spellCheckAction, SIGNAL(triggered()), this, SLOT(spellchecking()));
    mToolBar->addAction(spellCheckAction);
}

void ComposerEditor::updateCharFmt()
{
    kDebug();
    boldAction->setChecked( visualTextEditor->fontWeight() >= QFont::Bold );
    italicAction->setChecked( visualTextEditor->fontItalic() );
    underlineAction->setChecked( visualTextEditor->fontUnderline() );
    strikeoutAction->setChecked( visualTextEditor->currentFont().strikeOut() );
}

void ComposerEditor::spellchecking()
{
    visualTextEditor->checkSpelling();
}

void ComposerEditor::toggleItalic()
{
    visualTextEditor->setFontItalic ( !visualTextEditor->fontItalic() );
}

void ComposerEditor::toggleBold()
{
    kDebug();

    if ( visualTextEditor->fontWeight() >= QFont::Bold )
        visualTextEditor->setFontWeight( QFont::Normal );
    else
        visualTextEditor->setFontWeight( QFont::Bold );
}

void ComposerEditor::toggleUnderline()
{
    visualTextEditor->setFontUnderline ( !visualTextEditor->fontUnderline() );
}

void ComposerEditor::toggleStrikeout()
{
    QFont fontInVisual( visualTextEditor->currentFont() );
    fontInVisual.setStrikeOut(!fontInVisual.strikeOut());
    visualTextEditor->setCurrentFont(fontInVisual);
}

void ComposerEditor::toggleCode()
{
    static QString preFontFamily;
    if ( visualTextEditor->fontFamily() != "Courier New,courier" ) {
        preFontFamily = visualTextEditor->fontFamily();
        visualTextEditor->setFontFamily("Courier New,courier");
    } else {
        visualTextEditor->setFontFamily(preFontFamily);
    }
}

void ComposerEditor::fontSizeMore()
{
    kDebug();

    QTextCharFormat format = visualTextEditor->currentCharFormat ();

    int idx = format.intProperty(QTextFormat::FontSizeAdjustment);
    if ( idx < 3 ) {
        format.setProperty ( QTextFormat::FontSizeAdjustment, QVariant( ++idx ));
        visualTextEditor->setCurrentCharFormat (format);
    }
}

void ComposerEditor::fontSizeLess()
{
    kDebug();
    QTextCharFormat format = visualTextEditor->currentCharFormat ();

    int idx = format.intProperty(QTextFormat::FontSizeAdjustment);
    if ( idx > -1 ) {
        format.setProperty ( QTextFormat::FontSizeAdjustment, QVariant( --idx ));
        visualTextEditor->setCurrentCharFormat (format);
    }
}

void ComposerEditor::showUploadMediaDialog(const QString& filename )
{
    kDebug();
    if(!mMediaEnabled){
         kDebug() << "you can't add media with this api.";
         KMessageBox::sorry ( this, i18n( "File uploading is not possible on this blog." ) );
         return;
    }
    Q_ASSERT(mComposer );
    new UploadMediaDialog(filename, mComposer->blogname(), this);
}

void ComposerEditor::showMediaList()
{
    kDebug();
    if(!mMediaEnabled){
         kDebug() << "you can't add media with this api.";
         KMessageBox::sorry ( this, i18n( "File uploading is not possible on this blog." ) );
         return;
    }
    new MediaListView(mComposer->blogname(), this);
}

void ComposerEditor::insertMedia(KBloggerMedia* media)
{
    kDebug();
    if (!media) return;
    QString name = media->name();
    QString target;
    kDebug() << "media->url(): " << media->url();
    if ( media->url().isValid() ) {
        //it's an uploaded file
        target = media->url().url();
    } else {
        //it's a local file
        target = media->cachedFilename();
    }

    if ( !media->mimetype().contains("image") ) {
        addLink(target, name);
    } else {
        QTextCursor cursor = visualTextEditor->textCursor();
        cursor.insertImage(target);
    }
}

void ComposerEditor::insertThumbnail(KBloggerMedia* thumbnail, KBloggerMedia* image)
{
    kDebug();
    if(!thumbnail || !image) return;
    QString imageFilename, thumbnailFilename;
    if ( image->url().isValid() ) {
        //it's an uploaded image
        thumbnailFilename = thumbnail->url().url();
        imageFilename = image->url().url();
    } else {
        //it's a local image
        thumbnailFilename = thumbnail->cachedFilename();
        imageFilename = image->cachedFilename();
    }
    visualTextEditor->insertHtml( "<a href="+imageFilename+"><img src="
                                                   +thumbnailFilename+"/></a>" );
}

void ComposerEditor::showLinkDialog()
{
    QTextCharFormat currentCharFormat(visualTextEditor->textCursor().charFormat());
    QString selectedText, ancorHref;
    selectedText = visualTextEditor->textCursor().selectedText();
    ancorHref = currentCharFormat.anchorHref();
    kDebug() << "ComposerEditor::showLinkDialog()" << selectedText << endl;

    if ( selectedText.isEmpty() ) { //Add a link at the cursor position
        mLinkDialog->setLinkName (QString());
        mLinkDialog->show();
        return;
    } else {
        if ( currentCharFormat.isAnchor() ) {
            currentCharFormat.setAnchor(false);
            currentCharFormat.setUnderlineStyle(QTextCharFormat::NoUnderline);
            currentCharFormat.clearForeground();
            visualTextEditor->textCursor().setCharFormat(currentCharFormat);
        } else {
            mLinkDialog->setLinkName ( selectedText );
            mLinkDialog->show();
        }
    };
}

void ComposerEditor::addLink ( const QString& target, const QString& name ) //TODO add Edit Link
{
    kDebug() << "target" << target << "name" << name;
    //insertTag (target,name,0,link);
    QTextCharFormat currentCharFormat( visualTextEditor->textCursor().charFormat() );
    if (target.isEmpty()) { //remove link
        currentCharFormat.setAnchor(false);
        currentCharFormat.setUnderlineStyle(QTextCharFormat::NoUnderline);
        currentCharFormat.clearForeground();
    } else { //set link
        kDebug();
        currentCharFormat.setAnchor(true);
        currentCharFormat.setAnchorHref(target);
        currentCharFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
        currentCharFormat.setForeground(KColorScheme(QPalette::Active, KColorScheme::Window).foreground(KColorScheme::LinkText).color());
        if ( name != visualTextEditor->textCursor().selectedText() )
            visualTextEditor->textCursor().insertText(name, currentCharFormat);
    }
    visualTextEditor->textCursor().setCharFormat(currentCharFormat);
}


void ComposerEditor::showHtmlDialog()
{
    QString code;
    QRegExp testRegExp("(<[^<]*>)([^<]*)(</[^<]*>)");
    QValidator* validator = new QRegExpValidator(testRegExp, this);
    code = KInputDialog::getText(i18n("KBlogger - Visual Editor"), i18n("Insert here your HTML code:"), "<tag>"+i18n("text")+"</tag>", 0, this, validator);
    visualTextEditor->insertHtml(code);
}

QString ComposerEditor::htmlToRichtext(const QString& html)
{
    kDebug() << "in" << html;
    QString richText = html;

    richText.remove(QChar('\n'));

    richText.replace(QRegExp("<del>(.*)</del>"), "<s>\\1</s>");

    //Note: Qt Error:
    //      QDocument converts <h1> in [ font-size: xx-large + bold ]
    //      and font-size: xx-large in <h1>
    richText.replace("<h1>", "<span style=\"font-size: xx-large\" >");
    richText.replace("<h2>", "<span style=\"font-size: x-large\" >");
    richText.replace("<h3>", "<span style=\"font-size: large\" >");
    //richText.replace("<h4>", "<span style=\"font-size: medium\" >");
    richText.replace(QRegExp("<h4>(.*)</h4>"), "\\1");
    richText.replace("<h5>", "<span style=\"font-size: small\" >");
    richText.replace(QRegExp("</h[1-5]>"), "</span>");

    //kDebug() << "out" << richText;
    //return richText;
    QString h;
    QString basePath = KBloggerMedia::cachePath();
    h = "<html><head><base href=\"" + basePath + "\" /></head>" +
        "<body><p>" + richText + "</p></body></html>";
    kDebug() << "out" << h;
    return h;
}

void ComposerEditor::syncEditors(int i)
{
    kDebug();

    QWidget* mTab = ComposerTabWidget->widget(i);
    // TODO remove if we know how to replace it, toHtml() creates a mess ( a lot of css )
    // toHtml() does not work with drupal
    // this is incompatible with licensing policy (it has gplv2 only)
    htmlExporter* htmlExp = new htmlExporter();
    if (!mTab) {
        if (VisualPageWidget->isVisible())
            ContentTextHtmlEditor->setPlainText( htmlExp->toHtml(visualTextEditor->document()) );
    }

    if (mTab == VisualPageWidget && prevPage == 1) // HTML Editor =>VISUAL composer
        visualTextEditor->setHtml(htmlToRichtext(ContentTextHtmlEditor->toPlainText()));
    else
        if (mTab == HtmlPageWidget && prevPage == 0) // Visual Editor => HTML composer.
            ContentTextHtmlEditor->setPlainText( htmlExp->toHtml(visualTextEditor->document()) );
        else
            if (mTab == PreviewPageWidget) { // HTML Editor =>Preview  & Visual Editor => Preview
                if ( prevPage == 0 )
                    ContentTextHtmlEditor->setPlainText( htmlExp->toHtml(visualTextEditor->document()) );
                setHtmlPreview( i18n("Post Preview"),
                                ContentTextHtmlEditor->toPlainText() );
            }
    prevPage = i;
    delete htmlExp;
}

void ComposerEditor::getStyle()
{
    kDebug();
    delete weblogStyleGetter;
    weblogStyleGetter = new WeblogStyleGetter(mComposer->blogname(), this);
    connect( weblogStyleGetter, SIGNAL( styleFetched() ), this, SLOT( reloadHtmlPreview()));
}

void ComposerEditor::reloadHtmlPreview()
{
    kDebug();
    setHtmlPreview( i18n("Post Preview"), ContentTextHtmlEditor->toPlainText() );
}

void ComposerEditor::setHtmlPreview(const QString& title, const QString& content)
{
    kDebug();
    if (!previewBrowser) return;
    previewBrowser->begin();
    previewBrowser->openStream( "text/html", KUrl() );
    QString html;
    if (!mComposer->blogname().isEmpty()) {
        html = WeblogStyleGetter::styledHtml(mComposer->blogname(), title, content);
    }
    previewBrowser->writeStream(html.toAscii() );
    previewBrowser->closeStream();

}

} //namespace

#include "composereditor.moc"


Generated by  Doxygen 1.6.0   Back to index