MythTV  0.26-pre
Groups.cpp
Go to the documentation of this file.
00001 /* Groups.cpp
00002 
00003    Copyright (C)  David C. J. Matthews 2004  dm at prolingua.co.uk
00004 
00005    This program is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU General Public License
00007    as published by the Free Software Foundation; either version 2
00008    of the License, or (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; if not, write to the Free Software
00017    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018    Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00019 
00020 */
00021 
00022 #include "Root.h"
00023 #include "Groups.h"
00024 #include "ASN1Codes.h"
00025 #include "ParseNode.h"
00026 #include "Ingredients.h"
00027 #include "Programs.h"
00028 #include "Variables.h"
00029 #include "Presentable.h"
00030 #include "Visible.h"
00031 #include "Engine.h"
00032 #include "Text.h"
00033 #include "Bitmap.h"
00034 #include "Stream.h"
00035 #include "DynamicLineArt.h"
00036 #include "Link.h"
00037 #include "TokenGroup.h"
00038 #include "Logging.h"
00039 
00040 MHGroup::MHGroup()
00041 {
00042     m_nOrigGCPriority = 127; // Default.
00043     m_fIsApp = false;
00044     m_nLastId = 0;
00045 }
00046 
00047 MHGroup::~MHGroup()
00048 {
00049     while (!m_Timers.isEmpty())
00050     {
00051         delete m_Timers.takeFirst();
00052     }
00053 }
00054 
00055 void MHGroup::Initialise(MHParseNode *p, MHEngine *engine)
00056 {
00057     engine->GetGroupId().Copy(""); // Set to empty before we start (just in case).
00058     MHRoot::Initialise(p, engine);
00059 
00060     // Must be an external reference with an object number of zero.
00061     if (m_ObjectReference.m_nObjectNo != 0 || m_ObjectReference.m_GroupId.Size() == 0)
00062     {
00063         MHERROR("Object reference for a group object must be zero and external");
00064     }
00065 
00066     // Set the group id for the rest of the group to this.
00067     engine->GetGroupId().Copy(m_ObjectReference.m_GroupId);
00068     // Some of the information is irrelevant.
00069     //  MHParseNode *pStdId = p->GetNamedArg(C_STANDARD_IDENTIFIER);
00070     //  MHParseNode *pStdVersion = p->GetNamedArg(C_STANDARD_VERSION);
00071     //  MHParseNode *pObjectInfo = p->GetNamedArg(C_OBJECT_INFORMATION);
00072 
00073     MHParseNode *pOnStartUp = p->GetNamedArg(C_ON_START_UP);
00074 
00075     if (pOnStartUp)
00076     {
00077         m_StartUp.Initialise(pOnStartUp, engine);
00078     }
00079 
00080     MHParseNode *pOnCloseDown = p->GetNamedArg(C_ON_CLOSE_DOWN);
00081 
00082     if (pOnCloseDown)
00083     {
00084         m_CloseDown.Initialise(pOnCloseDown, engine);
00085     }
00086 
00087     MHParseNode *pOriginalGCPrio = p->GetNamedArg(C_ORIGINAL_GC_PRIORITY);
00088 
00089     if (pOriginalGCPrio)
00090     {
00091         m_nOrigGCPriority = pOriginalGCPrio->GetArgN(0)->GetIntValue();
00092     }
00093 
00094     // Ignore the other stuff at the moment.
00095     MHParseNode *pItems = p->GetNamedArg(C_ITEMS);
00096 
00097     if (pItems == NULL)
00098     {
00099         p->Failure("Missing :Items block");
00100         return;
00101     }
00102 
00103     for (int i = 0; i < pItems->GetArgCount(); i++)
00104     {
00105         MHParseNode *pItem = pItems->GetArgN(i);
00106         MHIngredient *pIngredient = NULL;
00107 
00108         try
00109         {
00110             // Generate the particular kind of ingredient.
00111             switch (pItem->GetTagNo())
00112             {
00113                 case C_RESIDENT_PROGRAM:
00114                     pIngredient = new MHResidentProgram;
00115                     break;
00116                 case C_REMOTE_PROGRAM:
00117                     pIngredient = new MHRemoteProgram;
00118                     break;
00119                 case C_INTERCHANGED_PROGRAM:
00120                     pIngredient = new MHInterChgProgram;
00121                     break;
00122                 case C_PALETTE:
00123                     pIngredient = new MHPalette;
00124                     break;
00125                 case C_FONT:
00126                     pIngredient = new MHFont;
00127                     break;
00128                 case C_CURSOR_SHAPE:
00129                     pIngredient = new MHCursorShape;
00130                     break;
00131                 case C_BOOLEAN_VARIABLE:
00132                     pIngredient = new MHBooleanVar;
00133                     break;
00134                 case C_INTEGER_VARIABLE:
00135                     pIngredient = new MHIntegerVar;
00136                     break;
00137                 case C_OCTET_STRING_VARIABLE:
00138                     pIngredient = new MHOctetStrVar;
00139                     break;
00140                 case C_OBJECT_REF_VARIABLE:
00141                     pIngredient = new MHObjectRefVar;
00142                     break;
00143                 case C_CONTENT_REF_VARIABLE:
00144                     pIngredient = new MHContentRefVar;
00145                     break;
00146                 case C_LINK:
00147                     pIngredient = new MHLink;
00148                     break;
00149                 case C_STREAM:
00150                     pIngredient = new MHStream;
00151                     break;
00152                 case C_BITMAP:
00153                     pIngredient = new MHBitmap;
00154                     break;
00155                 case C_LINE_ART:
00156                     pIngredient = new MHLineArt;
00157                     break;
00158                 case C_DYNAMIC_LINE_ART:
00159                     pIngredient = new MHDynamicLineArt;
00160                     break;
00161                 case C_RECTANGLE:
00162                     pIngredient = new MHRectangle;
00163                     break;
00164                 case C_HOTSPOT:
00165                     pIngredient = new MHHotSpot;
00166                     break;
00167                 case C_SWITCH_BUTTON:
00168                     pIngredient = new MHSwitchButton;
00169                     break;
00170                 case C_PUSH_BUTTON:
00171                     pIngredient = new MHPushButton;
00172                     break;
00173                 case C_TEXT:
00174                     pIngredient = new MHText;
00175                     break;
00176                 case C_ENTRY_FIELD:
00177                     pIngredient = new MHEntryField;
00178                     break;
00179                 case C_HYPER_TEXT:
00180                     pIngredient = new MHHyperText;
00181                     break;
00182                 case C_SLIDER:
00183                     pIngredient = new MHSlider;
00184                     break;
00185                 case C_TOKEN_GROUP:
00186                     pIngredient = new MHTokenGroup;
00187                     break;
00188                 case C_LIST_GROUP:
00189                     pIngredient = new MHListGroup;
00190                     break;
00191                 default:
00192                     MHLOG(MHLogWarning, QString("Unknown ingredient %1").arg(pItem->GetTagNo()));
00193                     // Future proofing: ignore any ingredients that we don't know about.
00194                     // Obviously these can only arise in the binary coding.
00195             }
00196 
00197             if (pIngredient)
00198             {
00199                 // Initialise it from its argments.
00200                 pIngredient->Initialise(pItem, engine);
00201 
00202                 // Remember the highest numbered ingredient
00203                 if (pIngredient->m_ObjectReference.m_nObjectNo > m_nLastId)
00204                 {
00205                     m_nLastId = pIngredient->m_ObjectReference.m_nObjectNo;
00206                 }
00207 
00208                 // Add it to the ingedients of this group.
00209                 m_Items.Append(pIngredient);
00210             }
00211         }
00212         catch (...)
00213         {
00214             delete(pIngredient);
00215             throw;
00216         }
00217     }
00218 }
00219 
00220 void MHGroup::PrintMe(FILE *fd, int nTabs) const
00221 {
00222     MHRoot::PrintMe(fd, nTabs);
00223 
00224     if (m_StartUp.Size() != 0)
00225     {
00226         PrintTabs(fd, nTabs + 1);
00227         fprintf(fd, ":OnStartUp (\n");
00228         m_StartUp.PrintMe(fd, nTabs + 2);
00229         PrintTabs(fd, nTabs + 2);
00230         fprintf(fd, ")\n");
00231     }
00232 
00233     if (m_CloseDown.Size() != 0)
00234     {
00235         PrintTabs(fd, nTabs + 1);
00236         fprintf(fd, ":OnCloseDown (\n");
00237         m_CloseDown.PrintMe(fd, nTabs + 2);
00238         PrintTabs(fd, nTabs + 2);
00239         fprintf(fd, ")\n");
00240     }
00241 
00242     if (m_nOrigGCPriority != 127)
00243     {
00244         PrintTabs(fd, nTabs + 1);
00245         fprintf(fd, ":OrigGCPriority %d\n", m_nOrigGCPriority);
00246     }
00247 
00248     PrintTabs(fd, nTabs + 1);
00249     fprintf(fd, ":Items ( \n");
00250 
00251     for (int i = 0; i < m_Items.Size(); i++)
00252     {
00253         m_Items.GetAt(i)->PrintMe(fd, nTabs + 2);
00254     }
00255 
00256     PrintTabs(fd, nTabs + 1);
00257     fprintf(fd, ")\n");
00258 }
00259 
00260 // Preparation - sets up the run-time representation.  Sets m_fAvailable and generates IsAvailable event.
00261 void MHGroup::Preparation(MHEngine *engine)
00262 {
00263     // Prepare the ingredients first if they are initially active or are initially available programs.
00264     for (int i = 0; i < m_Items.Size(); i++)
00265     {
00266         MHIngredient *pIngredient = m_Items.GetAt(i);
00267 
00268         if (pIngredient->InitiallyActive() || pIngredient->InitiallyAvailable())
00269         {
00270             pIngredient->Preparation(engine);
00271         }
00272     }
00273 
00274     MHRoot::Preparation(engine); // Prepare the root object and send the IsAvailable event.
00275 }
00276 
00277 // Activation - starts running the object.  Sets m_fRunning and generates IsRunning event.
00278 void MHGroup::Activation(MHEngine *engine)
00279 {
00280     if (m_fRunning)
00281     {
00282         return;
00283     }
00284 
00285     MHRoot::Activation(engine);
00286     // Run any start-up actions.
00287     engine->AddActions(m_StartUp);
00288     engine->RunActions();
00289 
00290     // Activate the ingredients in order.
00291     for (int i = 0; i < m_Items.Size(); i++)
00292     {
00293         MHIngredient *pIngredient = m_Items.GetAt(i);
00294 
00295         if (pIngredient->InitiallyActive())
00296         {
00297             pIngredient->Activation(engine);
00298         }
00299     }
00300 
00301     m_fRunning = true;
00302     // Record the time here.  This is the basis for absolute times.
00303     m_StartTime.start();
00304     // Don't generate IsRunning here - that's done by the sub-classes.
00305 }
00306 
00307 // Deactivation - stops running the object.  Clears m_fRunning
00308 void MHGroup::Deactivation(MHEngine *engine)
00309 {
00310     if (! m_fRunning)
00311     {
00312         return;
00313     }
00314 
00315     // Run any close-down actions.
00316     engine->AddActions(m_CloseDown);
00317     engine->RunActions();
00318     MHRoot::Deactivation(engine);
00319 }
00320 
00321 // Destruction - deletes the run-time representation.  Clears m_fAvailable.
00322 void MHGroup::Destruction(MHEngine *engine)
00323 {
00324     for (int i = m_Items.Size(); i > 0; i--)
00325     {
00326         m_Items.GetAt(i - 1)->Destruction(engine);
00327     }
00328 
00329     MHRoot::Destruction(engine);
00330 }
00331 
00332 // Return an object if its object ID matches (or if it's a stream, if it has a matching component).
00333 MHRoot *MHGroup::FindByObjectNo(int n)
00334 {
00335     if (n == m_ObjectReference.m_nObjectNo)
00336     {
00337         return this;
00338     }
00339 
00340     for (int i = m_Items.Size(); i > 0; i--)
00341     {
00342         MHRoot *pResult = m_Items.GetAt(i - 1)->FindByObjectNo(n);
00343 
00344         if (pResult)
00345         {
00346             return pResult;
00347         }
00348     }
00349 
00350     return NULL;
00351 }
00352 
00353 // Set up a timer or cancel a timer.
00354 void MHGroup::SetTimer(int nTimerId, bool fAbsolute, int nMilliSecs, MHEngine *)
00355 {
00356     // First remove any existing timer with the same Id.
00357     for (int i = 0; i < m_Timers.size(); i++)
00358     {
00359         MHTimer *pTimer = m_Timers.at(i);
00360 
00361         if (pTimer->m_nTimerId == nTimerId)
00362         {
00363             delete m_Timers.takeAt(i);
00364             break;
00365         }
00366     }
00367 
00368     // If the time has passed we don't set up a timer.
00369     QTime currentTime;
00370     currentTime.start(); // Set current time
00371 
00372     if (nMilliSecs < 0 || (fAbsolute && m_StartTime.addMSecs(nMilliSecs) < currentTime))
00373     {
00374         return;
00375     }
00376 
00377     MHTimer *pTimer = new MHTimer;
00378     m_Timers.append(pTimer);
00379     pTimer->m_nTimerId = nTimerId;
00380 
00381     if (fAbsolute)
00382     {
00383         pTimer->m_Time = m_StartTime.addMSecs(nMilliSecs);
00384     }
00385     else
00386     {
00387         pTimer->m_Time = currentTime.addMSecs(nMilliSecs);
00388     }
00389 }
00390 
00391 // Fire any timers that have passed.
00392 int MHGroup::CheckTimers(MHEngine *engine)
00393 {
00394     QTime currentTime = QTime::currentTime(); // Get current time
00395     QList<MHTimer *>::iterator it = m_Timers.begin();
00396     MHTimer *pTimer;
00397     int nMSecs = 0;
00398 
00399     while (it != m_Timers.end())
00400     {
00401         pTimer = *it;
00402 
00403         if (pTimer->m_Time <= currentTime)   // Use <= rather than < here so we fire timers with zero time immediately.
00404         {
00405             // If the time has passed trigger the event and remove the timer from the queue.
00406             engine->EventTriggered(this, EventTimerFired, pTimer->m_nTimerId);
00407             delete pTimer;
00408             it = m_Timers.erase(it);
00409         }
00410         else
00411         {
00412             // This has not yet expired.  Set "nMSecs" to the earliest time we have.
00413             int nMSecsToGo = currentTime.msecsTo(pTimer->m_Time);
00414 
00415             if (nMSecs == 0 || nMSecsToGo < nMSecs)
00416             {
00417                 nMSecs = nMSecsToGo;
00418             }
00419 
00420             ++it;
00421         }
00422     }
00423 
00424     return nMSecs;
00425 }
00426 
00427 // Create a clone of the target and add it to the ingredients.
00428 void MHGroup::MakeClone(MHRoot *pTarget, MHRoot *pRef, MHEngine *engine)
00429 {
00430     MHIngredient *pClone = pTarget->Clone(engine); // Clone it.
00431     pClone->m_ObjectReference.m_GroupId.Copy(m_ObjectReference.m_GroupId); // Group id is the same as this.
00432     pClone->m_ObjectReference.m_nObjectNo = ++m_nLastId; // Create a new object id.
00433     m_Items.Append(pClone);
00434     // Set the object reference result to the newly constructed ref.
00435     pRef->SetVariableValue(pClone->m_ObjectReference);
00436     pClone->Preparation(engine); // Prepare the clone.
00437 }
00438 
00439 MHApplication::MHApplication()
00440 {
00441     m_fIsApp = true;
00442     m_nCharSet = 0;
00443     m_nTextCHook = 0;
00444     m_nIPCHook = 0;
00445     m_nStrCHook = 0;
00446     m_nBitmapCHook = 0;
00447     m_nLineArtCHook = 0;
00448     m_tuneinfo = 0;
00449 
00450     m_pCurrentScene = NULL;
00451     m_nLockCount = 0;
00452     m_fRestarting = false;
00453 }
00454 
00455 MHApplication::~MHApplication()
00456 {
00457     delete(m_pCurrentScene);
00458 }
00459 
00460 void MHApplication::Initialise(MHParseNode *p, MHEngine *engine)
00461 {
00462     MHGroup::Initialise(p, engine);
00463     // OnSpawnCloseDown
00464     MHParseNode *pOnSpawn = p->GetNamedArg(C_ON_SPAWN_CLOSE_DOWN);
00465 
00466     if (pOnSpawn)
00467     {
00468         m_OnSpawnCloseDown.Initialise(pOnSpawn, engine);
00469     }
00470 
00471     // OnRestart
00472     MHParseNode *pOnRestart = p->GetNamedArg(C_ON_RESTART);
00473 
00474     if (pOnRestart)
00475     {
00476         m_OnRestart.Initialise(pOnRestart, engine);
00477     }
00478 
00479     // Default attributes.  These are encoded in a group in binary.
00480     MHParseNode *pDefattrs = p->GetNamedArg(C_DEFAULT_ATTRIBUTES);
00481 
00482     // but in the text form they're encoded in the Application block.
00483     if (pDefattrs == NULL)
00484     {
00485         pDefattrs = p;
00486     }
00487 
00488     MHParseNode *pCharSet = pDefattrs->GetNamedArg(C_CHARACTER_SET);
00489 
00490     if (pCharSet)
00491     {
00492         m_nCharSet = pCharSet->GetArgN(0)->GetIntValue();
00493     }
00494 
00495     // Colours
00496     MHParseNode *pBGColour = pDefattrs->GetNamedArg(C_BACKGROUND_COLOUR);
00497 
00498     if (pBGColour)
00499     {
00500         m_BGColour.Initialise(pBGColour->GetArgN(0), engine);
00501     }
00502 
00503     MHParseNode *pTextColour = pDefattrs->GetNamedArg(C_TEXT_COLOUR);
00504 
00505     if (pTextColour)
00506     {
00507         m_TextColour.Initialise(pTextColour->GetArgN(0), engine);
00508     }
00509 
00510     MHParseNode *pButtonRefColour = pDefattrs->GetNamedArg(C_BUTTON_REF_COLOUR);
00511 
00512     if (pButtonRefColour)
00513     {
00514         m_ButtonRefColour.Initialise(pButtonRefColour->GetArgN(0), engine);
00515     }
00516 
00517     MHParseNode *pHighlightRefColour = pDefattrs->GetNamedArg(C_HIGHLIGHT_REF_COLOUR);
00518 
00519     if (pHighlightRefColour)
00520     {
00521         m_HighlightRefColour.Initialise(pHighlightRefColour->GetArgN(0), engine);
00522     }
00523 
00524     MHParseNode *pSliderRefColour = pDefattrs->GetNamedArg(C_SLIDER_REF_COLOUR);
00525 
00526     if (pSliderRefColour)
00527     {
00528         m_SliderRefColour.Initialise(pSliderRefColour->GetArgN(0), engine);
00529     }
00530 
00531     // Content hooks
00532     MHParseNode *pTextCHook = pDefattrs->GetNamedArg(C_TEXT_CONTENT_HOOK);
00533 
00534     if (pTextCHook)
00535     {
00536         m_nTextCHook = pTextCHook->GetArgN(0)->GetIntValue();
00537     }
00538 
00539     MHParseNode *pIPCHook = pDefattrs->GetNamedArg(C_IP_CONTENT_HOOK);
00540 
00541     if (pIPCHook)
00542     {
00543         m_nIPCHook = pIPCHook->GetArgN(0)->GetIntValue();
00544     }
00545 
00546     MHParseNode *pStrCHook = pDefattrs->GetNamedArg(C_STREAM_CONTENT_HOOK);
00547 
00548     if (pStrCHook)
00549     {
00550         m_nStrCHook = pStrCHook->GetArgN(0)->GetIntValue();
00551     }
00552 
00553     MHParseNode *pBitmapCHook = pDefattrs->GetNamedArg(C_BITMAP_CONTENT_HOOK);
00554 
00555     if (pBitmapCHook)
00556     {
00557         m_nBitmapCHook = pBitmapCHook->GetArgN(0)->GetIntValue();
00558     }
00559 
00560     MHParseNode *pLineArtCHook = pDefattrs->GetNamedArg(C_LINE_ART_CONTENT_HOOK);
00561 
00562     if (pLineArtCHook)
00563     {
00564         m_nLineArtCHook = pLineArtCHook->GetArgN(0)->GetIntValue();
00565     }
00566 
00567     // Font.  This is a little tricky.  There are two attributes both called Font.
00568     // In the binary notation the font here is encoded as 42 whereas the text form
00569     // finds the first occurrence of :Font in the table and returns 13.
00570     MHParseNode *pFont = pDefattrs->GetNamedArg(C_FONT2);
00571 
00572     if (pFont == NULL)
00573     {
00574         pFont = pDefattrs->GetNamedArg(C_FONT);
00575     }
00576 
00577     if (pFont)
00578     {
00579         m_Font.Initialise(pFont->GetArgN(0), engine);
00580     }
00581 
00582     // Font attributes.
00583     MHParseNode *pFontAttrs = pDefattrs->GetNamedArg(C_FONT_ATTRIBUTES);
00584 
00585     if (pFontAttrs)
00586     {
00587         pFontAttrs->GetArgN(0)->GetStringValue(m_FontAttrs);
00588     }
00589 }
00590 
00591 void MHApplication::PrintMe(FILE *fd, int nTabs) const
00592 {
00593     PrintTabs(fd, nTabs);
00594     fprintf(fd, "{:Application ");
00595     MHGroup::PrintMe(fd, nTabs);
00596 
00597     if (m_OnSpawnCloseDown.Size() != 0)
00598     {
00599         PrintTabs(fd, nTabs + 1);
00600         fprintf(fd, ":OnSpawnCloseDown");
00601         m_OnSpawnCloseDown.PrintMe(fd, nTabs + 1);
00602         fprintf(fd, "\n");
00603     }
00604 
00605     if (m_OnRestart.Size() != 0)
00606     {
00607         PrintTabs(fd, nTabs + 1);
00608         fprintf(fd, ":OnRestart");
00609         m_OnRestart.PrintMe(fd, nTabs + 1);
00610         fprintf(fd, "\n");
00611     }
00612 
00613     if (m_nCharSet > 0)
00614     {
00615         PrintTabs(fd, nTabs + 1);
00616         fprintf(fd, ":CharacterSet %d\n", m_nCharSet);
00617     }
00618 
00619     if (m_BGColour.IsSet())
00620     {
00621         PrintTabs(fd, nTabs + 1);
00622         fprintf(fd, ":BackgroundColour ");
00623         m_BGColour.PrintMe(fd, nTabs + 1);
00624         fprintf(fd, "\n");
00625     }
00626 
00627     if (m_nTextCHook > 0)
00628     {
00629         PrintTabs(fd, nTabs + 1);
00630         fprintf(fd, ":TextCHook %d\n", m_nTextCHook);
00631     }
00632 
00633     if (m_TextColour.IsSet())
00634     {
00635         PrintTabs(fd, nTabs + 1);
00636         fprintf(fd, ":TextColour");
00637         m_TextColour.PrintMe(fd, nTabs + 1);
00638         fprintf(fd, "\n");
00639     }
00640 
00641     if (m_Font.IsSet())
00642     {
00643         PrintTabs(fd, nTabs + 1);
00644         fprintf(fd, ":Font ");
00645         m_Font.PrintMe(fd, nTabs + 1);
00646         fprintf(fd, "\n");
00647     }
00648 
00649     if (m_FontAttrs.Size() > 0)
00650     {
00651         PrintTabs(fd, nTabs + 1);
00652         fprintf(fd, ":FontAttributes ");
00653         m_FontAttrs.PrintMe(fd, nTabs + 1);
00654         fprintf(fd, "\n");
00655     }
00656 
00657     if (m_nIPCHook > 0)
00658     {
00659         PrintTabs(fd, nTabs + 1);
00660         fprintf(fd, ":InterchgPrgCHook %d\n", m_nIPCHook);
00661     }
00662 
00663     if (m_nStrCHook > 0)
00664     {
00665         PrintTabs(fd, nTabs + 1);
00666         fprintf(fd, ":StreamCHook %d\n", m_nStrCHook);
00667     }
00668 
00669     if (m_nBitmapCHook > 0)
00670     {
00671         PrintTabs(fd, nTabs + 1);
00672         fprintf(fd, ":BitmapCHook %d\n", m_nBitmapCHook);
00673     }
00674 
00675     if (m_nLineArtCHook > 0)
00676     {
00677         PrintTabs(fd, nTabs + 1);
00678         fprintf(fd, ":LineArtCHook %d\n", m_nLineArtCHook);
00679     }
00680 
00681     if (m_ButtonRefColour.IsSet())
00682     {
00683         PrintTabs(fd, nTabs + 1);
00684         fprintf(fd, ":ButtonRefColour ");
00685         m_ButtonRefColour.PrintMe(fd, nTabs + 1);
00686         fprintf(fd, "\n");
00687     }
00688 
00689     if (m_HighlightRefColour.IsSet())
00690     {
00691         PrintTabs(fd, nTabs + 1);
00692         fprintf(fd, ":HighlightRefColour ");
00693         m_HighlightRefColour.PrintMe(fd, nTabs + 1);
00694         fprintf(fd, "\n");
00695     }
00696 
00697     if (m_SliderRefColour.IsSet())
00698     {
00699         PrintTabs(fd, nTabs + 1);
00700         fprintf(fd, ":SliderRefColour ");
00701         m_SliderRefColour.PrintMe(fd, nTabs + 1);
00702         fprintf(fd, "\n");
00703     }
00704 
00705     fprintf(fd, "}\n");
00706 }
00707 
00708 // This is a bit messy.  The MHEG corrigendum says that we need to process OnRestart actions
00709 // BEFORE generating IsRunning.  That's important because TransitionTo etc are ignored during
00710 // OnRestart but allowed in events triggered by IsRunning.
00711 void MHApplication::Activation(MHEngine *engine)
00712 {
00713     if (m_fRunning)
00714     {
00715         return;
00716     }
00717 
00718     MHGroup::Activation(engine);
00719 
00720     if (m_fRestarting)   // Set by Quit
00721     {
00722         engine->AddActions(m_OnRestart);
00723         engine->RunActions();
00724     }
00725 
00726     engine->EventTriggered(this, EventIsRunning);
00727 }
00728 
00729 int MHApplication::FindOnStack(const MHRoot *pVis) // Returns the index on the stack or -1 if it's not there.
00730 {
00731     for (int i = 0; i < m_DisplayStack.Size(); i++)
00732     {
00733         if (m_DisplayStack.GetAt(i) == pVis)
00734         {
00735             return i;
00736         }
00737     }
00738 
00739     return -1; // Not there
00740 }
00741 
00742 MHScene::MHScene()
00743 {
00744     m_fIsApp = false;
00745     // TODO: In UK MHEG 1.06 the aspect ratio is optional and if not specified "the
00746     // scene has no aspect ratio".
00747     m_nAspectRatioW = 4;
00748     m_nAspectRatioH = 3;
00749     m_fMovingCursor = false;
00750 }
00751 
00752 void MHScene::Initialise(MHParseNode *p, MHEngine *engine)
00753 {
00754     MHGroup::Initialise(p, engine);
00755     // Event register.
00756     MHParseNode *pInputEventReg = p->GetNamedArg(C_INPUT_EVENT_REGISTER);
00757 
00758     if (pInputEventReg)
00759     {
00760         m_nEventReg = pInputEventReg->GetArgN(0)->GetIntValue();
00761     }
00762 
00763     // Co-ordinate system
00764     MHParseNode *pSceneCoords = p->GetNamedArg(C_SCENE_COORDINATE_SYSTEM);
00765 
00766     if (pSceneCoords)
00767     {
00768         m_nSceneCoordX = pSceneCoords->GetArgN(0)->GetIntValue();
00769         m_nSceneCoordY = pSceneCoords->GetArgN(1)->GetIntValue();
00770     }
00771 
00772     // Aspect ratio
00773     MHParseNode *pAspectRatio = p->GetNamedArg(C_ASPECT_RATIO);
00774 
00775     if (pAspectRatio)
00776     {
00777         // Is the binary encoded as a sequence or a pair of arguments?
00778         m_nAspectRatioW = pAspectRatio->GetArgN(0)->GetIntValue();
00779         m_nAspectRatioH = pAspectRatio->GetArgN(1)->GetIntValue();
00780     }
00781 
00782     // Moving cursor
00783     MHParseNode *pMovingCursor = p->GetNamedArg(C_MOVING_CURSOR);
00784 
00785     if (pMovingCursor)
00786     {
00787         pMovingCursor->GetArgN(0)->GetBoolValue();
00788     }
00789 
00790     // Next scene sequence: this is just a hint and isn't implemented
00791 }
00792 
00793 void MHScene::PrintMe(FILE *fd, int nTabs) const
00794 {
00795     PrintTabs(fd, nTabs);
00796     fprintf(fd, "{:Scene ");
00797     MHGroup::PrintMe(fd, nTabs);
00798     PrintTabs(fd, nTabs + 1);
00799     fprintf(fd, ":InputEventReg %d\n", m_nEventReg);
00800     PrintTabs(fd, nTabs + 1);
00801     fprintf(fd, ":SceneCS %d %d\n", m_nSceneCoordX, m_nSceneCoordY);
00802 
00803     if (m_nAspectRatioW != 4 || m_nAspectRatioH != 3)
00804     {
00805         PrintTabs(fd, nTabs + 1);
00806         fprintf(fd, ":AspectRatio %d %d\n", m_nAspectRatioW, m_nAspectRatioH);
00807     }
00808 
00809     if (m_fMovingCursor)
00810     {
00811         PrintTabs(fd, nTabs + 1);
00812         fprintf(fd, ":MovingCursor true\n");
00813     }
00814 
00815     fprintf(fd, "}\n");
00816 }
00817 
00818 void MHScene::Activation(MHEngine *engine)
00819 {
00820     if (m_fRunning)
00821     {
00822         return;
00823     }
00824 
00825     MHGroup::Activation(engine);
00826     engine->EventTriggered(this, EventIsRunning);
00827 }
00828 
00829 // Action added in UK MHEG profile.  It doesn't define a new internal attribute for this.
00830 void MHScene::SetInputRegister(int nReg, MHEngine *engine)
00831 {
00832     m_nEventReg = nReg;
00833     engine->SetInputRegister(nReg);
00834 }
00835 
00836 
00837 void MHSendEvent::Initialise(MHParseNode *p, MHEngine *engine)
00838 {
00839     MHElemAction::Initialise(p, engine); // Target
00840     m_EventSource.Initialise(p->GetArgN(1), engine);
00841     m_EventType = (enum EventType)p->GetArgN(2)->GetEnumValue();
00842 
00843     if (p->GetArgCount() >= 4)
00844     {
00845         // TODO: We could check here that we only have bool, int or string and not object ref or content ref.
00846         m_EventData.Initialise(p->GetArgN(3), engine);
00847     }
00848 }
00849 
00850 void MHSendEvent::PrintArgs(FILE *fd, int) const
00851 {
00852     m_EventSource.PrintMe(fd, 0);
00853     QByteArray tmp = MHLink::EventTypeToString(m_EventType).toAscii();
00854     fprintf(fd, "%s", tmp.constData());
00855     fprintf(fd, " ");
00856 
00857     if (m_EventData.m_Type != MHParameter::P_Null)
00858     {
00859         m_EventData.PrintMe(fd, 0);
00860     }
00861 }
00862 
00863 void MHSendEvent::Perform(MHEngine *engine)
00864 {
00865     // The target is always the current scene so we ignore it here.
00866     MHObjectRef target, source;
00867     m_Target.GetValue(target, engine); // TODO: Check this is the scene?
00868     m_EventSource.GetValue(source, engine);
00869 
00870     // Generate the event.
00871     if (m_EventData.m_Type == MHParameter::P_Null)
00872     {
00873         engine->EventTriggered(engine->FindObject(source), m_EventType);
00874     }
00875     else
00876     {
00877         MHUnion data;
00878         data.GetValueFrom(m_EventData, engine);
00879         engine->EventTriggered(engine->FindObject(source), m_EventType, data);
00880     }
00881 }
00882 
00883 void MHSetTimer::Initialise(MHParseNode *p, MHEngine *engine)
00884 {
00885     MHElemAction::Initialise(p, engine);
00886     m_TimerId.Initialise(p->GetArgN(1), engine); // The timer id
00887 
00888     if (p->GetArgCount() > 2)
00889     {
00890         MHParseNode *pNewTimer = p->GetArgN(2);
00891         m_TimerValue.Initialise(pNewTimer->GetSeqN(0), engine);
00892 
00893         if (pNewTimer->GetSeqCount() > 1)
00894         {
00895             m_TimerType = ST_TimerAbsolute; // May be absolute - depends on the value.
00896             m_AbsFlag.Initialise(pNewTimer->GetSeqN(1), engine);
00897         }
00898         else
00899         {
00900             m_TimerType = ST_TimerRelative;
00901         }
00902     }
00903 }
00904 
00905 void MHSetTimer::PrintArgs(FILE *fd, int /*nTabs*/) const
00906 {
00907     m_TimerId.PrintMe(fd, 0);
00908 
00909     if (m_TimerType != ST_NoNewTimer)
00910     {
00911         fprintf(fd, "( ");
00912         m_TimerValue.PrintMe(fd, 0);
00913 
00914         if (m_TimerType == ST_TimerAbsolute)
00915         {
00916             m_AbsFlag.PrintMe(fd, 0);
00917         }
00918 
00919         fprintf(fd, ") ");
00920     }
00921 }
00922 
00923 void MHSetTimer::Perform(MHEngine *engine)
00924 {
00925     int nTimerId = m_TimerId.GetValue(engine);
00926     bool fAbsolute = false; // Defaults to relative time.
00927     int newTime = -1;
00928 
00929     switch (m_TimerType)
00930     {
00931         case ST_NoNewTimer:
00932             fAbsolute = true;
00933             newTime = -1;
00934             break; // We treat an absolute time of -1 as "cancel"
00935         case ST_TimerAbsolute:
00936             fAbsolute = m_AbsFlag.GetValue(engine); // And drop to the next
00937         case ST_TimerRelative:
00938             newTime = m_TimerValue.GetValue(engine);
00939     }
00940 
00941     Target(engine)->SetTimer(nTimerId, fAbsolute, newTime, engine);
00942 }
00943 
00944 void MHPersistent::Initialise(MHParseNode *p, MHEngine *engine)
00945 {
00946     MHElemAction::Initialise(p, engine); // Target
00947     m_Succeeded.Initialise(p->GetArgN(1), engine);
00948     MHParseNode *pVarSeq = p->GetArgN(2);
00949 
00950     for (int i = 0; i < pVarSeq->GetSeqCount(); i++)
00951     {
00952         MHObjectRef *pVar = new MHObjectRef;
00953         m_Variables.Append(pVar);
00954         pVar->Initialise(pVarSeq->GetSeqN(i), engine);
00955     }
00956 
00957     m_FileName.Initialise(p->GetArgN(3), engine);
00958 }
00959 
00960 void MHPersistent::PrintArgs(FILE *fd, int nTabs) const
00961 {
00962     m_Succeeded.PrintMe(fd, nTabs);
00963     fprintf(fd, " ( ");
00964 
00965     for (int i = 0; i < m_Variables.Size(); i++)
00966     {
00967         m_Variables.GetAt(i)->PrintMe(fd, 0);
00968     }
00969 
00970     fprintf(fd, " ) ");
00971     m_FileName.PrintMe(fd, nTabs);
00972 }
00973 
00974 void MHPersistent::Perform(MHEngine *engine)
00975 {
00976     MHObjectRef target;
00977     m_Target.GetValue(target, engine); // Get the target - this should always be the application
00978     MHOctetString fileName;
00979     m_FileName.GetValue(fileName, engine);
00980     bool fResult = engine->LoadStorePersistent(m_fIsLoad, fileName, m_Variables);
00981     engine->FindObject(m_Succeeded)->SetVariableValue(fResult);
00982 }
00983 
00984 MHTransitionTo::MHTransitionTo(): MHElemAction(":TransitionTo")
00985 {
00986     m_fIsTagged = false;
00987     m_nConnectionTag = 0;
00988     m_nTransitionEffect = -1;
00989 }
00990 
00991 void MHTransitionTo::Initialise(MHParseNode *p, MHEngine *engine)
00992 {
00993     MHElemAction::Initialise(p, engine); // Target
00994     // The next one may be present but NULL in binary.
00995     if (p->GetArgCount() > 1)
00996     {
00997         MHParseNode *pCtag = p->GetArgN(1);
00998 
00999         if (pCtag->m_nNodeType == MHParseNode::PNInt)
01000         {
01001             m_fIsTagged = true;
01002             m_nConnectionTag = pCtag->GetIntValue();
01003         }
01004     }
01005 
01006     if (p->GetArgCount() > 2)
01007     {
01008         MHParseNode *pTrEff = p->GetArgN(2);
01009         m_nTransitionEffect = pTrEff->GetIntValue();
01010     }
01011 }
01012 
01013 void MHTransitionTo::PrintArgs(FILE *fd, int /*nTabs*/) const
01014 {
01015     if (m_fIsTagged)
01016     {
01017         fprintf(fd, " %d ", m_nConnectionTag);
01018     }
01019     else if (m_nTransitionEffect >= 0)
01020     {
01021         fprintf(fd, " NULL ");
01022     }
01023 
01024     if (m_nTransitionEffect >= 0)
01025     {
01026         fprintf(fd, " %d", m_nTransitionEffect);
01027     }
01028 }
01029 
01030 // Do the action - Transition to a new scene.
01031 void MHTransitionTo::Perform(MHEngine *engine)
01032 {
01033     MHObjectRef target;
01034     m_Target.GetValue(target, engine); // Get the target
01035     engine->TransitionToScene(target);
01036 }
01037 
01038 void MHLaunch::Perform(MHEngine *engine)
01039 {
01040     MHObjectRef target;
01041     m_Target.GetValue(target, engine);
01042     engine->Launch(target);
01043 }
01044 void MHQuit::Perform(MHEngine *engine)
01045 {
01046     engine->Quit();
01047 }
01048 void MHSpawn::Perform(MHEngine *engine)
01049 {
01050     MHObjectRef target;
01051     m_Target.GetValue(target, engine);
01052     engine->Spawn(target);
01053 }
01054 void MHLockScreen::Perform(MHEngine *engine)
01055 {
01056     engine->LockScreen();
01057 }
01058 void MHUnlockScreen::Perform(MHEngine *engine)
01059 {
01060     engine->UnlockScreen();
01061 }
01062 
01063 void MHGetEngineSupport::Initialise(MHParseNode *p, MHEngine *engine)
01064 {
01065     MHElemAction::Initialise(p, engine);
01066     m_Feature.Initialise(p->GetArgN(1), engine);
01067     m_Answer.Initialise(p->GetArgN(2), engine);
01068 }
01069 
01070 void MHGetEngineSupport::Perform(MHEngine *engine)
01071 {
01072     // Ignore the target which isn't used.
01073     MHOctetString feature;
01074     m_Feature.GetValue(feature, engine);
01075     engine->FindObject(m_Answer)->SetVariableValue(engine->GetEngineSupport(feature));
01076 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends