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 : namespace framework{
34 :
35 : /* Throws a SaxException in case a wrong formated XML
36 : structure was detected.
37 :
38 : This macro combined the given comment with a generic
39 : way to find out the XML line (where the error occurred)
40 : to format a suitable message.
41 :
42 : @param COMMENT
43 : an ascii string, which describe the problem.
44 : */
45 : #define THROW_PARSEEXCEPTION(COMMENT) \
46 : { \
47 : OUStringBuffer sMessage(256); \
48 : sMessage.append (implts_getErrorLineString()); \
49 : sMessage.appendAscii(COMMENT ); \
50 : \
51 : throw css::xml::sax::SAXException( \
52 : sMessage.makeStringAndClear(), \
53 : static_cast< css::xml::sax::XDocumentHandler* >(this), \
54 : css::uno::Any()); \
55 : }
56 :
57 0 : AcceleratorConfigurationReader::AcceleratorConfigurationReader(AcceleratorCache& rContainer)
58 : : m_rContainer (rContainer )
59 : , m_bInsideAcceleratorList(false )
60 0 : , m_bInsideAcceleratorItem(false )
61 : {
62 0 : }
63 :
64 0 : AcceleratorConfigurationReader::~AcceleratorConfigurationReader()
65 : {
66 0 : }
67 :
68 0 : void SAL_CALL AcceleratorConfigurationReader::startDocument()
69 : throw(css::xml::sax::SAXException,
70 : css::uno::RuntimeException, std::exception )
71 : {
72 0 : }
73 :
74 0 : void SAL_CALL AcceleratorConfigurationReader::endDocument()
75 : throw(css::xml::sax::SAXException,
76 : css::uno::RuntimeException, std::exception )
77 : {
78 : // The xml file seems to be corrupted.
79 : // Because we found no end-tags ... at least for
80 : // one list or item.
81 0 : if (
82 0 : (m_bInsideAcceleratorList) ||
83 : (m_bInsideAcceleratorItem)
84 : )
85 : {
86 0 : THROW_PARSEEXCEPTION("No matching start or end element 'acceleratorlist' found!")
87 : }
88 0 : }
89 :
90 0 : void SAL_CALL AcceleratorConfigurationReader::startElement(const OUString& sElement ,
91 : const css::uno::Reference< css::xml::sax::XAttributeList >& xAttributeList)
92 : throw(css::xml::sax::SAXException,
93 : css::uno::RuntimeException, std::exception )
94 : {
95 0 : EXMLElement eElement = AcceleratorConfigurationReader::implst_classifyElement(sElement);
96 :
97 : // Note: We handle "accel:item" before "accel:acceleratorlist" to perform this operation.
98 : // Because an item occurs very often ... a list should occur one times only!
99 0 : if (eElement == E_ELEMENT_ITEM)
100 : {
101 0 : if (!m_bInsideAcceleratorList)
102 0 : THROW_PARSEEXCEPTION("An element \"accel:item\" must be embeded into 'accel:acceleratorlist'.")
103 0 : if (m_bInsideAcceleratorItem)
104 0 : THROW_PARSEEXCEPTION("An element \"accel:item\" is not a container.")
105 0 : m_bInsideAcceleratorItem = true;
106 :
107 0 : OUString sCommand;
108 0 : css::awt::KeyEvent aEvent;
109 :
110 0 : sal_Int16 c = xAttributeList->getLength();
111 0 : sal_Int16 i = 0;
112 0 : for (i=0; i<c; ++i)
113 : {
114 0 : OUString sAttribute = xAttributeList->getNameByIndex(i);
115 0 : OUString sValue = xAttributeList->getValueByIndex(i);
116 0 : EXMLAttribute eAttribute = AcceleratorConfigurationReader::implst_classifyAttribute(sAttribute);
117 0 : switch(eAttribute)
118 : {
119 : case E_ATTRIBUTE_URL :
120 0 : sCommand = sValue.intern();
121 0 : break;
122 :
123 : case E_ATTRIBUTE_KEYCODE :
124 0 : aEvent.KeyCode = m_rKeyMapping->mapIdentifierToCode(sValue);
125 0 : break;
126 :
127 : case E_ATTRIBUTE_MOD_SHIFT :
128 0 : aEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
129 0 : break;
130 :
131 : case E_ATTRIBUTE_MOD_MOD1 :
132 0 : aEvent.Modifiers |= css::awt::KeyModifier::MOD1;
133 0 : break;
134 :
135 : case E_ATTRIBUTE_MOD_MOD2 :
136 0 : aEvent.Modifiers |= css::awt::KeyModifier::MOD2;
137 0 : break;
138 :
139 : case E_ATTRIBUTE_MOD_MOD3 :
140 0 : aEvent.Modifiers |= css::awt::KeyModifier::MOD3;
141 : }
142 0 : }
143 :
144 : // validate command and key event.
145 0 : if (
146 0 : sCommand.isEmpty() ||
147 0 : (aEvent.KeyCode == 0 )
148 : )
149 : {
150 0 : THROW_PARSEEXCEPTION("XML element does not describe a valid accelerator nor a valid command.")
151 : }
152 :
153 : // register key event + command inside cache ...
154 : // Check for already existing items there.
155 0 : if (!m_rContainer.hasKey(aEvent))
156 0 : m_rContainer.setKeyCommandPair(aEvent, sCommand);
157 : else
158 : {
159 : // Attention: Its not really a reason to throw an exception and kill the office, if the configuration contains
160 : // multiple registrations for the same key :-) Show a warning ... and ignore the second item.
161 : // THROW_PARSEEXCEPTION("Command is registered for the same key more then once.")
162 : SAL_INFO("fwk",
163 : "AcceleratorConfigurationReader::startElement(): Double registration detected. Command=\"" <<
164 : sCommand <<
165 : "\" KeyCode=" <<
166 : aEvent.KeyCode <<
167 : "Modifiers=" <<
168 : aEvent.Modifiers);
169 0 : }
170 : }
171 :
172 0 : if (eElement == E_ELEMENT_ACCELERATORLIST)
173 : {
174 0 : if (m_bInsideAcceleratorList)
175 0 : THROW_PARSEEXCEPTION("An element \"accel:acceleratorlist\" cannot be used recursive.")
176 0 : m_bInsideAcceleratorList = true;
177 0 : return;
178 : }
179 : }
180 :
181 0 : void SAL_CALL AcceleratorConfigurationReader::endElement(const OUString& sElement)
182 : throw(css::xml::sax::SAXException,
183 : css::uno::RuntimeException, std::exception )
184 : {
185 0 : EXMLElement eElement = AcceleratorConfigurationReader::implst_classifyElement(sElement);
186 :
187 : // Note: We handle "accel:item" before "accel:acceleratorlist" to perform this operation.
188 : // Because an item occurs very often ... a list should occur one times only!
189 0 : if (eElement == E_ELEMENT_ITEM)
190 : {
191 0 : if (!m_bInsideAcceleratorItem)
192 0 : THROW_PARSEEXCEPTION("Found end element 'accel:item', but no start element.")
193 0 : m_bInsideAcceleratorItem = false;
194 : }
195 :
196 0 : if (eElement == E_ELEMENT_ACCELERATORLIST)
197 : {
198 0 : if (!m_bInsideAcceleratorList)
199 0 : THROW_PARSEEXCEPTION("Found end element 'accel:acceleratorlist', but no start element.")
200 0 : m_bInsideAcceleratorList = false;
201 : }
202 0 : }
203 :
204 0 : void SAL_CALL AcceleratorConfigurationReader::characters(const OUString&)
205 : throw(css::xml::sax::SAXException,
206 : css::uno::RuntimeException, std::exception )
207 : {
208 0 : }
209 :
210 0 : void SAL_CALL AcceleratorConfigurationReader::ignorableWhitespace(const OUString&)
211 : throw(css::xml::sax::SAXException,
212 : css::uno::RuntimeException, std::exception )
213 : {
214 0 : }
215 :
216 0 : void SAL_CALL AcceleratorConfigurationReader::processingInstruction(const OUString& /*sTarget*/,
217 : const OUString& /*sData*/ )
218 : throw(css::xml::sax::SAXException,
219 : css::uno::RuntimeException, std::exception )
220 : {
221 0 : }
222 :
223 0 : void SAL_CALL AcceleratorConfigurationReader::setDocumentLocator(const css::uno::Reference< css::xml::sax::XLocator >& xLocator)
224 : throw(css::xml::sax::SAXException,
225 : css::uno::RuntimeException, std::exception )
226 : {
227 0 : m_xLocator = xLocator;
228 0 : }
229 :
230 0 : AcceleratorConfigurationReader::EXMLElement AcceleratorConfigurationReader::implst_classifyElement(const OUString& sElement)
231 : {
232 : AcceleratorConfigurationReader::EXMLElement eElement;
233 :
234 0 : if (sElement.equals(NS_ELEMENT_ACCELERATORLIST))
235 0 : eElement = E_ELEMENT_ACCELERATORLIST;
236 0 : else if (sElement.equals(NS_ELEMENT_ITEM))
237 0 : eElement = E_ELEMENT_ITEM;
238 : else
239 : throw css::uno::RuntimeException(
240 : "Unknown XML element detected!",
241 0 : css::uno::Reference< css::xml::sax::XDocumentHandler >());
242 :
243 0 : return eElement;
244 : }
245 :
246 0 : AcceleratorConfigurationReader::EXMLAttribute AcceleratorConfigurationReader::implst_classifyAttribute(const OUString& sAttribute)
247 : {
248 : AcceleratorConfigurationReader::EXMLAttribute eAttribute;
249 :
250 0 : if (sAttribute.equals(NS_ATTRIBUTE_KEYCODE))
251 0 : eAttribute = E_ATTRIBUTE_KEYCODE;
252 0 : else if (sAttribute.equals(NS_ATTRIBUTE_MOD_SHIFT))
253 0 : eAttribute = E_ATTRIBUTE_MOD_SHIFT;
254 0 : else if (sAttribute.equals(NS_ATTRIBUTE_MOD_MOD1))
255 0 : eAttribute = E_ATTRIBUTE_MOD_MOD1;
256 0 : else if (sAttribute.equals(NS_ATTRIBUTE_MOD_MOD2))
257 0 : eAttribute = E_ATTRIBUTE_MOD_MOD2;
258 0 : else if (sAttribute.equals(NS_ATTRIBUTE_MOD_MOD3))
259 0 : eAttribute = E_ATTRIBUTE_MOD_MOD3;
260 0 : else if (sAttribute.equals(NS_ATTRIBUTE_URL))
261 0 : eAttribute = E_ATTRIBUTE_URL;
262 : else
263 : throw css::uno::RuntimeException(
264 : "Unknown XML attribute detected!",
265 0 : css::uno::Reference< css::xml::sax::XDocumentHandler >());
266 :
267 0 : return eAttribute;
268 : }
269 :
270 0 : OUString AcceleratorConfigurationReader::implts_getErrorLineString()
271 : {
272 0 : if (!m_xLocator.is())
273 0 : return OUString("Error during parsing XML. (No further info available ...)");
274 :
275 0 : OUStringBuffer sMsg(256);
276 0 : sMsg.appendAscii("Error during parsing XML in\nline = ");
277 0 : sMsg.append (m_xLocator->getLineNumber() );
278 0 : sMsg.appendAscii("\ncolumn = " );
279 0 : sMsg.append (m_xLocator->getColumnNumber() );
280 0 : sMsg.appendAscii("." );
281 0 : return sMsg.makeStringAndClear();
282 : }
283 :
284 : } // namespace framework
285 :
286 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|