$(OC_SERVER) \
$(SWIGDIRS-ALL) \
$(PYMAPIALL) \
- $(COVERAGE_INIT)
+ $(COVERAGE_INIT) \
+ $(OPENCHANGE_QT4)
install: all \
installlib \
# Suffixes compilation rules
#################################################################
-.SUFFIXES: .c .o .h .po .idl
+.SUFFIXES: .c .o .h .po .idl .cpp
.idl.h:
@echo "Generating $@"
.cpp.po:
@echo "Compiling $< with -fPIC"
- @$(CXX) $(CXXFLAGS) -fPIC -c $< -o $@
+ $(CXX) $(CXXFLAGS) -fPIC -c $< -o $@
#################################################################
# IDL compilation rules
libmapixx-installpc:
-libmapixx-clean: libmapixx-tests-clean libmapixx-libs-clean
+libmapixx-clean: libmapixx-tests-clean
libmapixx-install: libmapixx-installheader libmapixx-installlib
ln -sf libmapi.$(SHLIBEXT).$(PACKAGE_VERSION) $(DESTDIR)$(libdir)/libmapipp.$(SHLIBEXT).$(LIBMAPIPP_SO_VERSION)
endif
-libmapixx-libs-clean::
- rm -f libmapi++/src/*.po
- rm -f libmapi++/src/*.gcno libmapi/src/*.gcda
- rm -f libmapipp.$(SHLIBEXT).$(PACKAGE_VERSION)
-
libmapixx-uninstallheader:
rm -rf $(DESTDIR)$(includedir)/libmapi++
libmapixx-test-clean:
rm -f bin/libmapixx-test
rm -f libmapi++/tests/*.o
- rm -f libmapi++/tests/*.po
-clean:: libmapixx-clean
+clean:: libmapixx-tests-clean
bin/libmapixx-test: libmapi++/tests/test.cpp \
libmapipp.$(SHLIBEXT).$(PACKAGE_VERSION) \
# need config.mk
distclean::
rm -f config.mk
+
+####################################
+# Qt4 widgets
+####################################
+openchange_qt4: qt-lib qt-demoapp
+
+qt-lib: libqtmapi
+
+qt-demoapp: qt/demo/demoapp.moc qt/demo/demoapp
+
+# No install yet - we need to finish this first
+
+qt-clean::
+ rm -f qt/demo/demoapp
+ rm -f qt/demo/*.o
+ rm -f qt/lib/*.o
+ rm -f qt/demo/*.moc
+ rm -f qt/lib/*.moc
+ rm -f libqtmapi*
+
+clean:: qt-clean
+
+qt/demo/demoapp.moc: qt/demo/demoapp.h
+ moc -i qt/demo/demoapp.h -o qt/demo/demoapp.moc
+
+qt/lib/foldermodel.moc: qt/lib/foldermodel.h
+ moc -i qt/lib/foldermodel.h -o qt/lib/foldermodel.moc
+
+qt/lib/messagesmodel.moc: qt/lib/messagesmodel.h
+ moc -i qt/lib/messagesmodel.h -o qt/lib/messagesmodel.moc
+
+.cpp.o:
+ $(CXX) $(CXXFLAGS) $(QT4_CXXFLAGS) -fPIC -c $< -o $@
+
+libqtmapi: libmapi \
+ qt/lib/foldermodel.moc \
+ qt/lib/messagesmodel.moc \
+ libqtmapi.$(SHLIBEXT).$(PACKAGE_VERSION)
+
+LIBQTMAPI_SO_VERSION = 0
+
+libqtmapi.$(SHLIBEXT).$(PACKAGE_VERSION): \
+ qt/lib/foldermodel.o \
+ qt/lib/messagesmodel.o
+ @echo "Linking $@"
+ @$(CXX) $(DSOOPT) $(CXXFLAGS) $(LDFLAGS) -Wl,-soname,libqtmapi.$(SHLIBEXT).$(LIBQTMAPI_SO_VERSION) -o $@ $^ $(LIBS)
+
+
+qt/demo/demoapp: qt/demo/demoapp.o \
+ qt/demo/main.o \
+ libmapi.$(SHLIBEXT).$(PACKAGE_VERSION) \
+ libmapipp.$(SHLIBEXT).$(PACKAGE_VERSION) \
+ libqtmapi.$(SHLIBEXT).$(PACKAGE_VERSION)
+ @echo "Linking $@"
+ @$(CXX) $(CXXFLAGS) -o $@ $^ $(QT4_LIBS) $(LDFLAGS) $(LIBS)
+ # we don't yet install this...
+ ln -sf libqtmapi.$(SHLIBEXT).$(PACKAGE_VERSION) libqtmapi.$(SHLIBEXT)
+ ln -sf libqtmapi.$(SHLIBEXT).$(PACKAGE_VERSION) libqtmapi.$(SHLIBEXT).$(LIBQTMAPI_SO_VERSION)
+
MANUALLY_CREATE_SYMLINKS=@MANUALLY_CREATE_SYMLINKS@
+# Qt support
+QT4_CXXFLAGS=@Qt4_CFLAGS@
+QT4_LIBS=@Qt4_LIBS@
+OPENCHANGE_QT4=@OPENCHANGE_QT4@
AC_SUBST(DOXYGEN)
fi
+dnl ##########################################################################
+dnl Qt4 support
+dnl ##########################################################################
+AC_ARG_ENABLE(openchange-qt4,
+ AC_HELP_STRING([--disable-openchange-qt4],
+ [Don't compile OpenChange Qt4 wrapper.]),
+ enable_openchange_qt4=$enableval,
+ enable_openchange_qt4="try")
+if test x$enable_openchange_qt4 = xyes; then
+ PKG_CHECK_MODULES(Qt4,
+ QtCore >= 4.3.0 QtGui >= 4.3.0)
+elif test x$enable_openchange_qt4 = xtry; then
+ PKG_CHECK_MODULES(Qt4,
+ QtCore >= 4.3.0 QtGui >= 4.3.0,
+ [enable_openchange_qt4="yes"],
+ [enable_openchange_qt4="no"])
+fi
+
+AC_SUBST(Qt4_CFLAGS)
+AC_SUBST(Qt4_LIBS)
+
+if test "x$enable_openchange_qt4" = "xyes"; then
+ OPENCHANGE_QT4="openchange_qt4"
+fi
+AC_SUBST(OPENCHANGE_QT4)
+
dnl ***********************
dnl Makefiles
dnl ***********************
* OpenChange Bindings:
- Perl: $enable_perlswig
- Python: $enable_pymapi
+ - Qt4: $enable_openchange_qt4
===============================================================
--- /dev/null
+#include <Qt/QtGui>
+
+#include "demoapp.h"
+
+#include "../lib/foldermodel.h"
+#include "../lib/messagesmodel.h"
+
+#include <libmapi++/libmapi++.h>
+
+using namespace libmapipp;
+
+DemoApp::DemoApp()
+{
+ m_textEdit = new QTextEdit;
+ setCentralWidget( m_textEdit );
+
+ createActions();
+ createMenus();
+
+ login();
+
+ addFolderDockWidget();
+ addMessagesDockWidget();
+ openMessage( 0 );
+
+ resize( 1100, 900 );
+}
+
+void DemoApp::about()
+{
+ QMessageBox::about( this, tr( "OpenChange GUI Test Harness" ),
+ tr( "<qt>This test harness is for demonstrating and testing "
+ "some of the OpenChange functionality. It is not "
+ "intended for use in production.<br/><br/> <b>We mean it.</b></qt>" ) );
+}
+
+void DemoApp::createActions()
+{
+ m_aboutAction = new QAction( tr( "About" ), this );
+ connect( m_aboutAction, SIGNAL( triggered() ), this, SLOT( about() ) );
+
+ m_quitAction = new QAction( tr( "&Quit" ), this );
+ // Use this if we ever require Qt 4.6
+ // m_quitAction->setShortcuts( QKeySequence::Quit );
+ m_quitAction->setShortcut( QKeySequence( Qt::Key_Q, Qt::CTRL ) );
+ m_quitAction->setStatusTip( tr( "Quit the application" ) );
+ connect( m_quitAction, SIGNAL( triggered() ), this, SLOT( close() ) );
+}
+
+void DemoApp::createMenus()
+{
+ m_fileMenu = menuBar()->addMenu( tr( "&File" ) );
+ m_fileMenu->addAction( m_quitAction );
+
+ m_helpMenu = menuBar()->addMenu( tr( "&Help" ) );
+ m_helpMenu->addAction( m_aboutAction );
+}
+
+void DemoApp::login()
+{
+ // Initialize MAPI Session
+ m_mapi_session = new libmapipp::session();
+
+ m_mapi_session->login();
+}
+
+void DemoApp::addFolderDockWidget()
+{
+ m_folderDock = new QDockWidget( tr( "Folders" ), this );
+
+ FolderModel *folder = new FolderModel( m_mapi_session );
+ m_folderModel = folder->buildModel();
+
+ QTreeView *folderDockView = new QTreeView( m_folderDock );
+ folderDockView->setModel( m_folderModel );
+ folderDockView->expandToDepth( 2 );
+ connect( folderDockView, SIGNAL( clicked(QModelIndex) ), this, SLOT( folderChanged(QModelIndex) ) );
+ m_folderDock->setWidget( folderDockView );
+
+ addDockWidget(Qt::LeftDockWidgetArea, m_folderDock);
+}
+
+void DemoApp::addMessagesDockWidget()
+{
+ QDockWidget *messagesDock = new QDockWidget( tr( "Messages" ), this );
+
+ // Get Default Inbox folder ID.
+ mapi_id_t inbox_id = m_mapi_session->get_message_store().get_default_folder(olFolderInbox);
+ // std::cout << "inbox_id: " << inbox_id << std::endl;
+
+ // Open Inbox Folder
+ m_folder = new folder(m_mapi_session->get_message_store(), inbox_id);
+ MessagesModel *messages = new MessagesModel( m_folder );
+
+ m_messagesDockView = new QTableView( messagesDock );
+ m_messagesDockView->setModel( messages->buildModel() );
+ m_messagesDockView->setShowGrid( false );
+ m_messagesDockView->resizeColumnsToContents();
+ m_messagesDockView->resizeRowsToContents();
+ connect( m_messagesDockView, SIGNAL( clicked(QModelIndex) ), this, SLOT( messageChanged(QModelIndex) ) );
+ messagesDock->setWidget( m_messagesDockView );
+
+ splitDockWidget( m_folderDock, messagesDock, Qt::Horizontal );
+}
+
+void DemoApp::folderChanged(const QModelIndex &index)
+{
+ QStandardItem *item = m_folderModel->itemFromIndex( index );
+ if (item) {
+ qlonglong folderId = item->data().toLongLong();
+ m_folder = new folder(m_mapi_session->get_message_store(), folderId);
+ MessagesModel *messages = new MessagesModel( m_folder );
+ m_messagesModel = messages->buildModel();
+ m_messagesDockView->setModel( m_messagesModel );
+ }
+}
+
+void DemoApp::messageChanged( const QModelIndex &index )
+{
+ QStandardItem *item = m_messagesModel->itemFromIndex( index );
+ if ( item ) {
+ quint32 messageNumber = item->data().toUInt();
+ openMessage( messageNumber );
+ }
+}
+
+void DemoApp::openMessage( quint32 messageNumber )
+{
+ libmapipp::folder::message_container_type messages = m_folder->fetch_messages();
+ // std::cout << "Folder contains " << messages.size() << " messages" << std::endl;
+
+ // Get the properties we are interested in
+ libmapipp::property_container msg_props = messages[messageNumber]->get_property_container();
+ msg_props << PR_BODY_HTML;
+ msg_props.fetch();
+
+ if ( msg_props[PR_BODY_HTML] ) {
+ QString body = QString( (const char*)msg_props[PR_BODY_HTML] );
+ m_textEdit->setHtml( body );
+ } else {
+ m_textEdit->setHtml( QString() );
+ }
+}
+
+#include "demoapp.moc"
--- /dev/null
+#ifndef DEMOAPP_H
+#define DEMOAPP_H
+
+#include <QtGui/QMainWindow>
+#include <QtGui/QStandardItemModel>
+
+class QAction;
+class QMenu;
+class QTextEdit;
+class QStandardItem;
+class QTableView;
+
+namespace libmapipp
+{
+ class session;
+ class folder;
+};
+
+class DemoApp : public QMainWindow
+{
+ Q_OBJECT
+
+ public:
+ DemoApp();
+
+ private slots:
+ void about();
+ void folderChanged( const QModelIndex &index );
+ void messageChanged( const QModelIndex &index );
+
+ private:
+ void createActions();
+ void createMenus();
+
+ void login();
+
+ void addFolderDockWidget();
+ void addMessagesDockWidget();
+
+ void openMessage( quint32 messageNumber );
+
+ QMenu *m_fileMenu;
+ QMenu *m_helpMenu;
+
+ QAction *m_quitAction;
+ QAction *m_aboutAction;
+
+ QDockWidget *m_folderDock;
+ QStandardItemModel *m_folderModel;
+
+ QTableView *m_messagesDockView;
+ QStandardItemModel *m_messagesModel;
+
+ libmapipp::folder *m_folder;
+ QTextEdit *m_textEdit;
+
+ libmapipp::session *m_mapi_session;
+};
+
+#endif
+
--- /dev/null
+#include "demoapp.h"
+
+#include <QtGui/QApplication>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ DemoApp *demo = new DemoApp();
+ demo->show();
+
+ return app.exec();
+}
--- /dev/null
+#include <Qt/QtGui>
+#include <exception>
+#include <vector>
+#include <string>
+
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+
+#include "foldermodel.h"
+
+#include <libmapi++/libmapi++.h>
+
+using namespace libmapipp;
+
+FolderModel::FolderModel( libmapipp::session *mapi_session ) :
+ m_mapi_session( mapi_session )
+{
+ m_folderModel = new QStandardItemModel();
+ QStringList folderModelHeaders;
+ folderModelHeaders << QString( "Folder Name" ) << QString( "FolderId" ) << QString( "Container Class" );
+ m_folderModel->setHorizontalHeaderLabels( folderModelHeaders );
+}
+
+void FolderModel::add_folder_to_tree(libmapipp::folder& up_folder, QStandardItem *parentItem)
+{
+ property_container up_folder_property_container = up_folder.get_property_container();
+ up_folder_property_container << PR_DISPLAY_NAME << PR_CONTAINER_CLASS;
+ up_folder_property_container.fetch();
+
+ std::string display_name = static_cast<const char*>(up_folder_property_container[PR_DISPLAY_NAME]);
+ std::string container_class;
+ if (up_folder_property_container[PR_CONTAINER_CLASS])
+ container_class = static_cast<const char*>(up_folder_property_container[PR_CONTAINER_CLASS]);
+
+ QList< QStandardItem * > row;
+ QStandardItem *name = new QStandardItem( QString::fromStdString( display_name ) );
+ name->setData( (qlonglong)up_folder.get_id() );
+ QStandardItem *folderId = new QStandardItem( QString::number( up_folder.get_id(), 16 ) );
+ QStandardItem *containerClass = new QStandardItem( QString::fromStdString( container_class ) );
+ row << name << folderId << containerClass;
+
+ parentItem->appendRow( row );
+
+ // Fetch Top Information Folder Hierarchy (child folders)
+ folder::hierarchy_container_type hierarchy = up_folder.fetch_hierarchy();
+ for (unsigned int i = 0; i < hierarchy.size(); ++i) {
+ add_folder_to_tree(*hierarchy[i], name);
+ }
+}
+
+QStandardItemModel* FolderModel::buildModel()
+{
+ try {
+ // Get Default Top Information Store folder ID
+ mapi_id_t top_folder_id = m_mapi_session->get_message_store().get_default_folder(olFolderTopInformationStore);
+
+ // Open Top Information Folder
+ folder top_folder( m_mapi_session->get_message_store(), top_folder_id );
+
+ QStandardItem *parentItem = m_folderModel->invisibleRootItem();
+
+ add_folder_to_tree(top_folder, parentItem);
+ }
+ catch (mapi_exception e) // Catch any mapi exceptions
+ {
+ std::cout << "MAPI Exception @ main: " << e.what() << std::endl;
+ }
+ catch (std::runtime_error e) // Catch runtime exceptions
+ {
+ std::cout << "std::runtime_error exception @ main: " << e.what() << std::endl;
+ }
+ return m_folderModel;
+}
+
+
+#include "foldermodel.moc"
\ No newline at end of file
--- /dev/null
+#ifndef FOLDERMODEL_H
+#define FOLDERMODEL_H
+
+class QStandardItem;
+class QStandardItemModel;
+
+namespace libmapipp
+{
+class folder;
+class session;
+}
+
+class FolderModel : public QStandardItemModel
+{
+ Q_OBJECT
+
+ public:
+ FolderModel( libmapipp::session *mapi_session );
+
+ QStandardItemModel* buildModel();
+
+ private:
+ libmapipp::session *m_mapi_session;
+ QStandardItemModel *m_folderModel;
+
+ void add_folder_to_tree(libmapipp::folder& up_folder, QStandardItem *parentItem);
+};
+
+
+#endif
--- /dev/null
+#include "messagesmodel.h"
+
+#include <libmapi++/libmapi++.h>
+
+using namespace libmapipp;
+
+MessagesModel::MessagesModel( libmapipp::folder *folder ):
+ m_mapi_folder( folder )
+{
+}
+
+QStandardItemModel* MessagesModel::buildModel()
+{
+ // Fetch messages in Inbox Folder
+ folder::message_container_type messages = m_mapi_folder->fetch_messages();
+
+ QStandardItemModel *messagesModel = new QStandardItemModel();
+ QStringList messagesModelHeaders;
+ messagesModelHeaders << QString( "Topic" ) << QString( "To" ) << QString( "From" );
+ messagesModel->setHorizontalHeaderLabels( messagesModelHeaders );
+
+ for ( unsigned int i = 0; i < messages.size(); ++i ) {
+ property_container message_property_container = messages[i]->get_property_container();
+
+ // Add Property Tags to be fetched and then fetch the properties.
+ message_property_container << PR_DISPLAY_TO << PR_CONVERSATION_TOPIC << PR_SENDER_NAME;
+ message_property_container.fetch_all();
+
+ std::string to;
+ std::string subject;
+ std::string from;
+
+ for (property_container::iterator Iter = message_property_container.begin(); Iter != message_property_container.end(); Iter++)
+ {
+ if (Iter.get_tag() == PR_DISPLAY_TO)
+ to = (const char*) *Iter;
+ else if (Iter.get_tag() == PR_CONVERSATION_TOPIC)
+ subject = (const char*) *Iter;
+ else if (Iter.get_tag() == PR_SENDER_NAME)
+ from = (const char*) *Iter;
+ }
+ QList< QStandardItem * > row;
+ row << new QStandardItem( QString::fromStdString( subject ) );
+ row[0]->setData( (quint32) i );
+ row << new QStandardItem( QString::fromStdString( to ) );
+ row << new QStandardItem( QString::fromStdString( from ) );
+ messagesModel->appendRow( row );
+ }
+
+ return messagesModel;
+}
+
+
+
+#include "messagesmodel.moc"
--- /dev/null
+#ifndef MESSAGESMODEL_H
+#define MESSAGESMODEL_H
+
+class QStandardItem;
+#include <QStandardItemModel>
+
+namespace libmapipp
+{
+class folder;
+class session;
+}
+
+
+class MessagesModel : public QStandardItemModel
+{
+ Q_OBJECT
+
+ public:
+ MessagesModel( libmapipp::folder *folder );
+
+ QStandardItemModel *buildModel();
+
+ private:
+ libmapipp::folder *m_mapi_folder;
+};
+
+#endif