1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 /*
7 
8   This file provides the implementation for the XUL "controllers"
9   object.
10 
11 */
12 
13 #include "nsString.h"
14 
15 #include "nsIControllers.h"
16 #include "nsXULControllers.h"
17 #include "nsIController.h"
18 #include "mozilla/RefPtr.h"
19 
20 //----------------------------------------------------------------------
21 
nsXULControllerData(uint32_t inControllerID,nsIController * inController)22 nsXULControllerData::nsXULControllerData(uint32_t inControllerID,
23                                          nsIController* inController)
24     : mControllerID(inControllerID), mController(inController) {}
25 
GetController(nsIController ** outController)26 nsresult nsXULControllerData::GetController(nsIController** outController) {
27   NS_IF_ADDREF(*outController = mController);
28   return NS_OK;
29 }
30 
nsXULControllers()31 nsXULControllers::nsXULControllers() : mCurControllerID(0) {}
32 
~nsXULControllers(void)33 nsXULControllers::~nsXULControllers(void) { DeleteControllers(); }
34 
DeleteControllers()35 void nsXULControllers::DeleteControllers() {
36   uint32_t count = mControllers.Length();
37   for (uint32_t i = 0; i < count; i++) {
38     nsXULControllerData* controllerData = mControllers.ElementAt(i);
39     delete controllerData;  // releases the nsIController
40   }
41 
42   mControllers.Clear();
43 }
44 
45 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULControllers)
46 
47 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULControllers)
48   tmp->DeleteControllers();
49 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULControllers)50 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULControllers)
51   {
52     uint32_t i, count = tmp->mControllers.Length();
53     for (i = 0; i < count; ++i) {
54       nsXULControllerData* controllerData = tmp->mControllers[i];
55       if (controllerData) {
56         cb.NoteXPCOMChild(controllerData->mController);
57       }
58     }
59   }
60 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
61 
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULControllers)62 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULControllers)
63   NS_INTERFACE_MAP_ENTRY(nsIControllers)
64   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIControllers)
65 NS_INTERFACE_MAP_END
66 
67 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULControllers)
68 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULControllers)
69 
70 NS_IMETHODIMP
71 nsXULControllers::GetControllerForCommand(const char* aCommand,
72                                           nsIController** _retval) {
73   NS_ENSURE_ARG_POINTER(_retval);
74   *_retval = nullptr;
75 
76   uint32_t count = mControllers.Length();
77   for (uint32_t i = 0; i < count; i++) {
78     nsXULControllerData* controllerData = mControllers.ElementAt(i);
79     if (controllerData) {
80       nsCOMPtr<nsIController> controller;
81       controllerData->GetController(getter_AddRefs(controller));
82       if (controller) {
83         bool supportsCommand;
84         controller->SupportsCommand(aCommand, &supportsCommand);
85         if (supportsCommand) {
86           controller.forget(_retval);
87           return NS_OK;
88         }
89       }
90     }
91   }
92 
93   return NS_OK;
94 }
95 
96 NS_IMETHODIMP
InsertControllerAt(uint32_t aIndex,nsIController * controller)97 nsXULControllers::InsertControllerAt(uint32_t aIndex,
98                                      nsIController* controller) {
99   nsXULControllerData* controllerData =
100       new nsXULControllerData(++mCurControllerID, controller);
101 #ifdef DEBUG
102   nsXULControllerData** inserted =
103 #endif
104       mControllers.InsertElementAt(aIndex, controllerData);
105   NS_ASSERTION(inserted != nullptr, "Insertion of controller failed");
106   return NS_OK;
107 }
108 
109 NS_IMETHODIMP
RemoveControllerAt(uint32_t aIndex,nsIController ** _retval)110 nsXULControllers::RemoveControllerAt(uint32_t aIndex, nsIController** _retval) {
111   NS_ENSURE_ARG_POINTER(_retval);
112   *_retval = nullptr;
113 
114   nsXULControllerData* controllerData = mControllers.SafeElementAt(aIndex);
115   if (!controllerData) return NS_ERROR_FAILURE;
116 
117   mControllers.RemoveElementAt(aIndex);
118 
119   controllerData->GetController(_retval);
120   delete controllerData;
121 
122   return NS_OK;
123 }
124 
125 NS_IMETHODIMP
GetControllerAt(uint32_t aIndex,nsIController ** _retval)126 nsXULControllers::GetControllerAt(uint32_t aIndex, nsIController** _retval) {
127   NS_ENSURE_ARG_POINTER(_retval);
128   *_retval = nullptr;
129 
130   nsXULControllerData* controllerData = mControllers.SafeElementAt(aIndex);
131   if (!controllerData) return NS_ERROR_FAILURE;
132 
133   return controllerData->GetController(_retval);  // does the addref
134 }
135 
136 NS_IMETHODIMP
AppendController(nsIController * controller)137 nsXULControllers::AppendController(nsIController* controller) {
138   // This assigns controller IDs starting at 1 so we can use 0 to test if an ID
139   // was obtained
140   nsXULControllerData* controllerData =
141       new nsXULControllerData(++mCurControllerID, controller);
142 
143 #ifdef DEBUG
144   nsXULControllerData** appended =
145 #endif
146       mControllers.AppendElement(controllerData);
147   NS_ASSERTION(appended != nullptr, "Appending controller failed");
148   return NS_OK;
149 }
150 
151 NS_IMETHODIMP
RemoveController(nsIController * controller)152 nsXULControllers::RemoveController(nsIController* controller) {
153   // first get the identity pointer
154   nsCOMPtr<nsISupports> controllerSup(do_QueryInterface(controller));
155   // then find it
156   uint32_t count = mControllers.Length();
157   for (uint32_t i = 0; i < count; i++) {
158     nsXULControllerData* controllerData = mControllers.ElementAt(i);
159     if (controllerData) {
160       nsCOMPtr<nsIController> thisController;
161       controllerData->GetController(getter_AddRefs(thisController));
162       nsCOMPtr<nsISupports> thisControllerSup(
163           do_QueryInterface(thisController));  // get identity
164       if (thisControllerSup == controllerSup) {
165         mControllers.RemoveElementAt(i);
166         delete controllerData;
167         return NS_OK;
168       }
169     }
170   }
171   return NS_ERROR_FAILURE;  // right thing to return if no controller found?
172 }
173 
174 NS_IMETHODIMP
GetControllerId(nsIController * controller,uint32_t * _retval)175 nsXULControllers::GetControllerId(nsIController* controller,
176                                   uint32_t* _retval) {
177   NS_ENSURE_ARG_POINTER(_retval);
178 
179   uint32_t count = mControllers.Length();
180   for (uint32_t i = 0; i < count; i++) {
181     nsXULControllerData* controllerData = mControllers.ElementAt(i);
182     if (controllerData) {
183       nsCOMPtr<nsIController> thisController;
184       controllerData->GetController(getter_AddRefs(thisController));
185       if (thisController.get() == controller) {
186         *_retval = controllerData->GetControllerID();
187         return NS_OK;
188       }
189     }
190   }
191   return NS_ERROR_FAILURE;  // none found
192 }
193 
194 NS_IMETHODIMP
GetControllerById(uint32_t controllerID,nsIController ** _retval)195 nsXULControllers::GetControllerById(uint32_t controllerID,
196                                     nsIController** _retval) {
197   NS_ENSURE_ARG_POINTER(_retval);
198 
199   uint32_t count = mControllers.Length();
200   for (uint32_t i = 0; i < count; i++) {
201     nsXULControllerData* controllerData = mControllers.ElementAt(i);
202     if (controllerData && controllerData->GetControllerID() == controllerID) {
203       return controllerData->GetController(_retval);
204     }
205   }
206   return NS_ERROR_FAILURE;  // none found
207 }
208 
209 NS_IMETHODIMP
GetControllerCount(uint32_t * _retval)210 nsXULControllers::GetControllerCount(uint32_t* _retval) {
211   NS_ENSURE_ARG_POINTER(_retval);
212   *_retval = mControllers.Length();
213   return NS_OK;
214 }
215