Gallery

Gallery is a SOLoist sample application for a classical editable picture gallery. This is a simple, standalone application that demonstrates one way of using a Dynamic Panel.

By choosing an object of House from the suggest box, the gallery of pictures associated with that object is displayed.

A click on a thumbnail shows the full-sized picture. This functionality relies on an external JavaScript code, FancyBox, easily incorporated in the rest of the SOLoist code.

A click on the disclosure panel expands the form for adding new pictures to the gallery.

Pictures in the gallery can be reordered (by entering their order numbers in the boxes) and removed (by clicking on an X sign).

Live example

UML Model

Business Logic Code

AddToGallery.java
    public void execute() 
    // -------------<SOL id="e6326fe7-30c8-4f93-863a-2dc5825ac9aa:___throw__" />
    // -------------<LOS id="e6326fe7-30c8-4f93-863a-2dc5825ac9aa:___throw__" />
    {
        // ---------<SOL id="e6326fe7-30c8-4f93-863a-2dc5825ac9aa:___body___" />
    	ObjectOfClass owner = galleryOwner.val();
    	IAssociationEndInstance<PictureFromGallery> gallery = ((House) owner).gallery;
        picture.val().addToGallery(gallery);
        // ---------<LOS id="e6326fe7-30c8-4f93-863a-2dc5825ac9aa:___body___" />
    }
 
    // -------------<SOL id="519fec42-bffa-423b-997e-d6a6e567943e:___cend___" />
	@Override
	protected void doCheckPreconditions() throws CommandPreconditionsException {
		super.doCheckPreconditions();
		if (galleryOwner.val() == null) {
			throw new CommandPreconditionsException("Please select the house.");
		}
	}
    // -------------<LOS id="519fec42-bffa-423b-997e-d6a6e567943e:___cend___" />
MoveWithinGallery.java
    public void execute() 
    // -------------<SOL id="a7e66c29-b3b6-4471-8e5d-0f411c4c5a97:___throw__" />
    // -------------<LOS id="a7e66c29-b3b6-4471-8e5d-0f411c4c5a97:___throw__" />
    {
        // ---------<SOL id="a7e66c29-b3b6-4471-8e5d-0f411c4c5a97:___body___" />
    	ObjectOfClass owner = galleryOwner.val();
    	IAssociationEndInstance<PictureFromGallery> gallery = ((House) owner).gallery;    	
    	PictureFromGallery pfg = picture.val();
    	pfg.moveWithinGallery(gallery, position.val());
        // ---------<LOS id="a7e66c29-b3b6-4471-8e5d-0f411c4c5a97:___body___" />
    }
RemoveFromGallery.java
    public void execute() 
    // -------------<SOL id="23580b3c-e2c5-4b16-894c-e3f4464f5a98:___throw__" />
    // -------------<LOS id="23580b3c-e2c5-4b16-894c-e3f4464f5a98:___throw__" />
    {
        // ---------<SOL id="23580b3c-e2c5-4b16-894c-e3f4464f5a98:___body___" />
    	ObjectOfClass owner = galleryOwner.val();
    	IAssociationEndInstance<PictureFromGallery> gallery = ((House) owner).gallery;
        picture.val().removeFromGallery(gallery);
        // ---------<LOS id="23580b3c-e2c5-4b16-894c-e3f4464f5a98:___body___" />
    }
PictureFromGallery.java
     /**
     * Makes a thumbnail from the existing picture and sets it to the thumbnail slot.
     * The size of the created thumbnail is 100 x 100px and the aspect ratio is
     * preserved.
     */
    public void makeThumbnail() 
    // -------------<SOL id="d1e4657a-b5a1-4c4c-9f4c-e0446b338e28:___throw__" />
    // -------------<LOS id="d1e4657a-b5a1-4c4c-9f4c-e0446b338e28:___throw__" />
    {
        // ---------<SOL id="d1e4657a-b5a1-4c4c-9f4c-e0446b338e28:___body___" />
    	if (picture.val() != null)
			try {
				thumbnail.set(Picture.fromBufferedImage(Thumbnails.of(picture.val().toBufferedImage()).size(150, 150).outputFormat("jpg").asBufferedImage()));
			} catch (IOException e) {
				e.printStackTrace();
			}
        // ---------<LOS id="d1e4657a-b5a1-4c4c-9f4c-e0446b338e28:___body___" />
    }
 
 
    public void removeFromGallery(IAssociationEndInstance<PictureFromGallery> gallery) 
    // -------------<SOL id="0f0f610a-44b0-48dc-9a5d-2ed0887e62e3:___throw__" />
    // -------------<LOS id="0f0f610a-44b0-48dc-9a5d-2ed0887e62e3:___throw__" />
    {
        // ---------<SOL id="0f0f610a-44b0-48dc-9a5d-2ed0887e62e3:___body___" />
    	gallery.remove(this);
        if (this.house.read().isEmpty())
        	this.destroy();
        // ---------<LOS id="0f0f610a-44b0-48dc-9a5d-2ed0887e62e3:___body___" />
    }
 
 
    public void addToGallery(IAssociationEndInstance<PictureFromGallery> gallery) 
    // -------------<SOL id="8cfd27a3-13bd-44e5-bb1b-b4681d1111e6:___throw__" />
    // -------------<LOS id="8cfd27a3-13bd-44e5-bb1b-b4681d1111e6:___throw__" />
    {
        // ---------<SOL id="8cfd27a3-13bd-44e5-bb1b-b4681d1111e6:___body___" />
    	this.makeThumbnail();
    	this.submitted.set(Boolean.TRUE);
    	gallery.addLast(this);
        // ---------<LOS id="8cfd27a3-13bd-44e5-bb1b-b4681d1111e6:___body___" />
    }
 
 
    public void moveWithinGallery(IAssociationEndInstance<PictureFromGallery> gallery, Integer pos) 
    // -------------<SOL id="f77e5360-24d5-4e7c-ba30-4b91b2622f88:___throw__" />
    // -------------<LOS id="f77e5360-24d5-4e7c-ba30-4b91b2622f88:___throw__" />
    {
        // ---------<SOL id="f77e5360-24d5-4e7c-ba30-4b91b2622f88:___body___" />
    	int i = gallery.read().indexOf(this);
		int position = pos.toInt() - 1;
		if (position != -1) {
			if (position >= gallery.size())
				position = (int) (gallery.size() - 1);
			else if (position < 0)
				position = 0;
			gallery.reorder(i, position);
		}
        // ---------<LOS id="f77e5360-24d5-4e7c-ba30-4b91b2622f88:___body___" />
    }

