1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*!
34   \class QtNativePopupMenu Inventor/Qt/widgets/QtNativePopupMenu.h
35   \brief The QtNativePopupMenu class implements a common interface for popup
36   menu management for all the Coin GUI toolkit libraries.
37 */
38 
39 // *************************************************************************
40 
41 // FIXME: create a new Qt4NativePopupMenu. There are just too
42 // many differences between Qt3 menu handling and Qt4 menu handling.
43 
44 #include <qmetaobject.h>
45 
46 // *************************************************************************
47 
48 // Take care of class name incompatibilities between Qt 3 and Qt 4.
49 
50 #if QT_VERSION < 0x040000 // pre Qt 4
51 #include <qaction.h>
52 #include <qpopupmenu.h>
53 #define QPOPUPMENU_CLASS QPopupMenu
54 #else // Qt 4.0.0+
55 #include <QMenu>
56 #define QPOPUPMENU_CLASS QMenu
57 #endif // Qt 4.0.0+
58 
59 // ************************************************************************
60 
61 #include <Inventor/SoLists.h>
62 #include <Inventor/errors/SoDebugError.h>
63 
64 #include <Inventor/Qt/widgets/QtNativePopupMenu.h>
65 #include <Inventor/Qt/widgets/moc_QtNativePopupMenu.icc>
66 
67 #include <soqtdefs.h>
68 
69 // *************************************************************************
70 
71 struct MenuRecord {
72   int menuid;
73   char * name;
74   char * title;
75   QAction * action;
76   QPOPUPMENU_CLASS * menu;
77   QPOPUPMENU_CLASS * parent;
78 }; // struct MenuRecord
79 
80 struct ItemRecord {
81   int itemid;
82   int flags;
83   char * name;
84   char * title;
85   QAction * action;
86   QPOPUPMENU_CLASS * parent;
87 }; // struct ItemRecord
88 
89 #define ITEM_MARKED       0x0001
90 #define ITEM_SEPARATOR    0x0002
91 #define ITEM_ENABLED      0x0004
92 
93 // *************************************************************************
94 
95 /*!
96   The constructor.
97 */
98 
QtNativePopupMenu(void)99 QtNativePopupMenu::QtNativePopupMenu(
100   void)
101 {
102   this->menus = new SbPList;
103   this->items = new SbPList;
104 } // QtNativePopupMenu()
105 
106 /*!
107   Destructor.
108 */
109 
~QtNativePopupMenu()110 QtNativePopupMenu::~QtNativePopupMenu()
111 {
112   const int numMenus = this->menus->getLength();
113 
114   int i;
115   for (i = 0; i < numMenus; i++) {
116     MenuRecord * rec = (MenuRecord *) (*this->menus)[i];
117     delete [] rec->name;
118     delete [] rec->title;
119     // We used to delete only the root menu, and trust that Qt cleaned
120     // up all submenus, but after doing some testing with huge menus,
121     // we found that Qt does _not_ automatically delete submenus when
122     // the parent is destructed. We therefore delete all menus
123     // manually here. pederb, 2005-12-05
124     delete rec->menu;
125     delete rec;
126   }
127 
128   const int numItems = this->items->getLength();
129   for (i = 0; i < numItems; i++) {
130     ItemRecord * rec = (ItemRecord *) (*this->items)[i];
131     delete [] rec->name;
132     delete [] rec->title;
133     delete rec;
134   }
135 
136   delete this->menus;
137   delete this->items;
138 
139 } // ~QtNativePopupMenu()
140 
141 // *************************************************************************
142 
143 /*!
144 */
145 
146 int
newMenu(const char * name,int menuid)147 QtNativePopupMenu::newMenu(
148   const char * name,
149   int menuid)
150 {
151   // FIXME: this function is the same in the other So-libraries --
152   // move to common abstraction layer SoGuiPopupMenu of
153   // possible. 20031012 mortene.
154 
155   int id = menuid;
156   if (id == -1) {
157     id = 1;
158     while (this->getMenuRecord(id) != NULL) id++;
159   } else {
160     assert(this->getMenuRecord(id) == NULL &&
161             "requested menuid already taken");
162   }
163 
164   // id contains ok ID
165   MenuRecord * rec = this->createMenuRecord(name);
166   rec->menuid = id;
167   this->menus->append((void *) rec);
168   return id;
169 } // newMenu()
170 
171 /*!
172 */
173 
174 int
getMenu(const char * name)175 QtNativePopupMenu::getMenu(
176   const char * name)
177 {
178   const int numMenus = this->menus->getLength();
179   int i;
180   for (i = 0; i < numMenus; i++) {
181     MenuRecord * rec = (MenuRecord *) (*this->menus)[i];
182     if (strcmp(rec->name, name) == 0)
183       return rec->menuid;
184   }
185   return -1;
186 } // getMenu()
187 
188 /*!
189 */
190 
191 void
setMenuTitle(int menuid,const char * title)192 QtNativePopupMenu::setMenuTitle(
193   int menuid,
194   const char * title)
195 {
196   MenuRecord * rec = this->getMenuRecord(menuid);
197   assert(rec && "no such menu");
198   delete [] rec->title;
199   rec->title = strcpy(new char [strlen(title)+1], title);
200 #if QT_VERSION >= 200
201   if (rec->parent) {
202     //rec->parent->actionAt(QPoint(rec->menuid,0))->setText(rec->title);
203     getMenuRecord(rec->menuid)->action->setText(rec->title);
204   }
205 #else // Qt version < 2.0.0
206   // This QMenuData::changeItem() method is being obsoleted from Qt
207   // from version 2.0.0 onwards.
208   if (rec->parent)
209     rec->parent->changeItem(rec->title, rec->menuid);
210 #endif // Qt version < 2.0.0
211 } // setMenuTitle()
212 
213 /*!
214 */
215 
216 const char *
getMenuTitle(int menuid)217 QtNativePopupMenu::getMenuTitle(
218   int menuid)
219 {
220   MenuRecord * rec = this->getMenuRecord(menuid);
221   assert(rec && "no such menu");
222   return rec->title;
223 } // getMenuTitle()
224 
225 // *************************************************************************
226 
227 /*!
228 */
229 
230 int
newMenuItem(const char * name,int itemid)231 QtNativePopupMenu::newMenuItem(
232   const char * name,
233   int itemid)
234 {
235   int id = itemid;
236   if (id == -1) {
237     id = 1;
238     while (this->getItemRecord(id) != NULL) id++;
239   } else {
240     assert(this->getItemRecord(itemid) == NULL &&
241             "requested itemid already taken");
242   }
243   ItemRecord * rec = createItemRecord(name);
244   rec->itemid = id;
245   this->items->append(rec);
246   return id;
247 } // newMenuItem()
248 
249 /*!
250 */
251 
252 int
getMenuItem(const char * name)253 QtNativePopupMenu::getMenuItem(
254   const char * name)
255 {
256   const int numItems = this->items->getLength();
257   int i;
258   for (i = 0; i < numItems; i++) {
259     ItemRecord * rec = (ItemRecord *) (*this->items)[i];
260     if (strcmp(rec->name, name) == 0)
261       return rec->itemid;
262   }
263   return -1;
264 } // getMenuItem()
265 
266 /*!
267 */
268 
269 void
setMenuItemTitle(int itemid,const char * title)270 QtNativePopupMenu::setMenuItemTitle(
271   int itemid,
272   const char * title)
273 {
274   ItemRecord * rec = this->getItemRecord(itemid);
275   assert(rec && "no such menu");
276   delete [] rec->title;
277   rec->title = strcpy(new char [strlen(title)+1], title);
278 #if QT_VERSION >= 200
279   if (rec->parent)
280 #if QT_VERSION >= 0x040000
281     rec->parent->actionAt(QPoint(rec->itemid,0))->setText(rec->title);
282 #else
283     rec->parent->changeItem(rec->itemid, QString(rec->title));
284 #endif
285 #else // Qt version < 2.0.0
286   // This QMenuData::changeItem() method is being obsoleted from Qt
287   // from version 2.0.0 onwards.
288   if (rec->parent)
289     rec->parent->changeItem(rec->title, rec->itemid);
290 #endif // Qt version < 2.0.0
291 } // setMenuItemTitle()
292 
293 /*!
294 */
295 
296 const char *
getMenuItemTitle(int itemid)297 QtNativePopupMenu::getMenuItemTitle(
298   int itemid)
299 {
300   ItemRecord * rec = this->getItemRecord(itemid);
301   assert(rec && "no such menu");
302   return rec->title;
303 } // getMenuItemTitle()
304 
305 /*!
306 */
307 
308 void
setMenuItemEnabled(int itemid,SbBool enabled)309 QtNativePopupMenu::setMenuItemEnabled(int itemid,
310                                       SbBool enabled)
311 {
312   ItemRecord * rec = this->getItemRecord(itemid);
313   if (rec) {
314 #if QT_VERSION >= 0x040000
315     rec->parent->actionAt(QPoint(rec->itemid,0))->setEnabled(enabled ? true : false);
316 #else
317     rec->parent->setItemEnabled(rec->itemid, enabled ? true : false);
318 #endif
319     return;
320   }
321   MenuRecord * mrec = this->getMenuRecord(itemid);
322   assert(mrec && "no such menu");
323   assert(mrec->parent && "a menuitem must have a parent to be enabled/disabled");
324 
325 #if QT_VERSION >= 0x040000
326   mrec->parent->actionAt(QPoint(mrec->menuid,0))->setEnabled(enabled ? true : false);
327 #else
328   mrec->parent->setItemEnabled(mrec->menuid, enabled ? true : false);
329 #endif
330 } // setMenuItemEnabled()
331 
332 /*!
333 */
334 
335 SbBool
getMenuItemEnabled(int itemid)336 QtNativePopupMenu::getMenuItemEnabled(int itemid)
337 {
338   ItemRecord * rec = this->getItemRecord(itemid);
339 
340   if (rec) {
341 #if QT_VERSION >= 0x040000
342     return rec->parent->actionAt(QPoint(rec->itemid,0))->isEnabled();
343 #else
344     return rec->parent->isItemEnabled(rec->itemid) ? TRUE : FALSE;
345 #endif
346   }
347 
348   MenuRecord * mrec = this->getMenuRecord(itemid);
349   assert(mrec && "no such menu");
350   assert(mrec->parent && "a menuitem must have a parent to be enabled/disabled");
351 
352 #if QT_VERSION >= 0x040000
353   return mrec->parent->actionAt(QPoint(mrec->menuid,0))->isEnabled();
354 #else
355   return mrec->parent->isItemEnabled(mrec->menuid) ? TRUE : FALSE;
356 #endif
357 } // getMenuItemEnabled()
358 
359 /*!
360 */
361 
362 void
_setMenuItemMarked(int itemid,SbBool marked)363 QtNativePopupMenu::_setMenuItemMarked(int itemid, SbBool marked)
364 {
365   ItemRecord * rec = this->getItemRecord(itemid);
366   if (rec == NULL)
367     return;
368   if (marked)
369     rec->flags |= ITEM_MARKED;
370   else
371     rec->flags &= ~ITEM_MARKED;
372 
373   if (rec->parent != NULL) {
374 #if QT_VERSION >= 0x040000
375     QAction * action = rec->action;
376     if (action) {
377       //FIXME: Could this be done on creation? - BFG 20090910
378       action->setCheckable(true);
379       action->setChecked(marked ? true : false);
380     }
381 #else
382     rec->parent->setItemChecked(rec->itemid, marked ? true : false);
383 #endif
384   }
385 }
386 
387 /*!
388 */
389 
390 SbBool
getMenuItemMarked(int itemid)391 QtNativePopupMenu::getMenuItemMarked(
392   int itemid)
393 {
394   ItemRecord * rec = this->getItemRecord(itemid);
395   assert(rec && "no such menu");
396   if (rec->parent == NULL)
397     return (rec->flags & ITEM_MARKED) ? TRUE : FALSE;
398 
399 #if QT_VERSION >= 0x040000
400   QAction * action = rec->action;
401   if (!action) return false;
402   return action->isChecked();
403 #else
404   return rec->parent->isItemChecked(rec->itemid) ? TRUE : FALSE;
405 #endif
406 } // getMenuItemMarked()
407 
408 // *************************************************************************
409 
410 /*!
411 */
412 
413 void
addMenu(int menuid,int submenuid,int pos)414 QtNativePopupMenu::addMenu(int menuid,
415                            int submenuid,
416                            int pos)
417 {
418   MenuRecord * super = this->getMenuRecord(menuid);
419   MenuRecord * sub = this->getMenuRecord(submenuid);
420   assert(super && sub && "no such menu");
421 
422   // disconnect the submenu from the activated() signal. In Qt 4.0
423   // only the parent menu should be connected, since both the parent
424   // menu and the submenu will generate a call to
425   // itemActivation(). Multiple calls to itemActivation() causes a
426   // segfault when selecting Quadbuffer stereo, at least when it's not
427   // supported. (20050726 frodo)
428 
429   // this was changed/fixed again in Qt 4.4.0, so now we shouldn't
430   // disconnect menu items if this version is detected...
431   // (20070530 pederb)
432 #if (QT_VERSION >= 0x040000) && (QT_VERSION < 0x040400)
433   QObject::disconnect(sub->menu, SIGNAL(activated(int)),
434                       this, SLOT(itemActivation(int)));
435 #endif // QT-version >= 400 && QT-version < 4.4.0
436 
437 #if QT_VERSION >= 0x040000
438   QAction * action;
439   if (pos == -1) {
440     action = super->menu->addMenu(sub->menu);
441   }
442   else {
443     QAction * before = super->menu->actionAt(QPoint(pos,0));
444     action = super->menu->insertMenu(before,sub->menu);
445   }
446   action->setText(QString(sub->title));
447 #else
448   if (pos == -1)
449     super->menu->insertItem(QString(sub->title), sub->menu, sub->menuid);
450   else
451     super->menu->insertItem(QString(sub->title),
452 			    sub->menu, sub->menuid, pos);
453 #endif
454   sub->parent = super->menu;
455 } // addMenu()
456 
457 /*!
458 */
459 
460 void
addMenuItem(int menuid,int itemid,int pos)461 QtNativePopupMenu::addMenuItem(int menuid,
462                                int itemid,
463                                int pos)
464 {
465   MenuRecord * menu = this->getMenuRecord(menuid);
466   assert(menu && "invalid parent menu id");
467   ItemRecord * item = this->getItemRecord(itemid);
468   assert(item && "invalid child menu id");
469 
470 #if QT_VERSION >= 0x040000
471   item->action = new QAction(menu->menu);
472   item->action->setText(item->title);
473   if (pos == -1) {
474     menu->menu->addAction(item->action);
475   }
476   else {
477     menu->menu->insertAction(menu->menu->actionAt(QPoint(pos,0)),item->action);
478   }
479 #else
480   if (pos == -1)
481     menu->menu->insertItem(QString(item->title), item->itemid);
482   else
483     menu->menu->insertItem(QString(item->title), item->itemid, pos);
484 #endif
485   item->parent = menu->menu;
486 
487 #if QT_VERSION >= 0x040000
488   // FIXME: is this really safe? (20050726 frodo)
489   QAction * action = (QAction *) item->parent->actionAt(QPoint(itemid,0));
490   if (action) action->setCheckable(true);
491 #endif // Qt 4.*
492 
493   if (item->flags & ITEM_MARKED) {
494 #if QT_VERSION >= 0x040000
495     if (action) action->setChecked(true);
496 #else
497     item->parent->setItemChecked(item->itemid, true);
498 #endif
499   }
500 } // addMenuItem()
501 
502 void
addSeparator(int menuid,int pos)503 QtNativePopupMenu::addSeparator(int menuid,
504                                 int pos)
505 {
506   MenuRecord * menu = this->getMenuRecord(menuid);
507   assert(menu && "no such menu");
508 
509   ItemRecord * rec = createItemRecord("separator");
510 #if QT_VERSION >= 0x040000
511   menu->menu->insertSeparator(menu->menu->actionAt(QPoint(pos,0)));
512 #else
513   menu->menu->insertSeparator(pos);
514 #endif
515   rec->flags |= ITEM_SEPARATOR;
516   this->items->append(rec);
517 } // addSeparator()
518 
519 /*!
520   This method removes the submenu with the given \a menuid.
521 
522   A removed menu can be attached again later - its menuid will still be
523   allocated.
524 */
525 
526 void
removeMenu(int menuid)527 QtNativePopupMenu::removeMenu(int menuid)
528 {
529   MenuRecord * rec = this->getMenuRecord(menuid);
530   assert(rec && "no such menu");
531 
532   if (rec->menuid == 0) {
533 #if SOQT_DEBUG
534     SoDebugError::postInfo("QtNativePopupMenu::RemoveMenu", "can't remove root");
535 #endif // SOQT_DEBUG
536     return;
537   }
538   if (rec->parent == NULL) {
539 #if SOQT_DEBUG
540     SoDebugError::postInfo("QtNativePopupMenu::RemoveMenu", "menu not attached");
541 #endif // SOQT_DEBUG
542     return;
543   }
544 #if QT_VERSION >= 0x040000
545   rec->parent->removeAction(rec->parent->actionAt(QPoint(rec->menuid,0)));
546 #else
547   rec->parent->removeItem(rec->menuid);
548 #endif
549   rec->parent = NULL;
550 } // removeMenu()
551 
552 /*!
553   This method removes the menu item with the given \a itemid.
554 
555   A removed menu item can be attached again later - its itemid will still
556   be allocated.
557 */
558 
559 void
removeMenuItem(int itemid)560 QtNativePopupMenu::removeMenuItem(int itemid)
561 {
562   ItemRecord * rec = this->getItemRecord(itemid);
563   assert(rec && "no such item");
564 
565   if (rec->parent == NULL) {
566 #if SOQT_DEBUG
567     SoDebugError::postInfo("QtNativePopupMenu::RemoveMenu", "item not attached");
568 #endif // SOQT_DEBUG
569     return;
570   }
571 #if QT_VERSION >= 0x040000
572   rec->parent->removeAction(rec->parent->actionAt(QPoint(rec->itemid,0)));
573 #else
574   rec->parent->removeItem(rec->itemid);
575 #endif
576   rec->parent = NULL;
577 } // removeMenuItem()
578 
579 // *************************************************************************
580 
581 // Doc in superclass.
582 void
popUp(QWidget * inside,int x,int y)583 QtNativePopupMenu::popUp(QWidget * inside, int x, int y)
584 {
585   MenuRecord * rec = this->getMenuRecord(0);
586 
587   // Use exec() and not popup(). popup() doesn't seem to work properly
588   // with a GL widget (the GL-redraw seems to overwrite the popup
589   // widget or something). pederb, 2003-10-01
590   //
591   // An additional piece of information: the popup-menu misbehavior is
592   // that at first attempt just a "shadow" comes up, and then on the
593   // second RMB-press the menu actually comes up. This problem has
594   // only been seen on a few Windows 2000 platforms, though, so in
595   // case we ever need to revert to using popup() again, make sure the
596   // code is properly tested over a wide range of platforms.
597   // mortene, 2003-10-01
598   //
599   // Ignore return value. We use callbacks.
600   (void) rec->menu->exec(inside->mapToGlobal(QPoint(x, y)));
601 }
602 
603 // *************************************************************************
604 
605 /*!
606 */
607 
608 MenuRecord *
getMenuRecord(int menuid)609 QtNativePopupMenu::getMenuRecord(
610   int menuid)
611 {
612   const int numMenus = this->menus->getLength();
613   int i;
614   for (i = 0; i < numMenus; i++)
615     if (((MenuRecord *) (*this->menus)[i])->menuid == menuid)
616       return (MenuRecord *) (*this->menus)[i];
617   return (MenuRecord *) NULL;
618 } // getMenuRecord()
619 
620 /*!
621 */
622 ItemRecord *
getItemRecord(int itemid)623 QtNativePopupMenu::getItemRecord(int itemid)
624 {
625   const int numItems = this->items->getLength();
626   for (int i = 0; i < numItems; i++) {
627     const int recid = ((ItemRecord *) (*this->items)[i])->itemid;
628     if (recid == itemid) { return (ItemRecord *) (*this->items)[i]; }
629   }
630 
631   return (ItemRecord *) NULL;
632 }
633 
634 // *************************************************************************
635 
636 /*!
637 */
638 ItemRecord *
getItemRecordFromAction(QAction * action)639 QtNativePopupMenu::getItemRecordFromAction(QAction * action)
640 {
641   const int numItems = this->items->getLength();
642   for (int i = 0; i < numItems; i++) {
643     const ItemRecord * rec = static_cast<ItemRecord *>((*this->items)[i]);
644     if (rec->action == action) { return (ItemRecord *) (*this->items)[i]; }
645   }
646 
647   return (ItemRecord *) NULL;
648 }
649 
650 // *************************************************************************
651 
652 /*!
653 */
654 
655 MenuRecord *
createMenuRecord(const char * name)656 QtNativePopupMenu::createMenuRecord(
657   const char * name)
658 {
659   MenuRecord * rec = new MenuRecord;
660   rec->menuid = -1;
661   rec->name = strcpy(new char [strlen(name)+1], name);
662   rec->title = strcpy(new char [strlen(name)+1], name);
663 
664 #if QT_VERSION >= 0x040000
665   rec->menu = new QPOPUPMENU_CLASS(QString(name));
666   QObject::connect(rec->menu, SIGNAL(triggered(QAction *)),
667                    this, SLOT(itemActivation(QAction *)));
668 #else
669   rec->menu = new QPOPUPMENU_CLASS((QWidget *) NULL, name);
670   QObject::connect(rec->menu, SIGNAL(activated(int)),
671                    this, SLOT(itemActivation(int)));
672 #endif
673 
674   rec->parent = NULL;
675   rec->action = NULL;
676   return rec;
677 } // create()
678 
679 /*!
680 */
681 
682 ItemRecord *
createItemRecord(const char * name)683 QtNativePopupMenu::createItemRecord(
684   const char * name)
685 {
686   ItemRecord * rec = new ItemRecord;
687   rec->itemid = -1;
688   rec->flags = 0;
689   rec->name = strcpy(new char [strlen(name)+1], name);
690   rec->title = strcpy(new char [strlen(name)+1], name);
691   rec->parent = NULL;
692   rec->action = NULL;
693   return rec;
694 } // create()
695 
696 // *************************************************************************
697 
698 void
itemActivation(QAction * action)699 QtNativePopupMenu::itemActivation(// private slot
700   QAction * action
701   )
702 {
703   ItemRecord * rec = getItemRecordFromAction(action);
704   assert(rec);
705   inherited::invokeMenuSelection(rec->itemid);
706 } // menuSelection()
707 
708 void
itemActivation(int itemid)709 QtNativePopupMenu::itemActivation(// private slot used for Qt3 code path
710   int itemid
711   )
712 {
713   inherited::invokeMenuSelection(itemid);
714 }
715 
716 // *************************************************************************
717