[scribus-dev] Some notes/questions about Scribus internals and my project

Andreas Vox avox at arcor.de
Mon May 23 12:29:43 UTC 2011


Hi Elvis!

Good observations for the most part. Some comments inline:

> -----Ursprüngliche Nachricht-----
> Von: Elvis Stansvik [mailto:elvstone at gmail.com]
> Gesendet: Sonntag, 22. Mai 2011 14:30
> An: Scribus Development Mailing List
> Betreff: [scribus-dev] Some notes/questions about Scribus internals and
> my project
> 
> Hi all,
> 
> Today I took some time and did some browsing of the Scribus source to
> try to figure out how it all fits together. Below are some notes I've
> taken on some of the classes, mostly for my own sake.
> 
> Would be nice if someone could read through it and correct me if I got
> something wrong. After that follows a rough plan for the first two
> weeks of my project. Finally, there's a couple of specific questions
> that have popped up. I'll have more questions, but these two are most
> pressing right now as the project start is getting closer.
> 
> Best regards,
> Elvis
> 
> Central Classes
> -----------------------------
> These are notes on (a few of) the central classes of Scribus. I've
> excluded the styles system as it has kind of OK documentation in
> styles/overview.txt.
> 
> ScribusDoc
> ---------------
> Self-explanatory. Represents a document in Scribus. Some
> responsibilities seems to be:
> 
> - get a list of objects in the document.
> - get the current selection.
> - manage styles and colors.
> - manage grid and guides.
> 
> ScribusView
> ----------------
> Central zoomable scrollarea showing a document. Its primary
> responsibility seems to be to provide a UI for scrolling and zooming
> (naturally).
> 
> PageItem and its subclasses
> -------------------------------------
> PageItem is the base class for all items. The base class seems to be a
> bit intertwined with its subclasses, and can be queried for and
> converted to its subclass type using is*() and as*() methods,
> respectively (e.g. isArc(), asArc()). Page items have many
> responsibilities, but most important for me seems to be that they draw
> themselves to the canvas in their DrawObj_Item() method.
> 
> UndoManager
> ------------------
> Central singleton class of the undo/redo system. Manages a map of undo
> stacks, one for each document. I'm not 100% sure how the undo system
> works as it does not seem to use the traditional command pattern for
> undo/redo. But I understand that the undo stacks are stacks of
> UndoState:s, and that multiple UndoStates can be packed into a
> transaction which can be commited or rolled back. I wonder why it was
> made into a singleton with several stacks (one per doc) instead of
> having one undo manager per document? 

There may be different documents, but we only have one UndoAction linked to
the UI.
So at one point we need to decide which document to use anyway.

> Also, even though it is a
> singleton, pointers to the undo manager still seems to be kept in
> classes such as ScribusView and ScribusMainWindow. But I guess this is
> just for convenience?

I guess you are right (for some given value of "convenience"). Feel free to
use the singleton instead.

> 
> General Notes
> -------------------
> Many of the classes such as ScribusDoc, ScribusView and PageItem have
> a huge number of public member variables, many of them undocumented,
> which users (and subclasses) of the classes rely on, and it's a bit
> hard to tell what the responsibilities of each class really is. But I
> think I have a somewhat OK view of it now.

Yes, isn't that ugly? :-) It's on the roadmap for refactoring.

> 
> CanvasMode
> -----------------
> Different modes of operations on the canvas seems to be implemented in
> classes inheriting from CanvasMode. As an example, there is a canvas
> mode for editing a polygon, editing a spiral et.c.
> 
> At a even higher level there seems to be the concept of "application
> modes" (e.g. ScribusMainWindow::setAppMode(int)), which I'm not quite
> sure what they are. Are they the same as canvas modes? In any case,
> setting the "app mode" using ScribusMainWindow::setAppMode(int) seems
> to be what results in a canvas mode change.

In the beginning Scribus just had application modes and some huge switches
and
if-then-else constructs to do the right thing at the right time. I
refactored
all that code into CanvasModes (correspond to application modes) and
CanvasGestures
(correspond to submodes, ie. Scribus returns to the CanvasMode it was in
before the
CanvasGesture was started. Gestures could be stacked).

This structure made it possible to concentrate on a single user interaction
when
implementing mouse event code.

> 
> Notes on Painting of Items
> -----------------------------------
> Painting seems to be done in two places. The on-canvas painting of
> items seems to be done by items themselves in their DrawObj_Item()
> (and DrawObj_Decoration()) method. Painting of items for print output
> seems to be done in the respective drawItem_*() methods in
> ScPageOutput.

IIRC ScPageOutput is only used for printing in Scribus. There's additional
code
in pdflib_core.cpp and pslib.cpp (Yes, 4 versions of the same code. That's
another refactoring on the roadmap!) 

> 
> 
> Now on to more specifics regarding my project. Below is a rough plan
> for the first two weeks.
> 
> Week 1 - Prototype
> ------------------------
> Begin creating a first basic PageItem_Table that has the traditional
> basic table API. Something like (preliminary):
> 
> public:
>   qreal width() const;
>   qreal height() const;
> 
>   int rows () const;
>   int columns () const;
> 
>   void insertRows(int index, int rows);
>   void removeRows(int index, int rows);
>   QList<qreal> &rowHeights() const;
>   void setRowHeights(const QList<qreal> &rowHeights);
> 
>   void insertColumns(int index, int columns);
>   void removeColumns(int index, int columns);
>   QList<qreal> &columnWidths() const;
>   void setColumnWidths(const QList<qreal> &columnWidths);
> 
>   void mergeCells(int row, int column, int numRows, int numCols);
>   void splitCell(int row, int column, int numRows, int numCols);
> 
> private:
>   /// Returns rectangle available for cell content.
>   QRectF cellContentRect(int row, int column) const;
>

I don't see any API to acces the content of a cell?

> Note that the width/height API above refers to the dimensions of the
> table itself, not to the table frame. The dimensions of the table
> frame itself will be taken care of just like for other items.
> 
> The user should be able to insert the table the same way as current
> tables are inserted. The table will not support any content yet, and
> it will not use a style to draw itself but hard code cell/table
> border/background.
> 
> Week 2 - Resizing of rows / columns / table
> -------------------------------------------------------
> Finish off the above, then add support for resizing rows, columns and
> the entire table by implementing a new canvas mode.
> 
> Specific Questions
> ------------------------
> 1) Since painting of items is done in two places, in the
> DrawObj_Item() method of the item itself and in ScPageOutput, does
> this mean I'll have to write the painting code twice?

Or 4 times, see above. We'll have to discuss that (maybe find a way to
reuse existing text code or maybe we can do the refactoring earlier so
that DrawObj_Item(ScPainter) is enough).

> 2) How does the current undo/redo system work? How do I implement
> undoable actions? Will I need to implement one (or several?) new
> UndoState classes?

Yes, that's what I'd recommend. See my other post.

/Andreas




More information about the scribus-dev mailing list