GUI Code

package rs.sol.sampleapps.gallery;
 
import rs.sol.sampleapps.House;
import rs.sol.soloist.helpers.init.DefaultContextInit;
import rs.sol.soloist.helpers.init.Initializer;
import rs.sol.soloist.helpers.init.InitializerFailedException;
import rs.sol.soloist.server.guiconfiguration.components.GUIApplicationComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUILabelComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUIPanelComponent;
import rs.sol.soloist.server.guiconfiguration.construction.GUIComponentBinding;
import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIInput;
import rs.sol.soloist.server.guiconfiguration.nonvisualcompoments.GUIFindAllInstancesSAPComponent;
import rs.sol.soloist.server.guiconfiguration.style.GUIContext;
import rs.sol.soloist.server.guiconfiguration.style.GUIObjectSetting;
import rs.sol.soloist.server.guiconfiguration.style.GUITextFeature;
import rs.sol.soloist.server.server.SoloistServiceServlet;
 
public enum Gallery implements Initializer {
 
	INSTANCE;
 
	@Override
	public void init() throws InitializerFailedException {
		GUIApplicationComponent application = new GUIApplicationComponent();
		application.setName("GallerySample");
		SoloistServiceServlet.registerApplication(application);
		application.setContext(createContextAndStyles());
 
		GUIPanelComponent root = GUIPanelComponent.createFlow(application);
 
		GUILabelComponent title = GUILabelComponent.create(root, "Gallery");
		title.setStyle("titleStyle");
 
		GUIPanelComponent topPanel = GUIPanelComponent.createFlow(root);
		topPanel.setStyle("topPanel");
 
		GUILabelComponent.create(topPanel, "Choose house:").setStyle("formLabel");
 
		GUIFindAllInstancesSAPComponent allHouses = GUIFindAllInstancesSAPComponent.create(topPanel, House.CLASSIFIER);
		GUIInput suggestBox = GUIInput.createSuggest(topPanel);
		suggestBox.setLowerBound(1);
		GUIComponentBinding.create(allHouses.opValue(), suggestBox.ipCollection());
 
		GalleryFragment gf = new GalleryFragment(topPanel);
		GUIComponentBinding.create(suggestBox.opValue(), gf.ipOwner());
    }
 
	private GUIContext createContextAndStyles() {
		GUIContext context = new GUIContext();
		DefaultContextInit.getRoot().addContext(context);
		GUIObjectSetting person = GUIObjectSetting.create(context, House.CLASSIFIER);
		GUITextFeature.createName(person, House.PROPERTIES.code);
		return context;
	}
 
}
package rs.sol.sampleapps.gallery;
 
