├── Gallery3WebClient ├── bin-release │ ├── .gitignore │ └── Gallery3WebClient.swf ├── libs │ └── as3corelib.swc ├── .settings │ └── org.eclipse.core.resources.prefs ├── .flexProperties ├── .project ├── src │ └── Gallery3WebClient.mxml ├── .actionScriptProperties └── html-template │ └── index.template.html ├── .gitignore ├── Gallery3Api ├── libs │ └── as3corelib.swc ├── .settings │ └── org.eclipse.core.resources.prefs ├── .project ├── .flexLibProperties ├── .actionScriptProperties └── src │ └── org │ └── gallery3 │ └── api │ ├── GalleryTag.as │ ├── GalleryRestResponder.as │ ├── GalleryRestToken.as │ ├── URLFileVariable.as │ ├── GalleryEntity.as │ ├── GalleryResource.as │ ├── GalleryItem.as │ ├── GalleryRestRequest.as │ └── GalleryAlbum.as └── Gallery3Organize ├── assets ├── Error.png ├── album.png ├── album_add.png ├── image_add.png ├── trashcan.png ├── google_home.png ├── defaultAlbum.png └── defaultImage.png ├── libs └── as3corelib.swc ├── .settings └── org.eclipse.core.resources.prefs ├── .project ├── .flexLibProperties ├── .actionScriptProperties └── src └── org └── gallery3 └── organize ├── components ├── DropIndicator.mxml ├── ProgressDialog.mxml ├── DragProxy.as ├── IconButton.as ├── ErrorDialog.mxml ├── ProcessItemQueue.as ├── ImageRenderer.mxml ├── SelectionLasso.as ├── AlbumTree.as ├── AddAlbumDialog.mxml ├── PaddedTileLayout.as └── ThumbGrid.as ├── OrganizeDataDescriptor.as ├── skins ├── GalleryButtonSkin.mxml ├── IconButtonSkin.mxml ├── GalleryTitleWindowCloseButtonSkin.mxml └── GalleryTitleWindowSkin.mxml ├── OrganizeStyle.as ├── OrganizeText.as ├── OrganizeParameters.as ├── Organize.mxml └── OrganizeDialog.as /Gallery3WebClient/bin-release/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !Gallery3WebClient.swf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gallery3Api/bin/ 2 | Gallery3Organize/bin/ 3 | Gallery3WebClient/bin-debug/ 4 | 5 | -------------------------------------------------------------------------------- /Gallery3Api/libs/as3corelib.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Api/libs/as3corelib.swc -------------------------------------------------------------------------------- /Gallery3Organize/assets/Error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Organize/assets/Error.png -------------------------------------------------------------------------------- /Gallery3Organize/assets/album.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Organize/assets/album.png -------------------------------------------------------------------------------- /Gallery3Organize/assets/album_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Organize/assets/album_add.png -------------------------------------------------------------------------------- /Gallery3Organize/assets/image_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Organize/assets/image_add.png -------------------------------------------------------------------------------- /Gallery3Organize/assets/trashcan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Organize/assets/trashcan.png -------------------------------------------------------------------------------- /Gallery3Organize/libs/as3corelib.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Organize/libs/as3corelib.swc -------------------------------------------------------------------------------- /Gallery3WebClient/libs/as3corelib.swc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3WebClient/libs/as3corelib.swc -------------------------------------------------------------------------------- /Gallery3Organize/assets/google_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Organize/assets/google_home.png -------------------------------------------------------------------------------- /Gallery3Organize/assets/defaultAlbum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Organize/assets/defaultAlbum.png -------------------------------------------------------------------------------- /Gallery3Organize/assets/defaultImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3Organize/assets/defaultImage.png -------------------------------------------------------------------------------- /Gallery3Api/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Sat Apr 10 09:33:19 PDT 2010 2 | eclipse.preferences.version=1 3 | encoding/=utf-8 4 | -------------------------------------------------------------------------------- /Gallery3Organize/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Thu Apr 15 06:38:04 PDT 2010 2 | eclipse.preferences.version=1 3 | encoding/=utf-8 4 | -------------------------------------------------------------------------------- /Gallery3WebClient/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Thu Apr 15 06:36:07 PDT 2010 2 | eclipse.preferences.version=1 3 | encoding/=utf-8 4 | -------------------------------------------------------------------------------- /Gallery3WebClient/bin-release/Gallery3WebClient.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gallery/gallery3-flex/master/Gallery3WebClient/bin-release/Gallery3WebClient.swf -------------------------------------------------------------------------------- /Gallery3WebClient/.flexProperties: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Gallery3Api/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Gallery3Api 4 | 5 | 6 | 7 | 8 | 9 | com.adobe.flexbuilder.project.flexbuilder 10 | 11 | 12 | 13 | 14 | 15 | com.adobe.flexbuilder.project.flexlibnature 16 | com.adobe.flexbuilder.project.actionscriptnature 17 | 18 | 19 | -------------------------------------------------------------------------------- /Gallery3WebClient/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Gallery3WebClient 4 | 5 | 6 | 7 | 8 | 9 | com.adobe.flexbuilder.project.flexbuilder 10 | 11 | 12 | 13 | 14 | 15 | com.adobe.flexbuilder.project.flexnature 16 | com.adobe.flexbuilder.project.actionscriptnature 17 | 18 | 19 | -------------------------------------------------------------------------------- /Gallery3WebClient/src/Gallery3WebClient.mxml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Gallery3Api/.flexLibProperties: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Gallery3Organize/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Gallery3Organize 4 | 5 | 6 | Gallery3Api 7 | 8 | 9 | 10 | com.adobe.flexbuilder.project.flexbuilder 11 | 12 | 13 | 14 | 15 | 16 | com.adobe.flexbuilder.project.flexlibnature 17 | com.adobe.flexbuilder.project.actionscriptnature 18 | 19 | 20 | -------------------------------------------------------------------------------- /Gallery3Organize/.flexLibProperties: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Gallery3Api/.actionScriptProperties: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Gallery3Organize/.actionScriptProperties: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Gallery3Api/src/org/gallery3/api/GalleryTag.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.api { 20 | public dynamic class GalleryTag extends GalleryResource { 21 | public function GalleryTag() {} 22 | 23 | public function get id(): int { 24 | return this.entity.id; 25 | } 26 | 27 | public function get count(): Number { 28 | return Number(this.entity.count); 29 | } 30 | public function set count(value:Number): void { 31 | this.entity.count = value; 32 | } 33 | 34 | public function get name(): String { 35 | return this.entity.name; 36 | } 37 | public function set name(value:String): void { 38 | this.entity.name = value; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Gallery3WebClient/.actionScriptProperties: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/DropIndicator.mxml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 25 | 26 | 27 | 28 | 29 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/ProgressDialog.mxml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/OrganizeDataDescriptor.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize { 20 | import flash.events.Event; 21 | 22 | import mx.collections.ArrayCollection; 23 | import mx.collections.CursorBookmark; 24 | import mx.collections.ICollectionView; 25 | import mx.collections.IViewCursor; 26 | import mx.controls.Tree; 27 | import mx.controls.treeClasses.ITreeDataDescriptor; 28 | import mx.events.CollectionEvent; 29 | import mx.events.CollectionEventKind; 30 | 31 | import org.gallery3.api.GalleryAlbum; 32 | 33 | import spark.components.Application; 34 | 35 | public class OrganizeDataDescriptor implements ITreeDataDescriptor { 36 | public function OrganizeDataDescriptor() {} 37 | 38 | public function getChildren(node:Object, model:Object=null):ICollectionView { 39 | return node.albums; 40 | } 41 | 42 | public function hasChildren(node:Object, model:Object=null):Boolean { 43 | return node.members.length > 0; 44 | } 45 | 46 | public function isBranch(node:Object, model:Object=null):Boolean { 47 | return node.type == "album"; 48 | } 49 | 50 | public function getData(node:Object, model:Object=null):Object { 51 | return node; 52 | } 53 | 54 | public function addChildAt(parent:Object, newChild:Object, index:int, model:Object=null):Boolean { 55 | return false; 56 | } 57 | 58 | public function removeChildAt(parent:Object, child:Object, index:int, model:Object=null):Boolean { 59 | return false; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/DragProxy.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize.components { 20 | import org.gallery3.api.GalleryItem; 21 | import spark.components.BorderContainer; 22 | 23 | import spark.components.BorderContainer; 24 | import spark.layouts.ColumnAlign; 25 | import spark.layouts.RowAlign; 26 | import spark.layouts.VerticalAlign; 27 | import spark.layouts.TileLayout; 28 | import spark.layouts.TileOrientation; 29 | import spark.primitives.BitmapImage; 30 | 31 | public class DragProxy extends BorderContainer { 32 | public function DragProxy(items:Vector.) { 33 | super(); 34 | setStyle("backgroundAlpha", 0.5); 35 | 36 | var proxyLayout: TileLayout = new TileLayout(); 37 | 38 | var dragColumns:int = Math.min(items.length, 6); 39 | var dragRows:int = Math.ceil(items.length / 6); 40 | with (proxyLayout) { 41 | orientation = TileOrientation.ROWS; 42 | columnAlign = ColumnAlign.JUSTIFY_USING_WIDTH; 43 | columnWidth = 20; 44 | horizontalGap = 2; 45 | requestedColumnCount = dragColumns; 46 | rowAlign = RowAlign.TOP; 47 | verticalAlign = VerticalAlign.MIDDLE; 48 | } 49 | 50 | layout = proxyLayout; 51 | width = 4 + dragColumns * (200 * 0.1)/*maxProxyWidth*/ + (dragColumns - 1) * 2; 52 | height = 4 + dragRows * ((200 * 0.1) /*maxProxyHeight*/ + 2); 53 | 54 | for (var i:int = 0; i < items.length; i++) { 55 | var image:BitmapImage = new BitmapImage(); 56 | image.source = GalleryItem(items[i]).thumbnailData; 57 | image.scaleY = image.scaleX = .1; 58 | addElement(image); 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/skins/GalleryButtonSkin.mxml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 24 | 25 | [HostComponent("spark.components.Button")] 26 | 27 | 28 | 29 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 71 | 72 | -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/IconButton.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize.components { 20 | import spark.components.Button; 21 | import spark.primitives.BitmapImage; 22 | 23 | public class IconButton extends Button { 24 | public function IconButton() { 25 | super(); 26 | } 27 | 28 | //-------------------------------------------------------------------------- 29 | // 30 | // Properties 31 | // 32 | //-------------------------------------------------------------------------- 33 | 34 | //---------------------------------- 35 | // icon 36 | //---------------------------------- 37 | 38 | /** 39 | * @private 40 | * Internal storage for the icon property. 41 | */ 42 | private var _icon:Class; 43 | 44 | [Bindable] 45 | 46 | /** 47 | * 48 | */ 49 | public function get icon():Class { 50 | return _icon; 51 | } 52 | 53 | /** 54 | * @private 55 | */ 56 | public function set icon(val:Class): void { 57 | _icon = val; 58 | 59 | if (iconElement != null) { 60 | iconElement.source = _icon; 61 | } 62 | } 63 | 64 | //-------------------------------------------------------------------------- 65 | // 66 | // Skin Parts 67 | // 68 | //-------------------------------------------------------------------------- 69 | 70 | [SkinPart("false")] 71 | public var iconElement:BitmapImage; 72 | 73 | 74 | //-------------------------------------------------------------------------- 75 | // 76 | // Overridden methods 77 | // 78 | //-------------------------------------------------------------------------- 79 | 80 | /** 81 | * @private 82 | */ 83 | override protected function partAdded(partName:String, instance:Object):void { 84 | super.partAdded(partName, instance); 85 | 86 | if (icon !== null && instance == iconElement) 87 | iconElement.source = icon; 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/OrganizeStyle.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize { 20 | import flash.external.ExternalInterface; 21 | 22 | import mx.core.FlexGlobals; 23 | 24 | import spark.components.Application; 25 | 26 | [Bindable] 27 | public class OrganizeStyle { 28 | private static var _instance:OrganizeStyle = null; 29 | 30 | public static function get instance(): OrganizeStyle { 31 | if (_instance == null) { 32 | _instance = new OrganizeStyle(); 33 | var colors:Object = ExternalInterface.call("getOrganizeStyles"); 34 | var appl:Application = FlexGlobals.topLevelApplication as Application; 35 | for (var key:String in colors) { 36 | appl.setStyle(key, colors[key]); 37 | } 38 | appl.setStyle("baseColor", colors["backgroundColor"]); 39 | appl.setStyle("contentBackgroundColor", colors["backgroundColor"]); 40 | } 41 | return _instance; 42 | } 43 | 44 | public function OrganizeStyle() {} 45 | 46 | public function get baseColor(): uint { 47 | return FlexGlobals.topLevelApplication.getStyle("baseColor"); 48 | } 49 | 50 | public function get backgroundColor(): uint { 51 | return FlexGlobals.topLevelApplication.getStyle("backgroundColor"); 52 | } 53 | 54 | public function get contentBackgroundColor(): uint { 55 | return FlexGlobals.topLevelApplication.getStyle("contentBackgroundColor"); 56 | } 57 | 58 | public function get color(): uint { 59 | return FlexGlobals.topLevelApplication.getStyle("color"); 60 | } 61 | 62 | public function get borderColor(): uint { 63 | return FlexGlobals.topLevelApplication.getStyle("borderColor"); 64 | } 65 | 66 | public function get rollOverColor(): uint { 67 | return FlexGlobals.topLevelApplication.getStyle("rollOverColor"); 68 | } 69 | 70 | public function get selectionColor(): uint { 71 | return FlexGlobals.topLevelApplication.getStyle("selectionColor"); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/skins/IconButtonSkin.mxml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 23 | 28 | 29 | 32 | 33 | [HostComponent("org.gallery3.organize.components.IconButton")] 34 | 35 | 36 | 37 | 53 | 54 | 55 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /Gallery3Api/src/org/gallery3/api/GalleryRestResponder.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.api { 20 | import mx.rpc.AsyncResponder; 21 | import mx.rpc.Fault; 22 | import mx.rpc.IResponder; 23 | 24 | /** 25 | * This class provides an Gallery RESTFul specific implementation of mx.rpc.IResponder. 26 | * 27 | * It allows the creator to associate data (a token) and methods that should be 28 | * called when a request is completed. 29 | * 30 | * The result method specified must have the following signature: 31 | *
32 | 	 *     public function myResultFunction(resource: GalleryResource): void;
33 | 	 *  
34 | * 35 | * The fault method specified must have the following signature: 36 | *
37 | 	 *     public function myFaultFunction(info:Object): void;
38 | 	 *  
39 | * 40 | * Any other signature will result in a runtime error. 41 | */ 42 | public dynamic class GalleryRestResponder implements IResponder { 43 | private var _resultHandler: Function; 44 | private var _faultHandler: Function; 45 | 46 | /** 47 | * Constructs an instance of the responder with the specified data and 48 | * handlers. 49 | * 50 | * @param result Function that should be called when the request has 51 | * completed successfully. 52 | * Must have the following signature: 53 | *
public function (resource: Object):void;
54 | * @param fault Function that should be called when the request has 55 | * completed with errors. 56 | * Must have the following signature: 57 | *
public function (info:Object):void;
58 | */ 59 | public function GalleryRestResponder(result:Function, fault:Function) { 60 | super(); 61 | _resultHandler = result; 62 | _faultHandler = fault; 63 | } 64 | 65 | public function result(resource: Object): void { 66 | _resultHandler(resource); 67 | } 68 | 69 | public function fault(fault: Object): void { 70 | _faultHandler(fault); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/OrganizeText.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize { 20 | import flash.events.Event; 21 | import flash.events.EventDispatcher; 22 | import flash.events.IEventDispatcher; 23 | import flash.external.ExternalInterface; 24 | import flash.utils.flash_proxy; 25 | import flash.utils.Proxy; 26 | 27 | import mx.events.PropertyChangeEvent; 28 | 29 | [Bindable("propertyChange")] 30 | dynamic public class OrganizeText extends Proxy implements IEventDispatcher { 31 | private static var _instance:OrganizeText = null; 32 | 33 | private var _evtDispatcher: IEventDispatcher; 34 | private var _data: Object; 35 | 36 | public static function get instance(): OrganizeText { 37 | if (_instance == null) { 38 | _instance = new OrganizeText(); 39 | } 40 | return _instance; 41 | } 42 | 43 | public function OrganizeText() { 44 | _evtDispatcher = new EventDispatcher(); 45 | _data = ExternalInterface.call("getTextStrings"); 46 | for (var key: String in _data) { 47 | dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, key, null, _data[key])); 48 | } 49 | } 50 | 51 | flash_proxy override function getProperty(name: *): * { 52 | return _data[name]; 53 | } 54 | 55 | flash_proxy override function setProperty(name: *, value: *): void { 56 | var oldValue: * = _data[name]; 57 | _data[name] = value; 58 | dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, name, oldValue, value)); 59 | } 60 | 61 | public function addEventListener(type: String, listener: Function, useCapture: Boolean = false, priority:int=0.0, useWeakReference:Boolean=false): void { 62 | _evtDispatcher.addEventListener(type, listener, useCapture); 63 | } 64 | 65 | public function removeEventListener(type: String, listener: Function, useCapture: Boolean = false): void { 66 | _evtDispatcher.removeEventListener(type, listener, useCapture); 67 | } 68 | 69 | public function dispatchEvent(event: Event): Boolean { 70 | return _evtDispatcher.dispatchEvent(event); 71 | } 72 | 73 | public function hasEventListener(type: String): Boolean { 74 | return _evtDispatcher.hasEventListener(type); 75 | } 76 | 77 | public function willTrigger(type: String): Boolean { 78 | return _evtDispatcher.willTrigger(type); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/ErrorDialog.mxml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 27 | 28 | 29 | 30 | 31 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 74 | 75 | 77 | 78 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/OrganizeParameters.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize { 20 | import flash.events.Event; 21 | import flash.events.EventDispatcher; 22 | import flash.events.IEventDispatcher; 23 | import flash.external.ExternalInterface; 24 | import flash.utils.Proxy; 25 | import flash.utils.flash_proxy; 26 | 27 | import mx.events.PropertyChangeEvent; 28 | 29 | [Bindable("propertyChange")] 30 | dynamic public class OrganizeParameters extends Proxy implements IEventDispatcher { 31 | private static var _instance:OrganizeParameters = null; 32 | 33 | private var _evtDispatcher: IEventDispatcher; 34 | private var _data: Object; 35 | 36 | public static function get instance(): OrganizeParameters { 37 | if (_instance == null) { 38 | _instance = new OrganizeParameters(); 39 | } 40 | return _instance; 41 | } 42 | 43 | public function OrganizeParameters() { 44 | _evtDispatcher = new EventDispatcher(); 45 | _data = ExternalInterface.call("getGalleryParameters"); 46 | for (var key: String in _data) { 47 | dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, key, null, _data[key])); 48 | } 49 | } 50 | 51 | flash_proxy override function getProperty(name: *): * { 52 | switch (name.localName) { 53 | case "baseUrl": 54 | return _data["protocol"] + "://" + _data["domain"] + _data["restUri"]; 55 | case "controller": 56 | return _data["protocol"] + "://" + _data["domain"] + _data["controllerUri"]; 57 | case "url": 58 | var restUri: String = _data["restUri"]; 59 | var url: String = restUri.substring(0, restUri.indexOf("rest/")); 60 | return _data["protocol"] + "://" + _data["domain"] + url; 61 | } 62 | 63 | return _data[name.localName]; 64 | } 65 | 66 | flash_proxy override function setProperty(name: *, value: *): void { 67 | var oldValue: * = _data[name.localName]; 68 | _data[name.localName] = value; 69 | dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, name, oldValue, value)); 70 | } 71 | 72 | public function addEventListener(type: String, listener: Function, useCapture: Boolean = false, priority:int=0.0, useWeakReference:Boolean=false): void { 73 | _evtDispatcher.addEventListener(type, listener, useCapture); 74 | } 75 | 76 | public function removeEventListener(type: String, listener: Function, useCapture: Boolean = false): void { 77 | _evtDispatcher.removeEventListener(type, listener, useCapture); 78 | } 79 | 80 | public function dispatchEvent(event: Event): Boolean { 81 | return _evtDispatcher.dispatchEvent(event); 82 | } 83 | 84 | public function hasEventListener(type: String): Boolean { 85 | return _evtDispatcher.hasEventListener(type); 86 | } 87 | 88 | public function willTrigger(type: String): Boolean { 89 | return _evtDispatcher.willTrigger(type); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Gallery3Api/src/org/gallery3/api/GalleryRestToken.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.api { 20 | import flash.events.EventDispatcher; 21 | 22 | import mx.events.PropertyChangeEvent; 23 | import mx.rpc.AsyncToken; 24 | import mx.rpc.IResponder; 25 | import mx.rpc.events.FaultEvent; 26 | import mx.rpc.events.ResultEvent; 27 | 28 | /** 29 | * Dispatched when a property of the channel set changes. 30 | * 31 | * @eventType mx.events.PropertyChangeEvent.PROPERTY_CHANGE 32 | */ 33 | [Event(name="propertyChange", type="mx.events.PropertyChangeEvent")] 34 | 35 | public dynamic class GalleryRestToken extends EventDispatcher { 36 | public function GalleryRestToken() { 37 | super(); 38 | } 39 | 40 | private var _resource: Object = null; 41 | private var _responders: Array; 42 | 43 | /** 44 | * The result that was returned by the associated RPC call. 45 | * Once the result property on the token has been assigned 46 | * it will be strictly equal to the result property on the associated 47 | * ResultEvent. 48 | */ 49 | [Bindable(event="propertyChange")] 50 | public function get resource(): Object { 51 | return _resource; 52 | } 53 | public function set resource(value: Object): void { 54 | if (_resource !== value) { 55 | var event:PropertyChangeEvent = PropertyChangeEvent.createUpdateEvent(this, "resource", _resource, value); 56 | _resource = value; 57 | dispatchEvent(event); 58 | } 59 | 60 | if (_responders != null) { 61 | for (var i:uint = 0; i < _responders.length; i++) { 62 | var responder:IResponder = _responders[i]; 63 | if (responder != null) { 64 | responder.result(_resource); 65 | } 66 | } 67 | } 68 | } 69 | 70 | //-------------------------------------------------------------------------- 71 | // 72 | // Methods 73 | // 74 | //-------------------------------------------------------------------------- 75 | 76 | /** 77 | * Adds a responder to an Array of responders. 78 | * The object assigned to the responder parameter must implement 79 | * mx.rpc.IResponder. 80 | * 81 | * @param responder A handler which will be called when the asynchronous request completes. 82 | * 83 | * @see mx.rpc.IResponder 84 | */ 85 | public function addResponder(responder:IResponder): void { 86 | if (_responders == null) { 87 | _responders = []; 88 | } 89 | 90 | _responders.push(responder); 91 | } 92 | 93 | /** 94 | * Determines if this token has at least one mx.rpc.IResponder registered. 95 | * @return true if at least one responder has been added to this token. 96 | */ 97 | public function hasResponder():Boolean { 98 | return (_responders != null && _responders.length > 0); 99 | } 100 | 101 | /** 102 | * @private 103 | */ 104 | internal function applyFault(fault: Object): void { 105 | if (_responders != null) { 106 | for (var i:uint = 0; i < _responders.length; i++) { 107 | var responder:IResponder = _responders[i]; 108 | if (responder != null) { 109 | responder.fault(fault); 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /Gallery3Api/src/org/gallery3/api/URLFileVariable.as: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) Mike Stead 2009, All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | * Neither the name of Adobe Systems Incorporated nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | package org.gallery3.api { 32 | import flash.utils.ByteArray; 33 | 34 | /** 35 | * The URLFileVariable class wraps file data to be sent to the server using a URLRequest. 36 | * 37 | *

To add an instance of URLFileVariable to a URLRequest you must first create a URLVariables 38 | * instance and then set one or more of its properties with a URLFileVariable instance. This 39 | * URLVariables instance should then be passed to a URLRequestBuilder which can construct 40 | * the URLRequest with the correct encoding to transport the file(s) to the server.

41 | * 42 | * @example 43 | *
 44 |      * // Construct variables (name-value pairs) to be sent to sever
 45 |      * var variables:URLVariable = new URLVariables();
 46 |      * variables.userImage = new URLFileVariable(jpegEncodedData, "user_image.jpg");
 47 |      * variables.userPDF = new URLFileVariable(pdfEncodedData, "user_doc.pdf");
 48 |      * variables.userName = "Mike";
 49 |      * // Build the request which houses these variables
 50 |      * var request:URLRequest = new URLRequestBuilder(variables).build();
 51 |      * request.url = "some.web.address.php";
 52 |      * // Create the loader and use it to send the request off to the server
 53 |      * var loader:URLLoader = new URLLoader();
 54 |      * loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
 55 |      * loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onError);
 56 |      * loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
 57 |      * loader.addEventListener(Event.COMPLETE, onServerResponse);
 58 |      * loader.load(request);
 59 |      * function onServerResponse(event:Event):void
 60 |      * {
 61 |      *     trace("Variables uploaded successfully");
 62 |      * }
 63 |      * function onError(event:Event):void
 64 |      * {
 65 |      *     trace("An error occured while trying to upload data to the server: \n" + event);
 66 |      * }
 67 |      * 
68 | * 69 | * @author Mike Stead 70 | * @see URLRequestBuilder 71 | */ 72 | public class URLFileVariable 73 | { 74 | private var _name:String; 75 | private var _data:ByteArray; 76 | 77 | /** 78 | * Constructor. 79 | * 80 | * @param data The contents of the file to be sent to the server 81 | * @param name The name to be given to the file on the server, e.g. user_image.jpg 82 | */ 83 | public function URLFileVariable(data:ByteArray, name:String) 84 | { 85 | _data = data; 86 | _name = name; 87 | } 88 | 89 | /** 90 | * The name to be given to the file on the server 91 | */ 92 | public function get name():String 93 | { 94 | return _name; 95 | } 96 | 97 | /** 98 | * The contents of the file 99 | */ 100 | public function get data():ByteArray 101 | { 102 | return _data; 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /Gallery3Api/src/org/gallery3/api/GalleryEntity.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.api { 20 | import flash.events.Event; 21 | import flash.events.EventDispatcher; 22 | import flash.events.IEventDispatcher; 23 | import flash.utils.Proxy; 24 | import flash.utils.flash_proxy; 25 | 26 | import mx.core.IUID; 27 | import mx.events.PropertyChangeEvent; 28 | import mx.events.PropertyChangeEventKind; 29 | 30 | use namespace flash_proxy; 31 | [Bindable("propertyChange")] 32 | public dynamic class GalleryEntity extends Proxy implements IEventDispatcher, IUID { 33 | protected var _eventDispatcher:EventDispatcher; 34 | protected var _values: Object = {}; 35 | protected var _dirty:Vector. = new Vector.(); 36 | 37 | public function GalleryEntity() { 38 | super(); 39 | _eventDispatcher = new EventDispatcher(this); 40 | } 41 | 42 | flash_proxy override function getProperty(name: *): * { 43 | return name.localName == "dirty" ? this._dirty : (_values[name.localName] || null); 44 | } 45 | 46 | flash_proxy override function setProperty(name: *, value: *): void { 47 | if (name.localName == "dirty") { 48 | this._dirty = value; 49 | } else { 50 | var oldValue: * = _values[name.localName]; 51 | _values[name.localName] = value; 52 | var kind:String = PropertyChangeEventKind.UPDATE; 53 | _dirty.push(name.localName); 54 | dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE, false, false, kind, name, oldValue, value, this)); 55 | } 56 | } 57 | 58 | protected var _propertyNames:Array; // array of object's properties 59 | flash_proxy override function nextNameIndex(index:int):int { 60 | if (index == 0) { // initial call 61 | _propertyNames = new Array(); 62 | for (var x:* in _values) { 63 | _propertyNames.push(x); 64 | } 65 | } 66 | return (index < _propertyNames.length) ? index + 1 : 0; 67 | } 68 | 69 | override flash_proxy function nextValue(index:int):* { 70 | return _values[index - 1]; 71 | } 72 | override flash_proxy function nextName(index:int):String { 73 | return _propertyNames[index - 1]; 74 | } 75 | 76 | public function get isDirty(): Boolean { 77 | return _dirty.length > 0; 78 | } 79 | 80 | //---------------------------------- 81 | // IEventDispatcher interface implementation 82 | //---------------------------------- 83 | public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, 84 | priority:int=0, useWeakReference:Boolean=false): void { 85 | _eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); 86 | } 87 | 88 | public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false): void { 89 | _eventDispatcher.removeEventListener(type, listener, useCapture); 90 | } 91 | 92 | public function dispatchEvent(event:Event): Boolean { 93 | return _eventDispatcher.dispatchEvent(event); 94 | } 95 | 96 | public function hasEventListener(type:String): Boolean { 97 | return _eventDispatcher.hasEventListener(type); 98 | } 99 | 100 | public function willTrigger(type:String): Boolean { 101 | return _eventDispatcher.willTrigger(type); 102 | } 103 | 104 | //---------------------------------- 105 | // IUID interface implementation 106 | //---------------------------------- 107 | /** 108 | * The unique identifier for this object. 109 | */ 110 | public function get uid(): String { 111 | return this._values["id"]; 112 | } 113 | 114 | /** 115 | * @private 116 | */ 117 | public function set uid(value:String): void { 118 | this._values["id"] = value; 119 | this._dirty.push("id"); 120 | } 121 | } 122 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/Organize.mxml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 29 | 30 | 31 | 32 | 33 | 48 | 49 | 52 | 53 | 56 | 66 | 67 | 68 | 69 | 74 | 79 | 80 | 81 | 87 | 93 | 100 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/ProcessItemQueue.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize.components { 20 | import flash.display.DisplayObject; 21 | import flash.events.Event; 22 | import flash.events.ProgressEvent; 23 | 24 | import mx.collections.ArrayCollection; 25 | import mx.core.FlexGlobals; 26 | import mx.managers.PopUpManager; 27 | import mx.rpc.Fault; 28 | import mx.utils.StringUtil; 29 | 30 | import org.gallery3.api.GalleryRestResponder; 31 | import org.gallery3.api.GalleryRestToken; 32 | import org.gallery3.organize.OrganizeText; 33 | import org.gallery3.organize.components.ErrorDialog; 34 | import org.gallery3.organize.components.ProgressDialog; 35 | 36 | public class ProcessItemQueue extends ArrayCollection { 37 | public static const MOVE_OPERATION: String = "move"; 38 | public static const DELETE_OPERATION: String = "delete"; 39 | public static const UPLOAD_OPERATION: String = "upload"; 40 | public static const SAVE_OPERATION: String = "save"; 41 | 42 | private var _completionCallback: Function = null; 43 | private var _progressCount: int; 44 | private var _progressTotal: int; 45 | private var _progressWindow: ProgressDialog; 46 | private var _operation: String; 47 | 48 | public function ProcessItemQueue(operation: String) { 49 | super(null); 50 | _operation = operation; 51 | } 52 | 53 | public function processQueue(onComplete: Function=null): void { 54 | var textStrings: OrganizeText = OrganizeText.instance; 55 | _progressCount = 0; 56 | _progressTotal = length; 57 | 58 | // @todo start a batch or do we want to start the batch when the dialog is displayed 59 | var mainWindow: DisplayObject = FlexGlobals.topLevelApplication.organizeDialog as DisplayObject; 60 | _progressWindow = PopUpManager.createPopUp(mainWindow, ProgressDialog, true) as ProgressDialog; 61 | _progressWindow.title = textStrings[_operation + "Title"]; 62 | if (_operation == UPLOAD_OPERATION) { 63 | _progressWindow.currentState = "hasSubtask"; 64 | _progressWindow.subTaskProgressBar.indeterminate = true; 65 | } else { 66 | _progressWindow.currentState = "basic"; 67 | } 68 | 69 | _progressWindow.overallProgressBar.label = textStrings.progressLabel; 70 | _progressWindow.overallProgressBar.setProgress(0, _progressTotal); 71 | PopUpManager.centerPopUp(_progressWindow); 72 | 73 | _completionCallback = onComplete; 74 | _processItem(); 75 | } 76 | 77 | private function _processItem(): void { 78 | if (length > 0) { 79 | var queueItem: Object = this.removeItemAt(0); 80 | var token: GalleryRestToken; 81 | switch (queueItem.action) { 82 | case "save": 83 | token = queueItem.item.save(); 84 | token.addResponder(new GalleryRestResponder(_onItemProcessingComplete, _onFault)); 85 | break; 86 | case "delete": 87 | token = queueItem.item.deleteResource(); 88 | token.addResponder(new GalleryRestResponder(_onItemProcessingComplete, _onFault)); 89 | break; 90 | case "loadFile": 91 | queueItem.item.loadFile() 92 | .addResponder(new GalleryRestResponder(function (resource: Object) : void { 93 | queueItem.item.save().addResponder(new GalleryRestResponder(_onItemProcessingComplete, _onFault)); 94 | }, _onFault)); 95 | break; 96 | default: 97 | // Just log any invalid items and then process the next one. 98 | trace("Action: '" + queueItem.action + "' is not implemented"); 99 | _onItemProcessingComplete(null); 100 | } 101 | } else { 102 | if (_completionCallback != null) { 103 | _completionCallback(); 104 | } 105 | PopUpManager.removePopUp(_progressWindow); 106 | this.removeAll(); 107 | // @todo stop the batch 108 | } 109 | } 110 | 111 | private function _onItemProcessingComplete(resource: Object): void { 112 | _progressWindow.overallProgressBar.setProgress(++_progressCount, _progressTotal); 113 | _processItem(); 114 | } 115 | 116 | private function _onFault(fault: Object): void { 117 | PopUpManager.removePopUp(_progressWindow); 118 | this.removeAll(); 119 | ErrorDialog.display(fault as Fault); 120 | } 121 | } 122 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/skins/GalleryTitleWindowCloseButtonSkin.mxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 24 | 26 | 27 | 28 | 29 | 35 | 36 | 37 | 38 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 91 | 92 | 93 | 94 | 95 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/ImageRenderer.mxml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | THUMBNAIL_MAX_SIZE || bmData.height > THUMBNAIL_MAX_SIZE) { 97 | if (bmData.width > bmData.height) { 98 | height = THUMBNAIL_MAX_SIZE * bmData.height / bmData.width; 99 | width = THUMBNAIL_MAX_SIZE; 100 | } else { 101 | width = THUMBNAIL_MAX_SIZE * bmData.width / bmData.height; 102 | height = THUMBNAIL_MAX_SIZE; 103 | } 104 | } else { 105 | height = bmData.height; 106 | width = bmData.width; 107 | } 108 | yOffset = (THUMBNAIL_CELL_HEIGHT - height) / 2; 109 | xOffset = (THUMBNAIL_CELL_WIDTH - width) / 2; 110 | bmBitmap = new Bitmap(bmData); 111 | itemTitle = GalleryItem(data).title; 112 | } else { 113 | yOffset = xOffset = 0; 114 | bmBitmap = null; 115 | itemTitle = "itemTitle"; 116 | } 117 | invalidateDisplayList(); 118 | } 119 | ]]> 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 132 | 133 | 134 | 136 | 137 | 138 | 139 | 141 | 143 | 144 | -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/SelectionLasso.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize.components { 20 | import flash.display.BitmapData; 21 | import flash.geom.Matrix; 22 | import flash.geom.Point; 23 | import flash.geom.Rectangle; 24 | 25 | import mx.core.UIComponent; 26 | 27 | import org.gallery3.organize.OrganizeStyle; 28 | 29 | import spark.core.IViewport; 30 | 31 | public class SelectionLasso extends UIComponent { 32 | private var _horizontalBitmap:BitmapData; 33 | private var _verticalBitmap:BitmapData; 34 | private var _bitmapScroll:Number = 0; 35 | private var _startPos:Point = null; 36 | private var _rawRegion:Rectangle = new Rectangle(); 37 | private var _constraints:Rectangle; 38 | 39 | /** 40 | * Create a selection lasso 41 | * 42 | * @param constraints Point maximum height and width of the selection region. 43 | */ 44 | public function SelectionLasso(constraints:Point) { 45 | super(); 46 | _constraints = new Rectangle(0, 0, constraints.x, constraints.y); 47 | includeInLayout = false; 48 | initBitmaps(); 49 | invalidateDisplayList(); 50 | } 51 | 52 | public function get rectangle(): Rectangle { 53 | return _constraints.intersection(_rawRegion.clone()); 54 | } 55 | 56 | /** 57 | * Set the current position of the mouse 58 | * @param mousePos Point location of the mouse in the owner content coordinates 59 | */ 60 | public function setMousePosition(mousePos:Point):void { 61 | _startPos = _startPos == null ? mousePos : _startPos; 62 | 63 | _rawRegion.topLeft = _startPos; 64 | _rawRegion.bottomRight = mousePos; 65 | if (_rawRegion.height < 0) { 66 | var rawRegionY:Number = _rawRegion.top; 67 | _rawRegion.top = _rawRegion.bottom; 68 | _rawRegion.bottom = rawRegionY; 69 | } 70 | if (_rawRegion.width < 0) { 71 | var rawRegionX:Number = _rawRegion.left; 72 | _rawRegion.left = _rawRegion.right; 73 | _rawRegion.right = rawRegionX; 74 | } 75 | 76 | if (initialized) { 77 | update(); 78 | } 79 | } 80 | 81 | private function scrollBitmaps():void { 82 | _bitmapScroll = (++_bitmapScroll) % 4; 83 | } 84 | 85 | private function initBitmaps():void { 86 | _horizontalBitmap = new BitmapData(4, 2, false, OrganizeStyle.instance.borderColor); 87 | _verticalBitmap = new BitmapData(2, 4, false, OrganizeStyle.instance.borderColor); 88 | for(var _x:Number = 0; _x < 2; _x++){ 89 | for(var _y:Number = 0; _y < 2; _y++){ 90 | _horizontalBitmap.setPixel(_x, _y, OrganizeStyle.instance.contentBackgroundColor); 91 | _verticalBitmap.setPixel(_x, _y, OrganizeStyle.instance.contentBackgroundColor); 92 | } 93 | } 94 | } 95 | 96 | private function update():void { 97 | scrollBitmaps(); 98 | graphics.clear(); 99 | 100 | // Get a copy of the selection lasso coordinates 101 | var rect:Rectangle = rectangle; 102 | var viewPort:IViewport = ThumbGrid(owner).scroller.viewport; 103 | 104 | // Create the clipping region that corresponds to the visible area of the owner 105 | var clippingRect: Rectangle = new Rectangle(0, viewPort.verticalScrollPosition, owner.width, 106 | viewPort.verticalScrollPosition + owner.height); 107 | rect = clippingRect.intersection(rect); 108 | 109 | var drawTop:Boolean = rectangle.x >= rect.x; 110 | var drawBottom:Boolean = rectangle.bottom >= rect.bottom; 111 | 112 | // Reset the clipping rectangle to visible coordinates 113 | rect.offset(0, -viewPort.verticalScrollPosition); 114 | 115 | // Convert the clipping rectangle to this coordinate system 116 | var ownerRect:Rectangle = owner.getBounds(parent); 117 | rect.offsetPoint(ownerRect.topLeft); 118 | 119 | graphics.beginBitmapFill(_horizontalBitmap, new Matrix(1, 0, 0, 1, _bitmapScroll, 0),true,false); 120 | if (drawTop) { 121 | graphics.drawRect(rect.x, rect.y - 1, rect.width, 1); 122 | } 123 | if (drawBottom) { 124 | graphics.drawRect(rect.x, rect.bottom, rect.width, 1); 125 | } 126 | 127 | graphics.beginBitmapFill(_verticalBitmap, new Matrix(1, 0, 0, 1, 0, _bitmapScroll),true,false); 128 | graphics.drawRect(rect.x - 1, rect.y - 1, 1, rect.height + 2); 129 | graphics.drawRect(rect.right, rect.y - 1, 1, rect.height + 2); 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/AlbumTree.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize.components { 20 | import flash.events.MouseEvent; 21 | import flash.geom.Point; 22 | 23 | import mx.controls.Tree; 24 | import mx.controls.listClasses.BaseListData; 25 | import mx.controls.listClasses.IListItemRenderer; 26 | import mx.events.DragEvent; 27 | import mx.events.ListEvent; 28 | import mx.managers.DragManager; 29 | import mx.rpc.Fault; 30 | 31 | import org.gallery3.api.GalleryAlbum; 32 | import org.gallery3.api.GalleryItem; 33 | import org.gallery3.api.GalleryRestResponder; 34 | import org.gallery3.organize.OrganizeDataDescriptor; 35 | 36 | public class AlbumTree extends Tree { 37 | private var _lastHighlightItemRendererAtIndices: IListItemRenderer; 38 | private var _lastHighlightItemIndices: Point; 39 | 40 | private var _saveQueue: Vector. = new Vector.(); 41 | 42 | public function AlbumTree() { 43 | super(); 44 | dataDescriptor = new OrganizeDataDescriptor(); 45 | dropEnabled = true; 46 | focusEnabled = false; 47 | dragMoveEnabled = true; 48 | } 49 | 50 | override protected function dragDropHandler(event:DragEvent):void { 51 | var targetAlbum: GalleryAlbum = _lastHighlightItemRendererAtIndices.data as GalleryAlbum; 52 | var data: Vector. = event.dragSource.dataForFormat("items") as Vector.; 53 | var queue: ProcessItemQueue = new ProcessItemQueue(ProcessItemQueue.MOVE_OPERATION); 54 | while (data.length > 0) { 55 | var item: GalleryItem = data.shift(); 56 | item.parent = targetAlbum.url; 57 | _saveQueue.push(item); 58 | queue.addItem({"action": "save", "item": item}); 59 | } 60 | queue.processQueue( 61 | function(): void { 62 | GalleryAlbum(selectedItem).refreshResource().addResponder(new GalleryRestResponder( 63 | function(resource: Object): void {}, 64 | function (fault: Fault): void { 65 | ErrorDialog.display(fault as Fault); 66 | })); 67 | var targetAlbum: GalleryAlbum = _lastHighlightItemRendererAtIndices.data as GalleryAlbum; 68 | targetAlbum.refreshResource().addResponder(new GalleryRestResponder( 69 | function(resource: Object): void {}, 70 | function (fault: Fault): void { 71 | ErrorDialog.display(fault as Fault); 72 | })); 73 | }); 74 | } 75 | 76 | override protected function dragEnterHandler(event:DragEvent):void { 77 | if (event.isDefaultPrevented()) { 78 | return; 79 | } 80 | _acceptItems(event); 81 | } 82 | 83 | override protected function mouseOutHandler(event:MouseEvent) : void { 84 | if (!DragManager.isDragging) { 85 | super.mouseOutHandler(event); 86 | } else { 87 | var item:IListItemRenderer = mouseEventToItemRenderer(event); 88 | if (item != _lastHighlightItemRendererAtIndices && _lastHighlightItemRendererAtIndices) { 89 | _updateHighlight(_lastHighlightItemRendererAtIndices, _lastHighlightItemIndices, false); 90 | } 91 | } 92 | } 93 | 94 | override protected function mouseOverHandler(event:MouseEvent) : void { 95 | if (DragManager.isDragging) { 96 | var item:IListItemRenderer = mouseEventToItemRenderer(event); 97 | if (item) { 98 | // we're rolling onto different subpieces of ourself or our highlight indicator 99 | if (event.relatedObject) { 100 | var lastUID:String; 101 | if (_lastHighlightItemRendererAtIndices && highlightUID) { 102 | var rowData:BaseListData = rowMap[item.name]; 103 | lastUID = rowData.uid; 104 | } 105 | if (itemRendererContains(item, event.relatedObject) || 106 | uid == lastUID || 107 | event.relatedObject == highlightIndicator) { 108 | return; 109 | } 110 | } 111 | 112 | if (getStyle("useRollOver") && (item.data != null)) { 113 | drawItem(UIDToItemRenderer(uid), isItemSelected(item.data), true, uid == caretUID); 114 | var pt:Point = itemRendererToIndices(item); 115 | if (pt) { // during tweens, we may get null 116 | _updateHighlight(item, pt, true); 117 | } 118 | } 119 | } 120 | } else { 121 | super.mouseOverHandler(event); 122 | } 123 | } 124 | 125 | override protected function dragOverHandler(event:DragEvent): void { 126 | if (event.isDefaultPrevented()) { 127 | return; 128 | } 129 | _acceptItems(event); 130 | } 131 | 132 | override protected function dragExitHandler(event:DragEvent): void { 133 | if (_lastHighlightItemRendererAtIndices) { 134 | _updateHighlight(_lastHighlightItemRendererAtIndices, _lastHighlightItemIndices, false); 135 | } 136 | } 137 | 138 | private function _updateHighlight(item:IListItemRenderer, pt:Point, showHighlight:Boolean): void { 139 | var uid:String = itemToUID(item.data); 140 | drawItem(UIDToItemRenderer(uid), isItemSelected(item.data), showHighlight, uid == caretUID); 141 | var evt:ListEvent = new ListEvent(showHighlight? ListEvent.ITEM_ROLL_OVER : ListEvent.ITEM_ROLL_OUT); 142 | evt.columnIndex = pt.x; 143 | evt.rowIndex = pt.y; 144 | evt.itemRenderer = item; 145 | dispatchEvent(evt); 146 | if (showHighlight) { 147 | _lastHighlightItemIndices = pt; 148 | _lastHighlightItemRendererAtIndices = item; 149 | } else { 150 | _lastHighlightItemIndices = null; 151 | _lastHighlightItemRendererAtIndices = null; 152 | } 153 | } 154 | 155 | private function _acceptItems(event:DragEvent): void { 156 | if (event.dragSource.hasFormat("items")) { 157 | DragManager.acceptDragDrop(this); 158 | DragManager.showFeedback(DragManager.MOVE); 159 | } 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/AddAlbumDialog.mxml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 126 | 127 | 130 | 133 | 135 | 137 | 139 | 141 | 143 | 145 | 146 | 147 | 150 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /Gallery3WebClient/html-template/index.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | ${title} 15 | 16 | 21 | 42 | 43 | 44 | 48 | 49 | 50 | 138 | 139 | 140 | 144 |
145 |

146 | To view this page ensure that Adobe Flash Player version 147 | ${version_major}.${version_minor}.${version_revision} or greater is installed. 148 |

149 | 154 |
155 | 156 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /Gallery3Api/src/org/gallery3/api/GalleryResource.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.api { 20 | import com.adobe.serialization.json.JSON; 21 | import com.adobe.utils.StringUtil; 22 | 23 | import flash.events.Event; 24 | import flash.events.EventDispatcher; 25 | import flash.events.IEventDispatcher; 26 | import flash.net.URLVariables; 27 | import flash.utils.Proxy; 28 | import flash.utils.flash_proxy; 29 | 30 | import mx.collections.ArrayCollection; 31 | import mx.core.IUID; 32 | import mx.events.PropertyChangeEvent; 33 | import mx.events.PropertyChangeEventKind; 34 | import mx.rpc.AsyncResponder; 35 | import mx.rpc.Fault; 36 | import mx.rpc.events.FaultEvent; 37 | import mx.utils.ObjectUtil; 38 | import mx.utils.UIDUtil; 39 | 40 | use namespace flash_proxy; 41 | [Bindable("propertyChange")] 42 | public dynamic class GalleryResource extends Proxy implements IEventDispatcher, IUID { 43 | protected var _eventDispatcher:EventDispatcher; 44 | protected var _values: Object = {}; 45 | protected var _isNew: Boolean; 46 | 47 | public static function loadResource(resourceUri: String, data: URLVariables=null): GalleryRestToken { 48 | return GalleryRestRequest.factory() 49 | .setUri(resourceUri) 50 | .setData(data) 51 | .setMethod("GET") 52 | .sendRequest(function(token: GalleryRestToken, data: Object): void { 53 | var item: Object = JSON.decode(String(data)) as Object; 54 | 55 | // matches[1] has the resource type 56 | // matches[2] should be undefined or an s if the resource is a collection 57 | // matches[3] should have the resource ID 58 | var matches: Array = token.uri.match(/(.*?)(s){0,1}(?:\/(\d*))?$/i); 59 | if (matches[2] != "s") { 60 | token.resource = GalleryResource.factory(matches[1], item); 61 | } else { 62 | var collection: ArrayCollection = new ArrayCollection(); 63 | for (var member: Object in item) { 64 | collection.addItem(GalleryResource.factory(matches[1], item[member])); 65 | } 66 | token.resource = collection; 67 | } 68 | }); 69 | } 70 | 71 | public static function factory(resourceType: String, data: Object=null): GalleryResource { 72 | var resource: GalleryResource; 73 | switch (resourceType) { 74 | case "item": 75 | if (data == null || data.entity.type != "album") { 76 | resource = new GalleryItem(); 77 | break; 78 | } 79 | case "album": 80 | resource = new GalleryAlbum(); 81 | break; 82 | case "tag": 83 | resource = new GalleryTag(); 84 | break; 85 | default: 86 | resource = new GalleryResource(); 87 | } 88 | if (data != null) { 89 | resource.isNew = false; 90 | for (var property: String in data) { 91 | switch (property) { 92 | case "members": 93 | resource.members = new ArrayCollection(data.members); 94 | break; 95 | case "entity": 96 | resource.entity.data = data.entity; 97 | for (var entityProperty: String in data.entity) { 98 | resource.entity[entityProperty] = data.entity[entityProperty]; 99 | } 100 | break; 101 | default: 102 | resource[property] = data[property]; 103 | break; 104 | } 105 | } 106 | } 107 | 108 | resource.original = ObjectUtil.clone(resource.entity) as GalleryEntity; 109 | 110 | // Reset the dirty flags 111 | resource._dirty = new Vector.(); 112 | resource.entity.dirty = new Vector.(); 113 | return resource; 114 | } 115 | 116 | public function GalleryResource() { 117 | super(); 118 | _eventDispatcher = new EventDispatcher(this); 119 | this.entity = new GalleryEntity(); 120 | this.entity.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, function(event: PropertyChangeEvent): void { 121 | _eventDispatcher.dispatchEvent(event); 122 | }); 123 | this.relationships = {}; 124 | this.isNew = true; 125 | } 126 | 127 | public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, 128 | priority:int=0, useWeakReference:Boolean=false): void { 129 | _eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); 130 | } 131 | 132 | public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false): void { 133 | _eventDispatcher.removeEventListener(type, listener, useCapture); 134 | } 135 | 136 | public function dispatchEvent(event:Event): Boolean { 137 | return _eventDispatcher.dispatchEvent(event); 138 | } 139 | 140 | public function hasEventListener(type:String): Boolean { 141 | return _eventDispatcher.hasEventListener(type); 142 | } 143 | 144 | public function willTrigger(type:String): Boolean { 145 | return _eventDispatcher.willTrigger(type); 146 | } 147 | 148 | flash_proxy override function getProperty(name: *): * { 149 | return _values[name] || null; 150 | } 151 | 152 | flash_proxy override function setProperty(name: *, value: *): void { 153 | var propertyName: String = name.localName; 154 | var oldValue: * = _values[propertyName]; 155 | _values[propertyName] = value; 156 | var kind:String = PropertyChangeEventKind.UPDATE; 157 | dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE, false, false, kind, propertyName, oldValue, value, this)); 158 | } 159 | 160 | /** 161 | * Save any local changes made to this resource. If this is an existing resource, we'll return 162 | * the resource itself. If we're creating a new resource, return the newly created resource. 163 | * 164 | * @return object AsyncToken 165 | */ 166 | public function save(): GalleryRestToken { 167 | var dirty: Boolean = isDirty; 168 | 169 | var params: URLVariables = new URLVariables(); 170 | var entity:Object = {}; 171 | if (this.entity.id) { 172 | entity["id"] = this.entity.id; 173 | } 174 | for each (var property: String in this.entity.dirty) { 175 | entity[property] = this.entity[property]; 176 | } 177 | params.entity = JSON.encode(entity); 178 | if (this.members != null) { 179 | params.members = JSON.encode(this.members.source); 180 | } 181 | if (_values.hasOwnProperty("file")) { 182 | params.file = new URLFileVariable(this.file.data, this.file.name); 183 | } 184 | 185 | var self: GalleryResource = this; 186 | return GalleryRestRequest.factory() 187 | .setUrl(this.url) 188 | .setData(params) 189 | .setMethod(isNew ? "POST" : "PUT") 190 | .sendRequest(function(token: GalleryRestToken, data: Object): void { 191 | if (token.action == "POST") { 192 | var item: Object = JSON.decode(String(data)) as Object; 193 | self.url = item.url; 194 | } 195 | 196 | // Reset the dirty flags 197 | self._dirty = new Vector.(); 198 | self.entity.dirty = new Vector.(); 199 | 200 | token.resource = self; 201 | }); 202 | } 203 | 204 | /** 205 | * Refresh the resource from the server 206 | * @param responder Optional responder to handle the results of the refresh 207 | * @return object AsyncToken 208 | */ 209 | public function refreshResource(): GalleryRestToken { 210 | var self: GalleryResource = this; 211 | return GalleryRestRequest.factory() 212 | .setUrl(this.url) 213 | .setMethod("GET") 214 | .sendRequest(function(token: GalleryRestToken, data: Object): void { 215 | var item: Object = JSON.decode(String(data)) as Object; 216 | for (var property: String in item) { 217 | self[property] = (property == "members") ? new ArrayCollection(item[property]) : item[property]; 218 | } 219 | 220 | // Reset the dirty flags 221 | self._dirty = new Vector.(); 222 | 223 | token.resource = self; 224 | }); 225 | } 226 | 227 | /** 228 | * Refresh the resource from the server 229 | * @param responder Optional responder to handle the results of the refresh 230 | * @return object AsyncToken 231 | */ 232 | public function deleteResource(): GalleryRestToken { 233 | return GalleryRestRequest.factory() 234 | .setUrl(this.url) 235 | .setMethod("DELETE") 236 | .sendRequest(); 237 | } 238 | 239 | public function toString():String { 240 | return ObjectUtil.toString(_values); 241 | } 242 | 243 | public function isEntity(): Boolean { 244 | return _values.hasOwnProperty("entity"); 245 | } 246 | 247 | public function isCollection(): Boolean { 248 | return _values.hasOwnProperty("members"); 249 | } 250 | 251 | public function get isDirty(): Boolean { 252 | return ObjectUtil.compare(this.original, this.entity) != 0 || this.entity.isDirty(); 253 | } 254 | 255 | public function get isNew(): Boolean { 256 | return _isNew; 257 | } 258 | public function set isNew(value: Boolean): void { 259 | _isNew = value; 260 | } 261 | 262 | //---------------------------------- 263 | // IUID interface implementation 264 | //---------------------------------- 265 | /** 266 | * The unique identifier for this object. 267 | */ 268 | public function get uid(): String { 269 | return this.entity["id"]; 270 | } 271 | 272 | /** 273 | * @private 274 | */ 275 | public function set uid(value:String): void { 276 | this.entity["id"] = value; 277 | } 278 | } 279 | } -------------------------------------------------------------------------------- /Gallery3Api/src/org/gallery3/api/GalleryItem.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.api { 20 | import flash.display.Bitmap; 21 | import flash.display.BitmapData; 22 | import flash.display.Loader; 23 | import flash.errors.IOError; 24 | import flash.events.Event; 25 | import flash.events.EventDispatcher; 26 | import flash.events.HTTPStatusEvent; 27 | import flash.events.IOErrorEvent; 28 | import flash.net.FileReference; 29 | import flash.net.URLLoader; 30 | import flash.net.URLRequest; 31 | import flash.net.URLRequestHeader; 32 | import flash.net.URLRequestMethod; 33 | import flash.net.URLVariables; 34 | 35 | import mx.collections.ArrayCollection; 36 | import mx.collections.Sort; 37 | import mx.collections.SortField; 38 | import mx.events.CollectionEvent; 39 | import mx.events.CollectionEventKind; 40 | import mx.events.PropertyChangeEvent; 41 | import mx.events.Request; 42 | import mx.rpc.AsyncToken; 43 | 44 | import org.osmf.utils.URL; 45 | 46 | [Bindable("propertyChange")] 47 | public dynamic class GalleryItem extends GalleryResource { 48 | private var _isLoading:Boolean = false; 49 | private var _isLoadingThumbnail:Boolean = false; 50 | private var _thumbnailData: BitmapData = null; 51 | 52 | public function GalleryItem() { 53 | super(); 54 | } 55 | 56 | public function get id(): int { 57 | return this.entity.id; 58 | } 59 | 60 | public function get canEdit(): Boolean { 61 | return this.entity.can_edit; 62 | } 63 | 64 | public function get albumCover(): String { 65 | return this.entity.album_cover; 66 | } 67 | public function set albumCover(value:String): void { 68 | this.entity.album_cover = value; 69 | } 70 | 71 | public function get captured(): Date { 72 | var date: Date = new Date(); 73 | date.setTime(this.entity.captured * 1000); 74 | return date; 75 | } 76 | public function set captured(value: Date): void { 77 | this.entity.captured = Math.round(value.getTime() / 1000); 78 | } 79 | 80 | public function get created(): Date { 81 | var date: Date = new Date(); 82 | date.setTime(this.entity.created * 1000); 83 | return date; 84 | } 85 | 86 | public function get description(): String { 87 | return this.entity.description; 88 | } 89 | public function set description(value:String): void { 90 | this.entity.description = value; 91 | } 92 | 93 | public function get fullsizeUrl(): String { 94 | return this.entity.fullsize_url; 95 | } 96 | 97 | public function get height(): String { 98 | return this.entity.height; 99 | } 100 | public function set height(value:String): void { 101 | this.entity.height = value; 102 | } 103 | 104 | public function get mimeType(): String { 105 | return this.entity.mime_type; 106 | } 107 | public function set mimeType(value:String): void { 108 | this.entity.mime_type = value; 109 | } 110 | 111 | public function get name(): String { 112 | return this.entity.name; 113 | } 114 | public function set name(value:String): void { 115 | this.entity.name = value; 116 | } 117 | 118 | public function get parent(): String { 119 | return this.entity.parent; 120 | } 121 | public function set parent(value:String): void { 122 | this.entity.parent = value; 123 | } 124 | 125 | public function get randKey(): String { 126 | return this.entity.rand_key; 127 | } 128 | public function set randKey(value:String): void { 129 | this.entity.rand_key = value; 130 | } 131 | 132 | public function get resizeDirty(): Boolean { 133 | return this.entity.resize_dirty; 134 | } 135 | public function set resizeDirty(value:Boolean): void { 136 | this.entity.resize_dirty = value; 137 | } 138 | 139 | public function get resizeHeight(): Number { 140 | return Number(this.entity.resize_height); 141 | } 142 | public function set resizeHeight(value:Number): void { 143 | this.entity.resize_height = value; 144 | } 145 | 146 | public function get resizeUrl(): String { 147 | return this.entity.resize_url; 148 | } 149 | 150 | public function get resizeWidth(): Number { 151 | return Number(this.entity.resize_width); 152 | } 153 | public function set resizeWidth(value:Number): void { 154 | this.entity.resize_width = value; 155 | } 156 | 157 | public function get slug(): String { 158 | return this.entity.slug; 159 | } 160 | public function set slug(value:String): void { 161 | this.entity.slug = value; 162 | } 163 | 164 | [Bindable(event=PropertyChangeEvent.PROPERTY_CHANGE)] 165 | public function get thumbnailData(): BitmapData { 166 | if (_thumbnailData == null && !_isLoadingThumbnail) { 167 | if (!_isLoadingThumbnail) { 168 | _isLoadingThumbnail = true; 169 | var loader:Loader = new Loader(); 170 | var self:GalleryItem = this; 171 | loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(event:Event): void { 172 | _thumbnailData = Bitmap(loader.content).bitmapData.clone(); 173 | dispatchEvent(PropertyChangeEvent.createUpdateEvent(self, "thumbnailData", null, _thumbnailData)); 174 | _isLoadingThumbnail = false; 175 | }); 176 | loader.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS, function(event:HTTPStatusEvent): void { 177 | _isLoadingThumbnail = false; 178 | if (event.status != 200 && event.status != 404) { 179 | // log the error, but don't display an error... the user will just see the default image 180 | trace(event.status + ": " + GalleryRestRequest.HTTP_STATUS); 181 | } 182 | }); 183 | loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent): void { 184 | // log the error, but don't display an error... the user will just see the default image 185 | trace(event.text); 186 | }); 187 | 188 | // If there's a public url, use that because it'll be faster. Else make a RESTful request 189 | // to the data resource. 190 | if (thumbUrlPublic) { 191 | loader.load(new URLRequest(thumbUrlPublic)); 192 | } else { 193 | // @todo: refactor this into GalleryRestRequest 194 | var req:URLRequest = new URLRequest(thumbUrl); 195 | req.method = URLRequestMethod.POST; 196 | req.requestHeaders = [ 197 | new URLRequestHeader("Accept", "*/*"), 198 | new URLRequestHeader("Cache-Control", "no-cache"), 199 | new URLRequestHeader(GalleryRestRequest.METHOD_HEADER, "GET"), 200 | new URLRequestHeader(GalleryRestRequest.KEY_HEADER, GalleryRestRequest.accessKey) 201 | ]; 202 | var url:URL = new URL(thumbUrl); 203 | var size:String = url.getParamValue("size"); 204 | var urlVariables:URLVariables = new URLVariables(); 205 | urlVariables.size = size; 206 | req.data = urlVariables; 207 | loader.load(req); 208 | } 209 | } 210 | } 211 | return _thumbnailData; 212 | } 213 | 214 | public function get thumbHeight(): Number { 215 | return Number(this.entity.thumb_height); 216 | } 217 | public function set thumbHeight(value:Number): void { 218 | this.entity.thumb_height = value; 219 | } 220 | 221 | public function get thumbUrl(): String { 222 | return this.entity.thumb_url; 223 | } 224 | 225 | public function get thumbUrlPublic(): String { 226 | return this.entity.thumb_url_public; 227 | } 228 | 229 | public function get thumbWidth(): Number { 230 | return Number(this.entity.thumb_width); 231 | } 232 | public function set thumbWidth(value:Number): void { 233 | this.entity.thumb_width = value; 234 | } 235 | 236 | public function get title(): String { 237 | return this.entity.title; 238 | } 239 | public function set title(value:String): void { 240 | this.entity.title = value; 241 | } 242 | 243 | public function get type(): String { 244 | return this.entity.type; 245 | } 246 | public function set type(value:String): void { 247 | this.entity.type = value; 248 | } 249 | 250 | public function get updatedDate(): Date { 251 | var date: Date = new Date(); 252 | date.setTime(this.entity.updated * 1000); 253 | return date; 254 | } 255 | 256 | public function get viewCount(): Number { 257 | return Number(this.entity.view_count); 258 | } 259 | public function set viewCount(value:Number): void { 260 | this.entity.view_count = value; 261 | } 262 | 263 | public function get weight(): Number { 264 | return Number(this.entity.weight); 265 | } 266 | public function set weight(value:Number): void { 267 | this.entity.weight = value; 268 | } 269 | 270 | public function get width(): Number { 271 | return Number(this.entity.width); 272 | } 273 | public function set width(value:Number): void { 274 | this.entity.width = value; 275 | } 276 | 277 | public function get isLoading(): Boolean { 278 | return this._isLoading; 279 | } 280 | public function set isLoading(value:Boolean): void { 281 | this._isLoading = value; 282 | } 283 | 284 | public function get label(): String { 285 | return title; 286 | } 287 | 288 | public function loadFile(): GalleryRestToken { 289 | var token: GalleryRestToken = new GalleryRestToken(); 290 | var self: GalleryItem = this; 291 | this.file.addEventListener(Event.COMPLETE, function(event: Event): void { 292 | token.resource = self; 293 | }); 294 | this.file.load(); 295 | return token; 296 | } 297 | } 298 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/skins/GalleryTitleWindowSkin.mxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | import org.gallery3.organize.OrganizeStyle; 17 | [Bindable] 18 | private var foreColor:uint = OrganizeStyle.instance.color; 19 | [Bindable] 20 | private var backgroundColor:uint = OrganizeStyle.instance.backgroundColor; 21 | [Bindable] 22 | private var backgroundDownColor:uint = OrganizeStyle.instance.backgroundColor - 0x111111; 23 | [Bindable] 24 | private var selectedColor:uint = OrganizeStyle.instance.selectionColor; 25 | [Bindable] 26 | private var hoverColor:uint = OrganizeStyle.instance.rollOverColor; 27 | [Bindable] 28 | private var borderColor:uint = OrganizeStyle.instance.borderColor; 29 | 30 | /* Define the skin elements that should not be colorized. 31 | For panel, border and title background are skinned, but the content area and title text are not. */ 32 | static private const exclusions:Array = []; 33 | 34 | /** 35 | * @private 36 | */ 37 | override public function get colorizeExclusions():Array {return exclusions;} 38 | 39 | /** 40 | * @private 41 | */ 42 | override protected function initializationComplete():void { 43 | useChromeColor = true; 44 | super.initializationComplete(); 45 | } 46 | 47 | /** 48 | * @private 49 | */ 50 | override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void 51 | { 52 | if (getStyle("borderVisible") == true) { 53 | border.visible = true; 54 | background.left = background.top = background.right = background.bottom = 1; 55 | contents.left = contents.top = contents.right = contents.bottom = 1; 56 | } else { 57 | border.visible = false; 58 | background.left = background.top = background.right = background.bottom = 0; 59 | contents.left = contents.top = contents.right = contents.bottom = 0; 60 | } 61 | 62 | dropShadow.visible = getStyle("dropShadowVisible"); 63 | 64 | var cr:Number = getStyle("cornerRadius"); 65 | var withControls:Boolean = 66 | (currentState == "disabledWithControlBar" || 67 | currentState == "normalWithControlBar" || 68 | currentState == "inactiveWithControlBar"); 69 | 70 | if (cornerRadius != cr) { 71 | cornerRadius = cr; 72 | 73 | dropShadow.tlRadius = cornerRadius; 74 | dropShadow.trRadius = cornerRadius; 75 | dropShadow.blRadius = withControls ? cornerRadius : 0; 76 | dropShadow.brRadius = withControls ? cornerRadius : 0; 77 | 78 | setPartCornerRadii(topMaskRect, withControls); 79 | setPartCornerRadii(border, withControls); 80 | setPartCornerRadii(background, withControls); 81 | } 82 | 83 | if (bottomMaskRect) { 84 | setPartCornerRadii(bottomMaskRect, withControls); 85 | } 86 | 87 | super.updateDisplayList(unscaledWidth, unscaledHeight); 88 | } 89 | 90 | /** 91 | * @private 92 | */ 93 | private function setPartCornerRadii(target:Rect, includeBottom:Boolean): void { 94 | target.topLeftRadiusX = cornerRadius; 95 | target.topRightRadiusX = cornerRadius; 96 | target.bottomLeftRadiusX = includeBottom ? cornerRadius : 0; 97 | target.bottomRightRadiusX = includeBottom ? cornerRadius : 0; 98 | } 99 | 100 | private var cornerRadius:Number; 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 215 | 216 | 217 | 222 | 223 | 224 | 225 | 226 | 227 | 229 | 230 | 231 | 232 | 233 | 238 | 239 | 240 | 248 | 249 | 250 | 258 | 259 | 260 | 261 | 266 | 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /Gallery3Api/src/org/gallery3/api/GalleryRestRequest.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | * 19 | * This code is based on the work of Mike Stead (http://blog.mikestead.me/category/actionscript-3-0/) 20 | * 21 | */ 22 | package org.gallery3.api { 23 | import com.adobe.serialization.json.JSON; 24 | import com.adobe.utils.StringUtil; 25 | 26 | import flash.events.Event; 27 | import flash.events.HTTPStatusEvent; 28 | import flash.events.IEventDispatcher; 29 | import flash.events.IOErrorEvent; 30 | import flash.events.ProgressEvent; 31 | import flash.events.SecurityErrorEvent; 32 | import flash.net.URLLoader; 33 | import flash.net.URLRequest; 34 | import flash.net.URLRequestHeader; 35 | import flash.net.URLRequestMethod; 36 | import flash.net.URLVariables; 37 | import flash.utils.ByteArray; 38 | 39 | import mx.messaging.messages.HTTPRequestMessage; 40 | import mx.rpc.Fault; 41 | 42 | public class GalleryRestRequest { 43 | public static var HTTP_STATUS: Object = { 44 | "100": "Continue", 45 | "200": "Ok", 46 | "302": "Found", 47 | "304": "Not Modified", 48 | "400": "Bad Request", 49 | "401": "Unauthorized", 50 | "403": "Forbidden", 51 | "404": "Not Found", 52 | "405": "Method Not Allowed", 53 | "500": "Internal Server Error" 54 | } 55 | public static const METHOD_HEADER: String = "X-Gallery-Request-Method"; 56 | public static const KEY_HEADER: String = "X-Gallery-Request-Key"; 57 | private static const MULTIPART_BOUNDARY: String = "----------196f00b77b968397849367c61a2080"; 58 | private static const MULTIPART_MARK: String = "--"; 59 | private static const LF: String = "\r\n"; 60 | 61 | private static var _baseUrl: String; 62 | private static var _accessKey: String; 63 | 64 | public static function get baseURL(): String { 65 | if (_baseUrl == null) { 66 | throw new Error("REST interface base URL has not been set"); 67 | } 68 | return _baseUrl; 69 | } 70 | public static function set baseURL(url: String): void { 71 | _baseUrl = url; 72 | } 73 | 74 | public static function get accessKey(): String { 75 | if (_accessKey == null) { 76 | throw new Error("REST interface access key has not been set"); 77 | } 78 | return _accessKey; 79 | } 80 | public static function set accessKey(accessKey: String): void { 81 | _accessKey = accessKey; 82 | } 83 | 84 | public static function factory(accessKey: String=null): GalleryRestRequest { 85 | return new GalleryRestRequest(accessKey); 86 | } 87 | 88 | private var _contentType: String = null; 89 | private var _data: URLVariables = new URLVariables; 90 | private var _digest: String = null; 91 | private var _method: String = URLRequestMethod.GET; 92 | private var _uri: String = null; 93 | private var _requestHeaders: Array = new Array(); 94 | private var _requestAccessKey: String = null; 95 | 96 | public function GalleryRestRequest(accessKey: String=null) { 97 | _requestAccessKey = accessKey == null ? GalleryRestRequest.accessKey : accessKey; 98 | } 99 | 100 | public function get data(): URLVariables {return _data;} 101 | public function setData(value: URLVariables): GalleryRestRequest { 102 | _data = value != null ? value : new URLVariables(); 103 | return this; 104 | } 105 | 106 | public function get digest(): String {return _digest;} 107 | public function setDigest(value: String): GalleryRestRequest { 108 | _digest = value; 109 | return this; 110 | } 111 | 112 | public function get method(): String {return _method;} 113 | public function setMethod(value: String): GalleryRestRequest { 114 | _method = value; 115 | return this; 116 | } 117 | 118 | public function get url(): String {return _method;} 119 | public function setUrl(value: String): GalleryRestRequest { 120 | _uri = value.substr(baseURL.length); 121 | return this; 122 | } 123 | 124 | public function get uri(): String {return _uri;} 125 | public function setUri(value: String): GalleryRestRequest { 126 | _uri = value; 127 | return this; 128 | } 129 | 130 | public function sendRequest(responseHandler: Function=null): GalleryRestToken { 131 | var token: GalleryRestToken = new GalleryRestToken(); 132 | token.action = method; 133 | token.uri = uri; 134 | 135 | var loader: URLLoader = new URLLoader(); 136 | loader.addEventListener(Event.COMPLETE, function(event:Event): void { 137 | if (responseHandler != null) { 138 | responseHandler(token, loader.data); 139 | } else { 140 | token.data = loader.data; 141 | token.resource = null; 142 | } 143 | }); 144 | loader.addEventListener(ProgressEvent.PROGRESS, function(event: ProgressEvent): void { 145 | token.dispatchEvent(event); 146 | }); 147 | loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, function (event:HTTPStatusEvent): void { 148 | token.statusText = HTTP_STATUS[event.status]; 149 | token.statusCode = event.status; 150 | }); 151 | loader.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent): void { 152 | var fault: Fault; 153 | if (token.statusCode == 0) { 154 | // Seem to get this branch when we try to upload files. Not consistently 155 | var pattern: RegExp = /^Error #(\d+):\s(.*\.)\s(.*)$/; 156 | var parts: Array = pattern.exec(event.text); 157 | fault = new Fault(parts[1], parts[2], parts[3]); 158 | } else { 159 | if (loader.data != null) { 160 | fault = new Fault(token.statusCode, token.statusText, event.text); 161 | fault.content = JSON.decode(String(loader.data)) as Object; 162 | } else { 163 | fault = new Fault(token.statusCode, token.statusText, event.text); 164 | } 165 | } 166 | loader.close(); 167 | fault.rootCause = event; 168 | token.applyFault(fault); 169 | }); 170 | loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(event:SecurityErrorEvent): void { 171 | var fault: Fault = new Fault(token.statusCode, token.statusText, loader.data != null ? loader.data : event.text); 172 | fault.rootCause = event; 173 | loader.close(); 174 | token.applyFault(fault); 175 | }); 176 | loader.load(_createRequest()); 177 | 178 | return token; 179 | } 180 | 181 | private function _createRequest(): URLRequest { 182 | var request: URLRequest = new URLRequest(baseURL + uri); 183 | request.method = URLRequestMethod.POST; 184 | if (_digest != null) { 185 | request.digest = _digest; 186 | } 187 | 188 | var isMultipartData: Boolean = false; 189 | var hasData: Boolean = false; 190 | for each (var variable:* in _data) { 191 | hasData = true; 192 | if (variable is URLFileVariable) { 193 | isMultipartData = true; 194 | } 195 | } 196 | 197 | if (!hasData) { 198 | _data.noop = 1; 199 | } 200 | request.requestHeaders = [ 201 | new URLRequestHeader("Accept", "*/*"), 202 | new URLRequestHeader("Cache-Control", "no-cache"), 203 | new URLRequestHeader(METHOD_HEADER, _method), 204 | new URLRequestHeader(KEY_HEADER, _requestAccessKey) 205 | ]; 206 | if (isMultipartData) { 207 | request.data = _buildMultipartBody(); 208 | _addMultipartHeadersTo(request); 209 | } else { 210 | request.data = _data; 211 | } 212 | 213 | return request; 214 | } 215 | 216 | /** 217 | * Build a ByteArray instance containing the multipart/form-data encoded URLVariables. 218 | * 219 | * @return ByteArray containing the encoded variables 220 | */ 221 | private function _buildMultipartBody(): ByteArray { 222 | var body:ByteArray = new ByteArray(); 223 | 224 | // Write each encoded field into the request body 225 | for (var id:String in _data) { 226 | body.writeBytes(_encodeMultipartVariable(id, _data[id])); 227 | } 228 | 229 | // Mark the end of the request body 230 | // Note, we writeUTFBytes and not writeUTF because it can corrupt parsing on the server 231 | body.writeUTFBytes(MULTIPART_MARK + MULTIPART_BOUNDARY + MULTIPART_MARK + LF); 232 | return body; 233 | } 234 | 235 | /** 236 | * Encode a variable using multipart/form-data. 237 | * 238 | * @param id The unique id of the variable 239 | * @param value The value of the variable 240 | */ 241 | private function _encodeMultipartVariable(id:String, variable:Object): ByteArray { 242 | return variable is URLFileVariable ? 243 | _encodeMultipartFile(id, URLFileVariable(variable)) : 244 | _encodeMultipartString(id, variable.toString()); 245 | } 246 | 247 | /** 248 | * Encode a file using multipart/form-data. 249 | * 250 | * @param id The unique id of the file variable 251 | * @param file The URLFileVariable containing the file name and file data 252 | * 253 | * @return The encoded variable 254 | */ 255 | private function _encodeMultipartFile(id:String, file:URLFileVariable): ByteArray { 256 | var field:ByteArray = new ByteArray(); 257 | // Note, we writeUTFBytes and not writeUTF because it can corrupt parsing on the server 258 | field.writeUTFBytes(MULTIPART_MARK + MULTIPART_BOUNDARY + LF + 259 | "Content-Disposition: form-data; name=\"" + id + "\"; " + 260 | "filename=\"" + file.name + "\"" + LF + 261 | // "Content-Type: image/png" + LF + LF); 262 | "Content-Type: application/octet-stream" + LF + LF); 263 | 264 | field.writeBytes(file.data); 265 | field.writeUTFBytes(LF); 266 | field.position = 0; 267 | return field; 268 | } 269 | 270 | /** 271 | * Encode a string using multipart/form-data. 272 | * 273 | * @param id The unique id of the string 274 | * @param text The value of the string 275 | * 276 | * @return The encoded variable 277 | */ 278 | private function _encodeMultipartString(id:String, text:String): ByteArray { 279 | var field:ByteArray = new ByteArray(); 280 | // Note, we writeUTFBytes and not writeUTF because it can corrupt parsing on the server 281 | field.writeUTFBytes(MULTIPART_MARK + MULTIPART_BOUNDARY + LF + 282 | "Content-Disposition: form-data; name=\"" + id + "\"" + LF + LF + 283 | text + LF); 284 | return field; 285 | } 286 | 287 | /** 288 | * Add the relevant multipart/form-data headers to a URLRequest. 289 | */ 290 | private function _addMultipartHeadersTo(request:URLRequest): void { 291 | request.requestHeaders.push( 292 | new URLRequestHeader("Content-Type", "multipart/form-data; boundary=" + MULTIPART_BOUNDARY) 293 | ); 294 | 295 | // Note, the headers: Content-Length and Connection:Keep-Alive are auto set by URLRequest 296 | } 297 | } 298 | } -------------------------------------------------------------------------------- /Gallery3Api/src/org/gallery3/api/GalleryAlbum.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.api { 20 | import com.adobe.serialization.json.JSON; 21 | import com.adobe.utils.ArrayUtil; 22 | 23 | import flash.events.Event; 24 | import flash.net.URLVariables; 25 | import flash.utils.flash_proxy; 26 | 27 | import mx.collections.ArrayCollection; 28 | import mx.collections.ICollectionView; 29 | import mx.collections.IList; 30 | import mx.collections.IViewCursor; 31 | import mx.collections.Sort; 32 | import mx.collections.SortField; 33 | import mx.events.CollectionEvent; 34 | import mx.events.CollectionEventKind; 35 | import mx.events.PropertyChangeEvent; 36 | import mx.events.PropertyChangeEventKind; 37 | import mx.rpc.Fault; 38 | import mx.rpc.events.FaultEvent; 39 | import mx.utils.ArrayUtil; 40 | import mx.utils.ObjectUtil; 41 | 42 | use namespace flash_proxy; 43 | 44 | [Event(name="collectionChange", type="mx.events.CollectionEvent")] 45 | [Bindable("propertyChange")] 46 | [Bindable("collectionChange")] 47 | public dynamic class GalleryAlbum extends GalleryItem implements IList, ICollectionView { 48 | private var _childrenLoaded: Boolean = false; 49 | private var _albumsLoaded: Boolean = false; 50 | private var _children:ArrayCollection = new ArrayCollection(); 51 | private var _albums:ArrayCollection = new ArrayCollection(); 52 | 53 | public function GalleryAlbum() { 54 | super(); 55 | this.members = new ArrayCollection(); 56 | var self: GalleryAlbum = this; 57 | _children.addEventListener(CollectionEvent.COLLECTION_CHANGE, 58 | function(event: CollectionEvent): void { 59 | var newEvent: CollectionEvent = 60 | new CollectionEvent(CollectionEvent.COLLECTION_CHANGE, event.bubbles, event.cancelable, event.kind, 61 | event.location, event.oldLocation, event.items); 62 | self.dispatchEvent(newEvent); 63 | }); 64 | } 65 | 66 | public function get sortColumn(): String { 67 | return this.entity.sort_column; 68 | } 69 | public function set sortColumn(value:String): void { 70 | this.entity.sort_column = value; 71 | } 72 | 73 | public function get sortOrder(): String { 74 | return this.entity.sort_order; 75 | } 76 | public function set sortOrder(value:String): void { 77 | this.entity.sort_order = value; 78 | } 79 | 80 | flash_proxy override function getProperty(name: *): * { 81 | switch (name.localName) { 82 | case "label": 83 | return super.getProperty("title") + " (" + super.getProperty("members").length + ")"; 84 | case "albums": 85 | if ((!_albumsLoaded && (this.members.source as Array).length > 0)) { 86 | loadAlbums(); 87 | } 88 | return _albums; 89 | case "children": 90 | if ((!_childrenLoaded && (this.members.source as Array).length > 0)) { 91 | loadChildren(); 92 | } 93 | return _children; 94 | default: 95 | // Do nothing; 96 | break; 97 | } 98 | return super.getProperty(name); 99 | } 100 | 101 | flash_proxy override function setProperty(name: *, value: *): void { 102 | if (name == "albums") { 103 | var oldValue: * = _albums; 104 | _albums = value; 105 | var kind:String = PropertyChangeEventKind.UPDATE; 106 | dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE, false, false, kind, name, oldValue, value, this)); 107 | } else { 108 | super.setProperty(name, value); 109 | } 110 | } 111 | 112 | public function insert(at:int, items: Vector.): void { 113 | for (var idx: int=at; items.length > 0; idx++) { 114 | var item: GalleryItem = items.shift(); 115 | this.members.addItemAt(item.url, idx); 116 | } 117 | sortColumn = "weight"; 118 | sortOrder = "ASC"; 119 | } 120 | 121 | /** 122 | * @see mx.collections.ICollectionView#refresh() 123 | */ 124 | public override function refreshResource(): GalleryRestToken { 125 | var token: GalleryRestToken = super.refreshResource(); 126 | var self: GalleryAlbum = this; 127 | token.addResponder(new GalleryRestResponder( 128 | function (resource: Object): void { 129 | loadChildren(); 130 | loadAlbums(); 131 | }, 132 | function (fault: Fault): void { 133 | isLoading = false; 134 | token.dispatchEvent(new FaultEvent(FaultEvent.FAULT, false, true, fault)); 135 | })); 136 | return token; 137 | } 138 | 139 | public function loadChildren():void { 140 | if (!isLoading) { 141 | isLoading = true; 142 | 143 | if (this.members.length > 0) { 144 | var params: URLVariables = new URLVariables(); 145 | params.urls = JSON.encode(this.members.source); 146 | 147 | var token: GalleryRestToken = GalleryResource.loadResource("items", params); 148 | var self: GalleryAlbum = this; 149 | token.addResponder(new GalleryRestResponder( 150 | function (resource: Object): void { 151 | _updateChildren(resource); 152 | }, 153 | function (fault: Fault): void { 154 | isLoading = false; 155 | // @todo just throw it now and let flex's global error handler deal with it 156 | // in a future release, they will probably have some kind glabal error handler. 157 | throw fault; 158 | })); 159 | } else { 160 | _updateChildren(); 161 | } 162 | } 163 | } 164 | 165 | public function loadAlbums():void { 166 | if (this.members.length > 0) { 167 | var params: URLVariables = new URLVariables(); 168 | params.urls = JSON.encode(this.members.source); 169 | params.type = "album"; 170 | var token: GalleryRestToken = GalleryResource.loadResource("items", params); 171 | token.addResponder(new GalleryRestResponder( 172 | function (resource: Object): void { 173 | _updateAlbums(resource); 174 | }, 175 | function (fault: Fault): void { 176 | // @todo just throw it now and let flex's global error handler deal with it 177 | // in a future release, they will probably have some kind glabal error handler. 178 | throw fault; 179 | })); 180 | } else { 181 | _updateAlbums(); 182 | } 183 | _albumsLoaded = true; 184 | } 185 | 186 | private function _updateChildren(items:Object=null):void { 187 | isLoading = false; 188 | _childrenLoaded = true; 189 | _children.removeAll(); 190 | for each (var element:Object in items) { 191 | _children.addItem(element); 192 | } 193 | } 194 | 195 | private function _updateAlbums(items:Object=null):void { 196 | _albums.removeAll(); 197 | for each (var element:Object in items) { 198 | _albums.addItem(element); 199 | } 200 | _albums.dispatchEvent(new Event("AlbumLoaded", true)); 201 | } 202 | 203 | //-------------------------------------------------------------------------- 204 | // ICollectionView Interface Implementation 205 | //-------------------------------------------------------------------------- 206 | /** 207 | * @see mx.collections.ICollectionView#filterFunction() 208 | */ 209 | public function get filterFunction():Function { 210 | return _children.filterFunction; 211 | } 212 | 213 | /** 214 | * @see mx.collections.ICollectionView#filterFunction() 215 | * @private 216 | */ 217 | public function set filterFunction(value:Function):void { 218 | _children.filterFunction = value; 219 | } 220 | 221 | /** 222 | * @see mx.collections.ICollectionView#sort() 223 | */ 224 | public function get sort():Sort { 225 | return _children.sort; 226 | } 227 | 228 | /** 229 | * @see mx.collections.ICollectionView#sort() 230 | * @private 231 | */ 232 | public function set sort(value:Sort):void { 233 | _children.sort = value; 234 | } 235 | 236 | /** 237 | * @see mx.collections.ICollectionView#createCursor() 238 | */ 239 | public function createCursor():IViewCursor { 240 | return _children.createCursor(); 241 | } 242 | 243 | /** 244 | * @see mx.collections.ICollectionView#contains() 245 | */ 246 | public function contains(item:Object):Boolean { 247 | return _children.contains(item); 248 | } 249 | 250 | /** 251 | * @see mx.collections.ICollectionView#disableAutoUpdate() 252 | */ 253 | public function disableAutoUpdate():void { 254 | _children.disableAutoUpdate(); 255 | } 256 | 257 | /** 258 | * @see mx.collections.ICollectionView#enableAutoUpdate() 259 | */ 260 | public function enableAutoUpdate():void { 261 | _children.enableAutoUpdate(); 262 | } 263 | 264 | /** 265 | * @see mx.collections.ICollectionView#refresh() 266 | */ 267 | public function refresh():Boolean { 268 | loadChildren(); 269 | return true; 270 | } 271 | 272 | //-------------------------------------------------------------------------- 273 | // IList Interface Implementation 274 | //-------------------------------------------------------------------------- 275 | /** 276 | * @see mx.collections.ICollectionView#length() 277 | * @see mx.collections.IList#length() 278 | */ 279 | public function get length():int { 280 | return isLoading ? -1: this._children.length; 281 | } 282 | 283 | /** 284 | * @see mx.collections.IList#addItem() 285 | */ 286 | public function addItem(item:Object):void { 287 | addItemAt(item, _children.length); 288 | } 289 | 290 | /** 291 | * @see mx.collections.IList 292 | */ 293 | public function addItemAt(item:Object, index:int):void { 294 | this.members.addItemAt(item.url, index); 295 | this._children.addItemAt(item, index); 296 | itemUpdated(item); 297 | } 298 | 299 | /** 300 | * @see mx.collections.IList 301 | */ 302 | public function getItemAt(index:int, prefetch:int = 0):Object { 303 | return this._children.getItemAt(index, prefetch); 304 | } 305 | 306 | /** 307 | * @see mx.collections.IList 308 | */ 309 | public function getItemIndex(item:Object):int { 310 | return this._children.getItemIndex(item); 311 | } 312 | 313 | /** 314 | * @see mx.collections.ICollectionView#itemUpdated() 315 | * @see mx.collections.IList 316 | */ 317 | public function itemUpdated(item:Object, property:Object = null, 318 | oldValue:Object = null, 319 | newValue:Object = null):void { 320 | _children.itemUpdated(item, property, oldValue, newValue); 321 | } 322 | 323 | /** 324 | * @see mx.collections.IList#removeAll() 325 | * 326 | * Note: This does not update the remote server, its effect is only local. 327 | */ 328 | public function removeAll():void { 329 | _children.removeAll(); 330 | } 331 | 332 | /** 333 | * @see mx.collections.IList#removeItemAt() 334 | * 335 | * Note: This doesn't update the remote server, its effect is only local. 336 | */ 337 | public function removeItemAt(index:int):Object { 338 | this.members.removeItemAt(index); 339 | var o:GalleryItem = _children.removeItemAt(index) as GalleryItem; 340 | itemUpdated(o); 341 | return o; 342 | } 343 | 344 | /** 345 | * @see mx.collections.IList#setItemAt() 346 | * 347 | * Note: This does not update the remote server, its effect is only local. 348 | */ 349 | public function setItemAt(item:Object, index:int):Object { 350 | this.members.setItemAt(item.url, index); 351 | var o:GalleryItem = _children.setItemAt(item, index) as GalleryItem; 352 | 353 | itemUpdated(o); 354 | return o; 355 | } 356 | 357 | /** 358 | * @see mx.collections.IList 359 | */ 360 | public function toArray():Array { 361 | return _children.toArray(); 362 | } 363 | } 364 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/PaddedTileLayout.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize.components { 20 | import flash.geom.Point; 21 | import flash.geom.Rectangle; 22 | 23 | import mx.core.ILayoutElement; 24 | import mx.core.IVisualElement; 25 | 26 | import spark.components.DataGroup; 27 | import spark.components.List; 28 | import spark.components.supportClasses.GroupBase; 29 | import spark.layouts.supportClasses.DropLocation; 30 | import spark.layouts.supportClasses.LayoutBase; 31 | 32 | public class PaddedTileLayout extends LayoutBase { 33 | private var _previousRenderer: Object = null; 34 | //--------------------------------------------------------------- 35 | // 36 | // Class properties 37 | // 38 | //--------------------------------------------------------------- 39 | private var _usableWidth:Number 40 | private var _dropIndicator:DropIndicator; 41 | 42 | //--------------------------------------------------------------- 43 | // columnWidth 44 | //--------------------------------------------------------------- 45 | private var _columnCount:Number; 46 | public function get columnCount(): Number { 47 | return _columnCount; 48 | } 49 | 50 | //--------------------------------------------------------------- 51 | // columnWidth 52 | //--------------------------------------------------------------- 53 | private var _columnWidth:Number = 100; 54 | public function get columnWidth(): Number { 55 | return _columnWidth; 56 | } 57 | public function set columnWidth(value:Number): void { 58 | _columnWidth = value; 59 | 60 | // We must invalidate the layout 61 | var layoutTarget:GroupBase = target; 62 | if (layoutTarget) { 63 | layoutTarget.invalidateSize(); 64 | layoutTarget.invalidateDisplayList(); 65 | } 66 | } 67 | 68 | //--------------------------------------------------------------- 69 | // rowHeight 70 | //--------------------------------------------------------------- 71 | private var _rowHeight:Number = 10; 72 | public function get rowHeight(): Number { 73 | return _rowHeight; 74 | } 75 | public function set rowHeight(value:Number): void { 76 | _rowHeight = value; 77 | 78 | // We must invalidate the layout 79 | var layoutTarget:GroupBase = target; 80 | if (layoutTarget) { 81 | layoutTarget.invalidateSize(); 82 | layoutTarget.invalidateDisplayList(); 83 | } 84 | } 85 | 86 | //--------------------------------------------------------------- 87 | // rowCount 88 | //--------------------------------------------------------------- 89 | private var _rowCount:Number; 90 | public function get rowCount(): Number { 91 | return _rowCount; 92 | } 93 | 94 | //--------------------------------------------------------------- 95 | // horizontalGap 96 | //--------------------------------------------------------------- 97 | private var _horizontalGap:Number = 10; 98 | private var _measuredHGap:Number = -1; 99 | public function get horizontalGap(): Number { 100 | return _measuredHGap == -1 ? _horizontalGap : _measuredHGap; 101 | } 102 | public function set horizontalGap(value:Number): void { 103 | _horizontalGap = value; 104 | 105 | // We must invalidate the layout 106 | var layoutTarget:GroupBase = target; 107 | if (layoutTarget) { 108 | layoutTarget.invalidateSize(); 109 | layoutTarget.invalidateDisplayList(); 110 | } 111 | } 112 | 113 | //--------------------------------------------------------------- 114 | // verticalGap 115 | //--------------------------------------------------------------- 116 | private var _verticalGap:Number = 10; 117 | public function get verticalGap(): Number { 118 | return _verticalGap; 119 | } 120 | public function set verticalGap(value:Number): void { 121 | _verticalGap = value; 122 | 123 | // We must invalidate the layout 124 | var layoutTarget:GroupBase = target; 125 | if (layoutTarget) { 126 | layoutTarget.invalidateSize(); 127 | layoutTarget.invalidateDisplayList(); 128 | } 129 | } 130 | 131 | //--------------------------------------------------------------- 132 | // verticalAlign 133 | //--------------------------------------------------------------- 134 | private var _verticalAlign:String = "bottom"; 135 | public function set verticalAlign(value:String): void { 136 | _verticalAlign = value; 137 | 138 | // We must invalidate the layout 139 | var layoutTarget:GroupBase = target; 140 | if (layoutTarget) { 141 | layoutTarget.invalidateSize(); 142 | layoutTarget.invalidateDisplayList(); 143 | } 144 | } 145 | 146 | //--------------------------------------------------------------- 147 | // horizontalAlign 148 | //--------------------------------------------------------------- 149 | private var _horizontalAlign:String = "left"; // center, right 150 | 151 | public function set horizontalAlign(value:String): void { 152 | _horizontalAlign = value; 153 | 154 | // We must invalidate the layout 155 | var layoutTarget:GroupBase = target; 156 | if (layoutTarget) { 157 | layoutTarget.invalidateSize(); 158 | layoutTarget.invalidateDisplayList(); 159 | } 160 | } 161 | 162 | //--------------------------------------------------------------- 163 | // 164 | // Class methods 165 | // 166 | //--------------------------------------------------------------- 167 | override public function updateDisplayList(containerWidth:Number, containerHeight:Number): void { 168 | var element:ILayoutElement; 169 | var layoutTarget:GroupBase = target; 170 | var count:int = layoutTarget.numElements; 171 | 172 | _usableWidth = containerWidth - 2 * _horizontalGap; 173 | _columnCount = Math.floor(_usableWidth / (_columnWidth + _horizontalGap)); 174 | _rowCount = Math.ceil(count / _columnCount); 175 | 176 | if (_horizontalAlign == "justify") { 177 | _measuredHGap = _horizontalGap + (_usableWidth - (_columnCount * (_columnWidth + _horizontalGap))) / (_columnCount + 1); 178 | } else { 179 | _measuredHGap = -1; 180 | } 181 | // The position for the current element 182 | var x:Number = 0; 183 | var y:Number = _verticalGap; 184 | var elementWidth:Number; 185 | var elementHeight:Number; 186 | 187 | var vAlign:Number = 0; 188 | switch (_verticalAlign) { 189 | case "middle" : 190 | vAlign = 0.5; 191 | break; 192 | case "bottom" : 193 | vAlign = 1; 194 | break; 195 | } 196 | 197 | // Keep track of per-row height, maximum row width 198 | var maxRowWidth:Number = 0; 199 | 200 | // loop through the elements 201 | // while we can start a new row 202 | var rowStart:int = 0; 203 | while (rowStart < count) { 204 | var hGap:Number = horizontalGap; 205 | // The row always contains the start element 206 | element = useVirtualLayout ? layoutTarget.getVirtualElementAt(rowStart) : 207 | layoutTarget.getElementAt(rowStart); 208 | 209 | var rowWidth:Number = element.getPreferredBoundsWidth(); 210 | var rowHeight:Number = element.getPreferredBoundsHeight(); 211 | 212 | // Find the end of the current row 213 | var rowEnd:int = rowStart; 214 | while (rowEnd + 1 < count) { 215 | element = useVirtualLayout ? layoutTarget.getVirtualElementAt(rowEnd + 1) : 216 | layoutTarget.getElementAt(rowEnd + 1); 217 | 218 | // Since we haven't resized the element just yet, get its preferred size 219 | elementWidth = element.getPreferredBoundsWidth(); 220 | elementHeight = element.getPreferredBoundsHeight(); 221 | 222 | // Can we add one more element to this row? 223 | if (rowWidth + hGap + elementWidth > _usableWidth) { 224 | break; 225 | } 226 | 227 | rowWidth += hGap + elementWidth; 228 | rowHeight = Math.max(rowHeight, elementHeight); 229 | rowEnd++; 230 | } 231 | 232 | // Update the position to the beginning of the row 233 | x = hGap; 234 | switch (_horizontalAlign) { 235 | case "center" : 236 | x = Math.round(_usableWidth - rowWidth) / 2; 237 | break; 238 | case "right" : 239 | x = _usableWidth - rowWidth; 240 | break; 241 | case "justify" : 242 | } 243 | 244 | // Keep track of the maximum row width so that we can 245 | // set the correct contentSize 246 | maxRowWidth = Math.max(maxRowWidth, x + rowWidth + hGap); 247 | 248 | // Layout all the elements within the row 249 | for (var i:int = rowStart; i <= rowEnd; i++) { 250 | element = useVirtualLayout ? layoutTarget.getVirtualElementAt(i) : 251 | layoutTarget.getElementAt(i); 252 | 253 | // Resize the element to its preferred size by passing 254 | // NaN for the width and height constraints 255 | element.setLayoutBoundsSize(NaN, NaN); 256 | 257 | // Find out the element's dimensions sizes. 258 | // We do this after the element has been already resized 259 | // to its preferred size. 260 | elementWidth = element.getLayoutBoundsWidth(); 261 | elementHeight = element.getLayoutBoundsHeight(); 262 | 263 | // Calculate the position within the row 264 | var elementY:Number = Math.round((rowHeight - elementHeight) * vAlign); 265 | 266 | // Position the element 267 | element.setLayoutBoundsPosition(x, y + elementY); 268 | 269 | x += hGap + elementWidth; 270 | } 271 | 272 | // Next row will start with the first element after the current row's end 273 | rowStart = rowEnd + 1; 274 | 275 | y += rowHeight + _verticalGap; 276 | } 277 | 278 | // Set the content size which determines the scrolling limits 279 | // and is used by the Scroller to calculate whether to show up 280 | // the scrollbars when the the scroll policy is set to "auto" 281 | layoutTarget.setContentSize(maxRowWidth, y); 282 | } 283 | 284 | override protected function calculateDropIndicatorBounds(dropLocation:DropLocation) : Rectangle { 285 | var bounds:Rectangle = new Rectangle(); 286 | bounds.width = 3; 287 | bounds.height = 110; 288 | 289 | var insertPosition: Object = calculateInsertRenderer(dropLocation.dropPoint); 290 | if (insertPosition.renderer) { 291 | if (insertPosition.isBefore) { 292 | bounds.x = insertPosition.renderer.x - (horizontalGap / 2); 293 | } else { 294 | bounds.x = insertPosition.renderer.x + insertPosition.renderer.width + (horizontalGap / 2); 295 | } 296 | bounds.y = insertPosition.renderer.y; 297 | } 298 | 299 | return bounds; 300 | } 301 | 302 | protected function calculateInsertRenderer(dropPoint: Point): Object { 303 | var insertPosition: Object = {renderer: null, isBefore: true, index: -1}; 304 | var renderer: IVisualElement = null; 305 | 306 | var maxWidth: Number = _columnCount * (_columnWidth + _horizontalGap) + _horizontalGap; 307 | var position:Point = new Point(Math.min(dropPoint.x, maxWidth), dropPoint.y); 308 | var dataGroup: DataGroup = DataGroup(target); 309 | for each (var itemIndex:Number in dataGroup.getItemIndicesInView()) { 310 | renderer = dataGroup.getElementAt(itemIndex); 311 | var rendererBounds:Rectangle = new Rectangle(renderer.x, renderer.y, renderer.width, renderer.height); 312 | rendererBounds.inflate(horizontalGap, verticalGap); 313 | if (rendererBounds.containsPoint(position)) { 314 | break; 315 | } 316 | } 317 | if (renderer) { 318 | if (dropPoint.x >= rendererBounds.x + rendererBounds.width / 2) { 319 | insertPosition.isBefore = false; 320 | } 321 | insertPosition.renderer = renderer; 322 | insertPosition.index = itemIndex; 323 | _previousRenderer = insertPosition; 324 | } else { 325 | insertPosition.renderer = insertPosition; 326 | } 327 | return insertPosition; 328 | } 329 | 330 | override protected function calculateDropIndex(x:Number, y:Number) : int { 331 | var insertPosition: Object = calculateInsertRenderer(new Point(x, y)); 332 | 333 | // the return value is in the range 0 - number of elements. 334 | return insertPosition.index + (insertPosition.isBefore ? 0 : 1); 335 | } 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/components/ThumbGrid.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize.components { 20 | import flash.events.Event; 21 | import flash.events.MouseEvent; 22 | import flash.geom.Point; 23 | import flash.geom.Rectangle; 24 | import flash.net.FileReference; 25 | import flash.net.FileReferenceList; 26 | 27 | import mx.core.DragSource; 28 | import mx.core.IFlexDisplayObject; 29 | import mx.events.DragEvent; 30 | import mx.managers.DragManager; 31 | import mx.rpc.Fault; 32 | 33 | import org.gallery3.api.GalleryAlbum; 34 | import org.gallery3.api.GalleryItem; 35 | import org.gallery3.api.GalleryResource; 36 | import org.gallery3.api.GalleryRestResponder; 37 | 38 | import spark.components.Group; 39 | import spark.components.IItemRenderer; 40 | import spark.components.List; 41 | import spark.core.IViewport; 42 | import spark.layouts.supportClasses.DropLocation; 43 | 44 | [States("normal")] 45 | public class ThumbGrid extends List { 46 | private var _lasso:SelectionLasso; 47 | private var _originalSelection:Vector.; 48 | private var _dragStart:Point = null; 49 | private var _tolerance:Number = 5; 50 | private var _isCtrlKey:Boolean = false; 51 | private var _items:Vector.; 52 | 53 | private var _saveQueue: Vector. = new Vector.(); 54 | 55 | public function ThumbGrid() { 56 | super(); 57 | useVirtualLayout = false; 58 | dragMoveEnabled = true; 59 | this.layout = new PaddedTileLayout(); 60 | with (PaddedTileLayout(this.layout)) { 61 | verticalAlign = "middle"; 62 | horizontalAlign = "justify"; 63 | verticalGap = 15; 64 | horizontalGap = 15; 65 | columnWidth = 100; 66 | rowHeight = 110; 67 | } 68 | 69 | addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); 70 | addEventListener(DragEvent.DRAG_START, dragStartHandler); 71 | } 72 | 73 | public function deleteSelected(): void { 74 | if (selectedIndices.length > 0) { 75 | var indices:Vector. = selectedIndices; 76 | var queue: ProcessItemQueue = new ProcessItemQueue(ProcessItemQueue.DELETE_OPERATION); 77 | var album: GalleryAlbum = dataProvider as GalleryAlbum; 78 | for (var i:int=0; i < indices.length; i++) { 79 | queue.addItem({"action": "delete", "item": album.getItemAt(indices[i])}); 80 | } 81 | queue.processQueue( 82 | function(): void { 83 | GalleryAlbum(dataProvider).refreshResource().addResponder(new GalleryRestResponder( 84 | function(resource: Object): void {}, 85 | function (fault: Fault): void { 86 | ErrorDialog.display(fault as Fault); 87 | })); 88 | }); 89 | } 90 | } 91 | 92 | public function onFilesSelected(event:Event, typeMap: Object): void { 93 | var files: FileReferenceList = event.target as FileReferenceList; 94 | var queue: ProcessItemQueue = new ProcessItemQueue(ProcessItemQueue.UPLOAD_OPERATION); 95 | var album: GalleryAlbum = dataProvider as GalleryAlbum; 96 | for each (var fileRef: FileReference in files.fileList) { 97 | var item: GalleryItem = GalleryResource.factory("item") as GalleryItem; 98 | item.url = album.url; // When we add set the url to the parent 99 | item.type = typeMap[fileRef.type.toLowerCase()]; 100 | item.file = fileRef; 101 | item.name = fileRef.name; 102 | queue.addItem({"action": "loadFile", "item": item}); 103 | } 104 | queue.processQueue( 105 | function(): void { 106 | GalleryAlbum(dataProvider).refreshResource().addResponder(new GalleryRestResponder( 107 | function(resource: Object): void {}, 108 | function (fault: Fault): void { 109 | ErrorDialog.display(fault as Fault); 110 | })); 111 | }); 112 | } 113 | 114 | // --------------------------------------------------------------------------- 115 | // Mouse event handlers 116 | // --------------------------------------------------------------------------- 117 | protected function mouseDownHandler(event:MouseEvent): void { 118 | // In the tilelist grid, we are about to either drag or select 119 | var viewPort:IViewport = scroller.viewport; 120 | 121 | // If we are over an actual item, then don't start the lasso 122 | var eventPos:Point = new Point(event.stageX, event.stageY); 123 | if (mouseX <= viewPort.contentWidth) { 124 | _isCtrlKey = event.ctrlKey; 125 | if (_rendererUnderMouse(eventPos) == null) { 126 | var parent:Group = this.parent as Group; 127 | _lasso = new SelectionLasso(new Point(viewPort.contentWidth, viewPort.contentHeight)); 128 | _lasso.owner = this; 129 | if (!_isCtrlKey) { 130 | selectedIndices = new Vector.(); 131 | _originalSelection = selectedIndices; 132 | } else { 133 | _originalSelection = selectedIndices; 134 | } 135 | parent.addElement(_lasso); 136 | } else { 137 | _dragStart = eventPos; 138 | 139 | } 140 | stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); 141 | stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler); 142 | } 143 | } 144 | 145 | private function _rendererUnderMouse(eventPos:Point): IItemRenderer { 146 | var objects:Array = parent.getObjectsUnderPoint(eventPos); 147 | for (var i:String in objects) { 148 | if (objects[i] is IItemRenderer) { 149 | return objects[i]; 150 | } 151 | } 152 | return null; 153 | } 154 | 155 | override protected function mouseMoveHandler(event:MouseEvent): void { 156 | var viewPort:IViewport = scroller.viewport; 157 | if (_lasso != null) { 158 | _scrollViewport(viewPort); 159 | 160 | _lasso.setMousePosition(new Point(contentMouseX, contentMouseY + viewPort.verticalScrollPosition)); 161 | 162 | _updateSelectedItems(viewPort); 163 | } else { 164 | if (DragManager.isDragging) { 165 | _scrollViewport(viewPort); 166 | } 167 | super.mouseMoveHandler(event); 168 | } 169 | } 170 | 171 | override public function createDragIndicator() : IFlexDisplayObject { 172 | var indices:Vector. = selectedIndices; 173 | indices.sort(function(x:int, y:int): Number{ 174 | return y - x; 175 | }); 176 | for (var i:int=0; i < indices.length; i++) { 177 | dataProvider.removeItemAt(indices[i]); 178 | } 179 | selectedIndices = new Vector.(); 180 | 181 | var proxy:DragProxy = new DragProxy(_items); 182 | proxy.x = mouseX; proxy.y = mouseY; 183 | return proxy; 184 | } 185 | 186 | override public function addDragData(dragSource:DragSource) : void { 187 | _items = selectedItems.splice(0, selectedItems.length); 188 | dragSource.addHandler(getDragItems, "items"); 189 | } 190 | 191 | override protected function mouseUpHandler(event:Event): void { 192 | if (_lasso) { 193 | stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); 194 | stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler); 195 | Group(this.parent).removeElement(_lasso); 196 | _lasso = null; 197 | } else { 198 | // hopefully its already null, but make sure now. 199 | _dragStart = null; 200 | super.mouseUpHandler(event); 201 | } 202 | // Only process the mouse up event once 203 | event.stopPropagation(); 204 | } 205 | 206 | //user moves the drag proxy onto the drop target, so allow drop 207 | override protected function dragEnterHandler(event:DragEvent): void { 208 | if (!event.isDefaultPrevented()) { 209 | _acceptItems(event, true); 210 | } 211 | } 212 | 213 | //user moves the drag proxy onto the drop target, so allow drop 214 | override protected function dragOverHandler(event:DragEvent) : void { 215 | if (!event.isDefaultPrevented()) { 216 | _acceptItems(event); 217 | } 218 | } 219 | 220 | private function _acceptItems(event:DragEvent, onEnter:Boolean= false): void { 221 | if (event.dragSource.hasFormat("items")) { 222 | var dropLocation:DropLocation = layout.calculateDropLocation(event); 223 | if (dropLocation) { 224 | if (onEnter) { 225 | DragManager.acceptDragDrop(this); 226 | 227 | // Create the dropIndicator instance. The layout will take care of 228 | // parenting, sizing, positioning and validating the dropIndicator. 229 | createDropIndicator(); 230 | } 231 | 232 | // Notify manager we can drop 233 | DragManager.showFeedback(DragManager.MOVE); 234 | 235 | // Show drop indicator 236 | layout.showDropIndicator(dropLocation); 237 | } else { 238 | // Hide if previously showing 239 | layout.hideDropIndicator(); 240 | 241 | // Notify manager we can't drop 242 | DragManager.showFeedback(DragManager.NONE); 243 | } 244 | } 245 | } 246 | 247 | override protected function dragCompleteHandler(event:DragEvent): void { 248 | var items: Vector. = event.dragSource.dataForFormat("items") as Vector.; 249 | while (items.length > 0) { 250 | dataProvider.addItem(items.shift()); 251 | } 252 | super.dragCompleteHandler(event); 253 | } 254 | 255 | override protected function dragDropHandler(event:DragEvent): void { 256 | //super.dragDropHandler(event); 257 | if (event.isDefaultPrevented()) { 258 | return; 259 | } 260 | 261 | // Hide the drop indicator 262 | layout.hideDropIndicator(); 263 | destroyDropIndicator(); 264 | 265 | // Get the dropLocation 266 | var dropLocation:DropLocation = layout.calculateDropLocation(event); 267 | if (!dropLocation) { 268 | return; 269 | } 270 | 271 | // Find the dropIndex 272 | var dropIndex:int = dropLocation.dropIndex; 273 | 274 | var items: Vector. = event.dragSource.dataForFormat("items") as Vector.; 275 | var album: GalleryAlbum = dataProvider as GalleryAlbum; 276 | album.insert(dropIndex, items); 277 | 278 | var self: ThumbGrid = this; 279 | var queue: ProcessItemQueue = new ProcessItemQueue(ProcessItemQueue.SAVE_OPERATION); 280 | queue.addItem({"action": "save", "item": album}); 281 | queue.processQueue( 282 | function(): void { 283 | album.refreshResource().addResponder(new GalleryRestResponder( 284 | function(resource: Object): void { 285 | self.invalidateProperties(); 286 | var event:Event = new Event("ThumbGridItemsDropped"); 287 | self.dispatchEvent(event); 288 | }, 289 | function (fault: Fault): void { 290 | ErrorDialog.display(fault as Fault); 291 | })); 292 | }); 293 | } 294 | 295 | private function _scrollViewport(viewPort:IViewport): void { 296 | var delta:Number = 30; 297 | // @todo make sure that x is inside our width 298 | // @todo look at setting up a scroll timer to see if the mouse 299 | // is still within the bottom or top 30 as opposed outside the 300 | // bounds. 301 | if (-30 < contentMouseY && contentMouseY <= 0) { 302 | if (scroller.verticalScrollBar.value > scroller.verticalScrollBar.minimum) { 303 | var minScroll:Number = scroller.verticalScrollBar.value - scroller.verticalScrollBar.minimum; 304 | delta = minScroll < delta ? -minScroll : -delta; 305 | viewPort.verticalScrollPosition += delta; 306 | } 307 | } else if (height <= contentMouseY && contentMouseY < height + 30) { 308 | if (scroller.verticalScrollBar.value < scroller.verticalScrollBar.maximum) { 309 | var maxScroll:Number = scroller.verticalScrollBar.maximum - scroller.verticalScrollBar.value; 310 | delta = maxScroll < delta ? maxScroll : delta; 311 | viewPort.verticalScrollPosition += delta; 312 | } 313 | } 314 | } 315 | 316 | private function _updateSelectedItems(viewPort:IViewport): void { 317 | var selection:Vector. = new Vector.(); 318 | var lassoCoord:Rectangle = _lasso.rectangle; 319 | var tileLayout: PaddedTileLayout = layout as PaddedTileLayout; 320 | 321 | var columnWidth:int = tileLayout.horizontalGap + tileLayout.columnWidth; 322 | var rowHeight:int = tileLayout.verticalGap + tileLayout.rowHeight; 323 | var numberOfColumns:int = Math.round(viewPort.contentWidth / columnWidth); 324 | 325 | lassoCoord.inflate(-tileLayout.horizontalGap, -tileLayout.verticalGap); 326 | var startRow:int = Math.floor(lassoCoord.y / rowHeight) 327 | var maxRow:int = Math.ceil(lassoCoord.bottom / rowHeight) 328 | var startCol:int = Math.floor(lassoCoord.x / columnWidth); 329 | var maxColumn:int = Math.ceil(lassoCoord.right / columnWidth); 330 | 331 | for (var row:int = startRow; row < maxRow; row++) { 332 | for (var column:int = startCol; column < maxColumn; column++) { 333 | var index:int = row * numberOfColumns + column; 334 | if (index < dataProvider.length) { 335 | selection.push(index); 336 | } 337 | } 338 | } 339 | 340 | selectedIndices = _union(_originalSelection, selection); 341 | } 342 | 343 | private function _union(array1:Vector., array2:Vector.): Vector. { 344 | var union:Vector. = new Vector.; 345 | if (array1 != null) { 346 | for (var i:int = 0; i < array1.length; i++) { 347 | union[i] = array1[i]; 348 | } 349 | for (i = 0; i < array2.length; i++) { 350 | if (array1.indexOf(array2[i]) == -1) { 351 | union.push(array2[i]); 352 | } 353 | } 354 | } else { 355 | for (i = 0; i < array2.length; i++) { 356 | union[i] = array2[i]; 357 | } 358 | } 359 | return union; 360 | } 361 | 362 | public function getDragItems(): Vector. { 363 | return _items; 364 | } 365 | } 366 | } -------------------------------------------------------------------------------- /Gallery3Organize/src/org/gallery3/organize/OrganizeDialog.as: -------------------------------------------------------------------------------- 1 | /** 2 | * Gallery - a web based photo album viewer and editor 3 | * Copyright (C) 2000-2010 Bharat Mediratta 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or (at 8 | * your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | package org.gallery3.organize { 20 | // @todo implement mirrored layout when flex supports it (probably 4.1) 21 | import com.adobe.serialization.json.JSON; 22 | import com.adobe.utils.StringUtil; 23 | 24 | import flash.events.Event; 25 | import flash.events.IOErrorEvent; 26 | import flash.external.ExternalInterface; 27 | import flash.net.FileFilter; 28 | import flash.net.FileReferenceList; 29 | import flash.net.URLLoader; 30 | import flash.net.URLRequest; 31 | import flash.net.URLVariables; 32 | import flash.system.Security; 33 | 34 | import mx.binding.utils.BindingUtils; 35 | import mx.collections.ArrayCollection; 36 | import mx.containers.HDividedBox; 37 | import mx.events.CollectionEvent; 38 | import mx.events.FlexEvent; 39 | import mx.managers.PopUpManager; 40 | import mx.rpc.Fault; 41 | 42 | import org.gallery3.api.GalleryAlbum; 43 | import org.gallery3.api.GalleryItem; 44 | import org.gallery3.api.GalleryResource; 45 | import org.gallery3.api.GalleryRestRequest; 46 | import org.gallery3.api.GalleryRestResponder; 47 | import org.gallery3.api.GalleryRestToken; 48 | import org.gallery3.organize.components.AddAlbumDialog; 49 | import org.gallery3.organize.components.AlbumTree; 50 | import org.gallery3.organize.components.ErrorDialog; 51 | import org.gallery3.organize.components.ProcessItemQueue; 52 | import org.gallery3.organize.components.ThumbGrid; 53 | 54 | import spark.components.Button; 55 | import spark.components.ComboBox; 56 | import spark.components.Group; 57 | import spark.components.Label; 58 | import spark.events.IndexChangeEvent; 59 | 60 | public class OrganizeDialog extends HDividedBox { 61 | private var _fileFilters: Array; 62 | private var _typeMap: Object; 63 | 64 | // References to Controls must be declared public 65 | public var albumTree: AlbumTree; 66 | public var detailPane: Group; 67 | public var imageGrid: ThumbGrid; 68 | public var sortColumn: ComboBox; 69 | public var sortDirection: ComboBox; 70 | public var addAlbum: Button; 71 | public var addImages: Button; 72 | public var deleteImages: Button; 73 | public var dialogClose: Button; 74 | public var organizeStatus: Label; 75 | 76 | private var _selectedCount:int = 0; 77 | 78 | public var openPath: ArrayCollection; 79 | 80 | [Bindable] public var dialogWidth: Number = 600; 81 | [Bindable] public var dialogHeight: Number = 400; 82 | 83 | [Bindable] 84 | public var translations:OrganizeText; 85 | [Bindable] 86 | public var styles:OrganizeStyle; 87 | 88 | [Bindable] 89 | protected var sortColumnData: ArrayCollection = new ArrayCollection(); 90 | 91 | [Bindable] 92 | protected var sortDirectionData: ArrayCollection = new ArrayCollection(); 93 | 94 | private static var selectedId: int = OrganizeParameters.instance.selectedId; 95 | 96 | public function OrganizeDialog() { 97 | super(); 98 | addEventListener(FlexEvent.CREATION_COMPLETE, contentCreationCompleteHandler); 99 | addEventListener(FlexEvent.PREINITIALIZE, preinitializeHandler); 100 | } 101 | 102 | public function onAddedToStage(event: Event): void { 103 | dialogWidth = this.stage.stageWidth; 104 | dialogHeight = this.stage.stageHeight; 105 | albumTree.width = dialogWidth * .25; 106 | detailPane.width = dialogWidth * .75; 107 | albumTree.height = detailPane.height = dialogHeight - 20; 108 | 109 | invalidateParentSizeAndDisplayList(); 110 | } 111 | 112 | protected function contentCreationCompleteHandler(event: FlexEvent): void { 113 | translations = OrganizeText.instance; 114 | styles = OrganizeStyle.instance; 115 | 116 | BindingUtils.bindProperty(organizeStatus, "text", translations, "statusText"); 117 | BindingUtils.bindProperty(addAlbum, "label", translations, "addAlbum"); 118 | BindingUtils.bindProperty(addImages, "label", translations, "addImages"); 119 | BindingUtils.bindProperty(deleteImages, "label", translations, "deleteSelected"); 120 | BindingUtils.bindProperty(dialogClose, "label", translations, "close"); 121 | 122 | var params: URLVariables = new URLVariables(); 123 | params.ancestors_for = GalleryRestRequest.baseURL + "item/" + OrganizeParameters.instance.albumId; 124 | var token: GalleryRestToken = GalleryResource.loadResource("items", params); 125 | token.addResponder(new GalleryRestResponder( 126 | function (resource: Object): void { 127 | openPath = resource as ArrayCollection; 128 | var rootItem: GalleryAlbum = openPath.removeItemAt(0); 129 | rootItem.albums.addEventListener("AlbumLoaded", albumsUpdated); 130 | 131 | albumTree.dataProvider = [rootItem]; 132 | albumTree.validateNow(); 133 | if (openPath.length == 0) { 134 | callLater(function(): void { 135 | albumTree.selectedItem = albumTree.dataProvider.getItemAt(0); 136 | onTreeSelectedChange(null); 137 | }); 138 | } else { 139 | albumTree.expandItem(rootItem, true, true, true); 140 | } 141 | }, 142 | function (fault: Object): void { 143 | ErrorDialog.display(fault as Fault); 144 | }) 145 | ); 146 | 147 | imageGrid.addEventListener("ThumbGridItemsDropped", function(event: Event): void { 148 | setSortColumn("weight"); 149 | }); 150 | } 151 | 152 | protected function albumsUpdated(event: Event): void { 153 | if (openPath.length > 0) { 154 | for each (var item: GalleryAlbum in event.target) { 155 | if (item.url == openPath.getItemAt(0).url) { 156 | callLater(function(): void { 157 | openPath.removeItemAt(0); 158 | if (openPath.length > 0) { 159 | item.albums.addEventListener("AlbumLoaded", albumsUpdated); 160 | albumTree.expandItem(item, true, true, true); 161 | albumTree.invalidateProperties(); 162 | } else { 163 | albumTree.selectedItem = item; 164 | onTreeSelectedChange(null); 165 | } 166 | }); 167 | break; 168 | } 169 | } 170 | } else { // Special case where the selected album is the root 171 | callLater(function(): void { 172 | albumTree.selectedItem = albumTree.dataProvider.getItemAt(0); 173 | onTreeSelectedChange(null); 174 | }); 175 | } 176 | } 177 | 178 | protected function preinitializeHandler(event:FlexEvent):void { 179 | var p: Object = OrganizeParameters.instance; 180 | var domain: String = OrganizeParameters.instance.domain; 181 | Security.allowDomain(domain); 182 | 183 | var fileFilter: Object = JSON.decode(OrganizeParameters.instance.fileFilter); 184 | 185 | _typeMap = {}; 186 | _fileFilters = new Array(); 187 | for (var itemType:String in fileFilter) { 188 | var filter: Object = fileFilter[itemType]; 189 | var filterTypes: String = ""; 190 | for each (var type: String in filter.types) { 191 | filterTypes += ((filterTypes.length > 0) ? "; " : "") + type; 192 | _typeMap[type.substr(1)] = itemType; 193 | } 194 | _fileFilters.push(new FileFilter(filter.label + " (" + filterTypes + ")", filterTypes)); 195 | } 196 | 197 | var sortField: Object = JSON.decode(OrganizeParameters.instance.sortFields); 198 | for (var entry:String in sortField) { 199 | sortColumnData.addItem({label: sortField[entry], data: entry}); 200 | } 201 | 202 | var sortOrder: Object = JSON.decode(OrganizeParameters.instance.sortOrder); 203 | for (entry in sortOrder) { 204 | sortDirectionData.addItem({label: sortOrder[entry], data: entry}); 205 | } 206 | 207 | GalleryRestRequest.baseURL = OrganizeParameters.instance.baseUrl; 208 | GalleryRestRequest.accessKey = OrganizeParameters.instance.accessKey; 209 | } 210 | 211 | public function setSortColumn(column: String): void { 212 | for (var i:int = 0; i < sortColumn.dataProvider.length; i++) { 213 | if (sortColumn.dataProvider[i].data == column) { 214 | sortColumn.selectedIndex = i; 215 | break; 216 | } 217 | } 218 | } 219 | public function setSortOrder(order: String): void { 220 | for (var i:int = 0; i < sortDirection.dataProvider.length; i++) { 221 | if (sortDirection.dataProvider[i].data == order) { 222 | sortDirection.selectedIndex = i; 223 | break; 224 | } 225 | } 226 | } 227 | 228 | protected function onAddAlbum(event:FlexEvent):void { 229 | // @todo get the form fields as part of the initial download 230 | var request: URLRequest = new URLRequest(OrganizeParameters.instance.controller + "add_album_fields"); 231 | var loader: URLLoader = new URLLoader(); 232 | loader.addEventListener(Event.COMPLETE, function(event: Event): void { 233 | var fields: Object = JSON.decode(event.currentTarget.data); 234 | _showAddAlbumDialog(fields); 235 | }); 236 | loader.addEventListener(IOErrorEvent.IO_ERROR, function(event: IOErrorEvent): void { 237 | var pattern: RegExp = /^Error #(\d+):\s(.*\.)\s(.*)$/; 238 | var parts: Array = pattern.exec(event.text); 239 | ErrorDialog(new Fault(parts[1], parts[2], parts[3])); 240 | }); 241 | loader.load(request); 242 | } 243 | 244 | private function _showAddAlbumDialog(fields: Object): void { 245 | var dialog: AddAlbumDialog = PopUpManager.createPopUp(this, AddAlbumDialog, true) as AddAlbumDialog; 246 | dialog.parentAlbum = albumTree.selectedItem as GalleryAlbum; 247 | dialog.title = OrganizeText.instance.addAlbum; 248 | dialog.submitForm.label = OrganizeText.instance.addAlbum; 249 | dialog.cancelForm.label = OrganizeText.instance.cancel; 250 | dialog.labelTitle.text = fields.title; 251 | dialog.labelDescription.text = fields.description; 252 | dialog.labelName.text = fields.name; 253 | dialog.labelSlug.text = fields.slug; 254 | PopUpManager.centerPopUp(dialog); 255 | } 256 | 257 | protected function onAddContent(event:FlexEvent):void { 258 | var fileRefList: FileReferenceList = new FileReferenceList(); 259 | fileRefList.addEventListener(Event.SELECT, function(event:Event): void { 260 | imageGrid.onFilesSelected(event, _typeMap); 261 | }); 262 | fileRefList.browse(_fileFilters); 263 | } 264 | 265 | protected function onTreeSelectedChange(event:Event): void { 266 | if (albumTree.selectedIndex >= 0) { 267 | var album: GalleryAlbum = albumTree.selectedItem as GalleryAlbum; 268 | album.loadChildren(); 269 | imageGrid.dataProvider = album; 270 | // If we have received a selected item id as an input 271 | // parameter, then set up a listener to catch when the item 272 | // is actually loaded and added to the album. We will then 273 | // check the id and if its the one we want then we will 274 | // set the selectedItem property of the imageGrid. We 275 | // only do this the first time. 276 | if (selectedId != 0) { 277 | album.addEventListener(CollectionEvent.COLLECTION_CHANGE, 278 | _initialCollectionChanged); 279 | } 280 | sortColumn.enabled = album.canEdit; 281 | sortDirection.enabled = album.canEdit; 282 | addAlbum.enabled = album.canEdit; 283 | addImages.enabled = album.canEdit; 284 | 285 | setSortColumn(album.sortColumn); 286 | setSortOrder(album.sortOrder); 287 | var chars: Object = { 288 | "&": "&", "\"": """, "<": "<", ">": ">" 289 | }; 290 | var title:String = album.title; 291 | for (var char: String in chars) { 292 | StringUtil.replace(title, char, chars[char]); 293 | } 294 | ExternalInterface.call("setTitle", title); 295 | 296 | var path: String = ""; 297 | while (album.id != 1) { 298 | if (path.length > 0) { 299 | path = "/" + path; 300 | } 301 | path = (album.slug != null ? album.slug : "") + path; 302 | album = albumTree.getParentItem(album) as GalleryAlbum; 303 | } 304 | 305 | ExternalInterface.call("setLocation", OrganizeParameters.instance.url + path); 306 | 307 | } 308 | } 309 | 310 | private function _initialCollectionChanged(event:CollectionEvent): void { 311 | if (event.items[0].id == selectedId) { 312 | imageGrid.selectedItem = event.items[0]; 313 | selectedId = 0; 314 | event.target.removeEventListener(CollectionEvent.COLLECTION_CHANGE, _initialCollectionChanged); 315 | } 316 | } 317 | 318 | protected function onThumbChangeHandler(event:IndexChangeEvent): void { 319 | selectionChange(); 320 | } 321 | 322 | protected function onThumbValueCommitHandler(event:FlexEvent): void { 323 | selectionChange(); 324 | } 325 | 326 | private function selectionChange(): void { 327 | var newCount: int = imageGrid.selectedItems.length; 328 | if (newCount != _selectedCount) { 329 | var album: GalleryAlbum = albumTree.selectedItem as GalleryAlbum; 330 | _selectedCount = newCount; 331 | deleteImages.enabled = _selectedCount > 0 && album.canEdit; 332 | } 333 | } 334 | 335 | public function onDialogClose(event:FlexEvent): void { 336 | ExternalInterface.call("closeOrganizeDialog"); 337 | } 338 | 339 | protected function onSortColumnChange(event:IndexChangeEvent): void { 340 | var item: GalleryItem = albumTree.selectedItem as GalleryItem; 341 | item.sortColumn = sortColumn.selectedItem.data; 342 | var queue: ProcessItemQueue = new ProcessItemQueue(ProcessItemQueue.SAVE_OPERATION); 343 | queue.addItem({"action": "save", "item": item}); 344 | queue.processQueue( 345 | function(): void { 346 | item.refreshResource().addResponder(new GalleryRestResponder( 347 | function(resource: Object): void { 348 | imageGrid.invalidateProperties(); 349 | }, 350 | function (fault: Fault): void { 351 | ErrorDialog.display(fault as Fault); 352 | })); 353 | }); 354 | } 355 | 356 | protected function onSortDirectionChange(event:IndexChangeEvent): void { 357 | var item: GalleryItem = albumTree.selectedItem as GalleryItem; 358 | item.sortOrder = sortDirection.selectedItem.data; 359 | var queue: ProcessItemQueue = new ProcessItemQueue(ProcessItemQueue.SAVE_OPERATION); 360 | queue.addItem({"action": "save", "item": item}); 361 | queue.processQueue( 362 | function(): void { 363 | item.refreshResource().addResponder(new GalleryRestResponder( 364 | function(resource: Object): void { 365 | imageGrid.invalidateProperties(); 366 | }, 367 | function (fault: Fault): void { 368 | ErrorDialog.display(fault as Fault); 369 | })); 370 | }); 371 | } 372 | 373 | protected function onDeleteSelected(event:FlexEvent):void { 374 | imageGrid.deleteSelected(); 375 | } 376 | } 377 | } --------------------------------------------------------------------------------