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 <stdio.h>
21 #include <sal/macros.h>
22 #include <rtl/ref.hxx>
23 #include <rtl/ustrbuf.hxx>
24
25 #include <xml/menudocumenthandler.hxx>
26 #include <framework/menuconfiguration.hxx>
27
28 #include <com/sun/star/xml/sax/SAXException.hpp>
29 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
30 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
31 #include <com/sun/star/ui/ItemType.hpp>
32 #include <com/sun/star/ui/ItemStyle.hpp>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34
35 #include <comphelper/processfactory.hxx>
36 #include <comphelper/attributelist.hxx>
37
38 #ifdef ATTRIBUTE_HELPID
39 #undef ATTRIBUTE_HELPID
40 #endif
41
42 #define XMLNS_MENU "http://openoffice.org/2001/menu"
43
44 #define ELEMENT_MENUBAR "http://openoffice.org/2001/menu^menubar"
45 #define ELEMENT_MENU "http://openoffice.org/2001/menu^menu"
46 #define ELEMENT_MENUPOPUP "http://openoffice.org/2001/menu^menupopup"
47 #define ELEMENT_MENUITEM "http://openoffice.org/2001/menu^menuitem"
48 #define ELEMENT_MENUSEPARATOR "http://openoffice.org/2001/menu^menuseparator"
49
50 #define ELEMENT_NS_MENUBAR "menu:menubar"
51 #define ELEMENT_NS_MENU "menu:menu"
52 #define ELEMENT_NS_MENUPOPUP "menu:menupopup"
53 #define ELEMENT_NS_MENUITEM "menu:menuitem"
54 #define ELEMENT_NS_MENUSEPARATOR "menu:menuseparator"
55
56 #define ATTRIBUTE_ID "http://openoffice.org/2001/menu^id"
57 #define ATTRIBUTE_LABEL "http://openoffice.org/2001/menu^label"
58 #define ATTRIBUTE_HELPID "http://openoffice.org/2001/menu^helpid"
59 #define ATTRIBUTE_STYLE "http://openoffice.org/2001/menu^style"
60
61 #define ATTRIBUTE_NS_ID "menu:id"
62 #define ATTRIBUTE_NS_LABEL "menu:label"
63 #define ATTRIBUTE_NS_HELPID "menu:helpid"
64 #define ATTRIBUTE_NS_STYLE "menu:style"
65
66 #define ATTRIBUTE_XMLNS_MENU "xmlns:menu"
67
68 #define ATTRIBUTE_TYPE_CDATA "CDATA"
69
70 #define MENUBAR_DOCTYPE "<!DOCTYPE menu:menubar PUBLIC \"-//OpenOffice.org//DTD OfficeDocument 1.0//EN\" \"menubar.dtd\">"
71
72 #define ATTRIBUTE_ITEMSTYLE_TEXT "text"
73 #define ATTRIBUTE_ITEMSTYLE_IMAGE "image"
74 #define ATTRIBUTE_ITEMSTYLE_RADIO "radio"
75
76 // Property names of a menu/menu item ItemDescriptor
77 static const char ITEM_DESCRIPTOR_COMMANDURL[] = "CommandURL";
78 static const char ITEM_DESCRIPTOR_HELPURL[] = "HelpURL";
79 static const char ITEM_DESCRIPTOR_CONTAINER[] = "ItemDescriptorContainer";
80 static const char ITEM_DESCRIPTOR_LABEL[] = "Label";
81 static const char ITEM_DESCRIPTOR_TYPE[] = "Type";
82 static const char ITEM_DESCRIPTOR_STYLE[] = "Style";
83
84 // using namespaces
85
86 using namespace ::com::sun::star::uno;
87 using namespace ::com::sun::star::lang;
88 using namespace ::com::sun::star::beans;
89 using namespace ::com::sun::star::xml::sax;
90 using namespace ::com::sun::star::container;
91 using namespace ::com::sun::star::ui;
92
93 namespace framework
94 {
95
96 struct MenuStyleItem
97 {
98 sal_Int16 nBit;
99 const char* attrName;
100 };
101
102 const MenuStyleItem MenuItemStyles[ ] = {
103 { css::ui::ItemStyle::ICON, ATTRIBUTE_ITEMSTYLE_IMAGE },
104 { css::ui::ItemStyle::TEXT, ATTRIBUTE_ITEMSTYLE_TEXT },
105 { css::ui::ItemStyle::RADIO_CHECK, ATTRIBUTE_ITEMSTYLE_RADIO }
106 };
107
108 sal_Int32 const nMenuStyleItemEntries = SAL_N_ELEMENTS(MenuItemStyles);
109
ExtractMenuParameters(const Sequence<PropertyValue> & rProp,OUString & rCommandURL,OUString & rLabel,OUString & rHelpURL,Reference<XIndexAccess> & rSubMenu,sal_Int16 & rType,sal_Int16 & rStyle)110 static void ExtractMenuParameters( const Sequence< PropertyValue >& rProp,
111 OUString& rCommandURL,
112 OUString& rLabel,
113 OUString& rHelpURL,
114 Reference< XIndexAccess >& rSubMenu,
115 sal_Int16& rType,
116 sal_Int16& rStyle )
117 {
118 for ( sal_Int32 i = 0; i < rProp.getLength(); i++ )
119 {
120 if ( rProp[i].Name == ITEM_DESCRIPTOR_COMMANDURL )
121 {
122 rProp[i].Value >>= rCommandURL;
123 rCommandURL = rCommandURL.intern();
124 }
125 else if ( rProp[i].Name == ITEM_DESCRIPTOR_HELPURL )
126 {
127 rProp[i].Value >>= rHelpURL;
128 }
129 else if ( rProp[i].Name == ITEM_DESCRIPTOR_CONTAINER )
130 {
131 rProp[i].Value >>= rSubMenu;
132 }
133 else if ( rProp[i].Name == ITEM_DESCRIPTOR_LABEL )
134 {
135 rProp[i].Value >>= rLabel;
136 }
137 else if ( rProp[i].Name == ITEM_DESCRIPTOR_TYPE )
138 {
139 rProp[i].Value >>= rType;
140 }
141 else if ( rProp[i].Name == ITEM_DESCRIPTOR_STYLE )
142 {
143 rProp[i].Value >>= rStyle;
144 }
145 }
146 }
147
148 // Base class implementation
149
ReadMenuDocumentHandlerBase()150 ReadMenuDocumentHandlerBase::ReadMenuDocumentHandlerBase() :
151 m_aType( ITEM_DESCRIPTOR_TYPE ),
152 m_aLabel( ITEM_DESCRIPTOR_LABEL ),
153 m_aContainer( ITEM_DESCRIPTOR_CONTAINER ),
154 m_aHelpURL( ITEM_DESCRIPTOR_HELPURL ),
155 m_aCommandURL( ITEM_DESCRIPTOR_COMMANDURL ),
156 m_aStyle( ITEM_DESCRIPTOR_STYLE )
157 {
158 }
159
~ReadMenuDocumentHandlerBase()160 ReadMenuDocumentHandlerBase::~ReadMenuDocumentHandlerBase()
161 {
162 }
163
ignorableWhitespace(const OUString &)164 void SAL_CALL ReadMenuDocumentHandlerBase::ignorableWhitespace(
165 const OUString& )
166 {
167 }
168
processingInstruction(const OUString &,const OUString &)169 void SAL_CALL ReadMenuDocumentHandlerBase::processingInstruction(
170 const OUString& /*aTarget*/, const OUString& /*aData*/ )
171 {
172 }
173
setDocumentLocator(const Reference<XLocator> & xLocator)174 void SAL_CALL ReadMenuDocumentHandlerBase::setDocumentLocator(
175 const Reference< XLocator > &xLocator)
176 {
177 m_xLocator = xLocator;
178 }
179
getErrorLineString()180 OUString ReadMenuDocumentHandlerBase::getErrorLineString()
181 {
182 if ( m_xLocator.is() )
183 {
184 char buffer[32];
185 snprintf( buffer, sizeof(buffer), "Line: %ld - ", static_cast<long>( m_xLocator->getLineNumber() ));
186 return OUString::createFromAscii( buffer );
187 }
188 else
189 return OUString();
190 }
191
initPropertyCommon(Sequence<PropertyValue> & rProps,const OUString & rCommandURL,const OUString & rHelpId,const OUString & rLabel,sal_Int16 nItemStyleBits)192 void ReadMenuDocumentHandlerBase::initPropertyCommon(
193 Sequence< PropertyValue > &rProps, const OUString &rCommandURL,
194 const OUString &rHelpId, const OUString &rLabel, sal_Int16 nItemStyleBits )
195 {
196 rProps[0].Name = m_aCommandURL;
197 rProps[1].Name = m_aHelpURL;
198 rProps[2].Name = m_aContainer;
199 rProps[3].Name = m_aLabel;
200 rProps[4].Name = m_aStyle;
201 rProps[5].Name = m_aType;
202
203 // Common values
204 rProps[0].Value <<= rCommandURL.intern();
205 rProps[1].Value <<= rHelpId;
206 rProps[2].Value <<= Reference< XIndexContainer >();
207 rProps[3].Value <<= rLabel;
208 rProps[4].Value <<= nItemStyleBits;
209 rProps[5].Value <<= css::ui::ItemType::DEFAULT;
210 }
211
OReadMenuDocumentHandler(const Reference<XIndexContainer> & rMenuBarContainer)212 OReadMenuDocumentHandler::OReadMenuDocumentHandler(
213 const Reference< XIndexContainer >& rMenuBarContainer )
214 : m_nElementDepth( 0 ),
215 m_eReaderMode( ReaderMode::None ),
216 m_xMenuBarContainer( rMenuBarContainer ),
217 m_xContainerFactory( rMenuBarContainer, UNO_QUERY )
218 {
219 }
220
~OReadMenuDocumentHandler()221 OReadMenuDocumentHandler::~OReadMenuDocumentHandler()
222 {
223 }
224
startDocument()225 void SAL_CALL OReadMenuDocumentHandler::startDocument()
226 {
227 }
228
endDocument()229 void SAL_CALL OReadMenuDocumentHandler::endDocument()
230 {
231 if ( m_nElementDepth > 0 )
232 {
233 OUString aErrorMessage = getErrorLineString() +
234 "A closing element is missing!";
235 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
236 }
237 }
238
startElement(const OUString & aName,const Reference<XAttributeList> & xAttrList)239 void SAL_CALL OReadMenuDocumentHandler::startElement(
240 const OUString& aName, const Reference< XAttributeList > &xAttrList )
241 {
242 if ( m_eReaderMode != ReaderMode::None )
243 {
244 ++m_nElementDepth;
245 m_xReader->startElement( aName, xAttrList );
246 }
247 else
248 {
249 if ( aName == ELEMENT_MENUBAR )
250 {
251 m_eReaderMode = ReaderMode::MenuBar;
252 m_xReader.set( new OReadMenuBarHandler( m_xMenuBarContainer, m_xContainerFactory ));
253 }
254 else if ( aName == ELEMENT_MENUPOPUP )
255 {
256 m_eReaderMode = ReaderMode::MenuPopup;
257 m_xReader.set( new OReadMenuPopupHandler( m_xMenuBarContainer, m_xContainerFactory ));
258 }
259 ++m_nElementDepth;
260 m_xReader->startDocument();
261 }
262 }
263
characters(const OUString &)264 void SAL_CALL OReadMenuDocumentHandler::characters(const OUString&)
265 {
266 }
267
endElement(const OUString & aName)268 void SAL_CALL OReadMenuDocumentHandler::endElement( const OUString& aName )
269 {
270 if ( m_eReaderMode != ReaderMode::None )
271 {
272 --m_nElementDepth;
273 m_xReader->endElement( aName );
274 if ( 0 == m_nElementDepth )
275 {
276 m_xReader->endDocument();
277 m_xReader.clear();
278 if ( m_eReaderMode == ReaderMode::MenuBar && aName != ELEMENT_MENUBAR )
279 {
280 OUString aErrorMessage = getErrorLineString() +
281 "closing element menubar expected!";
282 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
283 }
284 else if ( m_eReaderMode == ReaderMode::MenuPopup && aName != ELEMENT_MENUPOPUP )
285 {
286 OUString aErrorMessage = getErrorLineString() +
287 "closing element menupopup expected!";
288 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
289 }
290 m_eReaderMode = ReaderMode::None;
291 }
292 }
293 }
294
OReadMenuBarHandler(const Reference<XIndexContainer> & rMenuBarContainer,const Reference<XSingleComponentFactory> & rFactory)295 OReadMenuBarHandler::OReadMenuBarHandler(
296 const Reference< XIndexContainer >& rMenuBarContainer,
297 const Reference< XSingleComponentFactory >& rFactory )
298 : m_nElementDepth( 0 ),
299 m_bMenuMode( false ),
300 m_xMenuBarContainer( rMenuBarContainer ),
301 m_xContainerFactory( rFactory )
302 {
303 }
304
~OReadMenuBarHandler()305 OReadMenuBarHandler::~OReadMenuBarHandler()
306 {
307 }
308
startDocument()309 void SAL_CALL OReadMenuBarHandler::startDocument()
310 {
311 }
312
endDocument()313 void SAL_CALL OReadMenuBarHandler::endDocument()
314 {
315 }
316
startElement(const OUString & rName,const Reference<XAttributeList> & xAttrList)317 void SAL_CALL OReadMenuBarHandler::startElement(
318 const OUString& rName, const Reference< XAttributeList > &xAttrList )
319 {
320 if ( m_bMenuMode )
321 {
322 ++m_nElementDepth;
323 m_xReader->startElement( rName, xAttrList );
324 }
325 else if ( rName == ELEMENT_MENU )
326 {
327 ++m_nElementDepth;
328
329 OUString aHelpId;
330 OUString aCommandId;
331 OUString aLabel;
332 sal_Int16 nItemBits(0);
333
334 m_bMenuMode = true;
335
336 // Container must be factory to create sub container
337 Reference< XComponentContext > xComponentContext(
338 comphelper::getProcessComponentContext() );
339
340 Reference< XIndexContainer > xSubItemContainer;
341 if ( m_xContainerFactory.is() )
342 xSubItemContainer.set( m_xContainerFactory->createInstanceWithContext( xComponentContext ), UNO_QUERY );
343
344 if ( xSubItemContainer.is() )
345 {
346 // read attributes for menu
347 for ( sal_Int16 i=0; i< xAttrList->getLength(); i++ )
348 {
349 OUString aName = xAttrList->getNameByIndex( i );
350 const OUString aValue = xAttrList->getValueByIndex( i );
351 if ( aName == ATTRIBUTE_ID )
352 aCommandId = aValue;
353 else if ( aName == ATTRIBUTE_LABEL )
354 aLabel = aValue;
355 else if ( aName == ATTRIBUTE_HELPID )
356 aHelpId = aValue;
357 else if ( aName == ATTRIBUTE_STYLE )
358 {
359 sal_Int32 nIndex = 0;
360 do
361 {
362 OUString aToken = aValue.getToken( 0, '+', nIndex );
363 if ( !aToken.isEmpty() )
364 {
365 if ( aToken == ATTRIBUTE_ITEMSTYLE_TEXT )
366 nItemBits |= css::ui::ItemStyle::TEXT;
367 else if ( aToken == ATTRIBUTE_ITEMSTYLE_IMAGE )
368 nItemBits |= css::ui::ItemStyle::ICON;
369 else if ( aToken == ATTRIBUTE_ITEMSTYLE_RADIO )
370 nItemBits |= css::ui::ItemStyle::RADIO_CHECK;
371 }
372 }
373 while ( nIndex >= 0 );
374 }
375 }
376
377 if ( !aCommandId.isEmpty() )
378 {
379 Sequence< PropertyValue > aSubMenuProp( 6 );
380 initPropertyCommon( aSubMenuProp, aCommandId, aHelpId, aLabel, nItemBits );
381 aSubMenuProp[2].Value <<= xSubItemContainer;
382
383 m_xMenuBarContainer->insertByIndex( m_xMenuBarContainer->getCount(), makeAny( aSubMenuProp ) );
384 }
385 else
386 {
387 OUString aErrorMessage = getErrorLineString() +
388 "attribute id for element menu required!";
389 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
390 }
391
392 m_xReader.set( new OReadMenuHandler( xSubItemContainer, m_xContainerFactory ));
393 m_xReader->startDocument();
394 }
395 }
396 else
397 {
398 OUString aErrorMessage = getErrorLineString() +
399 "element menu expected!";
400 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
401 }
402 }
403
characters(const OUString &)404 void SAL_CALL OReadMenuBarHandler::characters(const OUString&)
405 {
406 }
407
endElement(const OUString & aName)408 void OReadMenuBarHandler::endElement( const OUString& aName )
409 {
410 if ( m_bMenuMode )
411 {
412 --m_nElementDepth;
413 if ( 0 == m_nElementDepth )
414 {
415 m_xReader->endDocument();
416 m_xReader.clear();
417 m_bMenuMode = false;
418 if ( aName != ELEMENT_MENU )
419 {
420 OUString aErrorMessage = getErrorLineString() +
421 "closing element menu expected!";
422 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
423 }
424 }
425 else
426 m_xReader->endElement( aName );
427 }
428 }
429
OReadMenuHandler(const Reference<XIndexContainer> & rMenuContainer,const Reference<XSingleComponentFactory> & rFactory)430 OReadMenuHandler::OReadMenuHandler(
431 const Reference< XIndexContainer >& rMenuContainer,
432 const Reference< XSingleComponentFactory >& rFactory ) :
433 m_nElementDepth( 0 ),
434 m_bMenuPopupMode( false ),
435 m_xMenuContainer( rMenuContainer ),
436 m_xContainerFactory( rFactory )
437 {
438 }
439
~OReadMenuHandler()440 OReadMenuHandler::~OReadMenuHandler()
441 {
442 }
443
startDocument()444 void SAL_CALL OReadMenuHandler::startDocument()
445 {
446 }
447
endDocument()448 void SAL_CALL OReadMenuHandler::endDocument()
449 {
450 }
451
startElement(const OUString & aName,const Reference<XAttributeList> & xAttrList)452 void SAL_CALL OReadMenuHandler::startElement(
453 const OUString& aName, const Reference< XAttributeList > &xAttrList )
454 {
455 if ( m_bMenuPopupMode )
456 {
457 ++m_nElementDepth;
458 m_xReader->startElement( aName, xAttrList );
459 }
460 else if ( aName == ELEMENT_MENUPOPUP )
461 {
462 ++m_nElementDepth;
463 m_bMenuPopupMode = true;
464 m_xReader.set( new OReadMenuPopupHandler( m_xMenuContainer, m_xContainerFactory ));
465 m_xReader->startDocument();
466 }
467 else
468 {
469 OUString aErrorMessage = getErrorLineString() +
470 "unknown element found!";
471 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
472 }
473 }
474
characters(const OUString &)475 void SAL_CALL OReadMenuHandler::characters(const OUString&)
476 {
477 }
478
endElement(const OUString & aName)479 void SAL_CALL OReadMenuHandler::endElement( const OUString& aName )
480 {
481 if ( m_bMenuPopupMode )
482 {
483 --m_nElementDepth;
484 if ( 0 == m_nElementDepth )
485 {
486 m_xReader->endDocument();
487 m_xReader.clear();
488 m_bMenuPopupMode = false;
489 if ( aName != ELEMENT_MENUPOPUP )
490 {
491 OUString aErrorMessage = getErrorLineString() +
492 "closing element menupopup expected!";
493 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
494 }
495 }
496 else
497 m_xReader->endElement( aName );
498 }
499 }
500
OReadMenuPopupHandler(const Reference<XIndexContainer> & rMenuContainer,const Reference<XSingleComponentFactory> & rFactory)501 OReadMenuPopupHandler::OReadMenuPopupHandler(
502 const Reference< XIndexContainer >& rMenuContainer,
503 const Reference< XSingleComponentFactory >& rFactory ) :
504 m_nElementDepth( 0 ),
505 m_bMenuMode( false ),
506 m_xMenuContainer( rMenuContainer ),
507 m_xContainerFactory( rFactory ),
508 m_xComponentContext( comphelper::getProcessComponentContext() ),
509 m_nNextElementExpected( ELEM_CLOSE_NONE )
510 {
511 }
512
~OReadMenuPopupHandler()513 OReadMenuPopupHandler::~OReadMenuPopupHandler()
514 {
515 }
516
startDocument()517 void SAL_CALL OReadMenuPopupHandler::startDocument()
518 {
519 }
520
endDocument()521 void SAL_CALL OReadMenuPopupHandler::endDocument()
522 {
523 }
524
startElement(const OUString & rName,const Reference<XAttributeList> & xAttrList)525 void SAL_CALL OReadMenuPopupHandler::startElement(
526 const OUString& rName, const Reference< XAttributeList > &xAttrList )
527 {
528 ++m_nElementDepth;
529
530 if ( m_bMenuMode )
531 m_xReader->startElement( rName, xAttrList );
532 else if ( rName == ELEMENT_MENU )
533 {
534 OUString aHelpId;
535 OUString aCommandId;
536 OUString aLabel;
537 sal_Int16 nItemBits(0);
538
539 m_bMenuMode = true;
540
541 // Container must be factory to create sub container
542 Reference< XIndexContainer > xSubItemContainer;
543 if ( m_xContainerFactory.is() )
544 xSubItemContainer.set( m_xContainerFactory->createInstanceWithContext( m_xComponentContext ), UNO_QUERY );
545
546 // read attributes for menu
547 for ( sal_Int16 i=0; i< xAttrList->getLength(); i++ )
548 {
549 OUString aName = xAttrList->getNameByIndex( i );
550 const OUString aValue = xAttrList->getValueByIndex( i );
551 if ( aName == ATTRIBUTE_ID )
552 aCommandId = aValue;
553 else if ( aName == ATTRIBUTE_LABEL )
554 aLabel = aValue;
555 else if ( aName == ATTRIBUTE_HELPID )
556 aHelpId = aValue;
557 else if ( aName == ATTRIBUTE_STYLE )
558 {
559 sal_Int32 nIndex = 0;
560 do
561 {
562 OUString aToken = aValue.getToken( 0, '+', nIndex );
563 if ( !aToken.isEmpty() )
564 {
565 if ( aToken == ATTRIBUTE_ITEMSTYLE_TEXT )
566 nItemBits |= css::ui::ItemStyle::TEXT;
567 else if ( aToken == ATTRIBUTE_ITEMSTYLE_IMAGE )
568 nItemBits |= css::ui::ItemStyle::ICON;
569 else if ( aToken == ATTRIBUTE_ITEMSTYLE_RADIO )
570 nItemBits |= css::ui::ItemStyle::RADIO_CHECK;
571 }
572 }
573 while ( nIndex >= 0 );
574 }
575
576 }
577
578 if ( !aCommandId.isEmpty() )
579 {
580 Sequence< PropertyValue > aSubMenuProp( 6 );
581 initPropertyCommon( aSubMenuProp, aCommandId, aHelpId, aLabel, nItemBits );
582 aSubMenuProp[2].Value <<= xSubItemContainer;
583
584 m_xMenuContainer->insertByIndex( m_xMenuContainer->getCount(), makeAny( aSubMenuProp ) );
585 }
586 else
587 {
588 OUString aErrorMessage = getErrorLineString() +
589 "attribute id for element menu required!";
590 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
591 }
592
593 m_xReader.set( new OReadMenuHandler( xSubItemContainer, m_xContainerFactory ));
594 m_xReader->startDocument();
595 }
596 else if ( rName == ELEMENT_MENUITEM )
597 {
598 OUString aHelpId;
599 OUString aCommandId;
600 OUString aLabel;
601 sal_Int16 nItemBits(0);
602 // read attributes for menu item
603 for ( sal_Int16 i=0; i< xAttrList->getLength(); i++ )
604 {
605 OUString aName = xAttrList->getNameByIndex( i );
606 const OUString aValue = xAttrList->getValueByIndex( i );
607 if ( aName == ATTRIBUTE_ID )
608 aCommandId = aValue;
609 else if ( aName == ATTRIBUTE_LABEL )
610 aLabel = aValue;
611 else if ( aName == ATTRIBUTE_HELPID )
612 aHelpId = aValue;
613 else if ( aName == ATTRIBUTE_STYLE )
614 {
615 sal_Int32 nIndex = 0;
616 do
617 {
618 OUString aToken = aValue.getToken( 0, '+', nIndex );
619 if ( !aToken.isEmpty() )
620 {
621 if ( aToken == ATTRIBUTE_ITEMSTYLE_TEXT )
622 nItemBits |= css::ui::ItemStyle::TEXT;
623 else if ( aToken == ATTRIBUTE_ITEMSTYLE_IMAGE )
624 nItemBits |= css::ui::ItemStyle::ICON;
625 else if ( aToken == ATTRIBUTE_ITEMSTYLE_RADIO )
626 nItemBits |= css::ui::ItemStyle::RADIO_CHECK;
627 }
628 }
629 while ( nIndex >= 0 );
630 }
631
632 }
633
634 if ( !aCommandId.isEmpty() )
635 {
636 Sequence< PropertyValue > aMenuItem( 6 );
637 initPropertyCommon( aMenuItem, aCommandId, aHelpId, aLabel, nItemBits );
638 aMenuItem[2].Value <<= Reference< XIndexContainer >();
639
640 m_xMenuContainer->insertByIndex( m_xMenuContainer->getCount(), makeAny( aMenuItem ) );
641 }
642
643 m_nNextElementExpected = ELEM_CLOSE_MENUITEM;
644 }
645 else if ( rName == ELEMENT_MENUSEPARATOR )
646 {
647 Sequence< PropertyValue > aMenuSeparator( 1 );
648 aMenuSeparator[0].Name = ITEM_DESCRIPTOR_TYPE;
649 aMenuSeparator[0].Value <<= css::ui::ItemType::SEPARATOR_LINE;
650
651 m_xMenuContainer->insertByIndex( m_xMenuContainer->getCount(), makeAny( aMenuSeparator ) );
652
653 m_nNextElementExpected = ELEM_CLOSE_MENUSEPARATOR;
654 }
655 else
656 {
657 OUString aErrorMessage = getErrorLineString() +
658 "unknown element found!";
659 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
660 }
661 }
662
characters(const OUString &)663 void SAL_CALL OReadMenuPopupHandler::characters(const OUString&)
664 {
665 }
666
endElement(const OUString & aName)667 void SAL_CALL OReadMenuPopupHandler::endElement( const OUString& aName )
668 {
669 --m_nElementDepth;
670 if ( m_bMenuMode )
671 {
672 if ( 0 == m_nElementDepth )
673 {
674 m_xReader->endDocument();
675 m_xReader.clear();
676 m_bMenuMode = false;
677 if ( aName != ELEMENT_MENU )
678 {
679 OUString aErrorMessage = getErrorLineString() +
680 "closing element menu expected!";
681 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
682 }
683 }
684 else
685 m_xReader->endElement( aName );
686 }
687 else
688 {
689 if ( m_nNextElementExpected == ELEM_CLOSE_MENUITEM )
690 {
691 if ( aName != ELEMENT_MENUITEM )
692 {
693 OUString aErrorMessage = getErrorLineString() +
694 "closing element menuitem expected!";
695 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
696 }
697 }
698 else if ( m_nNextElementExpected == ELEM_CLOSE_MENUSEPARATOR )
699 {
700 if ( aName != ELEMENT_MENUSEPARATOR )
701 {
702 OUString aErrorMessage = getErrorLineString() +
703 "closing element menuseparator expected!";
704 throw SAXException( aErrorMessage, Reference< XInterface >(), Any() );
705 }
706 }
707
708 m_nNextElementExpected = ELEM_CLOSE_NONE;
709 }
710 }
711
712 // --------------------------------- Write XML ---------------------------------
713
OWriteMenuDocumentHandler(const Reference<XIndexAccess> & rMenuBarContainer,const Reference<XDocumentHandler> & rDocumentHandler,bool bIsMenuBar)714 OWriteMenuDocumentHandler::OWriteMenuDocumentHandler(
715 const Reference< XIndexAccess >& rMenuBarContainer,
716 const Reference< XDocumentHandler >& rDocumentHandler,
717 bool bIsMenuBar ) :
718 m_xMenuBarContainer( rMenuBarContainer ),
719 m_xWriteDocumentHandler( rDocumentHandler ),
720 m_bIsMenuBar( bIsMenuBar )
721 {
722 ::comphelper::AttributeList* pList = new ::comphelper::AttributeList;
723 m_xEmptyList.set( static_cast<XAttributeList *>(pList), UNO_QUERY );
724 m_aAttributeType = ATTRIBUTE_TYPE_CDATA;
725 }
726
~OWriteMenuDocumentHandler()727 OWriteMenuDocumentHandler::~OWriteMenuDocumentHandler()
728 {
729 }
730
WriteMenuDocument()731 void OWriteMenuDocumentHandler::WriteMenuDocument()
732 {
733 rtl::Reference<::comphelper::AttributeList> pList = new ::comphelper::AttributeList;
734
735 m_xWriteDocumentHandler->startDocument();
736
737 // write DOCTYPE line!
738 Reference< XExtendedDocumentHandler > xExtendedDocHandler( m_xWriteDocumentHandler, UNO_QUERY );
739 if ( m_bIsMenuBar /*FIXME*/ && xExtendedDocHandler.is() )
740 {
741 xExtendedDocHandler->unknown( MENUBAR_DOCTYPE );
742 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
743 }
744
745 pList->AddAttribute( ATTRIBUTE_XMLNS_MENU,
746 m_aAttributeType,
747 XMLNS_MENU );
748
749 if ( m_bIsMenuBar ) //FIXME
750 pList->AddAttribute( ATTRIBUTE_NS_ID,
751 m_aAttributeType,
752 "menubar" );
753
754 OUString aRootElement;
755 if ( m_bIsMenuBar )
756 aRootElement = ELEMENT_NS_MENUBAR;
757 else
758 aRootElement = ELEMENT_NS_MENUPOPUP;
759 m_xWriteDocumentHandler->startElement( aRootElement, pList.get() );
760 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
761
762 WriteMenu( m_xMenuBarContainer );
763
764 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
765 m_xWriteDocumentHandler->endElement( aRootElement );
766 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
767 m_xWriteDocumentHandler->endDocument();
768 }
769
WriteMenu(const Reference<XIndexAccess> & rMenuContainer)770 void OWriteMenuDocumentHandler::WriteMenu( const Reference< XIndexAccess >& rMenuContainer )
771 {
772 sal_Int32 nItemCount = rMenuContainer->getCount();
773 bool bSeparator = false;
774 Any aAny;
775
776 for ( sal_Int32 nItemPos = 0; nItemPos < nItemCount; nItemPos++ )
777 {
778 Sequence< PropertyValue > aProps;
779 aAny = rMenuContainer->getByIndex( nItemPos );
780 if ( aAny >>= aProps )
781 {
782 OUString aCommandURL;
783 OUString aLabel;
784 OUString aHelpURL;
785 sal_Int16 nType( css::ui::ItemType::DEFAULT );
786 sal_Int16 nItemBits( 0 );
787 Reference< XIndexAccess > xSubMenu;
788
789 ExtractMenuParameters( aProps, aCommandURL, aLabel, aHelpURL, xSubMenu, nType, nItemBits );
790 if ( xSubMenu.is() )
791 {
792 if ( !aCommandURL.isEmpty() )
793 {
794 ::comphelper::AttributeList* pListMenu = new ::comphelper::AttributeList;
795 Reference< XAttributeList > xListMenu( static_cast<XAttributeList *>(pListMenu) , UNO_QUERY );
796
797 pListMenu->AddAttribute( ATTRIBUTE_NS_ID,
798 m_aAttributeType,
799 aCommandURL );
800
801 if ( !aLabel.isEmpty() )
802 pListMenu->AddAttribute( ATTRIBUTE_NS_LABEL,
803 m_aAttributeType,
804 aLabel );
805
806 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
807 m_xWriteDocumentHandler->startElement( ELEMENT_NS_MENU, xListMenu );
808 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
809 m_xWriteDocumentHandler->startElement( ELEMENT_NS_MENUPOPUP, m_xEmptyList );
810 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
811
812 WriteMenu( xSubMenu );
813
814 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
815 m_xWriteDocumentHandler->endElement( ELEMENT_NS_MENUPOPUP );
816 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
817 m_xWriteDocumentHandler->endElement( ELEMENT_NS_MENU );
818 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
819 bSeparator = false;
820 }
821 }
822 else
823 {
824 if ( nType == css::ui::ItemType::DEFAULT )
825 {
826 if ( !aCommandURL.isEmpty() )
827 {
828 bSeparator = false;
829 WriteMenuItem( aCommandURL, aLabel, aHelpURL, nItemBits );
830 }
831 }
832 else if ( !bSeparator )
833 {
834 // Don't write two separators together
835 WriteMenuSeparator();
836 bSeparator = true;
837 }
838 }
839 }
840 }
841 }
842
WriteMenuItem(const OUString & aCommandURL,const OUString & aLabel,const OUString & aHelpURL,sal_Int16 nStyle)843 void OWriteMenuDocumentHandler::WriteMenuItem( const OUString& aCommandURL, const OUString& aLabel, const OUString& aHelpURL, sal_Int16 nStyle )
844 {
845 ::comphelper::AttributeList* pList = new ::comphelper::AttributeList;
846 Reference< XAttributeList > xList( static_cast<XAttributeList *>(pList) , UNO_QUERY );
847
848 pList->AddAttribute( ATTRIBUTE_NS_ID,
849 m_aAttributeType,
850 aCommandURL );
851
852 if ( !aHelpURL.isEmpty() )
853 {
854 pList->AddAttribute( ATTRIBUTE_NS_HELPID,
855 m_aAttributeType,
856 aHelpURL );
857 }
858
859 if ( !aLabel.isEmpty() )
860 {
861 pList->AddAttribute( ATTRIBUTE_NS_LABEL,
862 m_aAttributeType,
863 aLabel );
864 }
865 if ( nStyle > 0 )
866 {
867 OUStringBuffer aValue;
868 const MenuStyleItem* pStyle = MenuItemStyles;
869
870 for ( sal_Int32 nIndex = 0; nIndex < nMenuStyleItemEntries; ++nIndex, ++pStyle )
871 {
872 if ( nStyle & pStyle->nBit )
873 {
874 if ( !aValue.isEmpty() )
875 aValue.append("+");
876 aValue.appendAscii( pStyle->attrName );
877 }
878 }
879 pList->AddAttribute( ATTRIBUTE_NS_STYLE,
880 m_aAttributeType,
881 aValue.makeStringAndClear() );
882 }
883
884 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
885 m_xWriteDocumentHandler->startElement( ELEMENT_NS_MENUITEM, xList );
886 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
887 m_xWriteDocumentHandler->endElement( ELEMENT_NS_MENUITEM );
888 }
889
WriteMenuSeparator()890 void OWriteMenuDocumentHandler::WriteMenuSeparator()
891 {
892 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
893 m_xWriteDocumentHandler->startElement( ELEMENT_NS_MENUSEPARATOR, m_xEmptyList );
894 m_xWriteDocumentHandler->ignorableWhitespace( OUString() );
895 m_xWriteDocumentHandler->endElement( ELEMENT_NS_MENUSEPARATOR );
896 }
897
898 } // namespace framework
899
900 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
901