Blokkal
an Extendable KDE Blogging Client
SourceForge.net Logo

blokkalentry.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2006 - 2008 by Martin Mueller                           *
00003  *   orvio@orvio.de                                                        *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 #include "blokkalentry.h"
00021 #include "blokkalentry.moc"
00022 
00023 #include "blokkalblog.h"
00024 #include "blokkalaccount.h"
00025 #include "blokkalaccountmanager.h"
00026 #include "blokkalprotocol.h"
00027 #include "blokkalpluginmanager.h"
00028 #include "blokkalui/viewmanager.h"
00029 #include "blokkalui/blogchooser.h"
00030 #include "blokkalui/globalsettings.h"
00031 
00032 #include <klocale.h>
00033 #include <kdebug.h>
00034 
00035 #include <QDomElement>
00036 #include <QFile>
00037 
00038 class Blokkal::Entry::Private
00039 {
00040 public:
00041         Private( void ) :
00042         internalDocument( QDomDocument( "BlokkalEntry" ) ),
00043         refcount( 0 ),
00044         isDirty( FALSE )
00045         {
00046                 internalDocument.appendChild( internalDocument.createElement( "entry" ) );
00047         }
00048 
00049         QDomDocument internalDocument;
00050         Blokkal::Blog * blog;
00051         int refcount;
00052         bool isDirty;
00053 };
00054 
00055 Blokkal::Entry::Entry( Blog * parentBlog, const QString & id, const KUrl & url ) :
00056 QObject( parentBlog ),
00057 Blokkal::ConfigBase(),
00058 d( new Private() )
00059 {
00060         setNode( d->internalDocument.firstChild().toElement() );
00061         
00062         d->blog = parentBlog;
00063 
00064         node().setAttribute( "blog", parentBlog->id() );
00065         node().setAttribute( "account", parentBlog->account()->id() );
00066         node().setAttribute( "protocol", parentBlog->account()->protocol()->pluginName() );
00067         node().setAttribute( "id", id );
00068         node().setAttribute( "url", url.url() );
00069 }
00070 
00071 Blokkal::Entry::~Entry( void )
00072 {
00073         emit entryDestroyed( this );
00074         delete d;
00075 }
00076 
00077 QString Blokkal::Entry::id( void ) const
00078 {
00079         return node().attribute( "id" );
00080 }
00081 
00082 Blokkal::Blog * Blokkal::Entry::blog( void ) const
00083 {
00084         return d->blog;
00085 }
00086 
00087 KIcon Blokkal::Entry::icon( void ) const
00088 {
00089         return blog()->icon();
00090 }
00091 
00092 QString Blokkal::Entry::text( void ) const
00093 {
00094         return node().namedItem( "text" ).firstChild().nodeValue();
00095 }
00096 
00097 void Blokkal::Entry::setText( const QString & text )
00098 {
00099         QDomElement textParent = d->internalDocument.firstChild().namedItem( "text" ).toElement();
00100         if( textParent.isNull() ) {
00101                 textParent = d->internalDocument.createElement( "text" );
00102                 d->internalDocument.firstChild().appendChild( textParent );
00103                 textParent.appendChild( d->internalDocument.createTextNode( 0 ) );
00104         }
00105 
00106         textParent.firstChild().toText().setData( text );
00107 }
00108 
00109 QString Blokkal::Entry::subject( void ) const
00110 {
00111         return d->internalDocument.firstChild().namedItem( "subject" ).firstChild().nodeValue();
00112 }
00113 
00114 
00115 QString Blokkal::Entry::preview( void ) const
00116 {
00117         QString preview = subject();
00118 
00119         if( !preview.isEmpty() ) {
00120                 return preview;
00121         }
00122 
00123         preview = text();
00124         
00125         if( preview.isEmpty() ) {
00126                 return i18n( "<No Subject>" );
00127         }
00128 
00129         if( preview.length() > 100 ) {
00130                 preview = preview.left( 100 );
00131                 preview.replace( 97, 3, i18n( "..." ) );
00132         }
00133 
00134         return preview;
00135 }
00136 
00137 void Blokkal::Entry::setSubject( const QString & subject )
00138 {
00139         QDomElement subjectParent = d->internalDocument.firstChild().namedItem( "subject" ).toElement();
00140         
00141         if( subjectParent.isNull() ) {
00142                 subjectParent = d->internalDocument.createElement( "subject" );
00143                 d->internalDocument.firstChild().appendChild( subjectParent );
00144                 subjectParent.appendChild( d->internalDocument.createTextNode( 0 ) );
00145         }
00146 
00147         subjectParent.firstChild().toText().setData( subject );
00148 }
00149 
00150 QDateTime Blokkal::Entry::date( void ) const
00151 {
00152         QDateTime entryDate;
00153         QDomElement entryElement = d->internalDocument.firstChild().toElement();
00154         
00155         if( entryElement.hasAttribute( "date" ) ) {
00156                 entryDate.setTime_t( entryElement.attribute( "date" ).toUInt() );
00157         }
00158         
00159         return entryDate;
00160 }
00161 
00162 void Blokkal::Entry::setDate( const QDateTime & date )
00163 {
00164         d->internalDocument.firstChild().toElement().setAttribute( "date", date.toTime_t() );
00165 }
00166 
00167 Blokkal::Ui::View * Blokkal::Entry::view( void )
00168 {
00169         return Ui::ViewManager::self()->view( this );
00170 }
00171 
00172 void Blokkal::Entry::ref( void )
00173 {
00174         d->refcount++;
00175 }
00176 
00177 void Blokkal::Entry::deref( void )
00178 {
00179         d->refcount--;
00180         if( d->refcount < 1 && !Blokkal::Ui::ViewManager::hasView( this ) ) {
00181                 deleteLater();
00182         }
00183 }
00184 
00185 QString Blokkal::Entry::fileName( bool check ) const
00186 {
00187         QString fileName = node().attribute( "filename" );
00188         if( check && !QFile::exists( fileName) ) {
00189                 fileName = QString::null;
00190                 setFileName( fileName );
00191                 
00192         }
00193         return fileName;
00194 }
00195 
00196 void Blokkal::Entry::setFileName( const QString & fileName ) const
00197 {
00198         node().setAttribute( "filename", fileName );
00199 }
00200 
00201 bool Blokkal::Entry::saveAs( const QString & fileName )
00202 {
00203         QFile file( fileName );
00204    if( !file.open( QIODevice::WriteOnly ) ) {
00205                 kError() << "error opening file for reading" << file.fileName() << endl;
00206            return FALSE;
00207         }
00208 
00209         saveProperties();
00210         setFileName( QString::null ); //don't save the filename in the file
00211         
00212    QTextStream fileStream( &file );
00213         node().ownerDocument().save( fileStream, 3 );
00214    file.close();
00215 
00216         setFileName( fileName );
00217         return TRUE;
00218 }
00219 
00220 Blokkal::Entry * Blokkal::Entry::open( const QString & fileName, bool * canceled, bool neverAsk )
00221 {
00222         bool error = FALSE;
00223         
00224         if( canceled ) {
00225                 *canceled = FALSE;
00226         }
00227 
00228         QDomDocument document( "BlokkalEntry" );
00229         
00230         //load the file
00231         QFile file( fileName );
00232         if( file.open( QIODevice::ReadOnly ) ) {
00233                 if( !document.setContent( &file ) ) {
00234                         kError() << "error parsing file " << file.fileName() << endl;
00235                         error = TRUE;
00236                 }
00237                 file.close();
00238         }
00239         else {
00240                 kError() << "error opening file " << file.fileName() << endl;
00241                 error = TRUE;
00242         }
00243 
00244         if( error ) {
00245                 return 0;
00246         }
00247 
00248         //examine content
00249         QDomElement entryNode = document.firstChild().toElement();
00250         if( entryNode.isNull() ) {
00251                 kError() << "malformed file " << file.fileName() << endl;
00252                 return 0;
00253         }
00254 
00255         const QString blogId = entryNode.attribute( "blog" );
00256         const QString accountId = entryNode.attribute( "account" );
00257         const QString protocolName = entryNode.attribute( "protocol" );
00258 
00259         QString message;
00260         Blog * blog = 0;
00261         Account * account = AccountManager::self()->account( accountId );
00262         if( !account ) {
00263                 message = i18n( "No account could be found for this entry. Please select the correct account and blog manually." );
00264         }
00265         else {
00266                 blog = account->blog( blogId );
00267                 if( !blog || account->protocol()->pluginName() != protocolName ) {
00268                         if( blog ) {
00269                                 message = i18n( "An account and a blog for the entry have been found. However, the protocol does not match. Please review the selection." );
00270                         }
00271                         else {
00272                                 message = i18n( "An account for the entry has been found. However, the account does not contain the blog this entry belongs to. Please select the correct blog manually.");
00273                         }
00274                 }
00275         }
00276 
00277         if( !message.isEmpty() ) {
00278                 if( neverAsk ) {
00279                         return 0;
00280                 }
00281                 
00282                 Ui::BlogChooserDialog * dialog = new Ui::BlogChooserDialog( message, Ui::GlobalSettings::self()->mainWidget() );
00283                 dialog->blogChooser()->setAccount( account );
00284                 dialog->blogChooser()->setBlog( blog );
00285                 blog = 0;
00286 
00287                 if( dialog->exec() ) {
00288                         blog = dialog->blogChooser()->blog();
00289                 }
00290                 else if( canceled ) {
00291                         *canceled = TRUE;
00292                 }
00293 
00294                 delete dialog;
00295         }
00296 
00297         if( !blog  ) {
00298                 return 0;
00299         }
00300         
00301         Entry * entry = blog->createEntry();
00302         entry->d->internalDocument = document;
00303         entry->setNode( entryNode );
00304         entry->setFileName( fileName );
00305 
00306         entry->node().setAttribute( "blog", blog->id() );
00307         entry->node().setAttribute( "account", blog->account()->id() );
00308         entry->node().setAttribute( "protocol", blog->account()->protocol()->pluginName() );
00309         entry->readProperties();
00310         
00311         return entry;
00312 }
00313 
00314 Blokkal::Ui::EntryExtensionWidget * Blokkal::Entry::createExtensionWidget( Ui::EntryExtensionWidget::ExtensionWidget /*extension*/, Blokkal::Ui::EditEntryWidget * /*parent*/ )
00315 {
00316         return 0;
00317 }
00318 
00319 QStringList Blokkal::Entry::categories( void ) const
00320 {
00321         QStringList ids;
00322 
00323         //read category childnodes for each item
00324         for( QDomNode currentNode = node().firstChild();
00325              !currentNode.isNull();
00326              currentNode = currentNode.nextSibling()
00327            )
00328         {
00329                 if( currentNode.isElement()
00330                     && currentNode.nodeName() == "category" )
00331                 {
00332                         ids.append( currentNode.toElement().attribute( "id" ) );
00333                 }
00334         }       
00335 
00336         return ids;
00337 }
00338 
00339 void Blokkal::Entry::setCategories( const QStringList & ids )
00340 {
00341         for( QDomNode currentNode = node().firstChild();
00342              !currentNode.isNull();)
00343         {
00344                 if( currentNode.isElement()
00345                     && currentNode.nodeName() == "category" )
00346                 {
00347                         QDomNode obsoleteNode = currentNode;
00348                         currentNode = currentNode.nextSibling();
00349                         node().removeChild( obsoleteNode );
00350                 }
00351                 else {
00352                         currentNode = currentNode.nextSibling();
00353                 }
00354         }
00355 
00356         //create category childnodes for each item
00357         for( QStringList::ConstIterator it = ids.begin();
00358              it != ids.end();
00359              ++it )
00360         {
00361                 QDomElement categoryElement = node().ownerDocument().createElement( "category" );
00362                 node().appendChild( categoryElement );
00363                 categoryElement.setAttribute( "id", *it );
00364         }
00365 }
00366 
00367 void Blokkal::Entry::merge( const Blokkal::Entry * entry )
00368 {
00369         setDate( entry->date() );
00370         setSubject( entry->subject() );
00371         setText( entry->text() );
00372 }
00373 
00374 bool Blokkal::Entry::isDirty( void ) const
00375 {
00376         return d->isDirty;
00377 }
00378 
00379 void Blokkal::Entry::setDirty( bool dirty )
00380 {
00381         d->isDirty = dirty;
00382 }
00383 
00384 KUrl Blokkal::Entry::url( void ) const
00385 {
00386         return node().attribute( "url" );
00387 }
00388 
00389 void Blokkal::Entry::saveProperties( void )
00390 {
00391 }
00392 
00393 void Blokkal::Entry::readProperties( void )
00394 {
00395 }