xref: /trunk/main/framework/source/xml/acceleratorconfigurationreader.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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