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 formated 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 occured)
59 to format a suitable message.
60
61 @param COMMENT
62 an ascii string, which describe 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 throw(css::xml::sax::SAXException,
100 css::uno::RuntimeException )
101 {
102 }
103
104 //-----------------------------------------------
endDocument()105 void SAL_CALL AcceleratorConfigurationReader::endDocument()
106 throw(css::xml::sax::SAXException,
107 css::uno::RuntimeException )
108 {
109 // The xml file seems to be corrupted.
110 // Because we found no end-tags ... at least for
111 // one list or item.
112 if (
113 (m_bInsideAcceleratorList) ||
114 (m_bInsideAcceleratorItem)
115 )
116 {
117 THROW_PARSEEXCEPTION("No matching start or end element 'acceleratorlist' found!")
118 }
119 }
120
121 //-----------------------------------------------
startElement(const::rtl::OUString & sElement,const css::uno::Reference<css::xml::sax::XAttributeList> & xAttributeList)122 void SAL_CALL AcceleratorConfigurationReader::startElement(const ::rtl::OUString& sElement ,
123 const css::uno::Reference< css::xml::sax::XAttributeList >& xAttributeList)
124 throw(css::xml::sax::SAXException,
125 css::uno::RuntimeException )
126 {
127 EXMLElement eElement = AcceleratorConfigurationReader::implst_classifyElement(sElement);
128
129 // Note: We handle "accel:item" before "accel:acceleratorlist" to perform this operation.
130 // Because an item occures very often ... a list should occure one times only!
131 if (eElement == E_ELEMENT_ITEM)
132 {
133 if (!m_bInsideAcceleratorList)
134 THROW_PARSEEXCEPTION("An element \"accel:item\" must be embeded into 'accel:acceleratorlist'.")
135 if (m_bInsideAcceleratorItem)
136 THROW_PARSEEXCEPTION("An element \"accel:item\" is not a container.")
137 m_bInsideAcceleratorItem = sal_True;
138
139 ::rtl::OUString sCommand;
140 css::awt::KeyEvent aEvent ;
141
142 sal_Int16 c = xAttributeList->getLength();
143 sal_Int16 i = 0;
144 for (i=0; i<c; ++i)
145 {
146 ::rtl::OUString sAttribute = xAttributeList->getNameByIndex(i);
147 ::rtl::OUString sValue = xAttributeList->getValueByIndex(i);
148 EXMLAttribute eAttribute = AcceleratorConfigurationReader::implst_classifyAttribute(sAttribute);
149 switch(eAttribute)
150 {
151 case E_ATTRIBUTE_URL :
152 sCommand = sValue.intern();
153 break;
154
155 case E_ATTRIBUTE_KEYCODE :
156 aEvent.KeyCode = m_rKeyMapping->mapIdentifierToCode(sValue);
157 break;
158
159 case E_ATTRIBUTE_MOD_SHIFT :
160 aEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
161 break;
162
163 case E_ATTRIBUTE_MOD_MOD1 :
164 aEvent.Modifiers |= css::awt::KeyModifier::MOD1;
165 break;
166
167 case E_ATTRIBUTE_MOD_MOD2 :
168 aEvent.Modifiers |= css::awt::KeyModifier::MOD2;
169 break;
170
171 case E_ATTRIBUTE_MOD_MOD3 :
172 aEvent.Modifiers |= css::awt::KeyModifier::MOD3;
173 }
174 }
175
176 // validate command and key event.
177 if (
178 (!sCommand.getLength()) ||
179 (aEvent.KeyCode == 0 )
180 )
181 {
182 THROW_PARSEEXCEPTION("XML element does not describe a valid accelerator nor a valid command.")
183 }
184
185 // register key event + command inside cache ...
186 // Check for already existing items there.
187 if (!m_rContainer.hasKey(aEvent))
188 m_rContainer.setKeyCommandPair(aEvent, sCommand);
189 #ifdef ENABLE_WARNINGS
190 else
191 {
192 // Attention: Its not realy a reason to throw an exception and kill the office, if the configuration contains
193 // multiple registrations for the same key :-) Show a warning ... and ignore the second item.
194 // THROW_PARSEEXCEPTION("Command is registered for the same key more then once.")
195 ::rtl::OUStringBuffer sMsg(256);
196 sMsg.appendAscii("Double registration detected.\nCommand = \"");
197 sMsg.append (sCommand );
198 sMsg.appendAscii("\"\nKeyCode = " );
199 sMsg.append ((sal_Int32)aEvent.KeyCode );
200 sMsg.appendAscii("\nModifiers = " );
201 sMsg.append ((sal_Int32)aEvent.Modifiers );
202 sMsg.appendAscii("\nIgnore this item!" );
203 LOG_WARNING("AcceleratorConfigurationReader::startElement()", U2B(sMsg.makeStringAndClear()))
204 }
205 #endif // ENABLE_WARNINGS
206 }
207
208 if (eElement == E_ELEMENT_ACCELERATORLIST)
209 {
210 if (m_bInsideAcceleratorList)
211 THROW_PARSEEXCEPTION("An element \"accel:acceleratorlist\" cannot be used recursive.")
212 m_bInsideAcceleratorList = sal_True;
213 return;
214 }
215 }
216
217 //-----------------------------------------------
endElement(const::rtl::OUString & sElement)218 void SAL_CALL AcceleratorConfigurationReader::endElement(const ::rtl::OUString& sElement)
219 throw(css::xml::sax::SAXException,
220 css::uno::RuntimeException )
221 {
222 EXMLElement eElement = AcceleratorConfigurationReader::implst_classifyElement(sElement);
223
224 // Note: We handle "accel:item" before "accel:acceleratorlist" to perform this operation.
225 // Because an item occures very often ... a list should occure one times only!
226 if (eElement == E_ELEMENT_ITEM)
227 {
228 if (!m_bInsideAcceleratorItem)
229 THROW_PARSEEXCEPTION("Found end element 'accel:item', but no start element.")
230 m_bInsideAcceleratorItem = sal_False;
231 }
232
233 if (eElement == E_ELEMENT_ACCELERATORLIST)
234 {
235 if (!m_bInsideAcceleratorList)
236 THROW_PARSEEXCEPTION("Found end element 'accel:acceleratorlist', but no start element.")
237 m_bInsideAcceleratorList = sal_False;
238 }
239 }
240
241 //-----------------------------------------------
characters(const::rtl::OUString &)242 void SAL_CALL AcceleratorConfigurationReader::characters(const ::rtl::OUString&)
243 throw(css::xml::sax::SAXException,
244 css::uno::RuntimeException )
245 {
246 }
247
248 //-----------------------------------------------
ignorableWhitespace(const::rtl::OUString &)249 void SAL_CALL AcceleratorConfigurationReader::ignorableWhitespace(const ::rtl::OUString&)
250 throw(css::xml::sax::SAXException,
251 css::uno::RuntimeException )
252 {
253 }
254
255 //-----------------------------------------------
processingInstruction(const::rtl::OUString &,const::rtl::OUString &)256 void SAL_CALL AcceleratorConfigurationReader::processingInstruction(const ::rtl::OUString& /*sTarget*/,
257 const ::rtl::OUString& /*sData*/ )
258 throw(css::xml::sax::SAXException,
259 css::uno::RuntimeException )
260 {
261 }
262
263 //-----------------------------------------------
setDocumentLocator(const css::uno::Reference<css::xml::sax::XLocator> & xLocator)264 void SAL_CALL AcceleratorConfigurationReader::setDocumentLocator(const css::uno::Reference< css::xml::sax::XLocator >& xLocator)
265 throw(css::xml::sax::SAXException,
266 css::uno::RuntimeException )
267 {
268 m_xLocator = xLocator;
269 }
270
271 //-----------------------------------------------
implst_classifyElement(const::rtl::OUString & sElement)272 AcceleratorConfigurationReader::EXMLElement AcceleratorConfigurationReader::implst_classifyElement(const ::rtl::OUString& sElement)
273 {
274 AcceleratorConfigurationReader::EXMLElement eElement;
275
276 if (sElement.equals(NS_ELEMENT_ACCELERATORLIST))
277 eElement = E_ELEMENT_ACCELERATORLIST;
278 else
279 if (sElement.equals(NS_ELEMENT_ITEM))
280 eElement = E_ELEMENT_ITEM;
281 else
282 throw css::uno::RuntimeException(
283 DECLARE_ASCII("Unknown XML element detected!"),
284 css::uno::Reference< css::xml::sax::XDocumentHandler >());
285
286 return eElement;
287 }
288
289 //-----------------------------------------------
implst_classifyAttribute(const::rtl::OUString & sAttribute)290 AcceleratorConfigurationReader::EXMLAttribute AcceleratorConfigurationReader::implst_classifyAttribute(const ::rtl::OUString& sAttribute)
291 {
292 AcceleratorConfigurationReader::EXMLAttribute eAttribute;
293
294 if (sAttribute.equals(NS_ATTRIBUTE_KEYCODE))
295 eAttribute = E_ATTRIBUTE_KEYCODE;
296 else
297 if (sAttribute.equals(NS_ATTRIBUTE_MOD_SHIFT))
298 eAttribute = E_ATTRIBUTE_MOD_SHIFT;
299 else
300 if (sAttribute.equals(NS_ATTRIBUTE_MOD_MOD1))
301 eAttribute = E_ATTRIBUTE_MOD_MOD1;
302 else
303 if (sAttribute.equals(NS_ATTRIBUTE_MOD_MOD2))
304 eAttribute = E_ATTRIBUTE_MOD_MOD2;
305 else
306 if (sAttribute.equals(NS_ATTRIBUTE_MOD_MOD3))
307 eAttribute = E_ATTRIBUTE_MOD_MOD3;
308 else
309 if (sAttribute.equals(NS_ATTRIBUTE_URL))
310 eAttribute = E_ATTRIBUTE_URL;
311 else
312 throw css::uno::RuntimeException(
313 DECLARE_ASCII("Unknown XML attribute detected!"),
314 css::uno::Reference< css::xml::sax::XDocumentHandler >());
315
316 return eAttribute;
317 }
318
319 //-----------------------------------------------
implts_getErrorLineString()320 ::rtl::OUString AcceleratorConfigurationReader::implts_getErrorLineString()
321 {
322 if (!m_xLocator.is())
323 return DECLARE_ASCII("Error during parsing XML. (No further info available ...)");
324
325 ::rtl::OUStringBuffer sMsg(256);
326 sMsg.appendAscii("Error during parsing XML in\nline = ");
327 sMsg.append (m_xLocator->getLineNumber() );
328 sMsg.appendAscii("\ncolumn = " );
329 sMsg.append (m_xLocator->getColumnNumber() );
330 sMsg.appendAscii("." );
331 return sMsg.makeStringAndClear();
332 }
333
334 } // namespace framework
335