Commit 191e1213 authored by David Faure's avatar David Faure
Browse files

Cleaning up the proko2 branch mess (that I originally created); this will...

Cleaning up the proko2 branch mess (that I originally created); this will require a few commits and a temporary branch.

svn path=/branches/kdepim/proko2-full/kdepim/; revision=541169
parent efed6853
How to implement DCOP communication between two applications so that
1) it works when the applications are standalone (separate processes)
2) it works when the applications are loaded as parts, embedded into kontact
3) it behaves properly when a separate process exits/crashes.
In the part
===========
Let's say that part 'A' wants to use the interface "Foo", via DCOP.
(where Foo is usually a generic name, e.g. Calendar, Mailer, AlarmDaemon, etc.)
The services which implement this interface are associated with the service type
"DCOP/Foo".
One of those services is application 'B', which implements "Foo" - note that
'B' should make sure that the "Foo" DCOP interface is available both when
'B' is used as standalone process and when 'B' is only loaded as a part.
(This means that if the app doesn't use its own part, then both should implement
"Foo", like kaddressbook does. Of course it's simpler if the app uses its own part :)
Here are some code snippets that must go into the part (A) that wants to use "Foo":
* Constructor:
m_foo_stub = 0L;
kapp->dcopClient()->setNotifications( true );
connect( kapp->dcopClient(), SIGNAL( applicationRemoved( const QCString&)),
this, SLOT( unregisteredFromDCOP( const QCString& )) );
* Destructor:
kapp->dcopClient()->setNotifications( false );
delete m_foo_stub;
[Note that setNotifications() is implemented with a refcount, this is the
correct way to do it and it won't mess up other parts]
* bool connectToFoo() method, which uses KDCOPServiceStarter::self()->findServiceFor("DCOP/Foo").
See test part for details (plugins/test/test_part.cpp).
* unregisteredFromDCOP( const QCString& appId ) slot, which will be called when
the process implementing Foo exits. The method simply does:
if ( m_foo_stub && m_foo_stub->app() == appId )
{
delete m_foo_stub;
m_foo_stub = 0;
}
* Now you can finally use the foo dcop interface. First you need to connect
to it:
if ( !connectToFoo() )
return;
Then you can use m_foo_stub to call the DCOP methods.
In case of critical methods, where you want to make 100% sure that the DCOP
call was correctly done (e.g. the remote app didn't crash during the call),
you can use if ( !m_foo_stub->ok() ).
In the kontact plugin
=====================
* Don't use dcopClient() until the part is loaded
* After loading the part, you might want to create a DCOP stub to use some
of its methods (do both in a loadPart() method, e.g.).
* Implement createDCOPInterface( const QString& serviceType ), to
load the part if the serviceType is one provided by it.
See KAddressbookPlugin (plugins/kaddressbook/*) for a working example.
Don't forget to
===============
* Define the service type, using a "Type=ServiceType" .desktop file,
with "X-KDE-ServiceType=DCOP/Foo".
See e.g. kdepim/kaddressbook/dcopaddressbook.desktop
* Add DCOP/Foo to the application's ServiceTypes list, in its .desktop file
See e.g. kdepim/kaddressbook/kaddressbook.desktop
* Make sure that X-DCOP-ServiceType and X-DCOP-ServiceName are specified too.
Designing DCOP interfaces
=========================
Porting the kroupware signals/slots to DCOP requires some changes.
For instance any non-const reference (such as those used for returning
values to the caller) has to be changed. If there is more than one
value to be returned, you need to
* define a structure containing all the returned values
* define QDataStream << and >> operators for that structure.
$Id$
Coding Style
============
See http://korganizer.kde.org/develop/hacking.html for an HTML version.
Formatting
----------
- No Tabs.
- Indent with 2 spaces.
- A line must not have more than 80 chars.
- Put Spaces between brackets and arguments of functions.
- For if, else, while and similar statements put the brackets on the same line
as the statement.
- Function and class definitions have their brackets on separate lines.
Example:
void MyClass::myFunction()
{
if ( blah == fasel ) {
blubbVariable = arglValue;
} else {
blubbVariable = oerxValue;
}
}
Header Formatting
-----------------
- General formatting rules apply.
- Access modifiers are indented.
- Put curly brackets of class definition on its own line.
- Double inclusion protection defines are all upper case letters and are
composed of the namespace (if available), the classname and a H suffix
separated by underscores.
- Inside a namespace there is no indentation.
Example:
#ifndef XKJ_MYCLASS_H
#define XKJ_MYCLASS_H
namespace XKJ {
class MyClass
{
public:
MyClass();
private:
int mMyInt;
};
}
#endif
API docs
--------
- Each public function must have a Doxygen compatible comment in the header
- Use C-style comments without additional asterisks
- Indent correctly.
- Comments should be grammatically correct, e.g. sentences start with uppercase
letters and end with a full stop.
- Be concise.
Example:
/**
This function makes tea.
@param cups number of cups.
@result tea
*/
Tea makeTea( int cups );
Class and File Names
--------------------
- Put classes in files, which have the same name as the class, but only
lower-case letters.
- Designer-generated files should have a name classname_base.ui and shoul
contain a class called ClassnameBase.
- Classes inheriting from designer-generated classes have the same name as the
generated class, but without the Base suffix.
Class and Variable Names
------------------------
- For class, variable, function names seperate multiple words by upper-casing
the words precedeed by other words.
- Class names start with an upper-case letter.
- Function names start with a lower-case letter.
- Variable names start with a lower-case letter.
- Member variables of a class start with "m" followed by an upper-case letter.
SUBDIRS = interfaces plugins src pics
include ../admin/Doxyfile.am
messages: rc.cpp
$(EXTRACTRC) src/*.kcfg >> rc.cpp
$(XGETTEXT) src/*.cpp interfaces/*.cpp plugins/*/*.cpp plugins/*/*.h -o $(podir)/kontact.pot
UNTIL KDE 3.2
==============
- merge config of parts into a unified config dialog
* Unified Identity handling (Name, Mail address, SMTP, use KMIdentity KDEPIM wide?)
Currently this is dublicated in at least KMail, KNode and KOrganizer
* Molularize KOrganizer and KMail Settings and turn them into kcm's
* Think about extending the kcm idea and add a framework to locate kcm's for apps via KTrader
- same for unified credits
- find a solution for a setup wizard
- replace Splash class with QSplashScreen (done)
- make the "new" action a bit smarter (done)
- make korganizers part offer the normal dcop interface
- move plugins to respective apps for code sharing(?)
- Summary (what's next) view (slueppken) (done)
- Basic groupware functionality (Exchange 2k and Kolab)
- make the headerWidget look nicer (we might use KIconLoader
for larger icons) (slueppken) (done)
- make all parts use the InfoExtension (done)
- make KCMultiDialog not crash when non-existent desktop-file
is given to addModule() (done)
- support icon and buttons sidebar (done)
- enable/disable single plugins (done)
LATER
======
- Support other groupware solutions
- your stuff here...
* Note: Lines starting with a d are my comments - Daniel
* Note: Lines starting with a # are my comments - Cornelius
* Note: Lines starting with a "z" are my comments - Zack :)
* Note: Lines starting with a "s" are my comments - Simon
* Note: Lines starting with a "Don:" are my comments - Don
* Note: Lines starting with a "g" are my comments - Guenter
* Note: Lines starting with a "m" are my comments - Matthias Kretz
* Note: Lines starting with a "MiB:" are my comments - Michael
* Note: Lines starting with a "h" are my comments - Holger
Misc:
=====
Configuration Merge
-------------------
d Idea: The KOffice way of life: Offer a method that adds a given wiget of a
d predefined type as page in a KDialogBase or offer a pointer to a KDialogBase
d -> requires a Kontact part or an external lib per part
m I believe this is a more general problem. Please take a look at
m kdegraphics/kview/kpreferences{dialog,module}.{h,cpp}. I'd like to generalize
m these classes and include them into kdelibs (the same configuration merge is
m being done in Kate, Noatun, Kopete, KView and probably more).
# The problem is even more generic. We also have to merge about boxes, tips of
# the day and maybe more.
Merged Foldertree View
----------------------
d Idea: Let the part send a description of their folders and reaction to calls
d as XML, similar to XMLGUI
# Is a folder tree really the right tool to represent events, todos or
# contacts?
MiB: On the one hand, Notes can be hierarchic, so a folder tree would be the
MiB: nearest solution...
z I think so. Applications could send the root of their tree to
z Kontact so that the interface looks like
- Mail
| \
| - Local Folders
| \
| Inbox
| |
| Thrash
| |
| Sent
- Notes
| \
| Notes 1
| |
| Notes 2
|
- Events
\
Event 1
|
Event 2
z which is not that bad. The question would be how to render the tree
z on the Kontact side while keeping the items on the parts side ( because
z e.g. KMails hold custom pixmaps for the folders which had to be
z displayed in the Kontact tree).
g I'm currently having 248 events. A tree is a very bad solution to visualize
g them. selecting "Events" in the tree should just only start the korganizer
g part.
MiB: ...OTOH... yes, /me agrees with g, a folder tree becomes complex quite fast.
Don: The folder tree makes sense for advanced users, but I think
Don: the simplicity of the current navigator widget has advantages for
Don: non power users.
Don:
Don: Actually instead of the navigator widget I think it makes sense
Don: to consider reusing the widget choosing widget in the latest
Don: version of the Qt designer, which in a sense can be
Don: considered a generalization of the navigator widget. And could
Don: make the folder tree in kmail unnecessary.
Don:
Don: I might investigate the Qt designer widget further but if someone
Don: else wants to look at a folder tree widget that's cool with me.
# I had a look at the Qt designer widget choosing widget. I think it has a
# severe usability problem, because the buttons (or kind of tabs) which are used
# to access the widget subgroups are not always at the same place but move
# around when you click on them. Dependening on which group is shown, the button
# is at the top or at the bottom of the widget. In my opinion this solution is
# unacceptable.
# But Daniel had a good idea how to improve that. It looks similar to the Qt
# designer widget, but it opens the current group always at the top of the
# widget and only highlights the current group in the list at the bottom, but
# doesn't move it. This seems to also be the way Outlook does it.
Don: Guenter, agree.
Don: Wouldn't the idea to be to show calendars in the tree or
Don: navigator widget, rather than individual events?
# Yes, that makes sense. Calendars are much more similar to mail folders than
# single events. You wouldn't integrate individual mails in the folder tree,
# would you?
d That raises an interesting point: The KNotes plugin would not need an own
d canvas in the WidgetStack then. It's sufficient to have the notes in the
d folder view, an RMB menu on them and a "New Note" action.
d So the new design must be able to catch that case (the current one does not).
# I think notes are on the same level as mails or events. They should be listed
# in the view. KNotes would probably just create a single entry in the folder
# tree.
KNotes integration
------------------
MiB: Which reminds me of my own concern about the 'how' of integrating KNotes:
MiB: * the current solution is to start KNotes extern, it is not embedded in Kontact
MiB: at all. Thus opening a note that is on another desktop either leaves the Kontact
MiB: window or moves the note. Either not perfect. Also, Kontact is likely to cover
MiB: notes that reside on the desktop, easy working is impossible. Which is the reason
MiB: I don't like the current approach too much.
MiB: * but there's always hope---my idea would be to show the notes in Kontact itself.
MiB: Now I tend to say it's a bit intrusive to not allow starting KNotes and
MiB: Kontact/KNotes at the same time which raises the following issues:
MiB: - if KNotes and Kontact are running at the same time, changes to the notes have
MiB: to be synchronized (not much of a problem). Changes to be synced are the
MiB: text/contents itself, the text color/style..., the note color. Not sure about
MiB: the note size. Not to be synced is the position.
MiB: - so the position in Kontact has to be saved individually and independently
MiB: of the real desktop position (realized by attaching two display config
MiB: files, works in make_it_cool branch mostly). Kontact's size is generally
MiB: smaller than the desktop.
MiB: - normally notes are on a specific desktop, now they have to be displayed on one
MiB: area---how to do this best?
MiB: what does M$ do? How do they manage the notes in their PIM app? (I don't know
MiB: it, never seen that thing)
Toolbar Items
-------------
d The KParts Technology only provides actions for the current part. It might be
d desireable to have common actions that are always available.
Don: I agree that it is desireable to have common actions always
Don: available (and parts too like the todo list)
Don:
Don: But are you sure Kparts is limited in this way? KOrganizer can load
Don: multiple plugins simultaneously. And all of these plugins are kparts
Don: (eg. birthday import), and kactions for all loaded plugins are
Don: created and made available simultaneously.
Don:
Don: Yeah, I'm quite positive you can load multiple parts simultaneously.
# Certainly. Actions like "New Mail", "New Contact", "New Event" should be
# available independently of a selected part.
Don: This is a very important issue, I think we need a library with three
Don: methods:
Don: KAddressBookIface loadKAddressBook()
Don: KMailIface loadKMail()
Don: KOrganizerIface loadKOrganizer()
MiB: And don't forget KNotesIface loadKNotes() :-)
h: That doesn't sound extendable ;)
h: So if I would like to add a 'New ShortMessage' part we would have to extend
h: that library... better use KTrader and some sort of a common framework
h: and Mib's comments shows that problem!
d: That's what KDCOPServiceStarter is for :)
Don: Now if kontact is running then loadX will load the X part in kontact
Don: (if it is not already loaded) and return a dcop iface for that
Don: part.
Don:
Don: If kontact is not running but is the users preferred application
Don: then loadX will start kontact and then do the above.
Don:
Don: If kontact is not running and is not the users preferred application
Don: then a standalone version of X should be started, and an iface for
Don: that standalone app returned.
Don:
Don: I think this library should be in libkdepim ad all the kdepim apps
Don: should be moved into kdepim, so their iface files all be in one
Don: package. Or alternatively a new kdeinterfaces package be created
Don: and used as a general repository for interface files.
Don:
Don: Another important issue is invokeMailer and the fact that currently
Don: KDE just runs kmail with command line arguments by default. That has
Don: to be made smarter.
Don:
Don: I guess when kmail is run with command line arguments it could
Don: actually use loadKMail() and then use the resulting iface.
Don:
Don: And the same for all other loadX apps.
Status Bar
----------
d We need a more sophisticated handling (progressbar, etc)
Don: Definitely.
# We now have kdelibs/kparts/statusbarextension. This is intended to solve these
# problems, right?
d: Right. Simply add it as childobject in your part and use it's API. Works even
d: for other KPart hosts than Kontact
Kontact plugin unification
-------------------------
# Currently all Kontact plugins look quite similar. It would be nice, if we
# could provide infratructure to reduce duplicated code as far as possible.
d I thouht of a KontactPart, similar to a KOPart, if that makes sense. I don't think
d a normal KPart is sufficient for us.
Don: I've spent quite a bit of time in all pim *_part files and IIRC
Don: the amount of duplicated code, is pretty much negligible.
Don:
Don: But a KontactPart could make sense for when the parts want to communicate with
Don: the container. Eg. if the parts want to add folders to the container
Don: apps folder tree (or navigator)
Don:
Don: And maybe for communicating with the status bar.
Communication/Interaction:
==========================
d Invoking parts when they are needed for the first time takes too long,
d starting all takes too long on startup
d Idea: Mark complex parts as basic parts that get loaded anyway
# parts could be loaded in the background based on usage patterns. Kontact could
# remember which parts were used at the last session and load them in the
# background after loading the initial part to be shown at startup.
z This idea seems to be similar to Microsoft's
z hide-unused-item-in-the-menu strategy. But it probably mess up
z kaddressbook integration. Although not used during every session
z this part is needed and should be always loaded. This strategy
z would be great for could-to-come parts, like a summary part.
z Background loading of parts is OK. The idea is simple : load the
z last used part on startup. Make sure its loading finishes and then
z load the rest once the user can already interact with the last used
z loaded part.
g why do we always need the addressbook? Is libkabc not sufficient?
Don: I guess my machine is too fast, starting parts is pretty quick here :-)
d DCOP is too slow, internal communication should be handled via a dedicated
d interface, communication with external applications (i.e. knotes) should be
d done via wrapper parts that communicate with their respective IPC method to
d their application using the native protocol (DCOP, Corba, etc).
# Are you sure that DCOP is too slow for in-process communications? I thought it
# would handle this special case efficiently.
s It is only efficient in the sense that it won't do a roundtrip to the server but
s dispatch locally. What remains is the datastream marshalling. Not necessarily
s ueberfast. But I think the point is a different one: It is simply not as intuitive
s to use as C++. Yes, DCOPRef already helps a lot for simple calls, but talking to
s remote components still requires one to do error checking after each method call.
s in addition the stub objects one deals with (AddressBookIface_stub for example)
s are no real references. To the programmer they look like a reference to a
s remote addressbook component, but it really isn't. there is no state involved.
s like if between two method calls on the stub the addressbook process gets restarted,
s the state is lost and the programmer on the client side has no way to find out
s about that. you'll end up with really complex code on the caller side to handle things
s like that.
d Yes, but of course one should always prefer in-process IPC if possible. DCOP
d currently _works_ for Kontact, but that's all about it. It isn't exactly elegant.
d The only advantange of the current approach is that we can allow the user to
d run one of the parts standalone. I am not really sure we want that. I used to find
d it desireable, but I am not sure anymore.
MiB: But that's the whole idea behind Kontact---to be able to integrate apps
MiB: _and_ to have standalone versions. Just think about KNotes... impossible
MiB: to have it limited to only Kontact!
Don: I love being able to run the apps inside or outside of the
Don: container, it's just really cool being able to choose I think it's a
Don: great feature and users will really love having the
Don: choice. Especially when they are migrating.
MiB: Definitely.
Don: I think if we use the loadX methods defined above then we can still
Don: support this. I'm PRO DCOP. And this way we don't have to special
Don: case of the code depending on whether the application is running in
Don: a container app or not.
Don:
Don: I find difficult to imagine a function that DCOP is not fast enough
Don: to support. It supports all our current PIM IPC needs fine.
MiB: yes, not too much against DCOP. But for KNotes I thought about turning
MiB: a note into a plugin that can be loaded by Kontact and KNotes independently.
MiB: like this, there's no DCOP necessary anymore and makes it much more flexible.
MiB: e.g. usage of different display configs, a note embedded somewhere and having
MiB: a parent or standalone on the desktop.
# Communication with external applications is something which doesn't fit too
# well with the 'integrated' approach of Kontact. Is this really necessary?
d We won't get around it, think knotes, maybe sync tools, think abstact 3rd party
d projects (not sure the latter is really that important, but we should consider it.
d it barely plays a role anyway).
MiB: hm. true. But not too important, IMHO. Just add a Kontact-DCOP interface :-)
h: Pretty much to talk about...
h: 1. the speed of DCOP is not that important. I worry more about the integration
h: of all parts. So how would I cross reference an 'Event' with a 3rd party
h: Kaplan Part? A common base class for all PIM records comes into my mind - again -
h: Now with normal C++ you can pass a pointer through the framework
h: Doing it with DCOP we need to marshall and demarshall it. This part can get really
h: ugly if we want more tight integration of all KaplanParts. We could add
h: a pure virtual method to marshall to a QDataStream. So now marshalling is done.
h: For demarshalling we need to get the type of the QDataStream content and then we need
h: to ask someone - a factory - to get a object for the type and then call another pure
h: virtual.....
h: The question is if this is really necessary
h: 2. stand a lone apps
h: The 'stand a lone' app can always run in the same address space but be a top level widget
h: itself. WIth some DCOP magic clicking on the KMAIL icon code make Kaplan detach the part...
h: 3. Integration!
h: The goal of Kaplan should not be to merge some XML files an give a common Toolbar for
h: X applications in one shell. I want true integration. Yes KMAIL can use KABC to show
h: all emails for one contact but a generic way to do such things would be more than nice.
h: It would be nice if I could relate the PIM objects in a common way. So I create an Event and
h: relate some todos to it. So for KDE4 I want a common base class for all PIM classes including mail
h: see Opies OPimRecord for a bit too huge base class
Security
--------
d If we use the kparts (ktrader) approach to find a parts by looking
d for an application with the correct mime type this might raise security
d problems. (Martin's concern)
# Looking up Kontact parts isn't based on mime types but on services of type
# "Kontact/Plugin". This is just as save as starting a program statically linking
# its parts. I really don't see any security concerns here.
d Ok, if we limit stuff to Kontact/Plugin and Kontact/Part that might be safe enough
d indeed. I (and Martin, who raise this concern initially) was just afraid of
d allowing "any" part.
h: hmm If somebody can install a Service into the global kde dir or the user kde home
h: there is something else broken IMHO
Summary View
------------
h: How would one best integrate a summary view into kontact?
h: a) add a virtual QWidget *summary(const QDateTime&, QWidget* parent );
h: to get a summary widget for a day?
h: b) use some sort of XML to UI to represent the summary informations
h: c) have a stand a lone part which opens the PIM data seperately? ( How
h: to synchronize access? )
\ No newline at end of file
INCLUDES = -I$(top_srcdir) $(all_includes)
lib_LTLIBRARIES = libkpinterfaces.la
libkpinterfaces_la_SOURCES = core.cpp plugin.cpp summary.cpp uniqueapphandler.cpp
libkpinterfaces_la_LDFLAGS = $(all_libraries) -no-undefined -version-info 1:0:0
libkpinterfaces_la_LIBADD = $(LIB_KPARTS) ../../libkdepim/libkdepim.la
kpincludedir = $(includedir)/kontact
kpinclude_HEADERS = core.h plugin.h summary.h
METASOURCES = AUTO
servicetypedir = $(kde_servicetypesdir)
servicetype_DATA = kontactplugin.desktop
/*
This file is part of KDE Kontact.
Copyright (c) 2001 Matthias Hoelzer-Kluepfel <mhk@kde.org>
Copyright (c) 2002-2003 Daniel Molkentin <molkentin@kde.org>
Copyright (c) 2003 Cornelius Schumacher <schumacher@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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "core.h"
#include <kparts/part.h>
#include <kparts/componentfactory.h>
#include <kdebug.h>
#include <qtimer.h>
using namespace Kontact;
Core::Core( QWidget *parent, const char *name )
: KParts::MainWindow( parent, name )
{
QTimer* timer = new QTimer( this );
mLastDate = QDate::currentDate();
connect(timer, SIGNAL( timeout() ), SLOT( checkNewDay() ) );
timer->start( 1000*60 );