View Javadoc

1   /**********************************************
2    * Copyright (C) 2010 Lukas Laag
3    * This file is part of vectomatic2.
4    * 
5    * vectomatic2 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 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * vectomatic2 is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   * 
15   * You should have received a copy of the GNU General Public License
16   * along with vectomatic2.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  package org.vectomatic.svg.edit.client;
19  
20  import java.io.IOException;
21  import java.util.Iterator;
22  
23  import org.vectomatic.dom.svg.OMAttr;
24  import org.vectomatic.dom.svg.OMElement;
25  import org.vectomatic.dom.svg.OMNode;
26  import org.vectomatic.dom.svg.impl.SVGParserImpl;
27  import org.vectomatic.dom.svg.utils.DOMHelper;
28  import org.vectomatic.dom.svg.utils.XPathPrefixResolver;
29  
30  import com.extjs.gxt.ui.client.Style.Scroll;
31  import com.extjs.gxt.ui.client.data.BeanModel;
32  import com.extjs.gxt.ui.client.data.BeanModelFactory;
33  import com.extjs.gxt.ui.client.data.BeanModelLookup;
34  import com.extjs.gxt.ui.client.data.BeanModelTag;
35  import com.extjs.gxt.ui.client.event.ButtonEvent;
36  import com.extjs.gxt.ui.client.event.Events;
37  import com.extjs.gxt.ui.client.event.Listener;
38  import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
39  import com.extjs.gxt.ui.client.event.SelectionListener;
40  import com.extjs.gxt.ui.client.store.ListStore;
41  import com.extjs.gxt.ui.client.util.Format;
42  import com.extjs.gxt.ui.client.widget.Dialog;
43  import com.extjs.gxt.ui.client.widget.ListView;
44  import com.google.gwt.core.client.GWT;
45  import com.google.gwt.dom.client.Document;
46  import com.google.gwt.http.client.Request;
47  import com.google.gwt.http.client.RequestBuilder;
48  import com.google.gwt.http.client.RequestCallback;
49  import com.google.gwt.http.client.RequestException;
50  import com.google.gwt.http.client.Response;
51  
52  /**
53   * Dialog to display the OpenClipArt 'new svg' RSS feed.
54   * @author laaglu
55   */
56  public class RSSReader extends Dialog {
57  	/**
58  	 * Bean to represent a single entry in the
59  	 * OpenClipArt 'new svg' RSS feed. 
60  	 * @author laaglu
61  	 */
62  	public static class RSSEntry implements BeanModelTag {
63  		private String pngPath;
64  		private String svgPath;
65  		public RSSEntry() {
66  		}
67  
68  		public void setPngPath(String pngPath) {
69  			this.pngPath = pngPath;
70  		}
71  
72  		public String getPngPath() {
73  			return pngPath;
74  		}
75  
76  		public void setSvgPath(String svgPath) {
77  			this.svgPath = svgPath;
78  		}
79  		
80  		public String getName() {
81  			int index = svgPath.lastIndexOf('/');
82  			return (index != -1) ? svgPath.substring(1 + index) : svgPath;
83  		}
84  
85  		public String getSvgPath() {
86  			return svgPath;
87  		}
88  	}
89  
90  	/**
91  	 * The list view
92  	 */
93  	private ListView<BeanModel> view;
94  	/**
95  	 * A store from which the list view fetches
96  	 * RSS records
97  	 */
98  	private ListStore<BeanModel> store;
99  	/**
100 	 * A bean factory to wrap RSSEntry into BeanModel
101 	 * to make them compatible with ListView
102 	 */
103 	private BeanModelFactory beanFactory;
104 	
105 	public RSSReader() {
106 		super();
107 		okText = AppConstants.INSTANCE.openButton();
108 		cancelText = AppConstants.INSTANCE.cancelButton();
109 		setButtons(Dialog.OKCANCEL);
110 		setScrollMode(Scroll.AUTO);
111 		setHideOnButtonClick(true);
112 		setHeading(AppConstants.INSTANCE.openRssFeedMenuItem());
113 		setModal(true);
114 		setSize(520, 300);
115 		getButtonById(OK).addSelectionListener(new SelectionListener<ButtonEvent>() {
116 			@Override
117 			public void componentSelected(ButtonEvent ce) {
118 				for (BeanModel beanModel :  view.getSelectionModel().getSelectedItems()) {
119 					RSSEntry rssEntry = (RSSEntry)beanModel.getBean();
120 					VectomaticApp2.APP.load(rssEntry.getSvgPath());
121 				}
122 			}
123 		});
124 		
125 		beanFactory = BeanModelLookup.get().getFactory(RSSEntry.class);
126 		store = new ListStore<BeanModel>();
127 		view = new ListView<BeanModel>() {
128 			@Override
129 			protected BeanModel prepareData(BeanModel model) {
130 				String s = model.get("name");
131 				model.set("shortName", Format.ellipse(s, 15));
132 				return model;
133 			}
134 		};
135 	    view.setTemplate(getTemplate());
136 	    view.setStore(store);
137 	    view.setItemSelector("div.thumb-wrap");
138 	    view.getSelectionModel().addListener(Events.SelectionChange,
139             new Listener<SelectionChangedEvent<BeanModel>>() {
140               public void handleEvent(SelectionChangedEvent<BeanModel> be) {
141             	  BeanModel beanModel = be.getSelectedItem();
142             	  if (beanModel != null) {
143 	            	  RSSEntry rssEntry = (RSSEntry)beanModel.getBean();
144 	            	  GWT.log("Selected: " + rssEntry.getName());
145             	  }
146               }
147         });
148 	    add(view);
149 	    load();
150 	}
151 
152 	public void load() {
153 
154 		final String url = "http://www.openclipart.org/rss/new.xml";
155 		String resourceUrl = GWT.getHostPageBaseURL() + "fetch?url=" + url + "&type=text/xml";
156 		RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, resourceUrl);
157 		requestBuilder.setCallback(new RequestCallback() {
158 			public void onError(Request request, Throwable e) {
159 				GWT.log("Cannot fetch " + url, e);
160 				VectomaticApp2.APP.info(AppConstants.INSTANCE.openRssFeedMenuItem(), AppMessages.INSTANCE.loadErrorMessage(url, e.getMessage()));
161 			}
162 
163 			private void onSuccess(Request request, Response response) {
164 				// Create a store of BeanModel of RSSEntry
165 				SVGParserImpl impl = GWT.create(SVGParserImpl.class);
166 				Document doc = impl.parseFromString(response.getText(), "text/xml").cast();
167 				OMElement root = OMNode.convert(doc.getDocumentElement());
168 
169 
170 				Iterator<OMAttr> iterator = DOMHelper.evaluateXPath(root, "//rss/channel/item/enclosure/@url", null);
171 				while(iterator.hasNext()) {
172 					RSSEntry rssEntry = new RSSEntry();
173 					rssEntry.setSvgPath(iterator.next().getValue());
174 					store.add(beanFactory.createModel(rssEntry));
175 				}
176 
177 				iterator = DOMHelper.evaluateXPath(root, "//rss/channel/item/media:thumbnail/@url", new XPathPrefixResolver() {
178 
179 					@Override
180 					public String resolvePrefix(String prefix) {
181 						if ("media".equals(prefix)) {
182 							return "http://search.yahoo.com/mrss/";
183 						}
184 						return null;
185 					}
186 				});
187 				int index = 0;
188 				while(iterator.hasNext()) {
189 					BeanModel beanModel = store.getAt(index++);
190 					RSSEntry rssEntry = (RSSEntry)beanModel.getBean();
191 					rssEntry.setPngPath(iterator.next().getValue());
192 					store.update(beanModel);
193 				}
194 			}
195 			
196 			public void onResponseReceived(Request request, Response response) {
197 				if (response.getStatusCode() == Response.SC_OK) {
198 					onSuccess(request, response);
199 				} else {
200 					onError(request, new IOException(AppMessages.INSTANCE.httpErrorMessage(Integer.toString(response.getStatusCode()))));
201 				}
202 			}
203 		});
204 		try {
205 			requestBuilder.send();
206 		} catch (RequestException e) {
207 			GWT.log("Cannot fetch " + url, e);
208 			VectomaticApp2.APP.info(AppConstants.INSTANCE.openRssFeedMenuItem(), AppMessages.INSTANCE.loadErrorMessage(url, e.getMessage()));
209 		}
210 	}
211 	
212 	private static native String getTemplate() /*-{
213 		return ['<tpl for=".">',
214 		'<div class="thumb-wrap" id="{svgPath}">',
215 		'<div class="thumb"><img src="{pngPath}" title="{name}"></div>',
216 		'<span class="x-editable">{shortName}</span></div>',
217 		'</tpl>',
218 		'<div class="x-clear"></div>'].join("");
219 	}-*/;
220 }