Hi Krzysztof,
hi all,
now I have more time because the first stage of the refactoring is done.
Chris asked me to look at your patch.
> * Added delayed mousewheel scrolling handling (implements smooth scrolling
> using a timer, not a busy loop)
> The ctrl+mousewheel zooming is still a bit "jerky" (where the first
> repaint shows wrong area, which is corrected by second repaint), but
> it's, in my opinion, a reasonable compromise between good-looking and
> uncomplicated. When Dimitry does his refactoring, I may try to improve
> the zooming further (unless the refactoring will already ensure a
> complete elimination of jerkiness).
> * An attempt at keeping map point under cursor intact during
> ctrl+mousewheel zooming (not perfect, but better than a couple of
> simpler changes); it required adding a repaint flag to update and
> updateAll in NodeView)
Look at the current integration branch. I like the way the map reacts to
the ctrl+mousewheel zooming now even better than in your patch, because
I have eliminated some problems with repainting and laying out at the
wrong times. Thank you for you sign making me to look at this problem.
And I am not sure whether we need the additional "smoothness" introduced
by your patch.
> * A tiny amount of source code re-formatting (affecting just a couple of
> functions; it was necessary in order to reduce the possibility of a
> mistake when changing long functions like NodeView.update)
NodeView.update is one of the changed functions: it does not call
"repaint" any more.
Anyway I would like to have a chat with you and all other interested
people in order to talk about the next tasks.
Chris and me have already started to discuss some of them, but we used
German. I post a part of our discussion here, but I do not have time to
translate it in English right now. But even if you do not understand
German, you can see that there is a number of some design problems which
is still to be discussed.
Best regards, Dimitry
------------------------------------------
Vor dem Einchecken wollte ich lediglich prüfen, dass keine Memory Leaks
entstehen. Bei dieser Kontrolle bin ich jetzt schon auf ein Pronlem
gestoßen: viele MindMapController - Actions oder z.B.
LineAdapterListener sind als innere Klassen anderer Klassen definiert
und bleiben auch nach dem das Map geschlossen wird an den Menus hängen
ader als Property-Listeners hängen. Schleppen sie Verweis auf das Map
mit, was dazu führt, dass das Map nicht vom Garbage Collector released
werden kann. Dieses Problem war aber anscheinend schon "immer" da
gewesen. Man wird sich alle solche Klassen anschauen müssen. Manche
Verbindungen werden auch dann nicht gelöscht, wenn das alte Map
geschlossen und ein neues Map geladen oder erzeugt wird. Um das Problem
zu lösen muss LineAdapterListener zu einer statischen Klasse
transformiert werden, und so weiter.
Eigentlich müsste man dieses Thema vor dem Release angehen und
mindestens eine Entscheidung treffen, was überarbeitet werden soll und
was nicht.
> Allerdings ist es nicht so, dass ich nicht das ein oder andere verändern
> würde: wegen der Attribute hatte ich Dir ja
> schon mehrfach geschrieben, dass ich das Interface für den Programmierer
> zu breit und unübersichtlich finde, und habe
> bereits angefangen ,es zu vereinfachen. Ferner hast Du ja gerade für die
> Attribute "leider" die Strukturen verdoppelt, wie Controler,
> Model, etc. ohne darauf zu achten, dass die Funktionalität für den
> Programmierer genauso verwendbar ist, wie für alle anderen Features.
Zu diesem Punkt wollte ich mich mit Dir schon lange austauschen. Aus
meiner Sicht sind Attribute grundsätzlich kein fester Bestandteil eines
Knotens, sondern ein Zusatz, in dem Sinne, dass man auch andere Zusätze
haben könne wie zum Beispiel eben Bilder, Formeln oder was auch immer.
Das jetzige Design ist für mich auch nur ein "Zwischenstand", aber ich
würde die Änderungen in die Richtung machen, dass man an dem Knoten
beliebige Objekte anhängen kann, die auch durch die Plugins eingebracht
werden könnten. Für jede Erweiterung eine zusätzliche Membervariable im
NodeAdapter zu deklarieren ist kein guter Weg.
In diesem Zusammenhang muss man auch diese Frage sehen:
>> * Und die Frage, wie man die Plugins informiert, wenn ein NodeView
>> erzeugt oder vernichtet wird, ist noch nicht gelöst. Es ist eine sehr
>> wichtige Frage, da die NodeViews jetzt schon Kontainer sind, in die neue
>> Inhalte in eigenen Components eingefügt werden können. Ich möchte gerne
>> ein Plugin für Anzeigen von mathematischen Formeln schreiben, wollte
>> aber angesichts der bestehenden Heterogenität der Verbindungen die
>> Schnittstelle vorher mit Dir besprechen.
> Bei Erzeugung von Knoten gibt es "onAddChild", etc. Aber das meinst Du
> wahrscheinlich nicht mit Deiner Frage nach
> der Erzeugung von neuen NodeViews. Wie ist der Anwendungsfall?
Aus meiner Sicht sollen Plugins ihre Erweiterungsobjekte persistieren
und direkt am Knoten anhängen können. An die NodeView können sie dann über
NodeView.getContentPane().addComponent(pluginComponent)
herankommen. Wenn ein NodeView z.B. nach einem "fold" erzeugt wird,
sollen die Plugins informiert werden können, um entsprechend zu reagieren.
Im weiteren schreibst Du:
>> * Dazu werden vom ControllerAdapter (warum nicht vom Model selber?)
>> Hooks aufgerufen(warum keine Listener) rekursiv aufgerufen.
>
> Pattern: Alle Aktionen gehen vom Controller aus.
>
> Das Modell hält nur die Werte. Verändert werden sie vom Controller
> (macht mehr Mühe, ist aber *sehr* sinnvoll).
>
> Dieses Pattern habe ich mühsam nun überall eingebaut (es war u.a. der
> Grundstein für Undo) und ich wäre sehr traurig,
> wenn sich davon Ausnahmen einschlichen.
>
Ich verstehe die Anforderung, dass alle Aktionen sich im Controller-Teil
befinden müssen, damit man das MVC -Pattern umsetzt. Controller is für
mich ein Package und keine einzige Klasse, da sich sonst diese Klasse um
sehr viele Operationen kümmern müsste wie z.B. wieder
Attributeoperationen, Editieren von mathematischen Formeln und so
weiter. Ich möchte deswegen das Design vom Controller am liebsten in
einem Chat besprechen.
> Die Hooks heißen so, weil es "Erweiterungspunkte" sind. Programme können
> diese anbieten, wenn es sinnvoll ist, dort etwas zu tun. Es sind
> keine Listener, da Hooks leere Hülsen darstellen ,die sowieso
> durchlaufen werden, aber überschriben werden können.
Das heißt für mich, dass die Hooks immer aufgerufen werden, egal ob der
Aufruf benutzt wird oder nicht. Was bringen solche Aufrufe? Dieser
Ansatz führt auch zu Notwendigkeit, zwischen verschiedenen Plugin-Typen
zu unterscheiden und sie in der XML-Beschreibung des Plugins zu
deklarieren und somit ein Sonderweg zu bestreiten, in dem Teile der
Typ-Information in XML ausgelagert werden. Ich kann mir aber kaum
vorstellen, dass man einen solchen Typ zur Laufzeit konfigurieren möchte.
Im weiteren bin ich mir unsicher, ob es richtig ist, die Plugins aus dem
Controller zu benachrichtigen: für mich sind alle Views Observers des
Modells. Durch mein Refaktoring ist es möglich, sich als Observer bie
Map oder bei MindMapNode zu registrieren (früher wurden alle diese
Events vom Map selber verarbeitet, jetzt werden sie vom Map an die
Listener von den Nodes weiter geleitet). Im ersten fall wird der
Observer bzw. Listener über alle TreeEvent im Map benachrichtigt, im
zweiten Fall nur über die auf das Node bezogenen Events. Diese
Schnittstelle könnten auch die Plugins nutzen.
Und warum soll diese Benachrichtigung über Controller laufen? Eine
bereits erfolgte Änderung im Modell löst normalerweise keine weiteren
Aktionen aus, aber zum größten Teil Veränderungen in der Anzeige. Die
Änderungen werden doch durch das User Interface initiiert, oder? Und
warum sollen sich die interessierten Objekte nicht als Listener bei
Modell anmelden?
Wie gesagt, teile ich deinen Wunsch uneingeschränkt, ein sauberes Design
zu haben. Dazu wäre meiner Ansicht nach etwas mehr Austausch sehr nützlich.
> Das Wiederherstellen der Selektion hat etwas mit den DestinationNodes zu
> tun.
> Es durfte ja nicht vorkommen, dass nach einem Plugin nichts markiert ist
> (ist dies nun anders??).
> Aber bevor Du riesen Umwege über InvokeLater gehst,
> so ändere doch einfach die Invoke-Methode, dass sie bool zurückgibt, ob
> die selektion wiederhergestellt werden soll, oder nicht.
> Oder besser: im beschreibenden XML gibt es ein Attribut, das man auf
> händische Selektion stellen kann. Das wäre sehr hilfreich.
Wäre es vielleicht noch transparente, wenn die Selektion nur dann
wiederhergestellt wird, wenn nach dem Plugin kein Knoten mehr selektiert
ist? Die meisten Plugins möchten an der Selektion nichts ändern, wozu
braucht man dann diese Wiederherstellung?
|