I dont really understand perfectly how verbs work.
So, I would like my code to be reviewed. Could anybody review these verbs and related code, please?
/* Color management */ SP_VERB_EDIT_LINK_COLOR_PROFILE, SP_VERB_EDIT_REMOVE_COLOR_PROFILE, /*Scripting*/ SP_VERB_EDIT_ADD_EXTERNAL_SCRIPT, SP_VERB_EDIT_REMOVE_EXTERNAL_SCRIPT,
JucaBlues
On Fri, Feb 6, 2009 at 9:59 AM, Felipe Sanches <felipe.sanches@...400...> wrote:
I dont really understand perfectly how verbs work.
So, I would like my code to be reviewed. Could anybody review these verbs and related code, please?
Are they linked to a UI command yet? If it compiles and calls the function when invoked then it is OK as a verb, but whether it does the right thing to the document is another matter :)
I need guidance on verbs coding because I have no idea about how to deal with them. These are there only because I needed to call sp_document_done and needed to get the undo stack working. But it was "guess-coding" so please, somebody review it or, alternatively, explain to me what is the right procedure to handling verbs, what is their meaning, what they are useful for, what is the reason for their existance, etc...
On Fri, Feb 6, 2009 at 9:15 PM, bulia byak <buliabyak@...400...> wrote:
On Fri, Feb 6, 2009 at 9:59 AM, Felipe Sanches <felipe.sanches@...400...> wrote:
I dont really understand perfectly how verbs work.
So, I would like my code to be reviewed. Could anybody review these verbs and related code, please?
Are they linked to a UI command yet? If it compiles and calls the function when invoked then it is OK as a verb, but whether it does the right thing to the document is another matter :)
-- bulia byak Inkscape. Draw Freely. http://www.inkscape.org
On Sat, 2009-02-07 at 06:16 -0200, Felipe Sanches wrote:
I need guidance on verbs coding because I have no idea about how to deal with them. These are there only because I needed to call sp_document_done and needed to get the undo stack working. But it was "guess-coding" so please, somebody review it or, alternatively, explain to me what is the right procedure to handling verbs, what is their meaning, what they are useful for, what is the reason for their existance, etc...
Basically verbs are action factories :)
You can think of a verb as something that you can 'do' in the GUI. The Actions connect documents to verbs. So basically once the verb function is called you know which document it applies do and it allows you to do some action on the document.
When a new window gets created there is a set of actions that are created in order to tie the document to the verbs. The verbs do the work, the actions are document specific.
--Ted
I think we need a wiki page about that with the details... because I am sure that I am not the only person who is confused about these concepts...
On Sat, Feb 7, 2009 at 9:27 AM, Ted Gould <ted@...11...> wrote:
On Sat, 2009-02-07 at 06:16 -0200, Felipe Sanches wrote:
I need guidance on verbs coding because I have no idea about how to deal with them. These are there only because I needed to call sp_document_done and needed to get the undo stack working. But it was "guess-coding" so please, somebody review it or, alternatively, explain to me what is the right procedure to handling verbs, what is their meaning, what they are useful for, what is the reason for their existance, etc...
Basically verbs are action factories :)
You can think of a verb as something that you can 'do' in the GUI. The Actions connect documents to verbs. So basically once the verb function is called you know which document it applies do and it allows you to do some action on the document.
When a new window gets created there is a set of actions that are created in order to tie the document to the verbs. The verbs do the work, the actions are document specific.
--Ted
On Sat, 2009-02-07 at 09:32 -0200, Felipe Sanches wrote:
I think we need a wiki page about that with the details... because I am sure that I am not the only person who is confused about these concepts...
Well, in general I don't think the wiki is a good idea for code documentation. I'd say that adding it here would be best:
http://inkscape.modevia.com/doxygen/html/classInkscape_1_1Verb.php#_details
--Ted
I have some questions too. 1. What are the differences between SPAction and Gtk::Action? I read the code and the only difference seems to be that SPActions derive from NRActiveObject, but this doesn't seem to matter much. 2. Why do we need verbs at all? Why SPActions are bound to a document when we can just perform them on SP_ACTIVE_DESKTOP when they are activated? Those are GUI actions, so I think it's impossible to perform an action on an inactive document. 3. Why do we have one class per several verbs and a switch in perform() instead of one class per verb?
Regards, Krzysztof Kosiński
On Feb 8, 2009, at 7:39 PM, Krzysztof Kosiński wrote:
- What are the differences between SPAction and Gtk::Action? I
read the code and the only difference seems to be that SPActions derive from NRActiveObject, but this doesn't seem to matter much.
Also SPAction predates Gtk::Action by some time, and were legacy C classes.
So the main thing to keep in mind is that they were in our codebase before something similar was released with GTK+ 2.4.
- Why do we need verbs at all? Why SPActions are bound to a
document when we can just perform them on SP_ACTIVE_DESKTOP when they are activated? Those are GUI actions, so I think it's impossible to perform an action on an inactive document.
There are some instances where a generic verb is more appropriate.
Additionally, SP_ACTIVE_DESKTOP is an older C-style approach that we really need to try to purge. Even with C, it's design breaks encapsulation and modularity. We should try to get rid of its use as much as possible.
Also, not all actions are GUI actions. Instead take the view that they are document actions, and some will manifest in the GUI. It's possible to get some that mainly get activated from a script or from the command-line.
- Why do we have one class per several verbs and a switch in
perform() instead of one class per verb?
There are often many reasons to not have a separate class per verb. The switch is just one particular way of implementing internals. Instead of the numeric enumeration we have been looking into switching to string names (and implementing certain things with atoms), but again that is internal.
For the big-picture, the design patterns the Verb class could be viewed as operating with include Facade, Factory, and perhaps Mediator.
There are some instances where a generic verb is more appropriate. I don't understand this bit, can you explain?
Additionally, SP_ACTIVE_DESKTOP is an older C-style approach that we really need to try to purge.
It is a macro so it can be replaced with a call to the application object that will return a refpointer to the currently activated desktop/view/document. I also don't see anything wrong with being able to globally know the active desktop.
Also, not all actions are GUI actions. Instead take the view that they are document actions, and some will manifest in the GUI. It's possible to get some that mainly get activated from a script or from the command-line.
The concept of the active desktop is still valid in command line mode, e.g. an abstraction over the file being open or processed now. Multiple desktops are not present in command line mode either. Also, Gtk::Action is not GUI-specific. You can leave the icon, label, etc. undefined, and you can init and use GTK without a display.
Regards, Krzysztof Kosiński
On Feb 9, 2009, at 12:37 PM, Krzysztof Kosiński wrote:
There are some instances where a generic verb is more appropriate. I don't understand this bit, can you explain?
I'll have to dig through lots of old notes to come up with some precise details. I'd gone over this a while back when someone else had been asking about Verbs, SPActions and GtkActions.
Additionally, SP_ACTIVE_DESKTOP is an older C-style approach that we really need to try to purge.
It is a macro so it can be replaced with a call to the application object that will return a refpointer to the currently activated desktop/view/document. I also don't see anything wrong with being able to globally know the active desktop.
That's the "how" of an implementation. What we need to look at is the "why" at the higher level. That's where the problem is.
Right off hand you have the equivalent of a global variable - the "active desktop". And for many many reasons, including multi- threading, globals are bad.
Additionally encapsulation and modularity are broken, as a tiny subcomponent says "Hey, I know that I belong to some editor window somewhere and that it is an Inkscape object, and should have these other links to other objects"
The proper approach is to have modules that know only what it is they do, with no idea of where the context they operate on came from. This makes them more robust, more thread-friendly, easier to test, and more reusable. They should be small building blocks that can be combined in different ways by things that might need to use them differently.
Now, a more concrete example is one of the problems we face today. Say you have two documents open, with one of them having two views. If you want to have a floating palette window, the "active desktop" tracking only partially works, with different operating systems having different concepts of what "active" means. Now go and add in the ability to dock a dialog, and we get some very ugly problems. For some dialogs if you open an embedded one in each of those windows and then focus different windows, you'll see strange things happening. The fix for this is to have the dialogs be handed a 'context' to operate through. This could be the SPDesktop pointer, or could be something different. The point is, the dialog gets handed an object that implements an interface it needs to use, instead of the dialog grabbing a global pointer that changes from moment to moment. For the case of an embedded panel/dialog that would simply get the context of the desktop of that window. However, for a floating one, an external class could listen for changes in the active desktop and then set the new context in to the floating dialogs as needed. So we just need to flip from polling a global variable to instead push an explicit context in.
Switching to that no-more-globals approach will gain better functionality with less code and fewer bugs.
Also, not all actions are GUI actions. Instead take the view that they are document actions, and some will manifest in the GUI. It's possible to get some that mainly get activated from a script or from the command-line.
The concept of the active desktop is still valid in command line mode, e.g. an abstraction over the file being open or processed now. Multiple desktops are not present in command line mode either. Also, Gtk::Action is not GUI-specific. You can leave the icon, label, etc. undefined, and you can init and use GTK without a display.
No.
The key is a Document. A Document can have many open Desktops. A Desktop is a UI-centric widget keyed to editing a Document.
Also, by it's very nature a GtkAction *is* a gui element. The "Gtk" layer has been split out from GLib, GObject, GdkPixbuf, and GDK. The Gtk grouping is generally for widgets (aka UI elements). Although GtkAction does not directly derive from GtkWidget, it does include such members as "is_visible", "is_sensitive", "set_accel_path" and has several methods that return GtkWidgets.
I would say that GtkAction is very comparable to Swing's Action interface. Action is in the javax.swing package, but is extended from EventListener which lives in the more generic and lower-level java.util package.
True, you *can* use GtkAction without gui specifics if you want, but then you'll be skipping over half of it's API.
Oh, and for more madness on the "active desktop" front, consider multi-threaded scripts and extensions operating within the gui but with a live DOM/tree hooked. eeek!
Jon A. Cruz wrote:
Now, a more concrete example is one of the problems we face today. Say you have two documents open, with one of them having two views.
That's another thing I don't understand, what is the difference between a document and a view? I presume that a document represents an SVG file, while a view represents a window in which that document is open. Why documents originally opened from the same file are treated differently than documents opened from distinct files?
For the case of an embedded panel/dialog that would simply get the context of the desktop of that window. However, for a floating one, an external class could listen for changes in the active desktop and then set the new context in to the floating dialogs as needed. So we just need to flip from polling a global variable to instead push an explicit context in.
Switching to that no-more-globals approach will gain better functionality with less code and fewer bugs.
The key is a Document. A Document can have many open Desktops. A Desktop is a UI-centric widget keyed to editing a Document.
Why do we treat desktops that show different files differently than desktops showing different files? Is this to reduce memory usage in some corner case where the user has the same file open multiple times? If I open icon.svg two times in the same instance of Inkscape, I would expect them to be independent, e.g. when I edit one of the copies the other is not affected in any way. Why do we need to keep track of whether two desktops are editing the same document?
Also, by it's very nature a GtkAction *is* a gui element. No, it is not. Gtk::Action has no GUI elements, but provides methods that generate menu widgets, toolbar widgets, etc. One Gtk::Action can have multiple GUI elements that can be used to activate it, but by default it has none.
Although
GtkAction does not directly derive from GtkWidget, it does include such members as "is_visible", "is_sensitive", "set_accel_path" and has several methods that return GtkWidgets. (...) True, you *can* use GtkAction without gui specifics if you want, but then you'll be skipping over half of it's API.
So does SPAction. It has a function to set whether it is sensitive and "active" (I have no idea what that means). It is still used in console mode. By the way, I also discovered an oddity called InkAction, and it looks like this is a subclass of GtkAction that is generated from SPAction for use in menus, so we have three levels of things, while I think that one (Gtk::Action) could be sufficient.
By the way, Gtk::Actions can also be document-specific. We can have multiple Gtk::ActionGroups, e.g. one for each desktop. That's even the recommended thing to do in GTK documentation. A Gtk::Action also contains a pointer to the ActionGroup it belongs to, so if we subclass ActionGroup to contain a desktop pointer, we can find out the desktop given only the Action.
Regards, Krzysztof Kosiński
Jon A. Cruz wrote:
Sorry, I couldn't follow most of that. The mail got the sections all run together by the time the mailing list was done and sent it out.
That's probably Nabble misbehaving... I also accidentally included a part of your post in my response without quoting it. It looks reasonably readable here: http://www.nabble.com/Verbs-td21872922.html
Regards, Krzysztof Kosiński
Slightly different answers than Jon.
On Sun, 2009-02-08 at 19:39 -0800, Krzysztof Kosiński wrote:
- What are the differences between SPAction and Gtk::Action? I read the
code and the only difference seems to be that SPActions derive from NRActiveObject, but this doesn't seem to matter much.
Historical reasons.
- Why do we need verbs at all? Why SPActions are bound to a document when
we can just perform them on SP_ACTIVE_DESKTOP when they are activated? Those are GUI actions, so I think it's impossible to perform an action on an inactive document.
This kinda ties into your next post, it basically comes down to knowing the active document is in many cases a little unreliable. For instance with sloppy focus, or multiple mouse pointers or with floating toolbars. If we can define this relationship explicitly we can be sure that it is accurate. It's part of making Inkscape rock-solid versus mostly-right.
- Why do we have one class per several verbs and a switch in perform()
instead of one class per verb?
When I converted the Verbs to be C++ I tried to make sure that the diff was small and readable to introduce less bugs in a fairly critical part of Inkscape code. This was the way that it was done before, and it remained. I would say that in general most of them could migrate to be classes themselves, but I personally haven't taken the time to do so. Some might be better as case statements as they have common code, but I don't believe that to be the majority case.
--Ted
participants (5)
-
bulia byak
-
Felipe Sanches
-
Jon A. Cruz
-
Krzysztof Kosiński
-
Ted Gould