[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-panel-devel
Subject:    Extender api review.
From:       Rob Scheepmaker <r.scheepmaker () student ! utwente ! nl>
Date:       2008-07-23 21:02:32
Message-ID: 200807232302.32323.r.scheepmaker () student ! utwente ! nl
[Download RAW message or body]

Hello all,

As you'll probably know, I've been working on extenders as part of GSoC. They're shaping up quite 
nicely, so now is a good time to review the api I've made so far. What I have done is go trough the 
headers in my branch and put all functions and apidox that I've added in one file. I've added comments 
where I think things should change (a lot of pimpl'ing to be done). I'm very interested in hearing your 
opinion about it. 

Regards,
Rob Scheepmaker (pinda)

["extenderapi.h" (text/x-chdr)]

class PLASMA_EXPORT Applet : public QGraphicsWidget
{
    public:
        /**
         * FIXME: Hmm, I guess this should be protected...
         * This will wrap the qgw in a DetachableWidget, and add it to the applet. \
                This is the way
         * to add detachables to your applet. This function requires \
                setSupportDetachables to be
         * true.
         * @param widget The widget to be added.
         * @param title The title that should appear in the detachables draghandle.
         * @param name The name of the widget. You can give unique names to your \
                detachables in
         * order to be able to find them back with the detachableWidgetForName() \
                function.
         * FIXME: Maybe I should use a qvariant instead of name? that way, all data \
                relevant to the
         * detachable can be passed around, which is probably a lot easier to use \
                then the current
         * approach, where you have a string as name, and can store extra information \
                directly in
         * the kconfiggroup.
         * @param detachableId The id to give this widget. Actually, to only case in \
                which this is
         * passed manually is in loadDetachables() so maybe just remove the parameter \
                here, and set
         * it manually through the pointer to the detachable in loadDetachables()?
         */
        virtual DetachableWidget *addDetachableWidget(QGraphicsWidget *widget, const \
                QString &title = QString(),
                                                      const QString &name = \
                QString(),
                                                      uint detachableId = 0);

        /**
         * @return whether or not this applet supports detachables
         * FIXME: only detachablewidget and applet uses this, maybe I should just use \
                this to
         * pimpl... detachable is allready friend. Or at least make it protected.
         */
        bool supportDetachables() const;

    protected:
        /**
         * factory method. any applet which is able to create detachables that can \
                remain between
         * sessions, will have to implement this function to create the detachable \
                widgets.
         *
         * Little example:
         * An clock applet that shows different timezones using extenders, might \
                implement the
         * function like this:
         *
         * QGraphicsWidget *widget = new SuperAwesomeClockWidget(this);
         * hostApplet->dataEngine("time")->connectSource(config.readEntry("timezone"), \
                widget,
         *                                               1000);
         * return widget;
         *
         * FIXME: As mentioned in the apidox of createCollapsedExtenderWidget: \
                consider not returning a qgw
         * here but require the developer to call addDetachableWidget in this \
                function to allow devs
         * to connect dataengines to the detachable widget itself, and register \
                qactions in a bit
         * clearer way. I think that could lead to a bit cleaner and easier to \
                understand code in
         * most cases.
         *
         * FIXME: as mentioned in the apidox of addDetachableWidget: consider passing \
                a QVariant
         * instead of QString as name. Of course it wouldn't be called name, but data \
                or something
         * like that in that case. Or maybe pass a name and data. But at least get \
                rid of the
         * kconfiggroup. I think they're overly complicated for most cases.
         *
         * @param name The name of the detachable that can be used to quickly \
                identify what to do.
         * @param hostApplet The applet that will 'host' the applet. Use this to \
                access applet
         * api like hostApplet->dataEngine(). Avoid using the source applet \
                dataEngine function,
         * since the source applet might only exist temporary, just to create \
                detachables.
         * @param config The configuration data associated with the to be \
                instantiated widget.
         * Through this you can connect the correct dataengines, set properties, or \
                even create
         * completely different widgets, depending on configuration data.
         * @return The instantiated widget, or 0 if the widget shouldn't be \
                instantiated
         * (because the source has disappeared for example, think of a deleted email \
                or
         * something like that)
         */
        virtual QGraphicsWidget *createDetachableWidget(const QString &name, \
KConfigGroup config, Applet *hostApplet);

        /**
         * this function is called when detachables are automagically moved to it's \
                extender, for
         * example, because there are more detachables then fit in a vertically \
                constrained space.
         * It's default implementation creates a Plasma::Icon with the icon of the \
                applet, and maps
         * it's clicked signal to toggle the extender's visibility. Implement this \
                function if you
         * want to display something more advanced when detachables have been moved \
                off to an
         * extender.
         * FIXME: maybe we should make the default implementation a little bit more \
                advanced: a lot
         * of times, an applet will probably like to show an icons together with a \
                little text
         * (number of emails, stuff like that), and change the icon depending on the \
                applets status
         * (there are new emails). Think about a way to simplify these common cases.
         * @return The widget that should be displayed when the applet is in a \
                collapsed state.
         */
        virtual QGraphicsWidget *createCollapsedExtenderWidget();

        /**
         * this function is called after a detachable is added, thus allowing the \
                applet to add it's
         * own qactions to the detachables dragger. 
         * FIXME: I'm thinking that I should maybe remove this
         * function, let createCollapsedExtenderWidget() not return a QGW but require \
                that function
         * to add the QGW using addDetachableWidget() so that function obtains a \
                pointer to the
         * detachable and can then register qactions using addAction. I think that \
                might be a bit
         * cleaner, and add's the possibility to hook the action detachableWidget \
                (and not only the
         * qgw) to a dataengine to for example show progress in the dragger, which \
                might be nice for
         * the kuiserver applet. Or maybe even for the notify applet to show the \
                expiration time.
         */
        virtual QList<QAction*> detachableActions(DetachableWidget *detachable);

        /**
         * @returns a list of detachable widgets where the source applet is this \
                applet.
         */
        QList<DetachableWidget*> detachableWidgets() const;

        /**
         * This function can be used for easily determining if a certain item is \
                allready displayed
         * in a detachable somewhere, so your applet doesn't duplicate this item. Say \
                the applet
         * displays 'jobs', from an engine which add's a source for every job. In \
                sourceAdded you
         * could do something like:
         * if (!detchableWidgetForName(source)) {
         *     //add a detachable widget monitoring this source.
         * }
         * FIXME: see earlier comments on maybe changing name to a qvariant.
         */
        DetachableWidget *detachableWidgetForName(const QString &name) const;

        /**
         * When an applet contains detachable widgets, the applet collapses into an \
                icon by default
         * when put into a panel. By setting forcePanelCollapse to false, the applet \
                only collapses
         * into an icon when the sum of the preferred heights of the detachables is \
                smaller then the
         * available space.
         * @param collapse Whether or not an applet always collapses when put in a \
                vertically 
         * constrained space.
         * TODO: maybe we'll need a more flexible approach featuring a couple of \
                different
         * 'collapsing stratagies'?
         */
        void setForcePanelCollapse(bool collapse);

        /**
         * @return whether or not an applet always collapses when put in a vertically \
                constrained
         * space.
         */
        bool forcePanelCollapse() const;

        /**
         * When supportDetachables is true, a label will automagically be put in the \
                layout whenever
         * the layout is empty.
         * @param noDetachablesLabel The text to be shown whenever the applet's \
                layout is empty.
         */
        void setNoDetachablesLabel(const QString &noDetachablesLabel);

        /**
         * @return The text to be shown whenever the applet's layout is empty.
         */
        QString noDetachablesLabel() const;

        /**
         * @param supportDetachables set to true if your applet whishes to use
         * detachables/extenders. This will add a layout to your applet, makes \
                detachables consider
         * this applet a valid drop target, and automagically add/remove a text label \
                when this
         * layout is empty.
         * By default this behavior is disabled, to ensure there's no breakage all \
                around plasma. If
         * you wish to support detachables, call this function in your applets \
                constructor, and not
         * in init, since reinstantiating detachables after a plasma restart happens \
                before the call
         * to init.
         * FIXME: since this function does a certain amount of initialization, maybe \
                we should call
         * it something like initDetachablesSupport(). I mean: it doesn't really make \
                sence to
         * actually turn this of again right, so the bool is actually quite obsolete.
         */
        void setSupportDetachables(bool supportDetachables);

    private:
        Q_PRIVATE_SLOT(d, void extenderSizeChanged())
        Q_PRIVATE_SLOT(d, void hideExtender())

        friend class DetachableWidget;


    //TODO: with the kuiserver applet, I didn't need it yet, but for for example \
notify applet, we  //might want to have protected attachedDetachableEvent() and \
detachedDetachableEvent()  //functions. Notify has detachables that 'expire' after a \
certain amount of time, but we don't  //want them to expire when detached, since the \
user detached the thingy to keep it around. This  //way we can accomplish that. So \
something like:

    protected:
        virtual void attachedEvent(DetachableWidget *detachable);
        virtual void detachedEvent(DetachableWidget *detachable);

    //Actually, also kuiserver might benefit from expiring jobs (finished, non \
detached jobs of  //course). Maybe even more applets. Maybe add to detachableWidget \
an  //setExpirationTimeWhenNotDetached(uint seconds) or something like that?

    //TODO: we want to be able to have scrolling extenders. Implementing this won't \
be that  //difficult, but what is a sane policy? To have a maximum size of an \
extender and automatically  //insert scroll arrows when it is smaller? And in that \
case: what would be a sane size? Or do we  //give the applet the option to control \
wherther or not arrows appear? This still needs some  //brainstorming.
};


class PLASMA_EXPORT DetachableWidget : public QGraphicsWidget
    public:
        /**
         * Creating DetachableWidgets is something that an applet itself actually \
                never has to
         * do (it can just use addWidget, which creates a detachable widget)
         * Why not pass a pointer to the applet instead of sourceAppletName and \
                sourceAppletId?
         * Well, maybe we don't have an instance of the source applet (the detachable \
                can live
         * on independently of the sourceApplet). But sourceApplet is still relevant: \
                what if
         * the source applet was removed by the user, but later added again? It makes \
                sense to
         * make this new applet the source applet of the detachable imo, I think \
                that's what
         * users would expect...
         * FIXME: actually, how it works now, there is always a sourceApplet when a \
                detachable is
         * created, though it might only exist temporarily. So we still have to store \
                it's name and
         * id, but we could pass a pointer which cuts down the immense amount of \
                parameters a bit.
         * @param widget The qgw that has to be wrapped in this widget.
         * @param sourceAppletName The name of the source applet.
         * @param sourceAppletId The id of the source applet.
         * @param detachableId the identifier of the widget that is to be created, 0 \
                for
         * automatically assigning a new, unique id.
         * @param name an unique identifier for this detachable so applets can search \
                within
         * it's detachables.
         * FIXME: maybe use a qvariant as explaned in the apidox of \
                addDetachableWidget?
         * @param parent the 'host applet' for this detachable widget. Actually, this \
                should
         * always be set if you want to make sane detachables (config functionality \
                needs a host
         * applet). So maybe I should remove the default =0 value and move this \
                parameter a bit to
         * the front of the list.
         */
        DetachableWidget(QGraphicsWidget *widget, const QString &sourceAppletName,
                         uint sourceAppletId, uint detachableId = 0, const QString \
&name = QString(),  QGraphicsWidget *parent = 0);

        ~DetachableWidget();

        /**
         * fetch the configuration of this widget.
         * @return the configuration of this widget.
         */
        KConfigGroup config();

        /**
         * @return the detachable's name.
         * FIXME: qvariant? 
         */
        QString name();

        /**
         * @return a pointer to the source applet. First this function would want to \
                check if
         * the sourceAppletName with that sourceAppletId still exists, and return a \
                pointer to
         * it. If there exists one applet with sourceAppletName, but it has a \
                different
         * sourceAppletId, it makes sence to return a pointer to that applet. (see \
                explanation
         * of the ctor)
         */
        //FIXME: move to pimpl? only applet uses this and applet could be made \
friend.  Applet *sourceApplet() const;

        //FIXME: are the following two function actually useful and/or used? I guess \
they should  //be removed. At least they aren't used anywhere.
        //On the other hand, if you wish to have for example one fixed item in the \
                layout that is
        //consistent in style with normal detachables, this might be usefull. The \
user must be made  //aware though, that that item can't be detached.
        //yeah, I guess these functions should just go away.
        /**
         * @param whether or not this widget is actually detachable.
         */
        void setDetachable(bool);

        /**
         * @return whether or not this widget is actually detachable.
         */
        bool detachable();

        /**
         * @param title the title that will be shown in the detachable's dragger.
         */
        void setTitle(const QString &title);

        /**
         * @return the title shown in the detachable's dragger.
         */
        QString title() const;

        /**
         * @param icon the icon to dispay in the detachable widget's drag bar.
         */
        void setIcon(const QString &icon);

        //TODO: I guess I should also add a getter for icon.

        /**
         * @return !(sourceApplet == hostApplet)
         */
        bool isDetached() const;

        /**
         * hmm, maybe make a qaction, just like returntosource? That would be a bit \
                more consistend.
         */
        /**
         * @param collapsed whether or not the detachable is collapsed (when \
                collapsed the widget
         * won't get shown, only the draghandle will
         */
        void setCollapsed(bool collapsed);

        /*
         * @param collapsed whether or not the detachable is collapsed (when \
                collapsed the widget
         * won't get shown, only the draghandle will
         */
        bool collapsed() const;

        /**
         * Add an qaction to the detachables dragger. These actions will be shown as \
                icons.
         */
        void addAction(QAction *action);

        //hmm, I don't think applets should ever remove actions: they can just hide \
                or disable
        //existing qactions, which makes more sence imo. Consider removing this \
function.  void removeAction(QAction *action);

        //TODO: maybe make the action stuff more like in applet: add an \
action(QString) function for  //easy lookup of qactions, and add actions with a name.
        //
        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget \
*widget);

    public slots:
        /**
         * Destroys the detachable. The difference between calling this function and \
                calling
         * delete, is that this function also cleans up it's configuration data, \
                which is
         * something we don't want to happen when we quit plasma.
         * FIXME: maybe we should use a qaction for this too for further consistency.
         */
        void destroy();

    //TODO:
    //instead of the detached/attached events in applets, we could instead fire \
signals here.  //This way the applet could be made aware of this fact, but the qgw in \
the detachable can be  //connected too, to for example show more information when \
detached, or do other special  //stuff. Consider this...
    //
    //TODO:
    //maybe add a dataUpdated and setValue function to allow the dragger to show \
progress in the  //kuiserver applet? I think that would be super neat :p

    protected:
        virtual void resizeEvent(QGraphicsSceneResizeEvent *event);
        virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
        virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
        virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

    private:
        Q_PRIVATE_SLOT(d, void moveBackToSourceApplet())
        Q_PRIVATE_SLOT(d, void toggleCollapse())
        Q_PRIVATE_SLOT(d, void updateToolBox())
};