import rs.sol.sampleapps.Document;
import rs.sol.sampleapps.PictureFromGallery;
import rs.sol.sampleapps.commands.AddToGallery;
import rs.sol.sampleapps.commands.MoveWithinGallery;
import rs.sol.sampleapps.commands.RemoveFromGallery;
import rs.sol.sampleapps.gui.GUIGalleryPanel;
import rs.sol.soloist.server.builtindomains.builtincommands.CmdCreateObjectOfClass;
import rs.sol.soloist.server.builtindomains.builtindatatypes.Boolean;
import rs.sol.soloist.server.guiconfiguration.components.GUIButtonComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUICommandComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUIDisclosurePanel;
import rs.sol.soloist.server.guiconfiguration.components.GUILabelComponent;
import rs.sol.soloist.server.guiconfiguration.components.GUIPanelComponent;
import rs.sol.soloist.server.guiconfiguration.components.PerformImmediately;
import rs.sol.soloist.server.guiconfiguration.construction.GUIComponentBinding;
import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIEdit;
import rs.sol.soloist.server.guiconfiguration.layout.TableLayoutData;
import rs.sol.soloist.server.guiconfiguration.layout.VerticalAlignment;
import rs.sol.soloist.server.guiconfiguration.nonvisualcompoments.GUIBooleanFilter;
import rs.sol.soloist.server.guiconfiguration.nonvisualcompoments.GUIBufferComponent;
import rs.sol.soloist.server.guiconfiguration.nonvisualcompoments.GUIRelayComponent;
import rs.sol.soloist.server.uml.concepts.runtime.ISlot;
 
public class GalleryFragment {
 
	private ISlot<?> owner;
 
	public ISlot<?> ipOwner(){
		return owner;
	}
 
	public static MoveWithinGallery cmdMoveWithinGallery = new MoveWithinGallery();
	public static RemoveFromGallery cmdRemoveFromGallery = new RemoveFromGallery();
 
	public GalleryFragment(GUIPanelComponent rootPanel) {
		GUIRelayComponent ownerRelay = GUIRelayComponent.create(rootPanel);
		owner = ownerRelay.ipRelay();
 
		GUIDisclosurePanel newPictureDisclosure = GUIDisclosurePanel.create(rootPanel, "Add picture to gallery");
 
		GUIPanelComponent subDisclosure = GUIPanelComponent.createFlow(newPictureDisclosure);
		subDisclosure.setStyle("disclosureForm");
		GUIPanelComponent table = GUIPanelComponent.createTable(subDisclosure);
		table.setStyle("table");
 
		CmdCreateObjectOfClass cmd = new CmdCreateObjectOfClass();
		cmd.setClass(PictureFromGallery.CLASSIFIER);
		GUICommandComponent cmdNewBlank = GUICommandComponent.create(rootPanel, cmd, PerformImmediately.NOTHING);
		GUIBooleanFilter gbf = GUIBooleanFilter.create(rootPanel);
		GUIComponentBinding.create(newPictureDisclosure.opOpen(), gbf.ipInput());
		GUIComponentBinding.create(gbf.opYes(), cmdNewBlank.ipClick());
 
		int row = 0;
		GUILabelComponent.create(table, "Title", row++, 0).setStyle("formLabel");
		GUILabelComponent.create(table, "Description", row++, 0).setStyle("formLabel");
		GUILabelComponent.create(table, "Picture", row++, 0).setStyle("formLabel");
 
		row = 0;
		GUIEdit title = GUIEdit.createField(table, Document.PROPERTIES.title, row++, 1);
		GUIEdit descrip = GUIEdit.createField(table, Document.PROPERTIES.description, row++, 1);
		descrip.setMaxLength(2000);
		descrip.setMultiline(true);
		descrip.setSize("265px", "192px");
		GUIPanelComponent picUpload = GUIEdit.createPicture(table, PictureFromGallery.PROPERTIES.picture, true);
		picUpload.setRowColumn(row++, 1);
 
		GUIPanelComponent picture = GUIEdit.createPicture(table, PictureFromGallery.PROPERTIES.picture, false);
		picture.setRowColumn(0, 2, 4, 1);
		picture.setCellAlignment(null, VerticalAlignment.TOP);
 
		GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, title.ipElement());
		GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, descrip.ipElement());
		GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, picUpload.ipRelay1());
		GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, picture.ipRelay1());
 
		GUIButtonComponent cmdAdd = GUIButtonComponent.create(table, "Add picture", new AddToGallery());
		cmdAdd.setLayoutData(TableLayoutData.create(row++, 0));
		GUIComponentBinding.create(ownerRelay.opRelay(), cmdAdd, AddToGallery.PROPERTIES.galleryOwner);
		GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, cmdAdd, AddToGallery.PROPERTIES.picture);
 
		GUIGalleryPanel galleryPanel = new GUIGalleryPanel();
		rootPanel.add(galleryPanel);
		GUIComponentBinding.create(ownerRelay.opRelay(), galleryPanel.ipElement());
		GUIComponentBinding.create(cmdAdd.opCommandExecuted(), galleryPanel.ipRefreshContents());
		GUIBufferComponent gbc = GUIBufferComponent.create(rootPanel, false, Boolean.FALSE);
		GUIComponentBinding.create(gbc.opOutput(), newPictureDisclosure.ipOpen());
		GUIComponentBinding.create(cmdAdd.opCommandExecuted(), gbc.ipSend());
	}
}
extension.js
    function htmlComponentChanged(id) {
 
	if (id == "fancyGallery") {
		setTimeout(function() {
			$("a.fancy_group").fancybox({
				'titlePosition' : 'over'
			});
		}, timeout);
	}
 
}
Print/export