MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
TokenGroup.cpp
Go to the documentation of this file.
1 /* TokenGroup.cpp
2 
3  Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU General Public License
7  as published by the Free Software Foundation; either version 2
8  of the License, or (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  Or, point your browser to http://www.gnu.org/copyleft/gpl.html
19 
20 */
21 
22 
23 #include "TokenGroup.h"
24 #include "Presentable.h"
25 #include "Ingredients.h"
26 #include "Root.h"
27 #include "BaseClasses.h"
28 #include "ParseNode.h"
29 #include "ASN1Codes.h"
30 #include "Engine.h"
31 
33 {
34  // A pair consisting of an object reference and an optional action slot sequence.
35  m_Object.Initialise(p->GetSeqN(0), engine);
36 
37  if (p->GetSeqCount() > 1)
38  {
39  MHParseNode *pSlots = p->GetSeqN(1);
40 
41  for (int i = 0; i < pSlots->GetSeqCount(); i++)
42  {
43  MHParseNode *pAct = pSlots->GetSeqN(i);
44  MHActionSequence *pActions = new MHActionSequence;
45  m_ActionSlots.Append(pActions);
46 
47  // The action slot entry may be NULL.
48  if (pAct->m_nNodeType != MHParseNode::PNNull)
49  {
50  pActions->Initialise(pAct, engine);
51  }
52  }
53  }
54 }
55 
56 void MHTokenGroupItem::PrintMe(FILE *fd, int nTabs) const
57 {
58  PrintTabs(fd, nTabs);
59  fprintf(fd, "( ");
60  m_Object.PrintMe(fd, nTabs + 1);
61  fprintf(fd, "\n");
62 
63  if (m_ActionSlots.Size() != 0)
64  {
65  PrintTabs(fd, nTabs + 1);
66  fprintf(fd, ":ActionSlots (\n");
67 
68  for (int i = 0; i < m_ActionSlots.Size(); i++)
69  {
70  PrintTabs(fd, nTabs + 2);
71  fprintf(fd, "( // slot %d\n", i);
72  MHActionSequence *pActions = m_ActionSlots.GetAt(i);
73 
74  if (pActions->Size() == 0)
75  {
76  PrintTabs(fd, nTabs + 2);
77  fprintf(fd, "NULL\n");
78  }
79  else
80  {
81  pActions->PrintMe(fd, nTabs + 2);
82  }
83 
84  PrintTabs(fd, nTabs + 2);
85  fprintf(fd, ")\n");
86  }
87 
88  PrintTabs(fd, nTabs + 1);
89  fprintf(fd, ")\n");
90  }
91 
92  PrintTabs(fd, nTabs);
93  fprintf(fd, ")\n");
94 }
95 
97 {
98  for (int i = 0; i < p->GetSeqCount(); i++)
99  {
101  }
102 }
103 
104 void MHMovement::PrintMe(FILE *fd, int nTabs) const
105 {
106  PrintTabs(fd, nTabs);
107  fprintf(fd, "( ");
108 
109  for (int i = 0; i < m_Movement.Size(); i++)
110  {
111  fprintf(fd, "%d ", m_Movement.GetAt(i));
112  }
113 
114  fprintf(fd, ")\n");
115 }
116 
118 {
119  m_nTokenPosition = 1; // Initial value
120 }
121 
123 {
124  MHPresentable::Initialise(p, engine);
125  MHParseNode *pMovements = p->GetNamedArg(C_MOVEMENT_TABLE);
126 
127  if (pMovements)
128  {
129  for (int i = 0; i < pMovements->GetArgCount(); i++)
130  {
131  MHMovement *pMove = new MHMovement;
132  m_MovementTable.Append(pMove);
133  pMove->Initialise(pMovements->GetArgN(i), engine);
134  }
135  }
136 
137  MHParseNode *pTokenGrp = p->GetNamedArg(C_TOKEN_GROUP_ITEMS);
138 
139  if (pTokenGrp)
140  {
141  for (int i = 0; i < pTokenGrp->GetArgCount(); i++)
142  {
143  MHTokenGroupItem *pToken = new MHTokenGroupItem;
144  m_TokenGrpItems.Append(pToken);
145  pToken->Initialise(pTokenGrp->GetArgN(i), engine);
146  }
147  }
148 
149  MHParseNode *pNoToken = p->GetNamedArg(C_NO_TOKEN_ACTION_SLOTS);
150 
151  if (pNoToken)
152  {
153  for (int i = 0; i < pNoToken->GetArgCount(); i++)
154  {
155  MHParseNode *pAct = pNoToken->GetArgN(i);
156  MHActionSequence *pActions = new MHActionSequence;
157  m_NoTokenActionSlots.Append(pActions);
158 
159  // The action slot entry may be NULL.
160  if (pAct->m_nNodeType != MHParseNode::PNNull)
161  {
162  pActions->Initialise(pAct, engine);
163  }
164  }
165  }
166 }
167 
168 // This is used to print the contents of the token group.
169 void MHTokenGroup::PrintContents(FILE *fd, int nTabs) const
170 {
171  MHPresentable::PrintMe(fd, nTabs + 1);
172 
173  if (m_MovementTable.Size() != 0)
174  {
175  PrintTabs(fd, nTabs + 1);
176  fprintf(fd, ":MovementTable (\n");
177 
178  for (int i = 0; i < m_MovementTable.Size(); i++)
179  {
180  m_MovementTable.GetAt(i)->PrintMe(fd, nTabs + 2);
181  }
182 
183  PrintTabs(fd, nTabs + 1);
184  fprintf(fd, ")\n");
185  }
186 
187  if (m_TokenGrpItems.Size() != 0)
188  {
189  PrintTabs(fd, nTabs + 1);
190  fprintf(fd, ":TokenGroupItems (\n");
191 
192  for (int i = 0; i < m_TokenGrpItems.Size(); i++)
193  {
194  m_TokenGrpItems.GetAt(i)->PrintMe(fd, nTabs + 2);
195  }
196 
197  PrintTabs(fd, nTabs + 1);
198  fprintf(fd, ")\n");
199  }
200 
201  if (m_NoTokenActionSlots.Size() != 0)
202  {
203  PrintTabs(fd, nTabs + 1);
204  fprintf(fd, ":NoTokenActionSlots (\n");
205 
206  for (int i = 0; i < m_NoTokenActionSlots.Size(); i++)
207  {
209 
210  if (pActions->Size() == 0)
211  {
212  PrintTabs(fd, nTabs + 2);
213  fprintf(fd, "NULL ");
214  }
215  else
216  {
217  pActions->PrintMe(fd, nTabs + 2);
218  }
219  }
220 
221  PrintTabs(fd, nTabs + 1);
222  fprintf(fd, ")\n");
223  }
224 
225 }
226 
227 void MHTokenGroup::PrintMe(FILE *fd, int nTabs) const
228 {
229  PrintTabs(fd, nTabs);
230  fprintf(fd, "{:TokenGroup ");
231  PrintContents(fd, nTabs);
232  PrintTabs(fd, nTabs);
233  fprintf(fd, "}\n");
234 }
235 
236 // Activate the token group following the standard.
238 {
239  if (m_fRunning)
240  {
241  return;
242  }
243 
245 
246  // We're supposed to apply Activation to each of the "items" but it isn't clear
247  // exactly what that means. Assume it means each of the visibles.
248  for (int i = 0; i < m_TokenGrpItems.Size(); i++)
249  {
250  MHObjectRef *pObject = &m_TokenGrpItems.GetAt(i)->m_Object;
251 
252  // The object reference may be the null reference.
253  // Worse: it seems that sometimes in BBC's MHEG the reference simply doesn't exist.
254  if (pObject->IsSet())
255  {
256  try
257  {
258  engine->FindObject(m_TokenGrpItems.GetAt(i)->m_Object)->Activation(engine);
259  }
260  catch (char const *) {}
261  }
262  }
263 
265  m_fRunning = true;
266  engine->EventTriggered(this, EventIsRunning);
267 }
268 
270 {
271  if (! m_fRunning)
272  {
273  return;
274  }
275 
278 }
279 
280 // Internal function to generate the appropriate events.
281 void MHTokenGroup::TransferToken(int newPos, MHEngine *engine)
282 {
283  if (newPos != m_nTokenPosition)
284  {
286  m_nTokenPosition = newPos;
288  }
289 }
290 
291 // Perform the actions depending on where the token is.
293 {
294  if (m_nTokenPosition == 0) // No slot has the token.
295  {
296  if (n > 0 && n <= m_NoTokenActionSlots.Size())
297  {
298  engine->AddActions(*(m_NoTokenActionSlots.GetAt(n - 1)));
299  }
300  }
301  else
302  {
304  {
306 
307  if (n > 0 && n <= pGroup->m_ActionSlots.Size())
308  {
309  engine->AddActions(*(pGroup->m_ActionSlots.GetAt(n - 1)));
310  }
311  }
312  }
313 }
314 
315 void MHTokenGroup::Move(int n, MHEngine *engine)
316 {
317  if (m_nTokenPosition == 0 || n < 1 || n > m_MovementTable.Size())
318  {
319  TransferToken(0, engine); // Not in the standard
320  }
321  else
322  {
324  }
325 }
326 
327 // ListGroup. This is a complex class and the description was extensively revised in the MHEG corrigendum.
328 // It doesn't seem to be used a great deal in practice and quite a few of the actions haven't been tested.
329 
331 {
332  m_fWrapAround = false;
333  m_fMultipleSelection = false;
334  m_nFirstItem = 1;
336  m_nLastCount = 0;
337 }
339 {
340  while (!m_ItemList.isEmpty())
341  {
342  delete m_ItemList.takeFirst();
343  }
344 }
345 
347 {
348  MHTokenGroup::Initialise(p, engine);
349  MHParseNode *pPositions = p->GetNamedArg(C_POSITIONS);
350 
351  if (pPositions)
352  {
353  for (int i = 0; i < pPositions->GetArgCount(); i++)
354  {
355  MHParseNode *pPos = pPositions->GetArgN(i);
356  QPoint pos(pPos->GetSeqN(0)->GetIntValue(), pPos->GetSeqN(1)->GetIntValue());
357  m_Positions.Append(pos);
358  }
359  }
360 
361  MHParseNode *pWrap = p->GetNamedArg(C_WRAP_AROUND);
362 
363  if (pWrap)
364  {
365  m_fWrapAround = pWrap->GetArgN(0)->GetBoolValue();
366  }
367 
368  MHParseNode *pMultiple = p->GetNamedArg(C_WRAP_AROUND);
369 
370  if (pMultiple)
371  {
372  m_fMultipleSelection = pMultiple->GetArgN(0)->GetBoolValue();
373  }
374 }
375 
376 void MHListGroup::PrintMe(FILE *fd, int nTabs) const
377 {
378  PrintTabs(fd, nTabs);
379  fprintf(fd, "{:ListGroup ");
380  MHTokenGroup::PrintContents(fd, nTabs);
381  PrintTabs(fd, nTabs + 1);
382  fprintf(fd, ":Positions (");
383 
384  for (int i = 0; i < m_Positions.Size(); i++)
385  {
386  fprintf(fd, " ( %d %d )", m_Positions.GetAt(i).x(), m_Positions.GetAt(i).y());
387  }
388 
389  fprintf(fd, ")\n");
390 
391  if (m_fWrapAround)
392  {
393  PrintTabs(fd, nTabs + 1);
394  fprintf(fd, ":WrapAround true\n");
395  }
396 
398  {
399  PrintTabs(fd, nTabs + 1);
400  fprintf(fd, ":MultipleSelection true\n");
401  }
402 
403  PrintTabs(fd, nTabs);
404  fprintf(fd, "}\n");
405 }
406 
408 {
410 
411  for (int i = 0; i < m_TokenGrpItems.Size(); i++)
412  {
413  // Find the item and add it to the list if it isn't already there.
414  try
415  {
416  MHRoot *pItem = (MHRoot *)engine->FindObject(m_TokenGrpItems.GetAt(i)->m_Object);
417  MHListItem *p = 0;
418  QList<MHListItem *>::iterator it = m_ItemList.begin();
419 
420  for (; it != m_ItemList.end(); ++it)
421  {
422  p = *it;
423 
424  if (p->m_pVisible == pItem)
425  {
426  break;
427  }
428  }
429 
430  if (!p)
431  {
432  m_ItemList.append(new MHListItem(pItem));
433  }
434  }
435  catch (...) // Ignore invalid or null objects.
436  {
437  }
438  }
439 }
440 
442 {
443  // Reset the positions of the visibles.
444  for (int j = 0; j < m_ItemList.size(); j++)
445  {
446  m_ItemList.at(j)->m_pVisible->ResetPosition();
447  }
448 
450 }
451 
453 {
455  MHTokenGroup::Activation(engine);
456  Update(engine);
457 }
458 
459 
461 {
462  // Deactivate the visibles.
463  for (int j = 0; j < m_ItemList.size(); j++)
464  {
465  m_ItemList.at(j)->m_pVisible->Deactivation(engine);
466  }
467 
469 }
470 
471 // Update action - set the position of the cells to be displayed and deactivate those
472 // which aren't.
474 {
475  if (m_ItemList.isEmpty()) // Special cases when the list becomes empty
476  {
478  {
479  m_fFirstItemDisplayed = false;
480  engine->EventTriggered(this, EventFirstItemPresented, false);
481  }
482 
484  {
485  m_fLastItemDisplayed = false;
486  engine->EventTriggered(this, EventLastItemPresented, false);
487  }
488  }
489  else // Usual case.
490  {
491  for (int i = 0; i < m_ItemList.size(); i++)
492  {
493  MHRoot *pVis = m_ItemList.at(i)->m_pVisible;
494  int nCell = i + 1 - m_nFirstItem; // Which cell does this item map onto?
495 
496  if (nCell >= 0 && nCell < m_Positions.Size())
497  {
498  if (i == 0 && ! m_fFirstItemDisplayed)
499  {
500  m_fFirstItemDisplayed = true;
501  engine->EventTriggered(this, EventFirstItemPresented, true);
502  }
503 
504  if (i == m_ItemList.size() - 1 && ! m_fLastItemDisplayed)
505  {
506  m_fLastItemDisplayed = true;
507  engine->EventTriggered(this, EventLastItemPresented, true);
508  }
509 
510  try
511  {
512  pVis->SetPosition(m_Positions.GetAt(i - m_nFirstItem + 1).x(), m_Positions.GetAt(i - m_nFirstItem + 1).y(), engine);
513  }
514  catch (...) {}
515 
516  if (! pVis->GetRunningStatus())
517  {
518  pVis->Activation(engine);
519  }
520  }
521  else
522  {
523  if (i == 0 && m_fFirstItemDisplayed)
524  {
525  m_fFirstItemDisplayed = false;
526  engine->EventTriggered(this, EventFirstItemPresented, false);
527  }
528 
529  if (i == m_ItemList.size() - 1 && m_fLastItemDisplayed)
530  {
531  m_fLastItemDisplayed = false;
532  engine->EventTriggered(this, EventLastItemPresented, false);
533  }
534 
535  if (pVis->GetRunningStatus())
536  {
537  pVis->Deactivation(engine);
538  pVis->ResetPosition();
539  }
540  }
541  }
542  }
543 
544  // Generate the HeadItems and TailItems events. Even in the MHEG corrigendum this is unclear.
545  // I'm not at all sure this is right.
547  {
549  }
550 
552  {
553  engine->EventTriggered(this, EventTailItems, m_ItemList.size() - m_nFirstItem);
554  }
555 
556  m_nLastCount = m_ItemList.size();
558 }
559 
560 // Add an item to the list
561 void MHListGroup::AddItem(int nIndex, MHRoot *pItem, MHEngine *engine)
562 {
563  // See if the item is already there and ignore this if it is.
564  QList<MHListItem *>::iterator it = m_ItemList.begin();
565 
566  for (; it != m_ItemList.end(); ++it)
567  {
568  if ((*it)->m_pVisible == pItem)
569  {
570  return;
571  }
572  }
573 
574  // Ignore this if the index is out of range
575  if (nIndex < 1 || nIndex > m_ItemList.size() + 1)
576  {
577  return;
578  }
579 
580  // Insert it at the appropriate position (MHEG indexes count from 1).
581  m_ItemList.insert(nIndex - 1, new MHListItem(pItem));
582 
583  if (nIndex <= m_nFirstItem && m_nFirstItem < m_ItemList.size())
584  {
585  m_nFirstItem++;
586  }
587 
588  Update(engine); // Apply the update behaviour
589 }
590 
591 // Remove an item from the list
593 {
594  // See if the item is already there and ignore this if it is.
595  for (int i = 0; i < m_ItemList.size(); i++)
596  {
597  if (m_ItemList.at(i)->m_pVisible == pItem) // Found it - remove it from the list and reset the posn.
598  {
599  delete m_ItemList.takeAt(i);
600  pItem->ResetPosition();
601 
602  if (i + 1 < m_nFirstItem && m_nFirstItem > 1)
603  {
604  m_nFirstItem--;
605  }
606 
607  return;
608  }
609  }
610 }
611 
612 // Set the selection status of the item to true
613 void MHListGroup::Select(int nIndex, MHEngine *engine)
614 {
615  MHListItem *pListItem = m_ItemList.at(nIndex - 1);
616 
617  if (pListItem == 0 || pListItem->m_fSelected)
618  {
619  return; // Ignore if already selected.
620  }
621 
622  if (! m_fMultipleSelection)
623  {
624  // Deselect any existing selections.
625  for (int i = 0; i < m_ItemList.size(); i++)
626  if (m_ItemList.at(i)->m_fSelected)
627  {
628  Deselect(i + 1, engine);
629  }
630  }
631 
632  pListItem->m_fSelected = true;
633  engine->EventTriggered(this, EventItemSelected, nIndex);
634 }
635 
636 // Set the selection status of the item to false
637 void MHListGroup::Deselect(int nIndex, MHEngine *engine)
638 {
639  MHListItem *pListItem = m_ItemList.at(nIndex - 1);
640 
641  if (pListItem == 0 || ! pListItem->m_fSelected)
642  {
643  return; // Ignore if not selected.
644  }
645 
646  pListItem->m_fSelected = false;
647  engine->EventTriggered(this, EventItemDeselected, nIndex);
648 }
649 
650 // Return the reference to the visible at the particular position.
651 void MHListGroup::GetCellItem(int nCell, const MHObjectRef &itemDest, MHEngine *engine)
652 {
653  if (nCell < 1)
654  {
655  nCell = 1; // First cell
656  }
657 
658  if (nCell > m_Positions.Size())
659  {
660  nCell = m_Positions.Size(); // Last cell.
661  }
662 
663  int nVisIndex = nCell + m_nFirstItem - 2;
664 
665  if (nVisIndex >= 0 && nVisIndex < m_ItemList.size())
666  {
667  MHRoot *pVis = m_ItemList.at(nVisIndex)->m_pVisible;
668  engine->FindObject(itemDest)->SetVariableValue(pVis->m_ObjectReference);
669  }
670  else
671  {
672  engine->FindObject(itemDest)->SetVariableValue(MHObjectRef::Null);
673  }
674 }
675 
676 int MHListGroup::AdjustIndex(int nIndex) // Added in the MHEG corrigendum
677 {
678  int nItems = m_ItemList.size();
679 
680  if (nItems == 0)
681  {
682  return 1;
683  }
684 
685  if (nIndex > nItems)
686  {
687  return ((nIndex - 1) % nItems) + 1;
688  }
689  else if (nIndex < 0)
690  {
691  return nItems - ((-nIndex) % nItems);
692  }
693  else
694  {
695  return nIndex;
696  }
697 }
698 
699 void MHListGroup::GetListItem(int nCell, const MHObjectRef &itemDest, MHEngine *engine)
700 {
701  if (m_fWrapAround)
702  {
703  nCell = AdjustIndex(nCell);
704  }
705 
706  if (nCell < 1 || nCell > m_ItemList.size())
707  {
708  return; // Ignore it if it's out of range and not wrapping
709  }
710 
711  engine->FindObject(itemDest)->SetVariableValue(m_ItemList.at(nCell - 1)->m_pVisible->m_ObjectReference);
712 }
713 
714 void MHListGroup::GetItemStatus(int nCell, const MHObjectRef &itemDest, MHEngine *engine)
715 {
716  if (m_fWrapAround)
717  {
718  nCell = AdjustIndex(nCell);
719  }
720 
721  if (nCell < 1 || nCell > m_ItemList.size())
722  {
723  return;
724  }
725 
726  engine->FindObject(itemDest)->SetVariableValue(m_ItemList.at(nCell - 1)->m_fSelected);
727 }
728 
729 void MHListGroup::SelectItem(int nCell, MHEngine *engine)
730 {
731  if (m_fWrapAround)
732  {
733  nCell = AdjustIndex(nCell);
734  }
735 
736  if (nCell < 1 || nCell > m_ItemList.size())
737  {
738  return;
739  }
740 
741  Select(nCell, engine);
742 }
743 
744 void MHListGroup::DeselectItem(int nCell, MHEngine *engine)
745 {
746  if (m_fWrapAround)
747  {
748  nCell = AdjustIndex(nCell);
749  }
750 
751  if (nCell < 1 || nCell > m_ItemList.size())
752  {
753  return;
754  }
755 
756  Deselect(nCell, engine);
757 }
758 
759 void MHListGroup::ToggleItem(int nCell, MHEngine *engine)
760 {
761  if (m_fWrapAround)
762  {
763  nCell = AdjustIndex(nCell);
764  }
765 
766  if (nCell < 1 || nCell > m_ItemList.size())
767  {
768  return;
769  }
770 
771  if (m_ItemList.at(nCell - 1)->m_fSelected)
772  {
773  Deselect(nCell, engine);
774  }
775  else
776  {
777  Select(nCell, engine);
778  }
779 }
780 
781 void MHListGroup::ScrollItems(int nCell, MHEngine *engine)
782 {
783  nCell += m_nFirstItem;
784 
785  if (m_fWrapAround)
786  {
787  nCell = AdjustIndex(nCell);
788  }
789 
790  if (nCell < 1 || nCell > m_ItemList.size())
791  {
792  return;
793  }
794 
795  m_nFirstItem = nCell;
796  Update(engine);
797 }
798 
799 void MHListGroup::SetFirstItem(int nCell, MHEngine *engine)
800 {
801  if (m_fWrapAround)
802  {
803  nCell = AdjustIndex(nCell);
804  }
805 
806  if (nCell < 1 || nCell > m_ItemList.size())
807  {
808  return;
809  }
810 
811  m_nFirstItem = nCell;
812  Update(engine);
813 }
814 
815 
816 
817 // Actions
819 {
820  MHElemAction::Initialise(p, engine);
821  m_Index.Initialise(p->GetArgN(1), engine);
822  m_Item.Initialise(p->GetArgN(2), engine);
823 }
824 
825 void MHAddItem::PrintArgs(FILE *fd, int) const
826 {
827  m_Index.PrintMe(fd, 0);
828  m_Item.PrintMe(fd, 0);
829 }
830 
832 {
833  MHObjectRef item;
834  m_Item.GetValue(item, engine);
835  Target(engine)->AddItem(m_Index.GetValue(engine), engine->FindObject(item), engine);
836 }
837 
839 {
840  MHElemAction::Initialise(p, engine);
841  m_Index.Initialise(p->GetArgN(1), engine);
842  m_Result.Initialise(p->GetArgN(2), engine);
843 }
844 
846 {
847  m_Index.PrintMe(fd, 0);
848  m_Result.PrintMe(fd, 0);
849 }