This is an old revision of the document!
Table of Contents
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 will be shown.
Clicking on a thumbnail will show the full-sized picture. This functionality relies on an external JavaScript code, FancyBox, easily incorporated in the rest of the SOLoist code.
Clicking on the disclosure panel will expand 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 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.builtindomains.builtindatatypes.Integer; import rs.sol.soloist.server.builtindomains.builtindatatypes.Text; 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.GUICollectionInput; import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIElementComponent; import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIInputKind; import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUISuggestWidget; 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.name.set(Text.fromString("GallerySample")); SoloistServiceServlet.registerApplication(application); application.context.set(createContextAndStyles()); GUIPanelComponent root = GUIPanelComponent.createFlow(application); GUILabelComponent title = GUILabelComponent.create(root, "Gallery"); title.styleName.set(Text.fromString("titleStyle")); GUIPanelComponent topPanel = GUIPanelComponent.createFlow(root); topPanel.styleName.set(Text.fromString("topPanel")); GUILabelComponent.create(topPanel, "Choose house:").styleName.set(Text.fromString("formLabel")); GUIFindAllInstancesSAPComponent allHouses = GUIFindAllInstancesSAPComponent.create(topPanel, House.FQ_TYPE_NAME); GUIElementComponent suggestBox = GUIElementComponent.createInput(topPanel, new GUISuggestWidget(), new GUICollectionInput()); GUIInputKind.get(suggestBox).lowerBound.set(Integer.valueOf(1)); GUIComponentBinding.create(allHouses.value, GUICollectionInput.get(suggestBox).collection); new GalleryFragment(topPanel); GUIComponentBinding.create(suggestBox.value, topPanel.input); } private GUIContext createContextAndStyles() { GUIContext context = new GUIContext(); context.supercontext.set(DefaultContextInit.getRoot()); 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.builtindomains.builtindatatypes.Integer; import rs.sol.soloist.server.builtindomains.builtindatatypes.Text; 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.construction.GUIFactory; import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIElementComponent; import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUIFieldWidget; import rs.sol.soloist.server.guiconfiguration.elementcomponents.GUISlotEditorKind; import rs.sol.soloist.server.guiconfiguration.layout.CellLayoutData; 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.uml.concepts.runtime.ISlot; public class GalleryFragment { private GUIPanelComponent rootPanel; private ISlot<Text> galleryOwner; private GUIGalleryPanel galleryPanel; public static MoveWithinGallery moveWithinGallery = new MoveWithinGallery(); public static RemoveFromGallery removeFromGallery = new RemoveFromGallery(); public GalleryFragment(GUIPanelComponent rootPanel) { this.rootPanel = rootPanel; this.galleryOwner = rootPanel.input; init(); } private void init() { GUIDisclosurePanel newPictureDisclosure = GUIDisclosurePanel.create(rootPanel, "Add picture to gallery"); GUIPanelComponent subDisclosure = GUIPanelComponent.createFlow(newPictureDisclosure); subDisclosure.styleName.set(Text.fromString("disclosureForm")); GUIPanelComponent table = GUIPanelComponent.createTable(subDisclosure); table.styleName.set(Text.fromString("table")); CmdCreateObjectOfClass cmd = new CmdCreateObjectOfClass(); cmd.className.set(Text.fromString(PictureFromGallery.FQ_TYPE_NAME)); GUICommandComponent cmdNewBlank = GUICommandComponent.create(rootPanel, cmd, PerformImmediately.NOTHING); GUIBooleanFilter gbf = GUIBooleanFilter.create(rootPanel, newPictureDisclosure.open); GUIComponentBinding.create(gbf.yes, cmdNewBlank.click); int row = 0; GUILabelComponent.create(table, "Title", row++, 0).styleName.set(Text.fromString("formLabel")); GUILabelComponent.create(table, "Description", row++, 0).styleName.set(Text.fromString("formLabel")); GUILabelComponent.create(table, "Picture", row++, 0).styleName.set(Text.fromString("formLabel")); row = 0; GUIElementComponent title = GUIElementComponent.createSlotEditor(table, Document.PROPERTIES.title, row++, 1); GUIElementComponent descrip = GUIElementComponent.createSlotEditor(table, Document.PROPERTIES.description, row++, 1); GUIFieldWidget.get(descrip).maxLength.set(Integer.valueOf(2000)); GUIFieldWidget.get(descrip).multiline.set(Boolean.TRUE); CellLayoutData.setSize(descrip, "265px", "192px"); GUIPanelComponent picUpload = GUIFactory.createPictureFileComponent(table, PictureFromGallery.PROPERTIES.picture, true); TableLayoutData.setRowColumn(picUpload, row++, 1); GUIPanelComponent picture = GUIFactory.createPictureFileComponent(table, PictureFromGallery.PROPERTIES.picture, false); TableLayoutData.setRowColumn(picture, 0, 2, 4, 1); TableLayoutData.setAlignment(picture, VerticalAlignment.TOP); GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, GUISlotEditorKind.get(title).element); GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, GUISlotEditorKind.get(descrip).element); GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, picUpload.input); GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, picture.input); GUICommandComponent cmdAdd = GUIButtonComponent.create(table, "Add picture", new AddToGallery(), row++, 0); GUIComponentBinding.create(galleryOwner, cmdAdd, AddToGallery.PROPERTIES.galleryOwner); GUIComponentBinding.create(cmdNewBlank, CmdCreateObjectOfClass.PROPERTIES.output, cmdAdd, AddToGallery.PROPERTIES.picture); galleryPanel = new GUIGalleryPanel(); rootPanel.children.add(galleryPanel); GUIComponentBinding.create(galleryOwner, galleryPanel.element); GUIComponentBinding.create(cmdAdd.commandExecuted, galleryPanel.refreshContents); GUIBufferComponent gbc = GUIBufferComponent.create(rootPanel, Boolean.FALSE); GUIComponentBinding.create(gbc.output, newPictureDisclosure.open); GUIComponentBinding.create(cmdAdd.commandExecuted, gbc.send); } }
- extension.js
function htmlComponentChanged(id) { if (id == "fancyGallery") { setTimeout(function() { $("a.fancy_group").fancybox({ 'titlePosition' : 'over' }); }, timeout); } }