1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_framework.hxx"
26 #include <xml/acceleratorconfigurationreader.hxx>
27
28 //_______________________________________________
29 // own includes
30
31 #ifndef __FRAMEWORK_ACCELERATORCONST_H_
32 #include <acceleratorconst.h>
33 #endif
34
35 //_______________________________________________
36 // interface includes
37 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
38 #include <com/sun/star/awt/KeyModifier.hpp>
39 #include <com/sun/star/awt/KeyEvent.hpp>
40 #include <com/sun/star/awt/Key.hpp>
41 #include <com/sun/star/container/ElementExistException.hpp>
42
43 //_______________________________________________
44 // other includes
45 #include <vcl/svapp.hxx>
46 #include <rtl/ustrbuf.hxx>
47
48 //_______________________________________________
49 // namespace
50
51 namespace framework{
52
53 //-----------------------------------------------
54 /* Throws a SaxException in case a wrong formatted XML
55 structure was detected.
56
57 This macro combined the given comment with a generic
58 way to find out the XML line (where the error occurred)
59 to format a suitable message.
60
61 @param COMMENT
62 an ascii string, which describes the problem.
63 */
64 #define THROW_PARSEEXCEPTION(COMMENT) \
65 { \
66 ::rtl::OUStringBuffer sMessage(256); \
67 sMessage.append (implts_getErrorLineString()); \
68 sMessage.appendAscii(COMMENT ); \
69 \
70 throw css::xml::sax::SAXException( \
71 sMessage.makeStringAndClear(), \
72 static_cast< css::xml::sax::XDocumentHandler* >(this), \
73 css::uno::Any()); \
74 }
75
76 //-----------------------------------------------
77 // XInterface
DEFINE_XINTERFACE_1(AcceleratorConfigurationReader,OWeakObject,DIRECT_INTERFACE (css::xml::sax::XDocumentHandler))78 DEFINE_XINTERFACE_1(AcceleratorConfigurationReader ,
79 OWeakObject ,
80 DIRECT_INTERFACE(css::xml::sax::XDocumentHandler))
81
82 //-----------------------------------------------
83 AcceleratorConfigurationReader::AcceleratorConfigurationReader(AcceleratorCache& rContainer)
84 : ThreadHelpBase (&Application::GetSolarMutex())
85 , OWeakObject ( )
86 , m_rContainer (rContainer )
87 , m_bInsideAcceleratorList(sal_False )
88 , m_bInsideAcceleratorItem(sal_False )
89 {
90 }
91
92 //-----------------------------------------------
~AcceleratorConfigurationReader()93 AcceleratorConfigurationReader::~AcceleratorConfigurationReader()
94 {
95 }
96
97 //-----------------------------------------------
startDocument()98 void SAL_CALL AcceleratorConfigurationReader::startDocument()
99 {
100 }
101
102 //-----------------------------------------------
endDocument()103 void SAL_CALL AcceleratorConfigurationReader::endDocument()
104 {
105 // The xml file seems to be corrupted.
106 // Because we found no end-tags... at least for
107 // one list or item.
108 if (
109 (m_bInsideAcceleratorList) ||
110 (m_bInsideAcceleratorItem)
111 )
112 {
113 THROW_PARSEEXCEPTION("No matching start or end element 'acceleratorlist' found!")
114 }
115 }
116
117 //-----------------------------------------------
startElement(const::rtl::OUString & sElement,const css::uno::Reference<css::xml::sax::XAttributeList> & xAttributeList)118 void SAL_CALL AcceleratorConfigurationReader::startElement(const ::rtl::OUString& sElement ,
119 const css::uno::Reference< css::xml::sax::XAttributeList >& xAttributeList)
120 {
121 EXMLElement eElement = AcceleratorConfigurationReader::implst_classifyElement(sElement);
122
123 // Note: We handle "accel:item" before "accel:acceleratorlist" to perform this operation.
124 // Because an item occurs very often... a list should occur one time only!
125 if (eElement == E_ELEMENT_ITEM)
126 {
127 if (!m_bInsideAcceleratorList)
128 THROW_PARSEEXCEPTION("An element \"accel:item\" must be embedded into 'accel:acceleratorlist'.")
129 if (m_bInsideAcceleratorItem)
130 THROW_PARSEEXCEPTION("An element \"accel:item\" is not a container.")
131 m_bInsideAcceleratorItem = sal_True;
132
133 ::rtl::OUString sCommand;
134 css::awt::KeyEvent aEvent ;
135
136 sal_Int16 c = xAttributeList->getLength();
137 sal_Int16 i = 0;
138 for (i=0; i<c; ++i)
139 {
140 ::rtl::OUString sAttribute = xAttributeList->getNameByIndex(i);
141 ::rtl::OUString sValue = xAttributeList->getValueByIndex(i);
142 EXMLAttribute eAttribute = AcceleratorConfigurationReader::implst_classifyAttribute(sAttribute);
143 switch(eAttribute)
144 {
145 case E_ATTRIBUTE_URL :
146 sCommand = sValue.intern();
147 break;
148
149 case E_ATTRIBUTE_KEYCODE :
150 aEvent.KeyCode = m_rKeyMapping->mapIdentifierToCode(sValue);
151 break;
152
153 case E_ATTRIBUTE_MOD_SHIFT :
154 aEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
155 break;
156
157 case E_ATTRIBUTE_MOD_MOD1 :
158 aEvent.Modifiers |= css::awt::KeyModifier::MOD1;
159 break;
160
161 case E_ATTRIBUTE_MOD_MOD2 :
162 aEvent.Modifiers |= css::awt::KeyModifier::MOD2;
163 break;
164
165 case E_ATTRIBUTE_MOD_MOD3 :
166 aEvent.Modifiers |= css::awt::KeyModifier::MOD3;
167 }
168 }
169
170 // validate command and key event.
171 if (
172 (!sCommand.getLength()) ||
173 (aEvent.KeyCode == 0 )
174 )
175 {
176 THROW_PARSEEXCEPTION("XML element does not describe a valid accelerator nor a valid command.")
177 }
178
179 // register key event + command inside cache...
180 // Check for already existing items there.
181 if (!m_rContainer.hasKey(aEvent))
182 m_rContainer.setKeyCommandPair(aEvent, sCommand);
183 #ifdef ENABLE_WARNINGS
184 else
185 {
186 // Attention: It's not really a reason to throw an exception and kill the office, if the configuration contains
187 // multiple registrations for the same key :-) Show a warning... and ignore the second item.
188 // THROW_PARSEEXCEPTION("Command is registered for the same key more than once.")
189 ::rtl::OUStringBuffer sMsg(256);
190 sMsg.appendAscii("Double registration detected.\nCommand = \"");
191 sMsg.append (sCommand );
192 sMsg.appendAscii("\"\nKeyCode = " );
193 sMsg.append ((sal_Int32)aEvent.KeyCode );
194 sMsg.appendAscii("\nModifiers = " );
195 sMsg.append ((sal_Int32)aEvent.Modifiers );
196 sMsg.appendAscii("\nIgnore this item!" );
197 LOG_WARNING("AcceleratorConfigurationReader::startElement()", U2B(sMsg.makeStringAndClear()))
198 }
199 #endif // ENABLE_WARNINGS
200 }
201
202 if (eElement == E_ELEMENT_ACCELERATORLIST)
203 {
204 if (m_bInsideAcceleratorList)
205 THROW_PARSEEXCEPTION("An element \"accel:acceleratorlist\" cannot be used recursive.")
206 m_bInsideAcceleratorList = sal_True;
207 return;
208 }
209 }
210
211 //-----------------------------------------------
endElement(const::rtl::OUString & sElement)212 void SAL_CALL AcceleratorConfigurationReader::endElement(const ::rtl::OUString& sElement)
213 {
214 EXMLElement eElement = AcceleratorConfigurationReader::implst_classifyElement(sElement);
215
216 // Note: We handle "accel:item" before "accel:acceleratorlist" to perform this operation.
217 // Because an item occurs very often... a list should occur one time only!
218 if (eElement == E_ELEMENT_ITEM)
219 {
220 if (!m_bInsideAcceleratorItem)
221 THROW_PARSEEXCEPTION("Found end element 'accel:item', but no start element.")
222 m_bInsideAcceleratorItem = sal_False;
223 }
224
225 if (eElement == E_ELEMENT_ACCELERATORLIST)
226 {
227 if (!m_bInsideAcceleratorList)
228 THROW_PARSEEXCEPTION("Found end element 'accel:acceleratorlist', but no start element.")
229 m_bInsideAcceleratorList = sal_False;
230 }
231 }
232
233 //-----------------------------------------------
characters(const::rtl::OUString &)234 void SAL_CALL AcceleratorConfigurationReader::characters(const ::rtl::OUString&)
235 {
236 }
237
238 //-----------------------------------------------
ignorableWhitespace(const::rtl::OUString &)239 void SAL_CALL AcceleratorConfigurationReader::ignorableWhitespace(const ::rtl::OUString&)
240 {
241 }
242
243 //-----------------------------------------------
processingInstruction(const::rtl::OUString &,const::rtl::OUString &)244 void SAL_CALL AcceleratorConfigurationReader::processingInstruction(const ::rtl::OUString& /*sTarget*/,
245 const ::rtl::OUString& /*sData*/ )
246 {
247 }
248
249 //-----------------------------------------------
setDocumentLocator(const css::uno::Reference<css::xml::sax::XLocator> & xLocator)250 void SAL_CALL AcceleratorConfigurationReader::setDocumentLocator(const css::uno::Reference< css::xml::sax::XLocator >& xLocator)
251 {
252 m_xLocator = xLocator;
253 }
254
255 //-----------------------------------------------
implst_classifyElement(const::rtl::OUString & sElement)256 AcceleratorConfigurationReader::EXMLElement AcceleratorConfigurationReader::implst_classifyElement(const ::rtl::OUString& sElement)
257 {
258 AcceleratorConfigurationReader::EXMLElement eElement;
259
260 if (sElement.equals(NS_ELEMENT_ACCELERATORLIST))
261 eElement = E_ELEMENT_ACCELERATORLIST;
262 else
263 if (sElement.equals(NS_ELEMENT_ITEM))
264 eElement = E_ELEMENT_ITEM;
265 else
266 throw css::uno::RuntimeException(
267 DECLARE_ASCII("Unknown XML element detected!"),
268 css::uno::Reference< css::xml::sax::XDocumentHandler >());
269
270 return eElement;
271 }
272
273 //-----------------------------------------------
implst_classifyAttribute(const::rtl::OUString & sAttribute)274 AcceleratorConfigurationReader::EXMLAttribute AcceleratorConfigurationReader::implst_classifyAttribute(const ::rtl::OUString& sAttribute)
275 {
276 AcceleratorConfigurationReader::EXMLAttribute eAttribute;
277
278 if (sAttribute.equals(NS_ATTRIBUTE_KEYCODE))
279 eAttribute = E_ATTRIBUTE_KEYCODE;
280 else
281 if (sAttribute.equals(NS_ATTRIBUTE_MOD_SHIFT))
282 eAttribute = E_ATTRIBUTE_MOD_SHIFT;
283 else
284 if (sAttribute.equals(NS_ATTRIBUTE_MOD_MOD1))
285 eAttribute = E_ATTRIBUTE_MOD_MOD1;
286 else
287 if (sAttribute.equals(NS_ATTRIBUTE_MOD_MOD2))
288 eAttribute = E_ATTRIBUTE_MOD_MOD2;
289 else
290 if (sAttribute.equals(NS_ATTRIBUTE_MOD_MOD3))
291 eAttribute = E_ATTRIBUTE_MOD_MOD3;
292 else
293 if (sAttribute.equals(NS_ATTRIBUTE_URL))
294 eAttribute = E_ATTRIBUTE_URL;
295 else
296 throw css::uno::RuntimeException(
297 DECLARE_ASCII("Unknown XML attribute detected!"),
298 css::uno::Reference< css::xml::sax::XDocumentHandler >());
299
300 return eAttribute;
301 }
302
303 //-----------------------------------------------
implts_getErrorLineString()304 ::rtl::OUString AcceleratorConfigurationReader::implts_getErrorLineString()
305 {
306 if (!m_xLocator.is())
307 return DECLARE_ASCII("Error during parsing XML. (No further info available...)");
308
309 ::rtl::OUStringBuffer sMsg(256);
310 sMsg.appendAscii("Error during parsing XML in\nline = ");
311 sMsg.append (m_xLocator->getLineNumber() );
312 sMsg.appendAscii("\ncolumn = " );
313 sMsg.append (m_xLocator->getColumnNumber() );
314 sMsg.appendAscii("." );
315 return sMsg.makeStringAndClear();
316 }
317
318 } // namespace framework
319