Last modified 14 years ago Last modified on 04/27/09 14:40:30

Error: Macro BackLinksMenu(None) failed
compressed data is corrupt

Error: Macro TicketQuery(summary=GROUP_BASE_SKINS_R0, format=table, col=summary|owner|status|type|component|priority|effort|importance, rows=description|analysis_owners|analysis_reviewers|analysis_score|design_owners|design_reviewers|design_score|implementation_owners|implementation_reviewers|implementation_score|test_owners|test_reviewers|test_score|) failed
current transaction is aborted, commands ignored until end of transaction block


(Give as much as possible of the needed information for designing and implementing the task in the following sections.)


Skins are used by the application to change the look and feel of the Sophie layout appearance. Skins define the look and interactions of a visual elements. Properties such as size, location, color, keyboard shortcuts and messages to send are all parts of the skins.

Task requirements

The requirements for this group of tasks include:

  • Write a short tutorial on how someone uses skins in their visual elements
  • Document the ENUMs used to define internal skin parts
  • Document skin naming conventions
  • Create two sample skins for the release
  • The user must have the ability to change skins (switch between installed skins, see the implementation idea for more information)
  • Decide where the skins will be kept and in what form (e.g. archive or something else)

Task result

The result of this task is code, and two skins.

Implementation idea

  • All installed skins are kept in skins directory in the installation folder of the user's machine
  • Skins use properties, so changing skin values at runtime should reflect the change in Sophie.
  • Annotations are used to define the internalSkin values, @SkinPartDef
  • See class SampleView in /sophie2/trunk/sophie2-platform/modules/org.sophie2.base.visual/src/test/java/org/sophie2/base/visual/interaction/
  • See /sophie2-platform/modules/org.sophie2.base.bound/src/main/java/org/sophie2/base/bound/ for a @SkinPartDef example


  • Skins need to be able to be written to files for the sake of persistence. Skins with media (images) should be stored in an archive.

Naming Conventions

  • Skins are hierarchical, starting with the InternalSkin, While there is no Sophie restricted naming convention, we should use the following naming convention for our skins:
  • The base skin file is the name of the skin, for example, "CoolBlueSkin"
  • Any child skins that define language specific parts of a skin should be named <base><language>, for example, CoolBlueSkinEN or CoolBlueSkinBG


  • The user must be able to switch between installed skins from the View ->Skins->Skin1 menu for example
  • Watch the discussion 2009-02-17-Design Discussion (Part 1).mpg, 2009-02-17-Design Discussion (Part 2).mpg, 2009-02-17-Design Discussion (Part 3).mpg for more skin details
  • org.sophie2.base.skins (not sure if this is valid after all refactorings) is milo's current implementation
  • SkinPart defines a piece of a skin. ElementID refers to a class. propID refers to the property in the element and value refers to the property value.

How to demo

I think it would be great if you could show how a skin is applied, how a value is created and changed. The video discussions cover the big picture, but never gave a concrete example on how to use the skins.


Currently there is one class that represents a skin in Sophie2. This class is org.sophie2.base.skins.Skin and it represents only one skin. Moreover it is singleton. A new class will be created - org.sophie2.base.skins.SkinManager and it will be responsible for managining skins. This class will have one property - the current skin, and everyone who want to add a new skin will have to change the reference of the current skin - to set the skin he wants.

The org.sophie2.base.skins.Skin will become more general. It will be defined as such depending on its name different skin parts are loaded. It won't be singleton anymore and it will have a name and a fallback skin with a name correspondingly. A skin will be defined by its A fallback skin is a skin from which the values will be retrieved if they are not found the current skin. Every skin definition is added to the default skin, this means that it can be used as a fallback skin whenever you want.

A new module will be added - - that will contain the alternative skin. It will have just one class - AlternativeSkinModule - which will add new values for the record ids (so far) in Sophie2

Also two menu items will be defined. One for the default skin and one for the alternative one. When one of them is clicked the selected skin should be loaded.


  • Create new icon set for the alternative skin:
    • try to use same pattern for all icons
    • the icons must be with size between 15x15 and 20x20 (18x18 is recommended).
    • use for example the sophie2-repo\trunk\sophie2-platform\modules\org.sophie2.base.commons\src\main\resources\distrib\icons directory
    • the new icons must be with the same file names but in the new module
    • all icons must be .png files

In this order to create a new skin, you should do the next steps:

  • to make new skin part with the name of the new skin
  • register this skin part through the extension point mechanism
  • fill the values that you want your new skin to overload/replace/override or whatever it is called
protected void defineExtensions(List<SophieExtension<?>> res) {
  SkinPart part = new BaseSkinPart("my-new-skin");
  //init the values that will be in the new skin


Implementation is done accorind to the design.

In addition a bug fix is made for MyDoggy integration. When a skin is selected all titles and tooltips change, then if the default skin is switched back an exception is thrown - something about "reinitialization". So... tool windows of MyDoggy are kept in a map, and when a tool window that doesn't exist is requested, it gets created. The key for the windows in this map is an id, which is the same as the title. When trying to switch back to the default skin, we try to take the same windows but to change their keys, which throws an exception about "reinitialization". The fix consists of adding a field - oldTitle : String, and when the new titile is different from the old one, all windows are removed from the map and then created again (by requesting them).

Changeset: [2343], [2344].


(Place the testing results here.)


(Write comments for this or later revisions here.)