1 /* -*- mode: C++; c-file-style: "gnu" -*-
3 * This file is part of KMail, the KDE mail client.
5 * Copyright (c) 2002-2003 Carsten Pfeiffer <pfeiffer@kde.org>
6 * Copyright (c) 2003 Zack Rusin <zack@kde.org>
8 * KMail is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License, version 2, as
10 * published by the Free Software Foundation.
12 * KMail is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * In addition, as a special exception, the copyright holders give
22 * permission to link the code of this program with any edition of
23 * the Qt library by Trolltech AS, Norway (or with modified versions
24 * of Qt that use the same license as Qt), and distribute linked
25 * combinations including the two. You must obey the GNU General
26 * Public License in all respects for all of the code used other than
27 * Qt. If you modify this file, you may extend this exception to
28 * your version of the file, but you are not obligated to do so. If
29 * you do not wish to do so, delete this exception statement from
32 #include <config-messageviewer.h>
34 #include "mailsourceviewer.h"
35 #include "findbar/findbarsourceview.h"
36 #include <kiconloader.h>
37 #include <KLocalizedString>
38 #include <kstandardguiitem.h>
39 #include <kwindowsystem.h>
41 #include <QtCore/QRegExp>
42 #include <QtGui/QApplication>
43 #include <QtGui/QIcon>
44 #include <QtGui/QPushButton>
45 #include <QtGui/QShortcut>
46 #include <QtGui/QTabBar>
47 #include <QtGui/QVBoxLayout>
48 #include <QContextMenuEvent>
51 namespace MessageViewer
{
54 MailSourceViewTextBrowserWidget::MailSourceViewTextBrowserWidget( QWidget
*parent
)
57 QVBoxLayout
*lay
= new QVBoxLayout
;
59 mTextBrowser
= new MailSourceViewTextBrowser();
60 mTextBrowser
->setLineWrapMode( QTextEdit::NoWrap
);
61 mTextBrowser
->setTextInteractionFlags( Qt::TextSelectableByMouse
| Qt::TextSelectableByKeyboard
);
62 connect( mTextBrowser
, SIGNAL( findText() ), SLOT( slotFind() ) );
63 lay
->addWidget( mTextBrowser
);
64 mFindBar
= new FindBarSourceView( mTextBrowser
, this );
65 lay
->addWidget( mFindBar
);
66 QShortcut
*shortcut
= new QShortcut( this );
67 shortcut
->setKey( Qt::Key_F
+Qt::CTRL
);
68 connect( shortcut
, SIGNAL(activated()), SLOT(slotFind()) );
71 void MailSourceViewTextBrowserWidget::slotFind()
74 mFindBar
->focusAndSetCursor();
77 void MailSourceViewTextBrowserWidget::setText( const QString
& text
)
79 mTextBrowser
->setText( text
);
82 void MailSourceViewTextBrowserWidget::setPlainText( const QString
& text
)
84 mTextBrowser
->setPlainText( text
);
87 MessageViewer::MailSourceViewTextBrowser
*MailSourceViewTextBrowserWidget::textBrowser() const
92 MailSourceViewTextBrowser::MailSourceViewTextBrowser( QWidget
*parent
)
93 :KTextBrowser( parent
)
97 void MailSourceViewTextBrowser::contextMenuEvent( QContextMenuEvent
*event
)
99 QMenu
*popup
= createStandardContextMenu(event
->pos());
101 popup
->addSeparator();
102 popup
->addAction( KStandardGuiItem::find().text(),this,SIGNAL( findText() ) , Qt::Key_F
+Qt::CTRL
);
103 //Code from KTextBrowser
104 KIconTheme::assignIconsToContextMenu( isReadOnly() ? KIconTheme::ReadOnlyText
105 : KIconTheme::TextEditor
,
108 popup
->exec( event
->globalPos() );
114 void MailSourceHighlighter::highlightBlock ( const QString
& text
) {
115 // all visible ascii except space and :
116 const QRegExp
regexp( "^([\\x21-9;-\\x7E]+:\\s)" );
117 const int headersState
= -1; // Also the initial State
118 const int bodyState
= 0;
120 // keep the previous state
121 setCurrentBlockState( previousBlockState() );
122 // If a header is found
123 if( regexp
.indexIn( text
) != -1 )
125 // Content- header starts a new mime part, and therefore new headers
126 // If a Content-* header is found, change State to headers until a blank line is found.
127 if ( text
.startsWith( QLatin1String( "Content-" ) ) )
129 setCurrentBlockState( headersState
);
131 // highligth it if in headers state
132 if( ( currentBlockState() == headersState
) )
134 QFont font
= document()->defaultFont ();
135 font
.setBold( true );
136 setFormat( 0, regexp
.matchedLength(), font
);
139 // Change to body state
140 else if ( text
.isEmpty() )
142 setCurrentBlockState( bodyState
);
146 void HTMLSourceHighlighter::highlightBlock ( const QString
& text
) {
148 if( ( pos
= HTMLPrettyFormatter::htmlTagRegExp
.indexIn( text
) ) != -1 )
150 QFont font
= document()->defaultFont();
151 font
.setBold( true );
152 setFormat( pos
, HTMLPrettyFormatter::htmlTagRegExp
.matchedLength(), font
);
156 const QString
HTMLPrettyFormatter::reformat( const QString
&src
)
158 const QRegExp
cleanLeadingWhitespace( "(?:\\n)+\\w*" );
159 QStringList tmpSource
;
160 QString
source( src
);
164 //First make sure that each tag is surrounded by newlines
165 while( (pos
= htmlTagRegExp
.indexIn( source
, pos
) ) != -1 )
167 source
.insert(pos
, '\n');
168 pos
+= htmlTagRegExp
.matchedLength() + 1;
169 source
.insert(pos
, '\n');
173 // Then split the source on newlines skiping empty parts.
174 // Now a line is either a tag or pure data.
175 tmpSource
= source
.split('\n', QString::SkipEmptyParts
);
177 // Then clean any leading whitespace
178 for( int i
= 0; i
!= tmpSource
.length(); i
++ )
180 tmpSource
[i
] = tmpSource
[i
].remove( cleanLeadingWhitespace
);
183 // Then indent as appropriate
184 for( int i
= 0; i
!= tmpSource
.length(); i
++ ) {
185 if( htmlTagRegExp
.indexIn( tmpSource
[i
] ) != -1 ) // A tag
187 if( htmlTagRegExp
.cap( 3 ) == "/" || htmlTagRegExp
.cap( 2 ) == "img" || htmlTagRegExp
.cap( 2 ) == "br" ) {
188 //Self closing tag or no closure needed
191 if( htmlTagRegExp
.cap( 1 ) == "/" ) {
194 tmpSource
[i
].prepend( indent
);
198 tmpSource
[i
].prepend( indent
);
199 indent
.append( " " );
203 tmpSource
[i
].prepend( indent
);
206 // Finally reassemble and return :)
207 return tmpSource
.join( "\n" );
210 MailSourceViewer::MailSourceViewer( QWidget
*parent
)
211 : KDialog( parent
), mRawSourceHighLighter( 0 )
213 setAttribute( Qt::WA_DeleteOnClose
);
216 QVBoxLayout
*layout
= new QVBoxLayout( mainWidget() );
217 layout
->setMargin( 0 );
218 mTabWidget
= new KTabWidget
;
219 layout
->addWidget( mTabWidget
);
221 connect( this, SIGNAL(closeClicked()), SLOT(close()) );
223 mRawBrowser
= new MailSourceViewTextBrowserWidget();
224 mTabWidget
->addTab( mRawBrowser
, i18nc( "Unchanged mail message", "Raw Source" ) );
225 mTabWidget
->setTabToolTip( 0, i18n( "Raw, unmodified mail as it is stored on the filesystem or on the server" ) );
228 mHtmlBrowser
= new MailSourceViewTextBrowserWidget();
229 mTabWidget
->addTab( mHtmlBrowser
, i18nc( "Mail message as shown, in HTML format", "HTML Source" ) );
230 mTabWidget
->setTabToolTip( 1, i18n( "HTML code for displaying the message to the user" ) );
231 mHtmlSourceHighLighter
= new HTMLSourceHighlighter( mHtmlBrowser
->textBrowser() );
234 mTabWidget
->setCurrentIndex( 0 );
236 // combining the shortcuts in one qkeysequence() did not work...
237 QShortcut
* shortcut
= new QShortcut( this );
238 shortcut
->setKey( Qt::Key_Escape
);
239 connect( shortcut
, SIGNAL(activated()), SLOT(close()) );
241 shortcut
= new QShortcut( this );
242 shortcut
->setKey( Qt::Key_W
+Qt::CTRL
);
243 connect( shortcut
, SIGNAL(activated()), SLOT(close()) );
245 KWindowSystem::setIcons( winId(),
246 qApp
->windowIcon().pixmap( IconSize( KIconLoader::Desktop
),
247 IconSize( KIconLoader::Desktop
) ),
248 qApp
->windowIcon().pixmap( IconSize( KIconLoader::Small
),
249 IconSize( KIconLoader::Small
) ) );
250 mRawSourceHighLighter
= new MailSourceHighlighter( mRawBrowser
->textBrowser() );
253 MailSourceViewer::~MailSourceViewer()
257 void MailSourceViewer::setRawSource( const QString
&source
)
259 mRawBrowser
->setText( source
);
262 void MailSourceViewer::setDisplayedSource( const QString
&source
)
265 mHtmlBrowser
->setPlainText( HTMLPrettyFormatter::reformat( source
) );
271 #include "mailsourceviewer.moc"