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