class PLASMA_EXPORT Corona : public QGraphicsScene
{
    //the following two functions are only used in detachablewidget (well, maybe \
applethandle might  //use it too). Let's just move this to pimpl and make \
detachablewidget friend of corona?  /**
     * @param pos a position in screen coordinates.
     * @return a pointer to the containment that is visible under the mouse pointer.
     */
    Containment* containmentFromScreenPos(const QPoint &pos);

    /**
     * @param pos a position in screen coordinates.
     * @return a pointer to the applet that is visible under the mouse pointer.
     */
    Applet *appletFromScreenPos(const QPoint &pos);

    /**
     * FIXME: this function is used in applet and containment. Maybe make both \
                friends and move to
     * pimpl? I don't think this function is usefull for applets.
     * returns a pointer to the requested applet.
     * @arg appletName the pluginName of the wanted applet.
     * @arg appletId the applet id of the wanted applet.
     */
    Applet *appletForName(const QString &appletName, uint appletId = 0) const;

    /**
     * adds an extender to a seperate containment in the topleft quadrant, which is \
                guaranteed to
     * remain hidden from ordinary views. Only used in applet so maybe move to pimpl?
     * OR make a bit more generic so applets can add all kinds of stuff to this \
                containment to hide
     * them from view. But in that case there should be an easy generic way to also \
                obtain a view on
     * it. I'm not entirely sure it would be usefull, think about it.
     * @arg extender the applet to add.
     */
    void addExtender(Applet *extender);

    /**
     * FIXME: only used in applet and containment. make both friends and move to \
                pimpl?
     * @return A pointer to the containment that manages all extenders.
     */
    Containment *extenderContainment();
};



_______________________________________________
Plasma-devel mailing list
Plasma-devel@kde.org
https://mail.kde.org/mailman/listinfo/plasma-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic