!import
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Blake Ross <blaker@netscape.com> (Original Author)
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39 // helper routines, for doing rdf-based cut/copy/paste/etc
40 // this needs to be more generic!
41
42 const nsTransferable_contractid = "@mozilla.org/widget/transferable;1";
43 const clipboard_contractid = "@mozilla.org/widget/clipboard;1";
44 const rdf_contractid = "@mozilla.org/rdf/rdf-service;1";
45 const supportswstring_contractid = "@mozilla.org/supports-string;1";
46 const rdfc_contractid = "@mozilla.org/rdf/container;1";
47
48 const nsISupportsString = Components.interfaces.nsISupportsString;
49 const nsIClipboard = Components.interfaces.nsIClipboard;
50 const nsITransferable = Components.interfaces.nsITransferable;
51 const nsIRDFLiteral = Components.interfaces.nsIRDFLiteral;
52 const nsIRDFContainer = Components.interfaces.nsIRDFContainer;
53
54 var gRDF;
55 var gClipboard;
56
isContainer
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
57 function isContainer(tree, index)
58 {
59 return tree.treeBoxObject.view.isContainer(index);
60 }
61
isContainerOpen
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
62 function isContainerOpen(tree, index)
63 {
64 return tree.treeBoxObject.view.isContainerOpen(index);
65 }
66
nsTreeController_SetTransferData
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
67 function nsTreeController_SetTransferData(transferable, flavor, text)
68 {
69 if (!text)
70 return;
71 var textData = Components.classes[supportswstring_contractid].createInstance(nsISupportsString);
72 textData.data = text;
73
74 transferable.addDataFlavor(flavor);
75 transferable.setTransferData(flavor, textData, text.length*2);
76 }
77
nsTreeController_copy
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
78 function nsTreeController_copy()
79 {
80 var rangeCount = this.treeSelection.getRangeCount();
81 if (rangeCount < 1)
82 return false;
83
84 // Build a url that encodes all the select nodes
85 // as well as their parent nodes
86 var url = "";
87 var text = "";
88 var html = "";
89 var min = new Object();
90 var max = new Object();
91
92 for (var i = rangeCount - 1; i >= 0; --i) {
93 this.treeSelection.getRangeAt(i, min, max);
94 for (var k = max.value; k >= min.value; --k) {
95 // If one of the selected items is
96 // a container, ignore it.
97 if (isContainer(this.tree, k))
98 continue;
99 var col = this.tree.columns["URL"];
100 var pageUrl = this.treeView.getCellText(k, col);
101 col = this.tree.columns["Name"];
102 var pageName = this.treeView.getCellText(k, col);
103
104 url += "ID:{" + pageUrl + "};";
105 url += "NAME:{" + pageName + "};";
106
107 text += pageUrl + "\r";
108 html += "<a href='" + pageUrl + "'>";
109 if (pageName) html += pageName;
110 html += "</a><p>";
111 }
112 }
113
114 if (!url)
115 return false;
116
117 // get some useful components
118 var trans = Components.classes[nsTransferable_contractid].createInstance(nsITransferable);
119
120 if (!gClipboard)
121 gClipboard = Components.classes[clipboard_contractid].getService(Components.interfaces.nsIClipboard);
122
123 gClipboard.emptyClipboard(nsIClipboard.kGlobalClipboard);
124
125 this.SetTransferData(trans, "text/unicode", text);
126 this.SetTransferData(trans, "moz/bookmarkclipboarditem", url);
127 this.SetTransferData(trans, "text/html", html);
128
129 gClipboard.setData(trans, null, nsIClipboard.kGlobalClipboard);
130 return true;
131 }
132
nsTreeController_cut
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
133 function nsTreeController_cut()
134 {
135 if (this.copy()) {
136 this.doDelete();
137 return true; // copy succeeded, don't care if delete failed
138 }
139 return false; // copy failed, so did cut
140 }
141
nsTreeController_selectAll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
142 function nsTreeController_selectAll()
143 {
144 this.treeSelection.selectAll();
145 }
146
nsTreeController_delete
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
147 function nsTreeController_delete()
148 {
149 var rangeCount = this.treeSelection.getRangeCount();
150 if (rangeCount < 1)
151 return false;
152
153 var datasource = this.tree.database;
154 var dsEnum = datasource.GetDataSources();
155 dsEnum.getNext();
156 var ds = dsEnum.getNext()
157 .QueryInterface(Components.interfaces.nsIRDFDataSource);
158
159 var count = this.treeSelection.count;
160
161 // XXX 9 is a random number, just looking for a sweetspot
162 // don't want to rebuild tree content for just a few items
163 if (count > 9) {
164 ds.beginUpdateBatch();
165 }
166
167 var min = new Object();
168 var max = new Object();
169 var dirty = false;
170 for (var i = rangeCount - 1; i >= 0; --i) {
171 this.treeSelection.getRangeAt(i, min, max);
172 for (var k = max.value; k >= min.value; --k) {
173 if (!gRDF)
174 gRDF = Components.classes[rdf_contractid].getService(Components.interfaces.nsIRDFService);
175
176 var IDRes = this.treeBuilder.getResourceAtIndex(k);
177 if (!IDRes)
178 continue;
179
180 var root = this.tree.getAttribute('ref');
181 var parentIDRes;
182 try {
183 parentIDRes = this.treeBuilder.getResourceAtIndex(this.treeView.getParentIndex(k));
184 }
185 catch(ex) {
186 parentIDRes = gRDF.GetResource(root);
187 }
188 if (!parentIDRes)
189 continue;
190
191 // otherwise remove the parent/child assertion then
192 var containment = gRDF.GetResource("http://home.netscape.com/NC-rdf#child");
193 ds.Unassert(parentIDRes, containment, IDRes);
194 dirty = true;
195 }
196 }
197
198 if (count > 9) {
199 ds.endUpdateBatch();
200 }
201
202 if (dirty) {
203 try {
204 var remote = datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
205 remote.Flush();
206 } catch (ex) {
207 }
208 }
209 if (max.value != -1) {
210 var newIndex = min.value;
211 if (newIndex >= this.treeView.rowCount)
212 --newIndex;
213 if (newIndex >= 0)
214 this.treeSelection.select(newIndex);
215 }
216 return true;
217 }
218
nsTreeController
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
219 function nsTreeController(tree)
220 {
221 this._tree = tree;
222 tree.controllers.appendController(this);
223 }
224
225 nsTreeController.prototype =
226 {
227 _treeSelection: null,
228 _treeView: null,
229 _treeBuilder: null,
230 _treeBoxObject: null,
231 _tree: null,
get_tree
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
232 get tree()
233 {
234 return this._tree;
235 },
get_treeBoxObject
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
236 get treeBoxObject()
237 {
238 if (this._treeBoxObject)
239 return this._treeBoxObject;
240 return this._treeBoxObject = this.tree.treeBoxObject;
241 },
get_treeView
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
242 get treeView()
243 {
244 if (this._treeView)
245 return this._treeView;
246 return this._treeView = this.tree.treeBoxObject.view;
247 },
get_treeSelection
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
248 get treeSelection()
249 {
250 if (this._treeSelection)
251 return this._treeSelection;
252 return this._treeSelection = this.tree.treeBoxObject.view.selection;
253 },
get_treeBuilder
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
254 get treeBuilder()
255 {
256 if (this._treeBuilder)
257 return this._treeBuilder;
258 return this._treeBuilder = this.tree.builder.
259 QueryInterface(Components.interfaces.nsIXULTreeBuilder);
260 },
261 SetTransferData : nsTreeController_SetTransferData,
262
supportsCommand
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
263 supportsCommand: function(command)
264 {
265 switch(command)
266 {
267 case "cmd_cut":
268 case "cmd_copy":
269 case "cmd_delete":
270 case "cmd_selectAll":
271 return true;
272 default:
273 return false;
274 }
275 },
276
isCommandEnabled
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
277 isCommandEnabled: function(command)
278 {
279 var haveCommand;
280 switch (command)
281 {
282 // commands which do not require selection
283 case "cmd_selectAll":
284 var treeView = this.treeView;
285 return (treeView.rowCount != treeView.selection.count);
286
287 // these commands require selection
288 case "cmd_cut":
289 haveCommand = (this.cut != undefined);
290 break;
291 case "cmd_copy":
292 haveCommand = (this.copy != undefined);
293 break;
294 case "cmd_delete":
295 haveCommand = (this.doDelete != undefined);
296 break;
297 }
298
299 // if we get here, then we have a command that requires selection
300 var haveSelection = (this.treeSelection.count);
301 return (haveCommand && haveSelection);
302 },
303
doCommand
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
304 doCommand: function(command)
305 {
306 switch(command)
307 {
308 case "cmd_cut":
309 return this.cut();
310 case "cmd_copy":
311 return this.copy();
312 case "cmd_delete":
313 return this.doDelete();
314 case "cmd_selectAll":
315 return this.selectAll();
316 }
317 return false;
318 },
319 copy: nsTreeController_copy,
320 cut: nsTreeController_cut,
321 doDelete: nsTreeController_delete,
322 selectAll: nsTreeController_selectAll
323 }