819f13f4ccc3268c1e90761d112a6c322381eec2
[p5sagit/p5-mst-13.2.git] / symbian / PerlApp.cpp
1 /* Copyright (c) 2004-2005 Nokia. All rights reserved. */
2
3 /* The PerlApp application is licensed under the same terms as Perl itself.
4  * Note that this PerlApp is for Symbian/Series 60/80 smartphones and it has
5  * nothing whatsoever to do with the ActiveState PerlApp. */
6
7 #include "PerlApp.h"
8
9 #ifdef __SERIES60__
10 # include <avkon.hrh>
11 # include <aknnotewrappers.h> 
12 # include <AknCommonDialogs.h>
13 # ifndef __SERIES60_1X__
14 #  include <CAknFileSelectionDialog.h>
15 # endif
16 #endif /* #ifdef __SERIES60__ */
17
18 #ifdef __SERIES80__
19 # include <eikon.hrh>
20 # include <cknflash.h>
21 # include <ckndgopn.h>
22 # include <ckndgfob.h>
23 # include <eiklabel.h>
24 # include <cknconf.h>
25 #endif /* #ifdef __SERIES80__ */
26
27 #include <apparc.h>
28 #include <e32base.h>
29 #include <e32cons.h>
30 #include <eikenv.h>
31 #include <bautils.h>
32 #include <eikappui.h>
33 #include <utf.h>
34 #include <f32file.h>
35
36 #include <coemain.h>
37
38 #ifndef PerlAppMinimal
39
40 #include "PerlApp.hrh"
41
42 #include "PerlApp.rsg"
43
44 #ifdef __SERIES80__
45 #include "Eikon.rsg"
46 #endif /* #ifdef __SERIES80__ */
47
48 #endif //#ifndef PerlAppMinimal
49
50 #include "EXTERN.h"
51 #include "perl.h"
52 #include "PerlBase.h"
53
54 const TUid KPerlAppUid = {
55 #ifdef PerlAppMinimalUid
56   PerlAppMinimalUid
57 #else
58   0x102015F6
59 #endif
60 };
61
62 _LIT(KDefaultScript, "default.pl");
63
64 // This is like the Symbian _LIT() but without the embedded L prefix,
65 // which enables using #defined constants (which need to carry their
66 // own L prefix).
67 #ifndef _LIT_NO_L
68 # define _LIT_NO_L(n, s) static const TLitC<sizeof(s)/2> n={sizeof(s)/2-1,s}
69 #endif // #ifndef _LIT_NO_L
70
71 #ifdef PerlAppMinimalName
72 _LIT_NO_L(KAppName, PerlAppMinimalName);
73 #else
74 _LIT(KAppName, "PerlApp");
75 #endif
76
77 #ifndef PerlAppMinimal
78
79 _LIT_NO_L(KFlavor, PERL_SYMBIANSDK_FLAVOR);
80 _LIT(KAboutFormat,
81      "Perl %d.%d.%d, Symbian port %d.%d.%d, built for %S SDK %d.%d");
82 _LIT(KCopyrightFormat,
83      "Copyright 1987-2005 Larry Wall and others, Symbian port Copyright Nokia 2004-2005");
84 _LIT(KInboxPrefix, "\\System\\Mail\\");
85 _LIT(KScriptPrefix, "\\Perl\\");
86
87 _LIT8(KModulePrefix, SITELIB); // SITELIB from Perl config.h
88
89 typedef TBuf<256>  TMessageBuffer;
90 typedef TBuf8<256> TPeekBuffer;
91 typedef TBuf8<256> TFileName8;
92
93 #endif // #ifndef PerlAppMinimal
94
95 // Usage: DEBUG_PRINTF((_L("%S"), &aStr))
96 #if 1
97 #define DEBUG_PRINTF(s) {TMessageBuffer message; message.Format s; YesNoDialogL(message);}
98 #endif
99
100 static void DoRunScriptL(TFileName aScriptName);
101
102 TUid CPerlAppApplication::AppDllUid() const
103 {
104     return KPerlAppUid;
105 }
106
107 enum TPerlAppPanic 
108 {
109     EPerlAppCommandUnknown = 1
110 };
111
112 void Panic(TPerlAppPanic aReason)
113 {
114     User::Panic(KAppName, aReason);
115 }
116
117 void CPerlAppUi::ConstructL()
118 {
119     BaseConstructL();
120     iAppView = CPerlAppView::NewL(ClientRect());
121     AddToStackL(iAppView);
122     iFs = NULL;
123     CEikonEnv::Static()->DisableExitChecks(ETrue); // Symbian FAQ-0577.
124 }
125
126 CPerlAppUi::~CPerlAppUi()
127 {
128     if (iAppView) {
129         iEikonEnv->RemoveFromStack(iAppView);
130         delete iAppView;
131         iAppView = NULL;
132     }
133     if (iFs) {
134         delete iFs;
135         iFs = NULL;
136     }
137     if (iDoorObserver) // Otherwise the embedding application waits forever.
138         iDoorObserver->NotifyExit(MApaEmbeddedDocObserver::EEmpty);
139 }
140
141 #ifndef PerlAppMinimal
142
143 #ifdef __SERIES60__
144
145 static TBool DlgOk(CAknNoteDialog* dlg)
146 {
147     return dlg && dlg->RunDlgLD() == EAknSoftkeyOk;
148 }
149
150 #endif /* #ifdef __SERIES60__ */
151
152 static TBool OkCancelDialogL(TDesC& aMessage)
153 {
154 #ifdef __SERIES60__
155     CAknNoteDialog* dlg =
156         new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
157     dlg->PrepareLC(R_OK_CANCEL_DIALOG);
158     dlg->SetTextL(aMessage);
159     return DlgOk(dlg);
160 #endif /* #ifdef __SERIES60__ */
161 #ifdef __SERIES80__
162     return CCknConfirmationDialog::RunDlgWithDefaultIconLD(aMessage, R_EIK_BUTTONS_CANCEL_OK);
163 #endif /* #ifdef __SERIES80__ */
164 }
165
166 static TBool YesNoDialogL(TDesC& aMessage)
167 {
168 #ifdef __SERIES60__
169     CAknNoteDialog* dlg =
170         new (ELeave) CAknNoteDialog(CAknNoteDialog::EConfirmationTone);
171     dlg->PrepareLC(R_YES_NO_DIALOG);
172     dlg->SetTextL(aMessage);
173     return DlgOk(dlg);
174 #endif /* #ifdef __SERIES60__ */
175 #ifdef __SERIES80__
176     return CCknConfirmationDialog::RunDlgWithDefaultIconLD(aMessage, R_EIK_BUTTONS_NO_YES);
177 #endif /* #ifdef __SERIES80__ */
178 }
179
180 static void InformationNoteL(TDesC& aMessage)
181 {
182 #ifdef __SERIES60__
183     CAknInformationNote* note = new (ELeave) CAknInformationNote;
184     note->ExecuteLD(aMessage);
185 #endif /* #ifdef __SERIES60__ */
186 #ifdef __SERIES80__
187     CEikonEnv::Static()->InfoMsg(aMessage);
188 #endif /* #ifdef __SERIES80__ */
189 }
190
191 static TInt WarningNoteL(TDesC& aMessage)
192 {
193 #ifdef __SERIES60__
194     CAknWarningNote* note = new (ELeave) CAknWarningNote;
195     return note->ExecuteLD(aMessage);
196 #endif /* #ifdef __SERIES60__ */
197 #ifdef __SERIES80__
198     CEikonEnv::Static()->AlertWin(aMessage);
199     return ETrue;
200 #endif /* #ifdef __SERIES80__ */
201 }
202
203 #ifdef __SERIES80__
204
205 CPerlAppTextQueryDialog::CPerlAppTextQueryDialog(HBufC*& aBuffer) :
206   iData(aBuffer)
207 {
208 }
209
210 TBool CPerlAppTextQueryDialog::OkToExitL(TInt /* aKeycode */)
211 {
212   iData = static_cast<CEikEdwin*>(Control(EPerlAppTextQueryInputField))->GetTextInHBufL();
213   return ETrue;
214 }
215
216 void CPerlAppTextQueryDialog::PreLayoutDynInitL()
217 {
218   SetTitleL(iTitle);
219   CEikLabel* promptLabel = ControlCaption(EPerlAppTextQueryInputField);
220   promptLabel->SetTextL(iPrompt);
221 }
222
223 /* TODO: OfferKeyEventL() so that newline can be seen as 'OK'.
224  * Or a hotkey for the button? */
225
226 #endif /* #ifdef __SERIES80__ */
227
228 static TInt TextQueryDialogL(const TDesC& aTitle, const TDesC& aPrompt, TDes& aData, const TInt aMaxLength)
229 {
230 #ifdef __SERIES60__
231     CAknTextQueryDialog* dlg =
232         new (ELeave) CAknTextQueryDialog(aData);
233     dlg->SetPromptL(aPrompt);
234     dlg->SetMaxLength(aMaxLength);
235     return dlg->ExecuteLD(R_TEXT_QUERY_DIALOG);
236 #endif /* #ifdef __SERIES60__ */
237 #ifdef __SERIES80__
238     HBufC* data = NULL;
239     CPerlAppTextQueryDialog* dlg =
240       new (ELeave) CPerlAppTextQueryDialog(data);
241     dlg->iTitle.Set(aTitle);
242     dlg->iPrompt.Set(aPrompt);
243     dlg->iMaxLength = aMaxLength;
244     if (dlg->ExecuteLD(R_PERL_ONELINER_DIALOG)) {
245       aData.Copy(*data);
246       return ETrue;
247     }
248     return EFalse;
249 #endif /* #ifdef __SERIES80__ */
250 }
251
252 static TBool FileQueryDialogL(TDes& aFilename)
253 {
254 #ifdef __SERIES60__
255   return AknCommonDialogs::RunSelectLD(aFilename,
256                                        R_MEMORY_SELECTION_DIALOG);
257 #endif /* #ifdef __SERIES60__ */
258 #ifdef __SERIES80__
259   if (CCknOpenFileDialog::RunDlgLD(aFilename,
260                                     CCknFileListDialogBase::EShowAllDrives
261                                    |CCknFileListDialogBase::EShowSystemFilesAndFolders
262                                    |CCknFileListDialogBase::EShowBothFilesAndFolders
263                                    )) {
264     TEntry aEntry; // Be paranoid and check that the file is there.
265     RFs aFs;
266     aFs.Connect();
267     if (aFs.Entry(aFilename, aEntry) == KErrNone)
268       return ETrue;
269     else
270       CEikonEnv::Static()->InfoMsg(_L("File not found"));
271   }
272   return EFalse;
273 #endif /* #ifdef __SERIES80__ */
274 }
275
276 // The isXXX() come from the Perl headers.
277 #define FILENAME_IS_ABSOLUTE(n) \
278         (isALPHA(((n)[0])) && ((n)[1]) == ':' && ((n)[2]) == '\\')
279
280 static TBool IsInPerl(TFileName aFileName)
281 {
282     TInt offset = aFileName.FindF(KScriptPrefix);
283     return ((offset == 0 && // \foo
284              aFileName[0] == '\\')
285             ||
286             (offset == 2 && // x:\foo
287              FILENAME_IS_ABSOLUTE(aFileName)));
288 }
289
290 static TBool IsInInbox(TFileName aFileName)
291 {
292     TInt offset = aFileName.FindF(KInboxPrefix);
293     return ((offset == 0 && // \foo
294              aFileName[0] == '\\')
295             ||
296             (offset == 2 && // x:\foo
297              FILENAME_IS_ABSOLUTE(aFileName)));
298 }
299
300 static TBool IsPerlModule(TParsePtrC aParsed)
301 {
302     return aParsed.Ext().CompareF(_L(".pm")) == 0; 
303 }
304
305 static TBool IsPerlScript(TParsePtrC aParsed)
306 {
307     return aParsed.Ext().CompareF(_L(".pl")) == 0; 
308 }
309
310 static void CopyFromInboxL(RFs aFs, const TFileName& aSrc, const TFileName& aDst)
311 {
312     TBool proceed = ETrue;
313     TMessageBuffer message;
314
315     message.Format(_L("%S is untrusted. Install only if you trust provider."), &aDst);
316     if (OkCancelDialogL(message)) {
317         message.Format(_L("Install as %S?"), &aDst);
318         if (OkCancelDialogL(message)) {
319             if (BaflUtils::FileExists(aFs, aDst)) {
320                 message.Format(_L("Replace old %S?"), &aDst);
321                 if (!OkCancelDialogL(message))
322                     proceed = EFalse;
323             }
324             if (proceed) {
325                 // Create directory?
326                 TInt err = BaflUtils::CopyFile(aFs, aSrc, aDst);
327                 if (err == KErrNone) {
328                     message.Format(_L("Installed %S"), &aDst);
329                     InformationNoteL(message);
330                 }
331                 else {
332                     message.Format(_L("Failure %d installing %S"), err, &aDst);
333                     WarningNoteL(message);
334                 }
335             }
336         }
337     }
338 }
339
340 static TBool FindPerlPackageName(TPeekBuffer aPeekBuffer, TInt aOff, TFileName& aFn)
341 {
342     aFn.SetMax();
343     TInt m = aFn.MaxLength();
344     TInt n = aPeekBuffer.Length();
345     TInt i = 0;
346     TInt j = aOff;
347
348     aFn.SetMax();
349     // The following is a little regular expression
350     // engine that matches Perl package names.
351     if (j < n && isSPACE(aPeekBuffer[j])) {
352         while (j < n && isSPACE(aPeekBuffer[j])) j++;
353         if (j < n && isALPHA(aPeekBuffer[j])) {
354             while (j < n && isALNUM(aPeekBuffer[j])) {
355                 while (j < n &&
356                        isALNUM(aPeekBuffer[j]) &&
357                        i < m)
358                     aFn[i++] = aPeekBuffer[j++];
359                 if (j + 1 < n &&
360                     aPeekBuffer[j    ] == ':' &&
361                     aPeekBuffer[j + 1] == ':' &&
362                     i < m) {
363                     aFn[i++] = '\\';
364                     j += 2;
365                     if (j < n &&
366                         isALPHA(aPeekBuffer[j])) {
367                         while (j < n &&
368                                isALNUM(aPeekBuffer[j]) &&
369                                i < m) 
370                             aFn[i++] = aPeekBuffer[j++];
371                     }
372                 }
373             }
374             while (j < n && isSPACE(aPeekBuffer[j])) j++;
375             if (j < n && aPeekBuffer[j] == ';' && i + 3 < m) {
376                 aFn.SetLength(i);
377                 aFn.Append(_L(".pm"));
378                 return ETrue;
379             }
380         }
381     }
382     return EFalse;
383 }
384
385 static void GuessPerlModule(TFileName& aGuess, TPeekBuffer aPeekBuffer, TParse aDrive)
386 {
387    TInt offset = aPeekBuffer.Find(_L8("package"));
388    if (offset != KErrNotFound) {
389        const TInt KPackageLen = 7;
390        TFileName q;
391
392        if (!FindPerlPackageName(aPeekBuffer, offset + KPackageLen, q))
393            return;
394
395        TFileName8 p;
396        p.Copy(aDrive.Drive());
397        p.Append(KModulePrefix);
398
399        aGuess.SetMax();
400        if (p.Length() + 1 + q.Length() < aGuess.MaxLength()) {
401            TInt i = 0, j;
402
403            for (j = 0; j < p.Length(); j++)
404                aGuess[i++] = p[j];
405            aGuess[i++] = '\\';
406            for (j = 0; j < q.Length(); j++)
407                aGuess[i++] = q[j];
408            aGuess.SetLength(i);
409        }
410        else
411            aGuess.SetLength(0);
412    }
413 }
414
415 static TBool LooksLikePerlL(TPeekBuffer aPeekBuffer)
416 {
417     return aPeekBuffer.Left(2).Compare(_L8("#!")) == 0 &&
418            aPeekBuffer.Find(_L8("perl")) != KErrNotFound;
419 }
420
421 static TBool InstallStuffL(const TFileName &aSrc, TParse aDrive, TParse aFile, TPeekBuffer aPeekBuffer, RFs aFs)
422 {
423     TFileName aDst;
424     TPtrC drive  = aDrive.Drive();
425     TPtrC namext = aFile.NameAndExt(); 
426
427     aDst.Format(_L("%S%S%S"), &drive, &KScriptPrefix, &namext);
428     if (!IsPerlScript(aDst) && !LooksLikePerlL(aPeekBuffer)) {
429         aDst.SetLength(0);
430         if (IsPerlModule(aDst))
431             GuessPerlModule(aDst, aPeekBuffer, aDrive);
432     }
433     if (aDst.Length() > 0) {
434         CopyFromInboxL(aFs, aSrc, aDst);
435         return ETrue;
436     }
437
438     return EFalse;
439 }
440
441 static TBool RunStuffL(const TFileName& aScriptName, TPeekBuffer aPeekBuffer)
442 {
443     TBool isModule = EFalse;
444
445     if (IsInPerl(aScriptName) &&
446         (IsPerlScript(aScriptName) ||
447          (isModule = IsPerlModule(aScriptName)) ||
448          LooksLikePerlL(aPeekBuffer))) {
449         TMessageBuffer message;
450
451         if (isModule)
452             message.Format(_L("Really run module %S?"), &aScriptName);
453         else 
454             message.Format(_L("Run %S?"), &aScriptName);
455         if (YesNoDialogL(message))
456             DoRunScriptL(aScriptName);
457         return ETrue;
458     }
459
460     return EFalse;
461 }
462
463 void CPerlAppUi::InstallOrRunL(const TFileName& aFileName)
464 {
465     TParse aFile;
466     TParse aDrive;
467     TMessageBuffer message;
468
469     aFile.Set(aFileName, NULL, NULL);
470     if (FILENAME_IS_ABSOLUTE(aFileName)) {
471         aDrive.Set(aFileName, NULL, NULL);
472     } else {
473         TFileName appName =
474           CEikonEnv::Static()->EikAppUi()->Application()->AppFullName();
475         aDrive.Set(appName, NULL, NULL);
476     }
477     if (!iFs)
478         iFs = &CEikonEnv::Static()->FsSession();
479     RFile f;
480     TInt err = f.Open(*iFs, aFileName, EFileRead);
481     if (err == KErrNone) {
482         TPeekBuffer aPeekBuffer;
483         err = f.Read(aPeekBuffer);
484         f.Close();  // Release quickly.
485         if (err == KErrNone) {
486             if (!(IsInInbox(aFileName) ?
487                   InstallStuffL(aFileName, aDrive, aFile, aPeekBuffer, *iFs) :
488                   RunStuffL(aFileName, aPeekBuffer))) {
489                 message.Format(_L("Failed for file %S"), &aFileName);
490                 WarningNoteL(message);
491             }
492         } else {
493             message.Format(_L("Error %d reading %S"), err, &aFileName);
494             WarningNoteL(message);
495         }
496     } else {
497         message.Format(_L("Error %d opening %S"), err, &aFileName);
498         WarningNoteL(message);
499     }
500     if (iDoorObserver)
501         delete CEikonEnv::Static()->EikAppUi();
502     else
503         Exit();
504 }
505
506 #endif // #ifndef PerlAppMinimal
507
508 static void DoRunScriptL(TFileName aScriptName)
509 {
510     CPerlBase* perl = CPerlBase::NewInterpreterLC();
511     TRAPD(error, perl->RunScriptL(aScriptName));
512 #ifndef PerlAppMinimal
513     if (error != KErrNone) {
514         TMessageBuffer message;
515         message.Format(_L("Error %d"), error);
516         YesNoDialogL(message);
517     }
518 #endif // #ifndef PerlAppMinimal
519     CleanupStack::PopAndDestroy(perl);
520 }
521
522 #ifndef PerlAppMinimal
523
524 void CPerlAppUi::OpenFileL(const TDesC& aFileName)
525 {
526     InstallOrRunL(aFileName);
527     return;
528 }
529
530 #endif // #ifndef PerlAppMinimal
531
532 TBool CPerlAppUi::ProcessCommandParametersL(TApaCommand aCommand, TFileName& /* aDocumentName */, const TDesC8& /* aTail */)
533 {
534     if (aCommand == EApaCommandRun) {
535         TFileName appName = Application()->AppFullName();
536         TParse p;
537         p.Set(KDefaultScript, &appName, NULL);
538         TEntry aEntry;
539         RFs aFs;
540         aFs.Connect();
541         if (aFs.Entry(p.FullName(), aEntry) == KErrNone) {
542             DoRunScriptL(p.FullName());
543             Exit();
544         }
545     }
546     return aCommand == EApaCommandOpen ? ETrue : EFalse;
547 }
548
549 #ifndef PerlAppMinimal
550
551 void CPerlAppUi::SetFs(const RFs& aFs)
552 {
553     iFs = (RFs*) &aFs;
554 }
555
556 #endif // #ifndef PerlAppMinimal
557
558 static void DoHandleCommandL(TInt aCommand) {
559 #ifndef PerlAppMinimal
560     TMessageBuffer message;
561 #endif // #ifndef PerlAppMinimal
562
563     switch(aCommand)
564     {
565 #ifndef PerlAppMinimal
566     case EPerlAppCommandAbout:
567         {
568             message.Format(KAboutFormat,
569                            PERL_REVISION,
570                            PERL_VERSION,
571                            PERL_SUBVERSION,
572                            PERL_SYMBIANPORT_MAJOR,
573                            PERL_SYMBIANPORT_MINOR,
574                            PERL_SYMBIANPORT_PATCH,
575                            &KFlavor,
576                            PERL_SYMBIANSDK_MAJOR,
577                            PERL_SYMBIANSDK_MINOR
578                            );
579             InformationNoteL(message);
580         }
581         break;
582     case EPerlAppCommandTime:
583         {
584             CPerlBase* perl = CPerlBase::NewInterpreterLC();
585             const char *const argv[] =
586               { "perl", "-le",
587                 "print 'Running in ', $^O, \"\\n\", scalar localtime" };
588             perl->ParseAndRun(sizeof(argv)/sizeof(char*), (char **)argv, 0);
589             CleanupStack::PopAndDestroy(perl);
590         }
591         break;
592      case EPerlAppCommandRunFile:
593         {
594             TFileName aScriptUtf16;
595             aScriptUtf16.Copy(_L("C:\\"));
596             if (FileQueryDialogL(aScriptUtf16))
597               DoRunScriptL(aScriptUtf16);
598         }
599         break;
600      case EPerlAppCommandOneLiner:
601         {
602 #ifdef __SERIES60__
603             _LIT(prompt, "Oneliner:");
604 #endif /* #ifdef __SERIES60__ */
605 #ifdef __SERIES80__
606             _LIT(prompt, "Code:"); // The title has "Oneliner" already.
607 #endif /* #ifdef __SERIES80__ */
608             CPerlAppUi* cAppUi =
609               STATIC_CAST(CPerlAppUi*, CEikonEnv::Static()->EikAppUi());
610             if (TextQueryDialogL(_L("Oneliner"),
611                                  prompt,
612                                  cAppUi->iOneLiner,
613                                  KPerlAppOneLinerSize)) {
614                const TUint KPerlAppUtf8Multi = 3;
615                 TBuf8<KPerlAppUtf8Multi * KPerlAppOneLinerSize> utf8;
616
617                 CnvUtfConverter::ConvertFromUnicodeToUtf8(utf8, cAppUi->iOneLiner);
618                 CPerlBase* perl = CPerlBase::NewInterpreterLC();
619                 int argc = 3;
620                 char **argv = (char**) malloc(argc * sizeof(char *));
621                 User::LeaveIfNull(argv);
622
623                 TCleanupItem argvCleanupItem = TCleanupItem(free, argv);
624                 CleanupStack::PushL(argvCleanupItem);
625                 argv[0] = (char *) "perl";
626                 argv[1] = (char *) "-le";
627                 argv[2] = (char *) utf8.PtrZ();
628                 perl->ParseAndRun(argc, argv);
629                 CleanupStack::PopAndDestroy(2, perl);
630             }
631         }
632         break;
633      case EPerlAppCommandCopyright:
634         {
635             message.Format(KCopyrightFormat);
636             InformationNoteL(message);
637         }
638         break;
639      case EPerlAppCommandAboutCopyright:
640         {
641             TMessageBuffer m1;
642             TMessageBuffer m2;
643             m1.Format(KAboutFormat,
644                       PERL_REVISION,
645                       PERL_VERSION,
646                       PERL_SUBVERSION,
647                       PERL_SYMBIANPORT_MAJOR,
648                       PERL_SYMBIANPORT_MINOR,
649                       PERL_SYMBIANPORT_PATCH,
650                       &KFlavor,
651                       PERL_SYMBIANSDK_MAJOR,
652                       PERL_SYMBIANSDK_MINOR
653                       );
654             InformationNoteL(m1);
655             User::After((TTimeIntervalMicroSeconds32) (1000*1000));
656             m2.Format(KCopyrightFormat);
657             InformationNoteL(m2);
658         }
659         break;
660 #endif // #ifndef PerlAppMinimal
661     default:
662         Panic(EPerlAppCommandUnknown);
663     }
664 }
665
666 #ifdef __SERIES60__
667
668 void CPerlAppUi::HandleCommandL(TInt aCommand)
669 {
670     switch(aCommand)
671     {
672     case EEikCmdExit:
673     case EAknSoftkeyExit:
674         Exit();
675         break;
676     default:
677         DoHandleCommandL(aCommand);
678         break;
679     }
680 }
681
682 #endif /* #ifdef __SERIES60__ */
683
684 #ifdef __SERIES80__
685
686 void CPerlAppView::HandleCommandL(TInt aCommand) {
687     DoHandleCommandL(aCommand);
688 }
689
690 void CPerlAppUi::HandleCommandL(TInt aCommand) {
691     switch(aCommand)
692     {
693     case EEikCmdExit:
694         Exit();
695         break;
696     default:
697         iAppView->HandleCommandL(aCommand);
698         break;
699     }
700 }
701
702 #endif /* #ifdef __SERIES80__ */
703
704 CPerlAppView* CPerlAppView::NewL(const TRect& aRect)
705 {
706     CPerlAppView* self = CPerlAppView::NewLC(aRect);
707     CleanupStack::Pop(self);
708     return self;
709 }
710
711 CPerlAppView* CPerlAppView::NewLC(const TRect& aRect)
712 {
713     CPerlAppView* self = new (ELeave) CPerlAppView;
714     CleanupStack::PushL(self);
715     self->ConstructL(aRect);
716     return self;
717 }
718
719 void CPerlAppView::ConstructL(const TRect& aRect)
720 {
721     CreateWindowL();
722     SetRect(aRect);
723     ActivateL();
724 }
725
726 CPerlAppView::~CPerlAppView()
727 {
728 }
729
730 void CPerlAppView::Draw(const TRect& /*aRect*/) const
731 {
732     CWindowGc& gc = SystemGc();
733     TRect rect = Rect();
734     gc.Clear(rect);
735 }
736
737 CApaDocument* CPerlAppApplication::CreateDocumentL() 
738 {
739     CPerlAppDocument* document = new (ELeave) CPerlAppDocument(*this);
740     return document;
741 }
742
743 CEikAppUi* CPerlAppDocument::CreateAppUiL()
744 {
745     CPerlAppUi* appui = new (ELeave) CPerlAppUi();
746     return appui;
747 }
748
749
750 #ifndef PerlAppMinimal
751
752 CFileStore* CPerlAppDocument::OpenFileL(TBool aDoOpen, const TDesC& aFileName, RFs& aFs)
753 {
754     CPerlAppUi* appui =
755       STATIC_CAST(CPerlAppUi*, CEikonEnv::Static()->EikAppUi());
756     appui->SetFs(aFs);
757     if (aDoOpen)
758         appui->OpenFileL(aFileName);
759     return NULL;
760 }
761
762 #endif // #ifndef PerlAppMinimal
763
764 EXPORT_C CApaApplication* NewApplication() 
765 {
766     return new CPerlAppApplication;
767 }
768
769 GLDEF_C TInt E32Dll(TDllReason /*aReason*/)
770 {
771     return KErrNone;
772 }
773