Stroika Library 3.0d23
 
Loading...
Searching...
No Matches
LedItApplication.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4
5#include "Stroika/Foundation/StroikaPreComp.h"
6
7#if qStroika_Foundation_Common_Platform_MacOS
8#include <Balloons.h>
9#include <Gestalt.h>
10#include <ToolUtils.h>
11
12#include <LCaption.h>
13#include <LDialogBox.h>
14#include <LEditField.h>
15#include <LGrowZone.h>
16#include <LMenu.h>
17#include <LMenuBar.h>
18#include <LPicture.h>
19#include <LPlaceHolder.h>
20#include <LPrintout.h>
21#include <LStdControl.h>
22#include <LTabGroup.h>
23#include <LTextButton.h>
24#include <LWindow.h>
25#include <PP_Messages.h>
26#include <PP_Resources.h>
27#include <TArrayIterator.h>
28#include <UAppleEventsMgr.h>
29#include <UDesktop.h>
30#include <UMemoryMgr.h>
31#include <UModalDialogs.h>
32#include <URegistrar.h>
33#elif defined(WIN32)
34
35#include <afx.h>
36
37#elif qStroika_FeatureSupported_XWindows
38#include <gtk/gtkoptionmenu.h>
39#endif
40
44
45#include "Stroika/Frameworks/Led/Config.h"
46#include "Stroika/Frameworks/Led/StdDialogs.h"
47#if qStroika_Foundation_Common_Platform_Windows
48#include "Stroika/Frameworks/Led/Platform/Windows_FileRegistration.h"
49#endif
50#include "Stroika/Frameworks/Led/StyledTextEmbeddedObjects.h"
51
52#if qStroika_Foundation_Common_Platform_Windows
53#include "LedItControlItem.h"
54#include "LedItInPlaceFrame.h"
55#include "LedItMainFrame.h"
56#elif qStroika_Foundation_Common_Platform_MacOS
57#include "FilteredFilePicker.h"
58#endif
59
60#include "LedItDocument.h"
61#include "LedItResources.h"
62#include "LedItView.h"
63#include "Options.h"
64
65#include "LedItApplication.h"
66
67#if qStroika_FeatureSupported_XWindows
68#include "AboutBoxImage.xpm"
69#endif
70
71using namespace Stroika::Foundation;
72using namespace Stroika::Frameworks::Led;
73using namespace Stroika::Frameworks::Led::Platform;
74using namespace Stroika::Frameworks::Led::StyledTextIO;
75
76using Memory::MakeSharedPtr;
77
78#if qStroika_Foundation_Common_Platform_MacOS
79static Handle sDeepShitCheeseBuf = NULL; // so no mem alerts don't crash...
80
81inline void DoStringyAlert (short alertID, const ConstStr255Param p0 = NULL, const ConstStr255Param p1 = NULL,
82 const ConstStr255Param p2 = NULL, const ConstStr255Param p3 = NULL)
83{
84 if (sDeepShitCheeseBuf != NULL) {
85 ::DisposeHandle (sDeepShitCheeseBuf);
86 sDeepShitCheeseBuf = NULL;
87 }
88 if (::GetResource ('ALRT', alertID) == nil) {
89 Led_BeepNotify ();
90 }
91 else {
92 try {
93 Led_CheckSomeLocalHeapRAMAvailable (4 * 1024); // empiricly arrived at how much needed to avoid crash
94 }
95 catch (...) {
96 Led_BeepNotify ();
97 return;
98 }
99 ::ParamText (p0 == NULL ? "\p" : p0, p1 == NULL ? "\p" : p1, p2 == NULL ? "\p" : p2, p3 == NULL ? "\p" : p3);
100 ::InitCursor ();
101 ::CautionAlert (alertID, nil);
102 }
103}
104#endif
105
106const char kAppName[] = "LedIt";
107
108#if qStroika_Foundation_Common_Platform_MacOS
109
110#define STANDARD_LEDITAPPLICATION_MACOS_CATCHERS() \
111 catch (OSErr err) \
112 { \
113 HandleMacOSException (err); \
114 } \
115 catch (bad_alloc) \
116 { \
117 HandleBadAllocException (); \
118 } \
119 catch (TextInteractor::BadUserInput&) \
120 { \
121 HandleBadUserInputException (); \
122 } \
123 catch (const LException& err) \
124 { \
125 HandlePowerPlantException ((OSErr)err.GetErrorCode ()); \
126 } \
127 catch (ExceptionCode err) \
128 { \
129 HandlePowerPlantException (err); \
130 } \
131 catch (...) \
132 { \
133 HandleUnknownException (); \
134 }
135
136#endif
137
138#if qStroika_Foundation_Common_Platform_Windows
139
140#define STD_EXCEPT_CATCHER(APP) \
141 catch (CMemoryException * e) \
142 { \
143 (APP).HandleBadAllocException (); \
144 e->Delete (); \
145 } \
146 catch (CException * e) \
147 { \
148 (APP).HandleMFCException (e); \
149 e->Delete (); \
150 } \
151 catch (bad_alloc) \
152 { \
153 (APP).HandleBadAllocException (); \
154 } \
155 catch (HRESULT hr) \
156 { \
157 (APP).HandleHRESULTException (hr); \
158 } \
159 catch (TextInteractor::BadUserInput&) \
160 { \
161 (APP).HandleBadUserInputException (); \
162 } \
163 catch (...) \
164 { \
165 (APP).HandleUnknownException (); \
166 }
167
168#endif
169
170#if qStroika_Foundation_Common_Platform_Windows
171class SimpleLedTemplate : public CSingleDocTemplate {
172public:
173 SimpleLedTemplate (const char* daStr);
174
175public:
176 virtual void LoadTemplate () override;
177
178public:
179 virtual CDocument* OpenDocumentFile (LPCTSTR lpszPathName, BOOL bMakeVisible) override
180 {
181 // Based on MFC CSingleDocTemplate::OpenDocumentFile () from MSVC.Net 2k3 (2003-11-29)
182 // But changed to cope with exceptions being thrown during OpenDoc (SPR#1572)
183 CDocument* pDocument = NULL;
184 CFrameWnd* pFrame = NULL;
185 BOOL bCreated = FALSE; // => doc and frame created
186 BOOL bWasModified = FALSE;
187
188 if (m_pOnlyDoc != NULL) {
189 // already have a document - reinit it
190 pDocument = m_pOnlyDoc;
191 if (!pDocument->SaveModified ())
192 return NULL; // leave the original one
193
194 pFrame = (CFrameWnd*)AfxGetMainWnd ();
195 ASSERT (pFrame != NULL);
196 ASSERT_KINDOF (CFrameWnd, pFrame);
197 ASSERT_VALID (pFrame);
198 }
199 else {
200 // create a new document
201 pDocument = CreateNewDocument ();
202 ASSERT (pFrame == NULL); // will be created below
203 bCreated = TRUE;
204 }
205
206 if (pDocument == NULL) {
207 AfxMessageBox (AFX_IDP_FAILED_TO_CREATE_DOC);
208 return NULL;
209 }
210 ASSERT (pDocument == m_pOnlyDoc);
211
212 if (pFrame == NULL) {
213 ASSERT (bCreated);
214
215 // create frame - set as main document frame
216 BOOL bAutoDelete = pDocument->m_bAutoDelete;
217 pDocument->m_bAutoDelete = FALSE;
218 // don't destroy if something goes wrong
219 pFrame = CreateNewFrame (pDocument, NULL);
220 pDocument->m_bAutoDelete = bAutoDelete;
221 if (pFrame == NULL) {
222 AfxMessageBox (AFX_IDP_FAILED_TO_CREATE_DOC);
223 delete pDocument; // explicit delete on error
224 return NULL;
225 }
226 }
227
228 if (lpszPathName == NULL) {
229 // create a new document
230 SetDefaultTitle (pDocument);
231
232 // avoid creating temporary compound file when starting up invisible
233 if (!bMakeVisible)
234 pDocument->m_bEmbedded = TRUE;
235
236 if (!pDocument->OnNewDocument ()) {
237 // user has been alerted to what failed in OnNewDocument
238 if (bCreated)
239 pFrame->DestroyWindow (); // will destroy document
240 return NULL;
241 }
242 }
243 else {
244 CWaitCursor wait;
245
246 // open an existing document
247 bWasModified = pDocument->IsModified ();
248 pDocument->SetModifiedFlag (FALSE); // not dirty for open
249
250 BOOL docOpenDocResult = false;
251 try {
252 docOpenDocResult = pDocument->OnOpenDocument (lpszPathName);
253 }
254 catch (...) {
255 if (bCreated) {
256 pDocument->OnNewDocument ();
257 CWinThread* pThread = AfxGetThread ();
258 ASSERT (pThread);
259 if (bCreated && pThread->m_pMainWnd == NULL) {
260 // set as main frame (InitialUpdateFrame will show the window)
261 pThread->m_pMainWnd = pFrame;
262 }
263 InitialUpdateFrame (pFrame, pDocument, bMakeVisible);
264 }
265 throw;
266 }
267
268 if (!docOpenDocResult) {
269 // user has been alerted to what failed in OnOpenDocument
270 if (bCreated) {
271 pFrame->DestroyWindow (); // will destroy document
272 }
273 else if (!pDocument->IsModified ()) {
274 // original document is untouched
275 pDocument->SetModifiedFlag (bWasModified);
276 }
277 else {
278 // we corrupted the original document
279 SetDefaultTitle (pDocument);
280
281 if (!pDocument->OnNewDocument ()) {
282 // assume we can continue
283 }
284 }
285 return NULL; // open failed
286 }
287 pDocument->SetPathName (lpszPathName);
288 }
289
290 CWinThread* pThread = AfxGetThread ();
291 ASSERT (pThread);
292 if (bCreated && pThread->m_pMainWnd == NULL) {
293 // set as main frame (InitialUpdateFrame will show the window)
294 pThread->m_pMainWnd = pFrame;
295 }
296 InitialUpdateFrame (pFrame, pDocument, bMakeVisible);
297
298 return pDocument;
299 }
300};
301
302class LedItDocManager : public CDocManager {
303public:
304 LedItDocManager ();
305 virtual void OnFileNew () override;
306 virtual CDocument* OpenDocumentFile (LPCTSTR lpszFileName) override;
307 nonvirtual CDocument* OpenDocumentFile (LPCTSTR lpszFileName, FileFormat format);
308
309public:
310 virtual void RegisterShellFileTypes (BOOL bWin95) override;
311
312private:
313 nonvirtual void RegisterShellFileType (bool bWin95, CString strPathName, int iconIndexInFile, CString strFilterExt,
314 CString strFileTypeId, CString strFileTypeName);
315
316public:
317 virtual BOOL DoPromptFileName (CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate) override;
318
319 virtual void OnFileOpen () override;
320};
321
322inline const void* LoadAppResource (long resID, LPCTSTR resType)
323{
324 HRSRC hrsrc = ::FindResource (::AfxGetResourceHandle (), MAKEINTRESOURCE (resID), resType);
325 AssertNotNull (hrsrc);
326 HGLOBAL hglobal = ::LoadResource (::AfxGetResourceHandle (), hrsrc);
327 const void* lockedData = ::LockResource (hglobal);
328 EnsureNotNull (lockedData);
329 return (lockedData);
330}
331static BOOL AFXAPI SetRegKey (LPCTSTR lpszKey, LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL)
332{
333 if (lpszValueName == NULL) {
334 if (::RegSetValue (HKEY_CLASSES_ROOT, lpszKey, REG_SZ, lpszValue, static_cast<DWORD> (::_tcslen (lpszValue))) != ERROR_SUCCESS) {
335 TRACE1 ("Warning: registration database update failed for key '%s'.\n", lpszKey);
336 return FALSE;
337 }
338 return TRUE;
339 }
340 else {
341 HKEY hKey;
342 if (::RegCreateKey (HKEY_CLASSES_ROOT, lpszKey, &hKey) == ERROR_SUCCESS) {
343 LONG lResult = ::RegSetValueEx (hKey, lpszValueName, 0, REG_SZ, (CONST BYTE*)lpszValue,
344 static_cast<DWORD> (::_tcslen (lpszValue) + sizeof (TCHAR)));
345 if (::RegCloseKey (hKey) == ERROR_SUCCESS && lResult == ERROR_SUCCESS) {
346 return TRUE;
347 }
348 }
349 TRACE1 ("Warning: registration database update failed for key '%s'.\n", lpszKey);
350 return FALSE;
351 }
352}
353#endif
354
355class MyAboutBox : public Led_StdDialogHelper_AboutBox {
356private:
357 using inherited = Led_StdDialogHelper_AboutBox;
358#if qStroika_Foundation_Common_Platform_Windows
359public:
360 MyAboutBox (HINSTANCE hInstance, HWND parentWnd)
361 : inherited (hInstance, parentWnd)
362 {
363 }
364#elif qStroika_FeatureSupported_XWindows
365public:
366 MyAboutBox (GtkWindow* modalParentWindow)
367 : inherited (modalParentWindow)
368 {
369 }
370#endif
371
372public:
373 virtual void PreDoModalHook () override
374 {
375 inherited::PreDoModalHook ();
376#if _UNICODE
377#define kUNICODE_NAME_ADORNER L" [UNICODE]"
378#else
379#define kUNICODE_NAME_ADORNER " [Internal UNICODE]"
380#endif
381
382#if qStroika_Foundation_Common_Platform_MacOS
383 const short kPictHeight = 273;
384 const short kPictWidth = 437;
385 SDKString verStr = SDKString{qLed_ShortVersionString} + kUNICODE_NAME_ADORNER " (" + __DATE__ + ")";
386 const int kVERWidth = 230;
387 SimpleLayoutHelper (kPictHeight, kPictWidth, Led_Rect (159, 15, 17, 142), Led_Rect (159, 227, 17, 179), verStr);
388#elif qStroika_Foundation_Common_Platform_Windows
389 // Cuz of fact that dlog sizes specified in dlog units, and that doesn't work well for bitmaps
390 // we must resize our dlog on the fly based on pict resource size...
391 const int kPictWidth = 437; // must agree with ACTUAL bitmap size
392 const int kPictHeight = 273;
393 const int kButHSluff = 17;
394 const int kButVSluff = 19;
395 {
396 RECT windowRect;
397 ::GetWindowRect (GetHWND (), &windowRect);
398 // figure size of non-client area...
399 int ncWidth = 0;
400 int ncHeight = 0;
401 {
402 RECT clientRect;
403 ::GetClientRect (GetHWND (), &clientRect);
404 ncWidth = AsLedRect (windowRect).GetWidth () - AsLedRect (clientRect).GetWidth ();
405 ncHeight = AsLedRect (windowRect).GetHeight () - AsLedRect (clientRect).GetHeight ();
406 }
407 ::MoveWindow (GetHWND (), windowRect.left, windowRect.top, kPictWidth + ncWidth, kPictHeight + ncHeight, false);
408 }
409
410 // Place and fill in version information
411 {
412 HWND w = ::GetDlgItem (GetHWND (), kLedStdDlg_AboutBox_VersionFieldID);
413 AssertNotNull (w);
414 const int kVERWidth = 230;
415 ::MoveWindow (w, kPictWidth / 2 - kVERWidth / 2, 32, kVERWidth, 16, false);
416 ::SetWindowText (w, _T (qLed_ShortVersionString) kUNICODE_NAME_ADORNER _T (" (") _T (__DATE__) _T (")"));
417 }
418
419 // Place hidden buttons which map to URLs
420 {
421 HWND w = ::GetDlgItem (GetHWND (), kLedStdDlg_AboutBox_InfoLedFieldID);
422 AssertNotNull (w);
423 ::MoveWindow (w, 15, 159, 142, 17, false);
424 w = ::GetDlgItem (GetHWND (), kLedStdDlg_AboutBox_LedWebPageFieldID);
425 AssertNotNull (w);
426 ::MoveWindow (w, 227, 159, 179, 17, false);
427 }
428
429 // Place OK button
430 {
431 HWND w = ::GetDlgItem (GetHWND (), IDOK);
432 AssertNotNull (w);
433 RECT tmp;
434 ::GetWindowRect (w, &tmp);
435 ::MoveWindow (w, kButHSluff, kPictHeight - AsLedRect (tmp).GetHeight () - kButVSluff, AsLedRect (tmp).GetWidth (),
436 AsLedRect (tmp).GetHeight (), false); // width/height we should presevere
437 }
438
439 ::SetWindowText (GetHWND (), _T ("About LedIt!"));
440#elif qStroika_FeatureSupported_XWindows
441 GtkWidget* window = GetWindow ();
442 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
443
444 /* now for the pixmap from gdk */
445 GtkStyle* style = gtk_widget_get_style (window);
446 GdkBitmap* mask = NULL;
447 GdkPixmap* pixmap = gdk_pixmap_create_from_xpm_d (window->window, &mask, &style->bg[GTK_STATE_NORMAL], (gchar**)AboutBoxImage_xpm);
448
449 /* Create box for xpm and label */
450 GtkWidget* box1 = gtk_hbox_new (FALSE, 0);
451 gtk_container_set_border_width (GTK_CONTAINER (box1), 2);
452
453 /* a pixmap widget to contain the pixmap */
454 GtkWidget* pixmapwid = gtk_pixmap_new (pixmap, mask);
455 SDKString verStr = SDKString{qLed_ShortVersionString} + " (" + __DATE__ + ")";
456
457 GtkWidget* label = gtk_label_new (verStr.c_str ());
458
459 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
460 gtk_box_pack_start (GTK_BOX (box1), pixmapwid, FALSE, FALSE, 3);
461
462 gtk_widget_show (pixmapwid);
463 gtk_widget_show (label);
464 gtk_widget_show (box1);
465
466 /* a button to contain the pixmap widget */
467 GtkWidget* button = gtk_button_new ();
468 gtk_container_add (GTK_CONTAINER (button), box1);
469 gtk_container_add (GTK_CONTAINER (window), button);
470 gtk_widget_show (button);
471 SetOKButton (button);
472
473#endif
474 }
475 virtual void OnClickInInfoField () override
476 {
477 try {
478 Led_URLManager::Get ().Open ("mailto:info-led@sophists.com");
479 }
480 catch (...) {
481 // ignore for now - since errors here prent dialog from dismissing (on MacOSX)
482 }
483 inherited::OnClickInInfoField ();
484 }
485
486 virtual void OnClickInLedWebPageField () override
487 {
488 try {
489 Led_URLManager::Get ().Open (MakeSophistsAppNameVersionURL ("/Led/LedIt/", kAppName));
490 }
491 catch (...) {
492 // ignore for now - since errors here prent dialog from dismissing (on MacOSX)
493 }
494 inherited::OnClickInLedWebPageField ();
495 }
496};
497
498#if qStroika_FeatureSupported_XWindows
499class LedItFilePickBox : public StdFilePickBox {
500private:
501 using inherited = StdFilePickBox;
502
503public:
504 LedItFilePickBox (GtkWindow* modalParentWindow, const SDKString& title, bool saveDialog, const SDKString& fileName, FileFormat fileFormat)
505 : inherited (modalParentWindow, title, saveDialog, fileName)
506 , fFileFormat (fileFormat)
507 , fFileTypeChoice (NULL)
508 {
509 }
510
511protected:
512 virtual void PreDoModalHook () override
513 {
514 inherited::PreDoModalHook ();
515
516 {
517 GtkBox* mainVBox = GTK_BOX (GTK_FILE_SELECTION (GetWindow ())->main_vbox);
518 GtkWidget* fileTypeHBox = gtk_hbox_new (TRUE, 10);
519 gtk_box_pack_start (mainVBox, fileTypeHBox, FALSE, FALSE, 0);
520 gtk_widget_show (fileTypeHBox);
521
522 // pulldown label
523 GtkWidget* filetypesLabel = gtk_label_new ("File Type:");
524 gtk_label_set_justify (GTK_LABEL (filetypesLabel), GTK_JUSTIFY_RIGHT);
525 gtk_misc_set_alignment (GTK_MISC (filetypesLabel), 1.0, 0.5);
526 gtk_widget_show (filetypesLabel);
527 gtk_box_pack_start (GTK_BOX (fileTypeHBox), filetypesLabel, FALSE, TRUE, 0);
528
529 // pulldown menu
530 fFileTypeChoice = GTK_OPTION_MENU (gtk_option_menu_new ());
531 gtk_widget_show (GTK_WIDGET (fFileTypeChoice));
532 gtk_box_pack_end (GTK_BOX (fileTypeHBox), GTK_WIDGET (fFileTypeChoice), FALSE, TRUE, 0);
533
534 /*
535 * Put the fileType box in the visually pleasing spot. Of course the number 3 is based on the current, gtk 1.2.10 behavior, and could
536 * become wrong as the gtk code it depends on changes.
537 */
538 gtk_box_reorder_child (mainVBox, fileTypeHBox, 5);
539
540 // Add the file types list (and autodetect for OPEN)
541 {
542 GtkWidget* menu = gtk_menu_new ();
543 if (not fSaveDialog) {
544 GtkWidget* m = gtk_menu_item_new_with_label ("Automatically recognize type");
545 gtk_object_set_user_data (GTK_OBJECT (m), reinterpret_cast<void*> (eUnknownFormat));
546 gtk_widget_show (m);
547 gtk_menu_append (GTK_MENU (menu), m);
548 // Should add a separator...TOO!
549 }
550 struct FileFilterDesc {
551 SDKString fDescription;
552 FileFormat fFormat;
553 };
554 static FileFilterDesc typeList[] = {
555 {"HTML file", eHTMLFormat},
556 {"Led Rich Text Format", eLedPrivateFormat},
557 {"Microsoft Rich Text Format (RTF)", eRTFFormat},
558 {"Text file", eTextFormat},
559 };
560 size_t defaultItem = 0;
561 for (size_t i = 0; i < std::size (typeList); ++i) {
562 GtkWidget* m = gtk_menu_item_new_with_label (typeList[i].fDescription.c_str ());
563 gtk_object_set_user_data (GTK_OBJECT (m), reinterpret_cast<void*> (typeList[i].fFormat));
564 gtk_widget_show (m);
565 gtk_menu_append (GTK_MENU (menu), m);
566 if (fSaveDialog) {
567 // set initial item selected to reflect original type
568 if (typeList[i].fFormat == fFileFormat) {
569 defaultItem = i;
570 }
571 }
572 }
573 gtk_widget_show (menu);
574 gtk_option_menu_set_menu (fFileTypeChoice, menu);
575 gtk_menu_set_active (GTK_MENU (menu), defaultItem);
576 gtk_option_menu_set_history (fFileTypeChoice, defaultItem);
577 }
578 }
579 }
580 virtual void OnOK () override
581 {
582 inherited::OnOK ();
583 // what a long ugly line of code
584 GtkWidget* activeItem = gtk_menu_get_active (GTK_MENU (gtk_option_menu_get_menu (fFileTypeChoice)));
585 AssertNotNull (activeItem);
586 fFileFormat = (FileFormat)(reinterpret_cast<int> (gtk_object_get_user_data (GTK_OBJECT (activeItem))));
587 }
588
589public:
590 nonvirtual FileFormat GetFileFormat () const
591 {
592 return fFileFormat;
593 }
594
595private:
596 FileFormat fFileFormat;
597 GtkOptionMenu* fFileTypeChoice;
598};
599#endif
600
601/*
602 ********************************************************************************
603 ******************************** LedItApplication ******************************
604 ********************************************************************************
605 */
606#if qStroika_Foundation_Common_Platform_Windows
607LedItApplication theApp;
608
609// This identifier was generated to be statistically unique for your app.
610// You may change it if you prefer to choose a specific identifier.
611// {0FC00620-28BD-11CF-899C-00AA00580324}
612static const CLSID clsid = {0xfc00620, 0x28bd, 0x11cf, {0x89, 0x9c, 0x0, 0xaa, 0x0, 0x58, 0x3, 0x24}};
613
614BEGIN_MESSAGE_MAP (LedItApplication, CWinApp)
615ON_COMMAND (ID_APP_ABOUT, OnAppAbout)
616ON_COMMAND (ID_FILE_NEW, OnFileNew)
617ON_COMMAND (ID_FILE_OPEN, OnFileOpen)
618ON_COMMAND (ID_FILE_PRINT_SETUP, OnFilePrintSetup)
619ON_COMMAND (kToggleUseSmartCutNPasteCmd, OnToggleSmartCutNPasteOptionCommand)
620ON_UPDATE_COMMAND_UI (kToggleUseSmartCutNPasteCmd, OnToggleSmartCutNPasteOptionUpdateCommandUI)
621ON_COMMAND (kToggleWrapToWindowCmd, OnToggleWrapToWindowOptionCommand)
622ON_UPDATE_COMMAND_UI (kToggleWrapToWindowCmd, OnToggleWrapToWindowOptionUpdateCommandUI)
623ON_COMMAND (kToggleShowHiddenTextCmd, OnToggleShowHiddenTextOptionCommand)
624ON_UPDATE_COMMAND_UI (kToggleShowHiddenTextCmd, OnToggleShowHiddenTextOptionUpdateCommandUI)
625ON_COMMAND (cmdChooseDefaultFontDialog, OnChooseDefaultFontCommand)
626ON_COMMAND (kGotoLedItWebPageCmd, OnGotoLedItWebPageCommand)
627ON_COMMAND (kGotoSophistsWebPageCmd, OnGotoSophistsWebPageCommand)
628ON_COMMAND (kCheckForUpdatesWebPageCmdID, OnCheckForUpdatesWebPageCommand)
629END_MESSAGE_MAP ()
630#endif
631
632LedItApplication* LedItApplication::sThe = NULL;
633
634LedItApplication::LedItApplication ()
635 :
636#if qStroika_Foundation_Common_Platform_MacOS || qStroika_Foundation_Common_Platform_Windows
637 inherited ()
638 ,
639#endif
640#if qStroika_Foundation_Common_Platform_MacOS
641 fHelpMenuItem (0)
642 , fGotoLedItWebPageMenuItem (0)
643 , fGotoSophistsWebPageMenuItem (0)
644 , fCheckForUpdatesWebPageMenuItem (0)
645 , fLastLowMemWarnAt (0.0f)
646#endif
647#if qStroika_Foundation_Common_Platform_Windows
648 fOleTemplateServer ()
649 ,
650#endif
651#if qStroika_Foundation_Common_Platform_Windows
652 fInstalledFonts ()
653#elif qStroika_FeatureSupported_XWindows
654 fInstalledFonts (GDK_DISPLAY ())
655 ,
656#endif
657#if qStroika_FeatureSupported_XWindows
658 fAppWindow (NULL)
659 , fDocument (NULL)
660#endif
661{
662 Require (sThe == NULL);
663 sThe = this;
664
665/*
666 * It would be nice to be able to add all the standard types in one place, but due to the quirkly requirement (or is it
667 * just a convention) with MFC of having the application object staticly constructed, we run into a 'race condition'
668 * of sorts. Its undefined by C++ the order of static constructors across modules. As a result - some of the static
669 * consts used in EmbeddedObjectCreatorRegistry aren't yet initialized. Sigh... Perhaps I could/should find
670 * a better way to make this work, but lets KISS (keep it simple stupid) for now, as we are very close to
671 * release -- LGP 2001-10-06.
672 */
673#if !qStroika_Foundation_Common_Platform_Windows
674 // Tell Led about the kinds of embeddings we will allow
675 EmbeddedObjectCreatorRegistry::Get ().AddStandardTypes ();
676
677#if qStroika_Foundation_Common_Platform_Windows
678 // Support OLE embeddings (both created from clip, and from RTF-format files)
679 EmbeddedObjectCreatorRegistry::Get ().AddAssoc (LedItControlItem::kClipFormat, LedItControlItem::kEmbeddingTag,
680 LedItControlItem::mkLedItControlItemStyleMarker, LedItControlItem::mkLedItControlItemStyleMarker);
681 EmbeddedObjectCreatorRegistry::Get ().AddAssoc (kBadClipFormat, RTFIO::RTFOLEEmbedding::kEmbeddingTag,
682 LedItControlItem::mkLedItControlItemStyleMarker, LedItControlItem::mkLedItControlItemStyleMarker);
683#endif
684#endif
685
686#if qStroika_Foundation_Common_Platform_MacOS
687 // Register classes for objects created from 'PPob' resources
688 TRegistrar<LPlaceHolder>::Register ();
689 TRegistrar<LPrintout>::Register ();
690 TRegistrar<LDialogBox>::Register ();
691 TRegistrar<LPicture>::Register ();
692 TRegistrar<LCaption>::Register ();
693 TRegistrar<LPane>::Register ();
694 TRegistrar<LTextButton>::Register ();
695 TRegistrar<LStdCheckBox>::Register ();
696 TRegistrar<LStdButton>::Register ();
697 TRegistrar<LEditField>::Register ();
698 TRegistrar<LTabGroup>::Register ();
699 TRegistrar<LStdPopupMenu>::Register ();
700
701 // Tell Led about the picture resources it needs to render some special embedding markers
702 StandardUnknownTypeStyleMarker::sUnknownPict = (Picture**)::GetResource ('PICT', kUnknownEmbeddingPictID);
703 StandardDIBStyleMarker::sUnsupportedFormatPict = (Picture**)::GetResource ('PICT', kUnsupportedDIBFormatPictID);
704
705 // Always make sure sleep time no longer than the caret blink time.
706 // But default to 6 ticks (PP's default) - 0.1 seconds.
707 SetSleepTime (Led_Min (6, GetCaretTime ()));
708#elif qStroika_FeatureSupported_XWindows
709 fDocument = new LedItDocument ();
710
711 fAppWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
712 gtk_signal_connect (GTK_OBJECT (fAppWindow), "destroy", GTK_SIGNAL_FUNC (xdestroy), this);
713 // gtk_window_set_title (GTK_WINDOW(fAppWindow), "LedIt!");
714 UpdateFrameWindowTitle ();
715 gtk_widget_set_usize (GTK_WIDGET (fAppWindow), 300, 200);
716 gtk_widget_set_usize (fAppWindow, 600, 500);
717 gtk_window_set_policy (GTK_WINDOW (fAppWindow), TRUE, TRUE, FALSE);
718 gtk_container_set_border_width (GTK_CONTAINER (fAppWindow), 0);
719
720 GtkWidget* main_vbox = gtk_vbox_new (FALSE, 1);
721 gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
722 gtk_container_add (GTK_CONTAINER (fAppWindow), main_vbox);
723 gtk_widget_show (main_vbox);
724
725 GtkWidget* menubar = get_main_menu (fAppWindow);
726
727 gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
728 gtk_widget_show (menubar);
729
730 {
731 GtkWidget* box1 = gtk_vbox_new (FALSE, 0);
732 gtk_container_add (GTK_CONTAINER (main_vbox), box1);
733 gtk_widget_show (box1);
734
735 GtkWidget* box2 = gtk_vbox_new (FALSE, 10);
736 gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
737 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
738 gtk_widget_show (box2);
739
740 GtkWidget* table = gtk_table_new (2, 2, false);
741 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
742 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
743 gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
744 gtk_widget_show (table);
745
746 /* Create the GtkText widget */
747 fTextEditor = new LedItView (fDocument);
748
749 gtk_table_attach (GTK_TABLE (table), fTextEditor->Get_GtkWidget (), 0, 1, 0, 1,
750 static_cast<GtkAttachOptions> (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
751 static_cast<GtkAttachOptions> (GTK_EXPAND | GTK_SHRINK | GTK_FILL), 0, 0);
752 gtk_widget_show (fTextEditor->Get_GtkWidget ());
753
754#if 1
755 /* Add a vertical scrollbar to the text widget */
756 GtkAdjustment* vAdj = fTextEditor->GetAdjustmentObject (TextInteractor::v);
757 GtkWidget* vscrollbar = gtk_vscrollbar_new (vAdj);
758 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1, static_cast<GtkAttachOptions> (GTK_FILL),
759 static_cast<GtkAttachOptions> (GTK_EXPAND | GTK_SHRINK | GTK_FILL), 0, 0);
760 gtk_widget_show (vscrollbar);
761
762 /* Add a horizontal scrollbar to the text widget */
763 GtkAdjustment* hAdj = fTextEditor->GetAdjustmentObject (TextInteractor::h);
764 GtkWidget* hscrollbar = gtk_hscrollbar_new (hAdj);
765 gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2, static_cast<GtkAttachOptions> (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
766 static_cast<GtkAttachOptions> (GTK_FILL), 0, 0);
767 gtk_widget_show (hscrollbar);
768#endif
769 gtk_widget_show (fAppWindow);
770
771 // Initially set focus to the text editor widget
772 gtk_widget_grab_focus (fTextEditor->Get_GtkWidget ());
773 }
774#endif
775}
776
777LedItApplication::~LedItApplication ()
778{
779 Require (sThe == this);
780 sThe = NULL;
781#if qStroika_FeatureSupported_XWindows
782 delete fDocument;
783#endif
784}
785
786LedItApplication& LedItApplication::Get ()
787{
788 EnsureNotNull (sThe);
789 return *sThe;
790}
791
792void LedItApplication::DoAboutBox ()
793{
794#if qStroika_Foundation_Common_Platform_MacOS
795 MyAboutBox dlg;
796#elif qStroika_Foundation_Common_Platform_Windows
797 MyAboutBox dlg (m_hInstance, AfxGetMainWnd ()->m_hWnd);
798#elif qStroika_FeatureSupported_XWindows
799 MyAboutBox dlg (GTK_WINDOW (fAppWindow));
800#endif
801 dlg.DoModal ();
802}
803
804void LedItApplication::OnGotoLedItWebPageCommand ()
805{
806 try {
807 Led_URLManager::Get ().Open (MakeSophistsAppNameVersionURL ("/Led/LedIt/", kAppName));
808 }
809 catch (...) {
810#if qStroika_Foundation_Common_Platform_MacOS
811 DoStringyAlert (kCannotOpenWebPageAlertID);
812#endif
813 }
814}
815
816void LedItApplication::OnGotoSophistsWebPageCommand ()
817{
818 try {
819 Led_URLManager::Get ().Open (MakeSophistsAppNameVersionURL ("/", kAppName));
820 }
821 catch (...) {
822#if qStroika_Foundation_Common_Platform_MacOS
823 DoStringyAlert (kCannotOpenWebPageAlertID);
824#endif
825 }
826}
827
828void LedItApplication::OnCheckForUpdatesWebPageCommand ()
829{
830 try {
831 Led_URLManager::Get ().Open (MakeSophistsAppNameVersionURL ("/Led/CheckForUpdates.asp", kAppName));
832 }
833 catch (...) {
834#if qStroika_Foundation_Common_Platform_MacOS
835 DoStringyAlert (kCannotOpenWebPageAlertID);
836#endif
837 }
838}
839
840#if qStroika_Foundation_Common_Platform_MacOS
841void LedItApplication::StartUp ()
842{
843 try {
844 ObeyCommand (cmd_New, nil); // create a new window
845 }
846 STANDARD_LEDITAPPLICATION_MACOS_CATCHERS ();
847}
848
849void LedItApplication::MakeMenuBar ()
850{
851 inherited::MakeMenuBar ();
852
853 // Base class has already constructed the menu bar, by this point...
854 // So we can add font menus, and associate command numbers...
855 {
856 MenuRef fontMenuHandle = ::GetMenuHandle (cmd_FontMenu);
857 AssertNotNull (fontMenuHandle);
858 ::AppendResMenu (fontMenuHandle, 'FONT');
859 AssertNotNull (LMenuBar::GetCurrentMenuBar ());
860 LMenu* fontMenu = LMenuBar::GetCurrentMenuBar ()->FetchMenu (cmd_FontMenu);
861 AssertNotNull (fontMenu);
862 size_t nMenuItems = ::CountMenuItems (fontMenu->GetMacMenuH ());
863 for (size_t i = 1; i <= nMenuItems; ++i) {
864 fontMenu->SetCommand (i, i - 1 + kBaseFontNameCmd); // make first cmd = kBaseFontNameCmd
865 }
866 }
867
868 bool aquaUI = false;
869 {
870 SInt32 gestaltResponse = 0;
871 aquaUI = (::Gestalt (gestaltMenuMgrAttr, &gestaltResponse) == noErr) and (gestaltResponse & gestaltMenuMgrAquaLayoutMask);
872 }
873
874 // Add a special help menu item you launch our help file
875 // (see NewIM Essential Macintosh Toolbox, 3-68)
876 {
877 MenuHandle helpMenu = NULL;
878#if !TARGET_CARBON
879 if (::HMGetHelpMenuHandle (&helpMenu) != noErr) {
880 helpMenu = NULL;
881 }
882#endif
883 if (helpMenu == NULL) {
884 // if there is no helpMenu, then add our own...
885 helpMenu = ::NewMenu (kHelpMenuID, "\pHelp");
886 AssertNotNull (helpMenu);
887 MenuID append = 0;
888 ::InsertMenu (helpMenu, append);
889 }
890 if (helpMenu != NULL) {
891 ::AppendMenu (helpMenu, "\pBrowse Local Help");
892 fHelpMenuItem = ::CountMenuItems (helpMenu);
893 ::AppendMenu (helpMenu, "\p-");
894 ::AppendMenu (helpMenu, "\pxxx"); // Text in SetMenuItemText() call cuz idiodic mac toolbox interprets '!' character!
895 ::SetMenuItemText (helpMenu, ::CountMenuItems (helpMenu), "\pGoto LedIt! Web Page");
896 fGotoLedItWebPageMenuItem = ::CountMenuItems (helpMenu);
897 ::AppendMenu (helpMenu, "\pGoto Sophist Solutions Web Page");
898 fGotoSophistsWebPageMenuItem = ::CountMenuItems (helpMenu);
899 ::AppendMenu (helpMenu, "\pCheck for LedIt! Web Updates");
900 fCheckForUpdatesWebPageMenuItem = ::CountMenuItems (helpMenu);
901 }
902 }
903
904 // For Aqua UI (OSX) - lose the Quit menu item.
905 if (aquaUI) {
906 MenuRef fileMenu = ::GetMenuHandle (kFileMenuID);
907 AssertNotNull (fileMenu);
908 // Lose the separator AND the Quit menu item.
909 ::DeleteMenuItem (fileMenu, ::CountMenuItems (fileMenu));
910 ::DeleteMenuItem (fileMenu, ::CountMenuItems (fileMenu));
911 }
912}
913
914void LedItApplication::ProcessNextEvent ()
915{
916 if (sDeepShitCheeseBuf == NULL) {
917 sDeepShitCheeseBuf = ::NewHandle (10 * 1024);
918 }
919 try {
920 inherited::ProcessNextEvent ();
921 }
922 STANDARD_LEDITAPPLICATION_MACOS_CATCHERS ();
923}
924
925void LedItApplication::HandleAppleEvent (const AppleEvent& inAppleEvent, AppleEvent& outAEReply, AEDesc& outResult, long inAENumber)
926{
927 try {
928 inherited::HandleAppleEvent (inAppleEvent, outAEReply, outResult, inAENumber);
929 }
930 STANDARD_LEDITAPPLICATION_MACOS_CATCHERS ();
931}
932
933void LedItApplication::HandleMacOSException (OSErr err)
934{
935 switch (err) {
936 case memFullErr: {
937 HandleBadAllocException ();
938 } break;
939
940 default: {
941 Str255 tmp;
942 NumToString (err, tmp);
943 DoStringyAlert (kGenericMacOSExceptionAlertID, tmp);
944 } break;
945 }
946}
947
948void LedItApplication::HandlePowerPlantException (ExceptionCode err)
949{
950 if (err > 32767 or err < -32768) {
951 Str255 tmp;
952 ::NumToString (err, tmp);
953 ::DoStringyAlert (kPowerPlantExceptionAlertID, tmp);
954 }
955 else {
956 Led_Assert (err == OSErr (err));
957 HandleMacOSException (OSErr (err));
958 }
959}
960
961Boolean LedItApplication::ObeyCommand (CommandT inCommand, void* ioParam)
962{
963 Boolean cmdHandled = true;
964
965 if ((HiWord ((-inCommand)) == kHMHelpMenuID or HiWord ((-inCommand)) == kHelpMenuID) and fHelpMenuItem == LoWord (-inCommand)) {
966 OnHelpMenuCommand ();
967 return true;
968 }
969 if ((HiWord ((-inCommand)) == kHMHelpMenuID or HiWord ((-inCommand)) == kHelpMenuID) and fGotoLedItWebPageMenuItem == LoWord (-inCommand)) {
970 OnGotoLedItWebPageCommand ();
971 return true;
972 }
973 if ((HiWord ((-inCommand)) == kHMHelpMenuID or HiWord ((-inCommand)) == kHelpMenuID) and fGotoSophistsWebPageMenuItem == LoWord (-inCommand)) {
974 OnGotoSophistsWebPageCommand ();
975 return true;
976 }
977 if ((HiWord ((-inCommand)) == kHMHelpMenuID or HiWord ((-inCommand)) == kHelpMenuID) and fCheckForUpdatesWebPageMenuItem == LoWord (-inCommand)) {
978 OnCheckForUpdatesWebPageCommand ();
979 return true;
980 }
981
982 if (inCommand >= kBaseWindowCmd and inCommand <= kLastWindowCmd) {
983 size_t windowIdx = (inCommand - kBaseWindowCmd);
984 const vector<LWindow*>& windows = LedItDocument::GetDocumentWindows ();
985 if (windowIdx < windows.size ()) {
986 LWindow* w = windows[windowIdx];
987 AssertNotNull (w);
988 UDesktop::SelectDeskWindow (w);
989 }
990 else {
991 Led_Assert (false); // we shouldn't get these!
992 }
993 return true;
994 }
995
996 switch (inCommand) {
997 case kToggleUseSmartCutNPasteCmd:
998 OnToggleSmartCutNPasteOptionCommand ();
999 break;
1000 case kToggleWrapToWindowCmd:
1001 OnToggleWrapToWindowOptionCommand ();
1002 break;
1003 case kToggleShowHiddenTextCmd:
1004 OnToggleShowHiddenTextOptionCommand ();
1005 break;
1006 default:
1007 cmdHandled = inherited::ObeyCommand (inCommand, ioParam);
1008 break;
1009 }
1010
1011 return cmdHandled;
1012}
1013
1014// Pass back status of a (menu) command
1015void LedItApplication::FindCommandStatus (CommandT inCommand, Boolean& outEnabled, Boolean& outUsesMark, UInt16& outMark, Str255 outName)
1016{
1017 if (inCommand >= kBaseWindowCmd and inCommand <= kLastWindowCmd) {
1018 size_t windowIdx = (inCommand - kBaseWindowCmd);
1019 const vector<LWindow*>& windows = LedItDocument::GetDocumentWindows ();
1020 if (windowIdx < windows.size ()) {
1021 LWindow* w = windows[windowIdx];
1022 AssertNotNull (w);
1023 outEnabled = true;
1024 (void)w->GetDescriptor (outName);
1025 outMark = UDesktop::WindowIsSelected (w) ? checkMark : 0;
1026 }
1027 else {
1028 Led_Assert (false); // we shouldn't get these!
1029 }
1030 outUsesMark = true;
1031 return;
1032 }
1033
1034 outUsesMark = false;
1035 switch (inCommand) {
1036 case kToggleUseSmartCutNPasteCmd:
1037 OnToggleSmartCutNPasteOption_UpdateCommandUI (&Led_PP_TmpCmdUpdater (inCommand, outEnabled, outUsesMark, outMark, outName));
1038 break;
1039 case kToggleWrapToWindowCmd:
1040 OnToggleWrapToWindowOption_UpdateCommandUI (&Led_PP_TmpCmdUpdater (inCommand, outEnabled, outUsesMark, outMark, outName));
1041 break;
1042 case kToggleShowHiddenTextCmd:
1043 OnToggleShowHiddenTextOption_UpdateCommandUI (&Led_PP_TmpCmdUpdater (inCommand, outEnabled, outUsesMark, outMark, outName));
1044 break;
1045 default:
1046 inherited::FindCommandStatus (inCommand, outEnabled, outUsesMark, outMark, outName);
1047 break;
1048 }
1049}
1050
1051void LedItApplication::OnHelpMenuCommand ()
1052{
1053 try {
1054 FSSpec fsp;
1055 Led_ThrowOSErr (::FSMakeFSSpec (0, 0, "\p:LedItDocs:index.html", &fsp));
1056 string helpURL = Led_URLManager::Get ().FileSpecToURL (fsp);
1057 Led_URLManager::Get ().Open (helpURL);
1058 }
1059 catch (...) {
1060 DoStringyAlert (kCannotOpenHelpFileAlertID);
1061 }
1062}
1063
1064void LedItApplication::UseIdleTime (const EventRecord& inMacEvent)
1065{
1066 inherited::UseIdleTime (inMacEvent);
1067
1068 /*
1069 * Check to see if we're too low on memory.
1070 */
1071 const float kIntervalBetweenWarnings = 10.0f;
1072 if (fLastLowMemWarnAt + kIntervalBetweenWarnings < ::Led_GetTickCount ()) {
1073 bool enufLocalMemory = true;
1074 bool enufMemory = true;
1075 try {
1076 Led_CheckSomeLocalHeapRAMAvailable (8 * 1024);
1077 }
1078 catch (...) {
1079 enufLocalMemory = false;
1080 }
1081 try {
1082 ::DisposeHandle (Led_DoNewHandle (8 * 1024));
1083 }
1084 catch (...) {
1085 enufMemory = false;
1086 }
1087
1088 if (not enufLocalMemory) {
1089 DoStringyAlert (kWarnLowLocalRAMAlertID);
1090 fLastLowMemWarnAt = ::Led_GetTickCount ();
1091 }
1092 if (not enufMemory) {
1093 DoStringyAlert (kWarnLowRAMAlertID);
1094 fLastLowMemWarnAt = ::Led_GetTickCount ();
1095 }
1096 }
1097
1098#if qUseMacTmpMemForAllocs && 0
1099 // Didn't help - See SPR#0351
1100 float sLastSendMemBackTryAt = 0;
1101 if (sLastSendMemBackTryAt + 30.0f < ::Led_GetTickCount ()) {
1102 extern void TryToSendSomeTmpMemBackToOS ();
1103 TryToSendSomeTmpMemBackToOS ();
1104 sLastSendMemBackTryAt = ::Led_GetTickCount ();
1105 }
1106#endif
1107}
1108
1109void LedItApplication::OpenDocument (FSSpec* inMacFSSpec)
1110{
1111 LedItDocument* doc = new LedItDocument (this, eUnknownFormat);
1112 try {
1113 doc->BuildDocWindow (inMacFSSpec);
1114 }
1115 catch (...) {
1116 delete doc;
1117 throw;
1118 }
1119}
1120
1121void LedItApplication::OpenDocument (FSSpec* inMacFSSpec, FileFormat format)
1122{
1123 LedItDocument* doc = new LedItDocument (this, format);
1124 try {
1125 doc->BuildDocWindow (inMacFSSpec);
1126 }
1127 catch (...) {
1128 delete doc;
1129 throw;
1130 }
1131}
1132
1133LModelObject* LedItApplication::MakeNewDocument ()
1134{
1135 LedItDocument* doc = new LedItDocument (this, eDefaultFormat);
1136 try {
1137 doc->BuildDocWindow (NULL);
1138 }
1139 catch (...) {
1140 delete doc;
1141 throw;
1142 }
1143 return doc;
1144}
1145
1146// Prompt the user to select a document to open
1147void LedItApplication::ChooseDocument ()
1148{
1149 static FilteredSFGetDLog::TypeSpec typeList[] = {
1150 {"HTML file", kTEXTFileType},
1151 {"Led Rich Text Format", kLedPrivateDocumentFileType},
1152 {"Microsoft Rich Text Format (RTF)", kTEXTFileType},
1153 {"Text file", kTEXTFileType},
1154 };
1155 FilteredSFGetDLog filteredPicker (typeList, (sizeof typeList) / (sizeof typeList[0]));
1156
1157 bool typeSpecified = false;
1158 size_t typeIndex = 0;
1159 FileFormat format = eUnknownFormat;
1160 FSSpec fileResult;
1161 if (filteredPicker.PickFile (&fileResult, &typeSpecified, &typeIndex)) {
1162 if (typeSpecified) {
1163 switch (typeIndex) {
1164 case 0:
1165 format = eHTMLFormat;
1166 break;
1167 case 1:
1168 format = eLedPrivateFormat;
1169 break;
1170 case 2:
1171 format = eRTFFormat;
1172 break;
1173 case 3:
1174 format = eTextFormat;
1175 break;
1176 default:
1177 Led_Assert (false);
1178 }
1179 }
1180 OpenDocument (&fileResult, format);
1181 }
1182}
1183
1184void LedItApplication::ShowAboutBox ()
1185{
1186 DoAboutBox ();
1187}
1188#endif
1189
1190void LedItApplication::OnToggleSmartCutNPasteOptionCommand ()
1191{
1192 Options o;
1193 o.SetSmartCutAndPaste (not o.GetSmartCutAndPaste ());
1194 UpdateViewsForPrefsChange ();
1195}
1196
1197void LedItApplication::OnToggleSmartCutNPasteOption_UpdateCommandUI (CMD_ENABLER* enabler)
1198{
1199 RequireNotNull (enabler);
1200 enabler->SetEnabled (true);
1201 enabler->SetChecked (Options{}.GetSmartCutAndPaste ());
1202}
1203
1204void LedItApplication::OnToggleWrapToWindowOptionCommand ()
1205{
1206 Options o;
1207 o.SetWrapToWindow (not o.GetWrapToWindow ());
1208 UpdateViewsForPrefsChange ();
1209}
1210
1211void LedItApplication::OnToggleWrapToWindowOption_UpdateCommandUI (CMD_ENABLER* enabler)
1212{
1213 RequireNotNull (enabler);
1214 enabler->SetEnabled (true);
1215 enabler->SetChecked (Options{}.GetWrapToWindow ());
1216}
1217
1218void LedItApplication::OnToggleShowHiddenTextOptionCommand ()
1219{
1220 Options o;
1221 o.SetShowHiddenText (not o.GetShowHiddenText ());
1222 UpdateViewsForPrefsChange ();
1223}
1224
1225void LedItApplication::OnToggleShowHiddenTextOption_UpdateCommandUI (CMD_ENABLER* enabler)
1226{
1227 RequireNotNull (enabler);
1228 enabler->SetEnabled (true);
1229 enabler->SetChecked (Options{}.GetShowHiddenText ());
1230}
1231
1232void LedItApplication::UpdateViewsForPrefsChange ()
1233{
1234 bool wrapToWindow = Options{}.GetWrapToWindow ();
1235 bool smartCutNPaste = Options{}.GetSmartCutAndPaste ();
1236 bool showHiddenText = Options{}.GetShowHiddenText ();
1237
1238#if qStroika_Foundation_Common_Platform_MacOS
1239 const TArray<LDocument*>& docList = LDocument::GetDocumentList ();
1240 TArrayIterator<LDocument*> iterator (docList);
1241 LDocument* theDoc = NULL;
1242 while (iterator.Next (theDoc)) {
1243 AssertMember (theDoc, LedItDocument);
1244 LedItDocument* d = dynamic_cast<LedItDocument*> (theDoc);
1245 AssertNotNull (d->GetTextView ());
1246 d->GetTextView ()->SetSmartCutAndPasteMode (smartCutNPaste);
1247 d->GetTextView ()->SetWrapToWindow (wrapToWindow);
1248 d->GetTextView ()->SetShowHiddenText (showHiddenText);
1249 }
1250#elif qStroika_Foundation_Common_Platform_Windows
1251 // Update each open view
1252 POSITION tp = GetFirstDocTemplatePosition ();
1253 while (tp != NULL) {
1254 CDocTemplate* t = GetNextDocTemplate (tp);
1255 AssertNotNull (t);
1256 POSITION dp = t->GetFirstDocPosition ();
1257 while (dp != NULL) {
1258 CDocument* doc = t->GetNextDoc (dp);
1259 AssertNotNull (doc);
1260 POSITION vp = doc->GetFirstViewPosition ();
1261 while (vp != NULL) {
1262 CView* v = doc->GetNextView (vp);
1263 AssertNotNull (v);
1264 LedItView* lv = dynamic_cast<LedItView*> (v);
1265 if (lv != NULL) {
1266 lv->SetSmartCutAndPasteMode (smartCutNPaste);
1267 lv->SetWrapToWindow (wrapToWindow);
1268 lv->SetShowHiddenText (showHiddenText);
1269 }
1270 }
1271 }
1272 }
1273#elif qStroika_FeatureSupported_XWindows
1274 AssertNotNull (fTextEditor);
1275 fTextEditor->SetSmartCutAndPasteMode (smartCutNPaste);
1276 fTextEditor->SetWrapToWindow (wrapToWindow);
1277 fTextEditor->SetShowHiddenText (showHiddenText);
1278#endif
1279}
1280
1281#if qStroika_Foundation_Common_Platform_Windows
1282BOOL LedItApplication::InitInstance ()
1283{
1284 SetRegistryKey (_T ("Sophist Solutions, Inc."));
1285
1286 // Initialize OLE libraries
1287 if (!AfxOleInit ()) {
1288 AfxMessageBox (IDP_OLE_INIT_FAILED);
1289 return false;
1290 }
1291
1292#if qIncludeBasicSpellcheckEngine
1293#if qStroika_Foundation_Debug_AssertionsChecked
1294 SpellCheckEngine_Basic::RegressionTest ();
1295#endif
1296
1297 fSpellCheckEngine = MakeSharedPtr<SpellCheckEngine_Basic_Simple> ();
1298
1299#if qStroika_Foundation_Common_Platform_Windows
1300 {
1301 // Place the dictionary in a reasonable - but hardwired place. Later - allow for editing that location,
1302 // and other spellchecking options (see SPR#1591)
1303 TCHAR defaultPath[MAX_PATH + 1];
1304 Verify (::SHGetSpecialFolderPath (nullptr, defaultPath, CSIDL_FLAG_CREATE | CSIDL_PERSONAL, true));
1305 fSpellCheckEngine->SetUserDictionary (SDKString{defaultPath} + Led_SDK_TCHAROF ("\\My LedIt Dictionary.txt"));
1306 }
1307#endif
1308
1309#endif
1310
1311 // Tell Led about the kinds of embeddings we will allow
1312 EmbeddedObjectCreatorRegistry::Get ().AddStandardTypes ();
1313
1314 // Support OLE embeddings (both created from clip, and from RTF-format files)
1315 EmbeddedObjectCreatorRegistry::Get ().AddAssoc (LedItControlItem::kClipFormat, LedItControlItem::kEmbeddingTag,
1316 LedItControlItem::mkLedItControlItemStyleMarker, LedItControlItem::mkLedItControlItemStyleMarker);
1317 EmbeddedObjectCreatorRegistry::Get ().AddAssoc (kBadClipFormat, RTFIO::RTFOLEEmbedding::kEmbeddingTag,
1318 LedItControlItem::mkLedItControlItemStyleMarker, LedItControlItem::mkLedItControlItemStyleMarker);
1319
1320 // Parse command line for standard shell commands, DDE, file open
1321 CCommandLineInfo cmdInfo;
1322 ParseCommandLine (cmdInfo);
1323
1324 AfxEnableControlContainer ();
1325
1326#if 0
1327 // LGP 960509 - doesn't appear to have any effect if present or not...
1328 // and prevents linking on Mac (CodeWarrior x-compiler).
1329 Enable3dControlsStatic (); // Call this when linking to MFC statically
1330#endif
1331
1332 //LoadStdProfileSettings (5); // Load standard INI file options (including MRU)
1333 LoadStdProfileSettings (9); // Load standard INI file options (including MRU)
1334
1335 Assert (m_pDocManager == NULL);
1336 m_pDocManager = new LedItDocManager ();
1337
1338 AddDocTemplateForString ("LedIt\n\nLedIt\nLed Rich Text Format (*.led)\n.led\nLedIt.Document\nLedIt Document", true);
1339
1340 // Enable DDE Open, and register icons / file types with the explorer/shell
1341 EnableShellOpen ();
1342 RegisterShellFileTypes (true); // ARG???
1343
1344 // When a server application is launched stand-alone, it is a good idea
1345 // to update the system registry in case it has been damaged.
1346 fOleTemplateServer.UpdateRegistry (OAT_INPLACE_SERVER);
1347 COleObjectFactory::UpdateRegistryAll ();
1348
1349 // Tell Led about the picture resources it needs to render some special embedding markers
1350 StandardUnknownTypeStyleMarker::sUnknownPict = (const Led_DIB*)::LoadAppResource (kUnknownEmbeddingPictID, RT_BITMAP);
1351 StandardMacPictureStyleMarker::sUnsupportedFormatPict = (const Led_DIB*)::LoadAppResource (kUnsupportedPICTFormatPictID, RT_BITMAP);
1352
1353#if qStroika_Foundation_Common_Platform_Windows
1354 {
1355 class MyRegistrationHelper : public Win32UIFileAssociationRegistrationHelper {
1356 private:
1357 using inherited = Win32UIFileAssociationRegistrationHelper;
1358
1359 public:
1360 MyRegistrationHelper ()
1361 : inherited (::AfxGetResourceHandle ())
1362 {
1363 }
1364
1365 public:
1366 virtual bool CheckUserSaysOKToUpdate () const override
1367 {
1368 Options o;
1369 if (o.GetCheckFileAssocsAtStartup ()) {
1370 Led_StdDialogHelper_UpdateWin32FileAssocsDialog dlg (::AfxGetResourceHandle (), ::GetActiveWindow ());
1371 dlg.fAppName = Led_SDK_TCHAROF ("LedIt!");
1372 dlg.fTypeList = Led_SDK_TCHAROF (".rtf");
1373 dlg.fKeepChecking = true;
1374 bool result = dlg.DoModal ();
1375 o.SetCheckFileAssocsAtStartup (dlg.fKeepChecking);
1376 return result;
1377 }
1378 else {
1379 return false;
1380 }
1381 }
1382 };
1383 MyRegistrationHelper fileAssocHelper;
1384 SDKString rtfDocIcon = Characters::CString::Format (Led_SDK_TCHAROF ("$EXE$,%d"), -kLedItRTFDocumentIconID);
1385 fileAssocHelper.Add (Win32UIFileAssociationInfo (Led_SDK_TCHAROF (".rtf"), Led_SDK_TCHAROF ("rtffile"),
1386 Led_SDK_TCHAROF ("Rich Text Document"), rtfDocIcon, Led_SDK_TCHAROF ("$EXE$ \"%1\"")));
1387 fileAssocHelper.DoIt ();
1388 }
1389#endif
1390
1391 // Check to see if launched as OLE server
1392 if (cmdInfo.m_bRunEmbedded || cmdInfo.m_bRunAutomated) {
1393 // Register all OLE server (factories) as running. This enables the
1394 // OLE libraries to create objects from other applications.
1395 COleTemplateServer::RegisterAll ();
1396
1397 // Application was run with /Embedding or /Automation. Don't show the
1398 // main window in this case.
1399 return true;
1400 }
1401
1402 // Dispatch commands specified on the command line
1403 if (not ProcessShellCommand (cmdInfo)) {
1404 return false;
1405 }
1406
1407 return true;
1408}
1409
1410#if _MFC_VER >= 0x0700
1411void LedItApplication::WinHelpInternal ([[maybe_unused]] DWORD_PTR dwData, [[maybe_unused]] UINT nCmd)
1412#else
1413void LedItApplication::WinHelp ([[maybe_unused]] DWORD dwData, [[maybe_unused]] UINT nCmd)
1414#endif
1415{
1416 // get path of executable
1417 TCHAR directoryName[_MAX_PATH];
1418 Verify (::GetModuleFileName (m_hInstance, directoryName, _MAX_PATH));
1419
1420 {
1421 LPTSTR lpszExt = _tcsrchr (directoryName, '\\');
1422 ASSERT (lpszExt != NULL);
1423 ASSERT (*lpszExt == '\\');
1424 *(lpszExt + 1) = '\0';
1425 }
1426 Characters::CString::Cat (directoryName, std::size (directoryName), _T ("LedItDocs\\"));
1427
1428 // wrap in try/catch, and display error if no open???
1429 // (NB: we use .htm instead of .html cuz some old systems - I think maybe
1430 // Win95 with only Netscape 2.0 installed - only have .htm registered - not
1431 // .html).
1432 (void)::ShellExecute (NULL, _T ("open"), _T ("index.htm"), NULL, directoryName, SW_SHOWNORMAL);
1433}
1434
1435BOOL LedItApplication::PumpMessage ()
1436{
1437 try {
1438 return inherited::PumpMessage ();
1439 }
1440 STD_EXCEPT_CATCHER (*this);
1441 return true;
1442}
1443
1444void LedItApplication::HandleMFCException ([[maybe_unused]] CException* e) noexcept
1445{
1446 // tmp hack for now...
1447 HandleUnknownException ();
1448}
1449
1450void LedItApplication::HandleHRESULTException ([[maybe_unused]] HRESULT hr) noexcept
1451{
1452 // tmp hack for now...
1453 HandleUnknownException ();
1454}
1455
1456#if 0
1457BOOL LedItApplication::OnIdle (LONG lCount)
1458{
1459 POSITION tp = GetFirstDocTemplatePosition ();
1460 while (tp != NULL) {
1461 CDocTemplate* t = GetNextDocTemplate (tp);
1462 AssertNotNull (t);
1463 POSITION dp = t->GetFirstDocPosition ();
1464 while (dp != NULL) {
1465 CDocument* doc = t->GetNextDoc (dp);
1466 AssertNotNull (doc);
1467 POSITION vp = doc->GetFirstViewPosition ();
1468 while (vp != NULL) {
1469 CView* v = doc->GetNextView (vp);
1470 AssertNotNull (v);
1471 LedItView* lv = dynamic_cast<LedItView*> (v);
1472 if (lv != NULL) {
1473 lv->CallEnterIdleCallback ();
1474 }
1475 }
1476 }
1477 }
1478 return inherited::OnIdle (lCount);
1479}
1480#endif
1481
1482BOOL LedItApplication::ProcessShellCommand (CCommandLineInfo& rCmdInfo)
1483{
1484 try {
1485 switch (rCmdInfo.m_nShellCommand) {
1486 case CCommandLineInfo::FileOpen: {
1487 try {
1488 if (not OpenDocumentFile (rCmdInfo.m_strFileName)) {
1489 throw "";
1490 }
1491 return true;
1492 }
1493 catch (...) {
1494 // see if file just doesn't exist. If so - then create NEW DOC with that file name (preset) - but not saved
1495 HANDLE h = ::CreateFile (rCmdInfo.m_strFileName, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1496 if (h == INVALID_HANDLE_VALUE) {
1497 OnFileNew ();
1498
1499 CDocument* newDoc = NULL;
1500 {
1501 POSITION tp = GetFirstDocTemplatePosition ();
1502 if (tp != NULL) {
1503 CDocTemplate* t = GetNextDocTemplate (tp);
1504 AssertNotNull (t);
1505 POSITION dp = t->GetFirstDocPosition ();
1506 if (dp != NULL) {
1507 newDoc = t->GetNextDoc (dp);
1508 }
1509 }
1510 }
1511
1512 if (newDoc != NULL) {
1513 // Set path and title so if you just hit save - you are promted to save in the name you specified, but
1514 // there are visual clues that this isn't the orig file
1515 newDoc->SetPathName (rCmdInfo.m_strFileName, false);
1516 newDoc->SetTitle (newDoc->GetTitle () + Led_SDK_TCHAROF (" {new}"));
1517 return true;
1518 }
1519 }
1520 else {
1521 ::CloseHandle (h);
1522 }
1523 throw;
1524 }
1525 } break;
1526 default: {
1527 return inherited::ProcessShellCommand (rCmdInfo);
1528 }
1529 }
1530 }
1531 STD_EXCEPT_CATCHER (*this);
1532 return false;
1533}
1534
1535void LedItApplication::AddDocTemplateForString (const char* tmplStr, bool connectToServer)
1536{
1537 CSingleDocTemplate* pDocTemplate = new SimpleLedTemplate (tmplStr);
1538 pDocTemplate->SetContainerInfo (IDR_CNTR_INPLACE);
1539 pDocTemplate->SetServerInfo (IDR_SRVR_EMBEDDED, IDR_SRVR_INPLACE, RUNTIME_CLASS (LedItInPlaceFrame));
1540 AddDocTemplate (pDocTemplate);
1541 if (connectToServer) {
1542 // Connect the COleTemplateServer to the document template.
1543 // The COleTemplateServer creates new documents on behalf
1544 // of requesting OLE containers by using information
1545 // specified in the document template.
1546 fOleTemplateServer.ConnectTemplate (clsid, pDocTemplate, true);
1547 // Note: SDI applications register server objects only if /Embedding
1548 // or /Automation is present on the command line.
1549 }
1550}
1551
1552void LedItApplication::OnAppAbout ()
1553{
1554 DoAboutBox ();
1555}
1556
1557void LedItApplication::OnToggleSmartCutNPasteOptionUpdateCommandUI (CCmdUI* pCmdUI)
1558{
1559 OnToggleSmartCutNPasteOption_UpdateCommandUI (CMD_ENABLER (pCmdUI));
1560}
1561
1562void LedItApplication::OnToggleWrapToWindowOptionUpdateCommandUI (CCmdUI* pCmdUI)
1563{
1564 OnToggleWrapToWindowOption_UpdateCommandUI (CMD_ENABLER (pCmdUI));
1565}
1566
1567void LedItApplication::OnToggleShowHiddenTextOptionUpdateCommandUI (CCmdUI* pCmdUI)
1568{
1569 OnToggleShowHiddenTextOption_UpdateCommandUI (CMD_ENABLER (pCmdUI));
1570}
1571#endif
1572
1573void LedItApplication::OnChooseDefaultFontCommand ()
1574{
1575#if qStroika_Foundation_Common_Platform_Windows
1576 FontSpecification fsp = Options{}.GetDefaultNewDocFont ();
1577
1578 LOGFONT lf;
1579 (void)::memset (&lf, 0, sizeof (lf));
1580 {
1581 Characters::CString::Copy (lf.lfFaceName, std::size (lf.lfFaceName), fsp.GetFontNameSpecifier ().fName);
1582 Assert (::_tcslen (lf.lfFaceName) < sizeof (lf.lfFaceName)); // cuz our cached entry - if valid - always short enuf...
1583 }
1584 lf.lfWeight = (fsp.GetStyle_Bold ()) ? FW_BOLD : FW_NORMAL;
1585 lf.lfItalic = (fsp.GetStyle_Italic ());
1586 lf.lfUnderline = (fsp.GetStyle_Underline ());
1587 lf.lfStrikeOut = (fsp.GetStyle_Strikeout ());
1588
1589 lf.lfHeight = fsp.PeekAtTMHeight ();
1590
1591 CFontDialog dlog (&lf);
1592 if (dlog.DoModal () == IDOK) {
1593 Options{}.SetDefaultNewDocFont (FontSpecification (*dlog.m_cf.lpLogFont));
1594 }
1595#else
1596 Led_Assert (false); // NYI
1597#endif
1598}
1599
1600void LedItApplication::HandleBadAllocException () noexcept
1601{
1602 try {
1603#if qStroika_Foundation_Common_Platform_Windows
1604 CDialog errorDialog (kBadAllocExceptionOnCmdDialogID);
1605 errorDialog.DoModal ();
1606#elif qStroika_Foundation_Common_Platform_MacOS
1607 // ALSO, FREE ANY MEMORY WE CAN...
1608 TArray<LDocument*>& docList = LDocument::GetDocumentList ();
1609 TArrayIterator<LDocument*> iterator (docList);
1610 LDocument* theDoc = NULL;
1611 while (iterator.Next (theDoc)) {
1612 AssertMember (theDoc, LedItDocument);
1613 LedItDocument* d = dynamic_cast<LedItDocument*> (theDoc);
1614 d->PurgeUnneededMemory ();
1615 }
1616
1617 DoStringyAlert (kMemoryExceptionAlertID);
1618#else
1619 HandleUnknownException ();
1620#endif
1621 }
1622 catch (...) {
1623 Led_BeepNotify ();
1624 }
1625}
1626
1627void LedItApplication::HandleBadUserInputException () noexcept
1628{
1629 try {
1630#if qStroika_Foundation_Common_Platform_MacOS
1631 DoStringyAlert (kBadUserInputExceptionAlertID);
1632#elif qStroika_Foundation_Common_Platform_Windows
1633 CDialog errorDialog (kBadUserInputExceptionOnCmdDialogID);
1634 errorDialog.DoModal ();
1635#else
1636 HandleUnknownException ();
1637#endif
1638 }
1639 catch (...) {
1640 Led_BeepNotify ();
1641 }
1642}
1643
1644void LedItApplication::HandleUnknownException () noexcept
1645{
1646 try {
1647#if qStroika_Foundation_Common_Platform_MacOS
1648 DoStringyAlert (kUnknownExceptionAlertID);
1649#elif qStroika_Foundation_Common_Platform_Windows
1650 CDialog errorDialog (kUnknownExceptionOnCmdDialogID);
1651 errorDialog.DoModal ();
1652#endif
1653 }
1654 catch (...) {
1655 Led_BeepNotify ();
1656 }
1657}
1658
1659#if qStroika_FeatureSupported_XWindows
1660gint LedItApplication::delete_event (GtkWidget* widget, gpointer data)
1661{
1662 // FIND ORIG GTK SAMPLE CODE AND SEE WHAT THIS USED TO GET HOOKED TO!!!!!!
1663
1664 /* If you return FALSE in the "delete_event" signal handler,
1665 * GTK will emit the "destroy" signal. Returning TRUE means
1666 * you don't want the window to be destroyed.
1667 * This is useful for popping up 'are you sure you want to quit?'
1668 * type dialogs. */
1669
1670 g_print ("delete event occurred\n");
1671
1672 /* Change TRUE to FALSE and the main window will be destroyed with
1673 * a "delete_event". */
1674
1675 return (TRUE);
1676}
1677
1678void LedItApplication::xdestroy (GtkWidget* widget, gpointer data)
1679{
1680 LedItApplication* THIS = reinterpret_cast<LedItApplication*> (data);
1681 THIS->OnQuitCommand ();
1682}
1683
1684void LedItApplication::OnNewDocumentCommand ()
1685{
1686 WordProcessor* wp = fTextEditor;
1687 TextStore& ts = wp->GetTextStore ();
1688 ts.Replace (ts.GetStart (), ts.GetEnd (), LED_TCHAR_OF (""), 0);
1689 wp->SetDefaultFont (wp->GetStaticDefaultFont ());
1690 fDocument->fPathName = string{};
1691 UpdateFrameWindowTitle ();
1692}
1693
1694void LedItApplication::OnOpenDocumentCommand ()
1695{
1696 LedItFilePickBox filePickerDlg (GTK_WINDOW (fAppWindow), Led_SDK_TCHAROF ("Open new document"), false, SDKString{}, eUnknownFormat);
1697 if (filePickerDlg.DoModal ()) {
1698 try {
1699 LoadFromFile (filePickerDlg.GetFileName (), filePickerDlg.GetFileFormat ());
1700 }
1701 catch (...) {
1702 // should print error dialog on errors...
1703 }
1704 }
1705}
1706
1707void LedItApplication::OnSaveDocumentCommand ()
1708{
1709#if qPrintGLIBTradeMessages
1710 g_message ("Entering OnSaveDocumentCommand\n");
1711#endif
1712 if (fDocument->fPathName.empty ()) {
1713 OnSaveAsDocumentCommand ();
1714 }
1715 else {
1716 Save ();
1717 }
1718}
1719
1720void LedItApplication::OnSaveAsDocumentCommand ()
1721{
1722 LedItFilePickBox filePickerDlg (GTK_WINDOW (fAppWindow), Led_SDK_TCHAROF ("Save document as:"), true, fDocument->fPathName, fDocument->fFileFormat);
1723 if (filePickerDlg.DoModal ()) {
1724 try {
1725 SaveAs (filePickerDlg.GetFileName (), filePickerDlg.GetFileFormat ());
1726 }
1727 catch (...) {
1728 // should print error dialog on errors...
1729 }
1730 }
1731}
1732
1733void LedItApplication::OnQuitCommand ()
1734{
1735#if qPrintGLIBTradeMessages
1736 g_message ("Entering OnQuitCommand\n");
1737#endif
1738 gtk_widget_destroy (fTextEditor->Get_GtkWidget ());
1739 fTextEditor = NULL;
1740 gtk_main_quit ();
1741}
1742
1743void LedItApplication::LoadFromFile (const string& fileName, FileFormat fileFormat)
1744{
1745 WordProcessor* wp = fTextEditor;
1746 TextStore& ts = wp->GetTextStore ();
1747 ts.Replace (ts.GetStart (), ts.GetEnd (), LED_TCHAR_OF (""), 0);
1748 wp->SetDefaultFont (wp->GetStaticDefaultFont ());
1749 fDocument->LoadFromFile (fileName, fileFormat);
1750 UpdateFrameWindowTitle ();
1751}
1752
1753inline SDKString StripKnownSuffix (const SDKString& from)
1754{
1755 SDKString result = from;
1756 SDKString suffix = ExtractFileSuffix (from);
1757 if (suffix == ".rtf" or suffix == ".txt" or suffix == ".led" or suffix == ".htm" or suffix == ".html") {
1758 result.erase (result.length () - suffix.length ());
1759 }
1760 return result;
1761}
1762void LedItApplication::SaveAs (const string& fileName, FileFormat fileFormat)
1763{
1764 Require (not fileName.empty ());
1765 AssertNotNull (fDocument);
1766
1767 fDocument->fPathName = fileName;
1768
1769 /*
1770 * Adjust file suffix - if needed.
1771 */
1772 {
1773 SDKString suffix = ExtractFileSuffix (fileName);
1774 switch (fileFormat) {
1775 case eHTMLFormat: {
1776 if (suffix != ".htm" and suffix != ".html") {
1777 fDocument->fPathName = StripKnownSuffix (fDocument->fPathName);
1778 fDocument->fPathName += ".htm";
1779 }
1780 } break;
1781 case eRTFFormat: {
1782 if (suffix != ".rtf") {
1783 fDocument->fPathName = StripKnownSuffix (fDocument->fPathName);
1784 fDocument->fPathName += ".rtf";
1785 }
1786 } break;
1787 case eLedPrivateFormat: {
1788 if (suffix != ".led") {
1789 fDocument->fPathName = StripKnownSuffix (fDocument->fPathName);
1790 fDocument->fPathName += ".led";
1791 }
1792 } break;
1793 }
1794 }
1795 fDocument->fFileFormat = fileFormat;
1796 Save ();
1797 UpdateFrameWindowTitle ();
1798}
1799
1800void LedItApplication::Save ()
1801{
1802 AssertNotNull (fDocument);
1803 fDocument->Save ();
1804}
1805
1806void LedItApplication::UpdateFrameWindowTitle ()
1807{
1808 AssertNotNull (fAppWindow);
1809 SDKString docName = Led_SDK_TCHAROF ("untitled");
1810 if (fDocument != NULL and not fDocument->fPathName.empty ()) {
1811 docName = fDocument->fPathName;
1812 }
1813 SDKString appTitle = Led_SDK_TCHAROF ("LedIt! [") + docName + Led_SDK_TCHAROF ("]");
1814 gtk_window_set_title (GTK_WINDOW (fAppWindow), appTitle.c_str ());
1815}
1816
1817void LedItApplication::AppCmdDispatcher (gpointer callback_data, guint callback_action, GtkWidget* widget)
1818{
1819 LedItApplication* THIS = reinterpret_cast<LedItApplication*> (callback_data);
1820 GtkWidget* w = THIS->fTextEditor->Get_GtkWidget ();
1821 switch (callback_action) {
1822 case kGotoLedItWebPageCmd:
1823 THIS->OnGotoLedItWebPageCommand ();
1824 break;
1825 case kGotoSophistsWebPageCmd:
1826 THIS->OnGotoSophistsWebPageCommand ();
1827 break;
1828 case kCheckForUpdatesWebPageCmdID:
1829 THIS->OnCheckForUpdatesWebPageCommand ();
1830 break;
1831 case kAboutBoxCmd:
1832 THIS->DoAboutBox ();
1833 break;
1834 case kNewDocumentCmd:
1835 THIS->OnNewDocumentCommand ();
1836 break;
1837 case kOpenDocumentCmd:
1838 THIS->OnOpenDocumentCommand ();
1839 break;
1840 case kSaveDocumentCmd:
1841 THIS->OnSaveDocumentCommand ();
1842 break;
1843 case kSaveAsDocumentCmd:
1844 THIS->OnSaveAsDocumentCommand ();
1845 break;
1846 case kToggleUseSmartCutNPasteCmd:
1847 THIS->OnToggleSmartCutNPasteOptionCommand ();
1848 break;
1849 case kToggleWrapToWindowCmd:
1850 THIS->OnToggleWrapToWindowOptionCommand ();
1851 break;
1852 case kToggleShowHiddenTextCmd:
1853 THIS->OnToggleShowHiddenTextOptionCommand ();
1854 break;
1855 case kQuitCmd:
1856 THIS->OnQuitCommand ();
1857 break;
1858 default:
1859 LedItView::DispatchCommandCallback (LedItView::WidgetToTHIS (w), callback_action, widget);
1860 }
1861}
1862
1863void LedItApplication::AppCmdOnInitMenu (GtkMenuItem* menuItem, gpointer callback_data)
1864{
1865 LedItApplication* THIS = reinterpret_cast<LedItApplication*> (callback_data);
1866 GtkWidget* w = THIS->fTextEditor->Get_GtkWidget ();
1867 {
1868 GtkWidget* subMenu = menuItem->submenu;
1869 // Iterate over each child...
1870 Led_Assert (GTK_IS_MENU_SHELL (subMenu));
1871 for (GList* i = GTK_MENU_SHELL (subMenu)->children; i != NULL; i = i->next) {
1872 GtkMenuItem* m = reinterpret_cast<GtkMenuItem*> (i->data);
1873 Led_Assert (GTK_IS_MENU_ITEM (m));
1874 bool bEnable = (GTK_MENU_ITEM (m)->submenu != NULL); //tmphack to test...
1875 gtk_widget_set_sensitive (GTK_WIDGET (m), bEnable);
1876 if (GTK_IS_CHECK_MENU_ITEM (m)) {
1877 GtkCheckMenuItem* cm = GTK_CHECK_MENU_ITEM (m);
1878 /*
1879 * NB: we just set the active field instead of calling gtk_check_menu_item_set_active ()
1880 * cuz for some weird reason - thats all that seems to work. I'm guessing its cuz calling the
1881 * method has other nasty side effects?? This applies to Gtk-1.2 - LGP 2001-05-22
1882 */
1883 cm->active = false;
1884 }
1885 Led_Gtk_TmpCmdUpdater::CommandNumber commandNum = reinterpret_cast<guint> (gtk_object_get_user_data (GTK_OBJECT (m)));
1886
1887 switch (commandNum) {
1888 case kGotoLedItWebPageCmd:
1889 gtk_widget_set_sensitive (GTK_WIDGET (m), true);
1890 break;
1891 case kGotoSophistsWebPageCmd:
1892 gtk_widget_set_sensitive (GTK_WIDGET (m), true);
1893 break;
1894 case kCheckForUpdatesWebPageCmdID:
1895 gtk_widget_set_sensitive (GTK_WIDGET (m), true);
1896 break;
1897 case kAboutBoxCmd:
1898 gtk_widget_set_sensitive (GTK_WIDGET (m), true);
1899 break;
1900 case kNewDocumentCmd:
1901 gtk_widget_set_sensitive (GTK_WIDGET (m), true);
1902 break;
1903 case kOpenDocumentCmd:
1904 gtk_widget_set_sensitive (GTK_WIDGET (m), true);
1905 break;
1906 //NO - MUST FIX!!! case kSaveDocumentCmd: THIS->OnSaveDocumentCommand (); break;
1907 case kSaveAsDocumentCmd:
1908 gtk_widget_set_sensitive (GTK_WIDGET (m), true);
1909 break;
1910 case kToggleUseSmartCutNPasteCmd:
1911 THIS->OnToggleSmartCutNPasteOption_UpdateCommandUI (CMD_ENABLER (m, commandNum));
1912 break;
1913 case kToggleWrapToWindowCmd:
1914 THIS->OnToggleWrapToWindowOption_UpdateCommandUI (CMD_ENABLER (m, commandNum));
1915 break;
1916 case kToggleShowHiddenTextCmd:
1917 THIS->OnToggleShowHiddenTextOption_UpdateCommandUI (CMD_ENABLER (m, commandNum));
1918 break;
1919 case kQuitCmd:
1920 gtk_widget_set_sensitive (GTK_WIDGET (m), true);
1921 break;
1922 default:
1923 THIS->fTextEditor->DispatchCommandUpdateCallback (m, commandNum);
1924 }
1925 }
1926 }
1927}
1928
1929GtkWidget* LedItApplication::GetAppWindow () const
1930{
1931 return fAppWindow;
1932}
1933
1934/* This is the GtkItemFactoryEntry structure used to generate new menus.
1935 Item 1: The menu path. The letter after the underscore indicates an
1936 accelerator key once the menu is open.
1937 Item 2: The accelerator key for the entry
1938 Item 3: The callback function.
1939 Item 4: The callback action. This changes the parameters with
1940 which the function is called. The default is 0.
1941 Item 5: The item type, used to define what kind of an item it is.
1942 Here are the possible values:
1943
1944 NULL -> "<Item>"
1945 "" -> "<Item>"
1946 "<Title>" -> create a title item
1947 "<Item>" -> create a simple item
1948 "<CheckItem>" -> create a check item
1949 "<ToggleItem>" -> create a toggle item
1950 "<RadioItem>" -> create a radio item
1951 <path> -> path of a radio item to link against
1952 "<Separator>" -> create a separator
1953 "<Branch>" -> create an item to hold sub items (optional)
1954 "<LastBranch>" -> create a right justified branch
1955*/
1956GtkItemFactoryEntry LedItApplication::kMenuItemResources[] = {
1957 {"/_File", NULL, NULL, 0, "<Branch>"},
1958 {"/File/_New", "<control>N", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kNewDocumentCmd, NULL},
1959 {"/File/_Open...", "<control>O", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kOpenDocumentCmd, NULL},
1960 {"/File/_Save", "<control>S", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSaveDocumentCmd, NULL},
1961 {"/File/Sa_ve As...", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSaveAsDocumentCmd, NULL},
1962 {"/File/sep1", NULL, NULL, 0, "<Separator>"},
1963 {"/File/_Quit", "<control>Q", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kQuitCmd, NULL},
1964
1965 {"/_Edit", NULL, NULL, 0, "<Branch>"},
1966 {"/Edit/_Undo", "<control>Z", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kCmdUndo, NULL},
1967 {"/Edit/_Redo", "<control>Y", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kCmdRedo, NULL},
1968 {"/Edit/", NULL, NULL, 0, "<Separator>"},
1969 {"/Edit/_Cut", "<control>X", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kCmdCut, NULL},
1970 {"/Edit/C_opy", "<control>C", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kCmdCopy, NULL},
1971 {"/Edit/_Paste", "<control>V", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kCmdPaste, NULL},
1972 {"/Edit/C_lear", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kCmdClear, NULL},
1973
1974 {"/_Select", NULL, NULL, 0, "<Branch>"},
1975 {"/Select/Select _Word(s)", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSelectWordCmd, NULL},
1976 {"/Select/Select Te_xt Row(s)", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSelectTextRowCmd, NULL},
1977 {"/Select/Select _Paragraph(s)", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSelectParagraphCmd, NULL},
1978 {"/Select/", NULL, NULL, 0, "<Separator>"},
1979 {"/Select/Select A_ll in Cell", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSelectTableIntraCellAllCmd, NULL},
1980 {"/Select/Select Table _Cell", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSelectTableCellCmd, NULL},
1981 {"/Select/Select Table Ro_w(s)", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSelectTableRowCmd, NULL},
1982 {"/Select/Select Table C_olumn(s)", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSelectTableColumnCmd, NULL},
1983 {"/Select/Select _Table", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSelectTableCmd, NULL},
1984 {"/Select/", NULL, NULL, 0, "<Separator>"},
1985 {"/Select/Select _All", "<control>A", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kCmdSelectAll, NULL},
1986 {"/Select/", NULL, NULL, 0, "<Separator>"},
1987 {"/Select/_Find...", "<control>F", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFindCmd, NULL},
1988 {"/Select/Find Aga_in", "<control>G", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFindAgainCmd, NULL},
1989 {"/Select/_Enter 'Find' String", "<control>E", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kEnterFindStringCmd, NULL},
1990 {"/Select/_Replace...", "<control>H", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kReplaceCmd, NULL},
1991 {"/Select/Replace Agai_n", "<control>R", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kReplaceAgainCmd, NULL},
1992 {"/Select/", NULL, NULL, 0, "<Separator>"},
1993 {"/Select/_Check Spelling...", "<control>L", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSpellCheckCmd, NULL},
1994
1995 {"/_Insert", NULL, NULL, 0, "<Branch>"},
1996 {"/Insert/Insert _Table", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kInsertTableCmd, NULL},
1997 {"/Insert/Insert Table _Row Above", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kInsertTableRowAboveCmd, NULL},
1998 {"/Insert/Insert Table R_ow Below", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kInsertTableRowBelowCmd, NULL},
1999 {"/Insert/Insert Table _Column Before", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kInsertTableColBeforeCmd, NULL},
2000 {"/Insert/Insert Table Co_lumn After", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kInsertTableColAfterCmd, NULL},
2001 {"/Insert/", NULL, NULL, 0, "<Separator>"},
2002 {"/Insert/Insert _URL", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kInsertURLCmd, NULL},
2003
2004 {"/_Format", NULL, NULL, 0, "<Branch>"},
2005 {"/_Format/Font _Name", NULL, NULL, 0, "<Branch>"},
2006 {"/_Format/Font _Style", NULL, NULL, 0, "<Branch>"},
2007 {"/_Format/Font _Style/_Plain", "<control>T", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontStylePlainCmd, "<CheckItem>"},
2008 {"/_Format/Font _Style/sep1", NULL, NULL, 0, "<Separator>"},
2009 {"/_Format/Font _Style/_Bold", "<control>B", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontStyleBoldCmd, "<CheckItem>"},
2010 {"/_Format/Font _Style/_Italic", "<control>I", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontStyleItalicCmd, "<CheckItem>"},
2011 {"/_Format/Font _Style/_Underline", "<control>U", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontStyleUnderlineCmd, "<CheckItem>"},
2012 {"/_Format/Font _Style/_Subscript", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSubScriptCmd, "<CheckItem>"},
2013 {"/_Format/Font _Style/Supe_rscript", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSuperScriptCmd, "<CheckItem>"},
2014 {"/_Format/Font Si_ze", NULL, NULL, 0, "<Branch>"},
2015 {"/_Format/Font Si_ze/9", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSize9Cmd, "<CheckItem>"},
2016 {"/_Format/Font Si_ze/10", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSize10Cmd, "<CheckItem>"},
2017 {"/_Format/Font Si_ze/12", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSize12Cmd, "<CheckItem>"},
2018 {"/_Format/Font Si_ze/14", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSize14Cmd, "<CheckItem>"},
2019 {"/_Format/Font Si_ze/18", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSize18Cmd, "<CheckItem>"},
2020 {"/_Format/Font Si_ze/24", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSize24Cmd, "<CheckItem>"},
2021 {"/_Format/Font Si_ze/36", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSize36Cmd, "<CheckItem>"},
2022 {"/_Format/Font Si_ze/48", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSize48Cmd, "<CheckItem>"},
2023 {"/_Format/Font Si_ze/72", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSize72Cmd, "<CheckItem>"},
2024 {"/_Format/Font Si_ze/sep1", NULL, NULL, 0, "<Separator>"},
2025 {"/_Format/Font Si_ze/_Smaller", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSizeSmallerCmd, NULL},
2026 {"/_Format/Font Si_ze/_Larger", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSizeLargerCmd, NULL},
2027 {"/_Format/Font Si_ze/sep2", NULL, NULL, 0, "<Separator>"},
2028 {"/_Format/Font Si_ze/_Other...", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontSizeOtherCmd, "<CheckItem>"},
2029 {"/_Format/Font _Color", NULL, NULL, 0, "<Branch>"},
2030 {"/_Format/Font _Color/_Black", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kBlackColorCmd, "<CheckItem>"},
2031 {"/_Format/Font _Color/_Maroon", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kMaroonColorCmd, "<CheckItem>"},
2032 {"/_Format/Font _Color/_Green", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kGreenColorCmd, "<CheckItem>"},
2033 {"/_Format/Font _Color/_Olive", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kOliveColorCmd, "<CheckItem>"},
2034 {"/_Format/Font _Color/_Navy", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kNavyColorCmd, "<CheckItem>"},
2035 {"/_Format/Font _Color/_Purple", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kPurpleColorCmd, "<CheckItem>"},
2036 {"/_Format/Font _Color/_Teal", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kTealColorCmd, "<CheckItem>"},
2037 {"/_Format/Font _Color/_Gray", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kGrayColorCmd, "<CheckItem>"},
2038 {"/_Format/Font _Color/_Silver", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kSilverColorCmd, "<CheckItem>"},
2039 {"/_Format/Font _Color/_Red", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kRedColorCmd, "<CheckItem>"},
2040 {"/_Format/Font _Color/_Lime", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kLimeColorCmd, "<CheckItem>"},
2041 {"/_Format/Font _Color/_Yellow", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kYellowColorCmd, "<CheckItem>"},
2042 {"/_Format/Font _Color/Bl_ue", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kBlueColorCmd, "<CheckItem>"},
2043 {"/_Format/Font _Color/_Fuchsia", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFuchsiaColorCmd, "<CheckItem>"},
2044 {"/_Format/Font _Color/_Aqua", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kAquaColorCmd, "<CheckItem>"},
2045 {"/_Format/Font _Color/_White", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kWhiteColorCmd, "<CheckItem>"},
2046 {"/_Format/Font _Color/sep", NULL, NULL, 0, "<Separator>"},
2047 {"/_Format/Font _Color/O_ther...", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kFontColorOtherCmd, "<CheckItem>"},
2048 {"/_Format/_Choose Font Dialog...", "<control>D", GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kChooseFontDialogCmd, NULL},
2049 {"/_Format/sep", NULL, NULL, 0, "<Separator>"},
2050 {"/_Format/_Justification", NULL, NULL, 0, "<Branch>"},
2051 {"/_Format/_Justification/_Left", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kJustifyLeftCmd, "<CheckItem>"},
2052 {"/_Format/_Justification/_Center", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kJustifyCenterCmd, "<CheckItem>"},
2053 {"/_Format/_Justification/_Right", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kJustifyRightCmd, "<CheckItem>"},
2054 {"/_Format/_Justification/_Full", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kJustifyFullCmd, "<CheckItem>"},
2055
2056 {"/_Remove/", NULL, NULL, 0, "<Separator>"},
2057 {"/_Remove/Remove _Rows", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kRemoveTableRowsCmd, NULL},
2058 {"/_Remove/Remove _Columns", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kRemoveTableColumnsCmd, NULL},
2059 {"/_Remove/sep", NULL, NULL, 0, "<Separator>"},
2060 {"/_Remove/_Hide Selection", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kHideSelectionCmd, NULL},
2061 {"/_Remove/_Unhide Selection", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kUnHideSelectionCmd, NULL},
2062
2063 {"/_Options", NULL, NULL, 0, "<Branch>"},
2064 {"/Options/_Smart Cut and Paste", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kToggleUseSmartCutNPasteCmd, "<CheckItem>"},
2065 {"/Options/_Wrap to Window", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kToggleWrapToWindowCmd, "<CheckItem>"},
2066 {"/Options/Show _Hidden Text", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kToggleShowHiddenTextCmd, "<CheckItem>"},
2067 {"/Options/_Paragraph Markers Shown", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kShowHideParagraphGlyphsCmd, "<CheckItem>"},
2068 {"/Options/_Tab Markers Shown", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kShowHideTabGlyphsCmd, "<CheckItem>"},
2069 {"/Options/Spa_ce characters Shown", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kShowHideSpaceGlyphsCmd, "<CheckItem>"},
2070
2071 {"/_Help", NULL, NULL, 0, "<LastBranch>"},
2072 {"/_Help/Goto _LedIt! Web Page", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kGotoLedItWebPageCmd, NULL},
2073 {"/_Help/Goto _Sophist Solutions Web Page", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kGotoSophistsWebPageCmd, NULL},
2074 {"/_Help/_Check for LedIt! Web Updates", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kCheckForUpdatesWebPageCmdID, NULL},
2075 {"/_Help/sep", NULL, NULL, 0, "<Separator>"},
2076 {"/_Help/_About", NULL, GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher), kAboutBoxCmd, NULL},
2077};
2078
2079static void RecursivelySetCallback (GtkWidget* menu, gpointer data)
2080{
2081 if (GTK_IS_MENU_ITEM (menu)) {
2082 GtkMenuItem* m = GTK_MENU_ITEM (menu);
2083 if (m->submenu != NULL) {
2084 gtk_signal_connect (GTK_OBJECT (menu), "activate", GTK_SIGNAL_FUNC (LedItApplication::AppCmdOnInitMenu), data);
2085 RecursivelySetCallback (m->submenu, data);
2086 }
2087 }
2088 if (GTK_IS_CONTAINER (menu)) {
2089 GtkContainer* c = GTK_CONTAINER (menu);
2090 gtk_container_foreach (c, RecursivelySetCallback, data);
2091 }
2092}
2093
2094GtkWidget* LedItApplication::get_main_menu (GtkWidget* window)
2095{
2096 GtkAccelGroup* accel_group = gtk_accel_group_new ();
2097
2098 /* This function initializes the item factory.
2099 Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
2100 or GTK_TYPE_OPTION_MENU.
2101 Param 2: The path of the menu.
2102 Param 3: A pointer to a gtk_accel_group. The item factory sets up
2103 the accelerator table while generating menus.
2104 */
2105
2106 GtkItemFactory* item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", accel_group);
2107
2108 /* This function generates the menu items. Pass the item factory,
2109 the number of items in the array, the array itself, and any
2110 callback data for the the menu items. */
2111 gtk_item_factory_create_items (item_factory, Led_NEltsOf (kMenuItemResources), kMenuItemResources, this);
2112
2113 /* Attach the new accelerator group to the window. */
2114 gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
2115
2116 {
2117 const string kFontMenuPath = "/Format/Font Name";
2118 GtkWidget* fontNameMenu = gtk_item_factory_get_widget (item_factory, kFontMenuPath.c_str ());
2119 vector<SDKString> fontNames = LedItApplication::Get ().fInstalledFonts.GetUsableFontNames ();
2120 for (vector<SDKString>::const_iterator i = fontNames.begin (); i != fontNames.end (); ++i) {
2121 GtkItemFactoryEntry entry;
2122 memset (&entry, 0, sizeof (entry));
2123 string fontName = *i; // really should munge it so its assured not to have any bad chars in it!!!
2124 string tmpPath = kFontMenuPath + "/" + fontName;
2125 entry.path = const_cast<char*> (tmpPath.c_str ());
2126 entry.callback = GTK_SIGNAL_FUNC (LedItApplication::AppCmdDispatcher);
2127 entry.callback_action = (i - fontNames.begin ()) + kBaseFontNameCmd;
2128 entry.item_type = "<CheckItem>";
2129 gtk_item_factory_create_items (item_factory, 1, &entry, this);
2130 {
2131 // Mark the newly created item with a CMDNUM so it will work with the CMD_UPDATE code...
2132 GtkWidget* justCreatedItem = gtk_item_factory_get_widget (item_factory, entry.path);
2133 AssertNotNull (justCreatedItem);
2134 gtk_object_set_user_data (GTK_OBJECT (justCreatedItem), reinterpret_cast<void*> (entry.callback_action));
2135 }
2136 }
2137 }
2138
2139 // Walk through the list of GtkMenuItem* widgets created by the last gtk_item_factory, and set the widgets USERDATA field
2140 // to be the command# - for use later on in the UPDATE_COMMAND processing
2141 {
2142 for (size_t i = 0; i < Led_NEltsOf (kMenuItemResources); ++i) {
2143 string path = kMenuItemResources[i].path;
2144 {
2145 // strip out _'s
2146 for (size_t idx; (idx = path.find ('_')) != string::npos;) {
2147 path.erase (idx, 1);
2148 }
2149 }
2150
2151 GtkWidget* aMenu = gtk_item_factory_get_widget (item_factory, path.c_str ());
2152 AssertNotNull (aMenu);
2153 gtk_object_set_user_data (GTK_OBJECT (aMenu), reinterpret_cast<void*> (kMenuItemResources[i].callback_action));
2154 }
2155 }
2156
2157 /* Finally, return the actual menu bar created by the item factory. */
2158 GtkWidget* menuBar = gtk_item_factory_get_widget (item_factory, "<main>");
2159 RecursivelySetCallback (menuBar, this);
2160 return menuBar;
2161}
2162#endif
2163
2164#if qStroika_Foundation_Common_Platform_Windows
2165const vector<SDKString>& LedItApplication::GetUsableFontNames ()
2166{
2167 return fInstalledFonts.GetUsableFontNames ();
2168}
2169
2170void LedItApplication::FixupFontMenu (CMenu* fontMenu)
2171{
2172 AssertMember (fontMenu, CMenu);
2173 const vector<SDKString>& fontNames = GetUsableFontNames ();
2174
2175 // delete all menu items
2176 while (fontMenu->DeleteMenu (0, MF_BYPOSITION) != 0) {
2177 ;
2178 }
2179
2180 for (UINT i = 0; i < fontNames.size (); ++i) {
2181 UINT cmdNum = kBaseFontNameCmd + i;
2182 fontMenu->AppendMenu (MF_STRING, cmdNum, fontNames[i].c_str ());
2183 }
2184}
2185
2186SDKString LedItApplication::CmdNumToFontName (UINT cmdNum)
2187{
2188 const vector<SDKString>& fontNames = GetUsableFontNames ();
2189 return (fontNames[cmdNum - kBaseFontNameCmd]);
2190}
2191#endif
2192
2193#if qStroika_Foundation_Common_Platform_Windows
2194/*
2195 ********************************************************************************
2196 ******************************** LedItDocManager *******************************
2197 ********************************************************************************
2198 */
2199SimpleLedTemplate::SimpleLedTemplate (const char* daStr)
2200 : CSingleDocTemplate (IDR_MAINFRAME, RUNTIME_CLASS (LedItDocument), RUNTIME_CLASS (LedItMainFrame), RUNTIME_CLASS (LedItView))
2201{
2202 m_strDocStrings = daStr;
2203}
2204
2205void SimpleLedTemplate::LoadTemplate ()
2206{
2207 bool doMenuEmbedding = (m_hMenuEmbedding == NULL);
2208 bool doMenuInPlaceServer = (m_hMenuInPlaceServer == NULL);
2209 bool doMenuInPlace = (m_hMenuInPlace == NULL);
2210 CSingleDocTemplate::LoadTemplate ();
2211
2212 // Now go and fixup the font menu...
2213 if (doMenuEmbedding and m_hMenuEmbedding != NULL) {
2214 // Not understood well just what each of these are, but I think this
2215 // contains a format menu.
2216 // LGP 960101
2217 CMenu tmp;
2218 tmp.Attach (m_hMenuEmbedding);
2219 LedItApplication::Get ().FixupFontMenu (tmp.GetSubMenu (4)->GetSubMenu (0));
2220 tmp.Detach ();
2221 }
2222 if (doMenuInPlaceServer and m_hMenuInPlaceServer != NULL) {
2223 // Not understood well just what each of these are, but I think this
2224 // contains a format menu.
2225 // LGP 960101
2226 CMenu tmp;
2227 tmp.Attach (m_hMenuInPlaceServer);
2228 LedItApplication::Get ().FixupFontMenu (tmp.GetSubMenu (3)->GetSubMenu (0));
2229 tmp.Detach ();
2230 }
2231 if (doMenuInPlace and m_hMenuInPlace != NULL) {
2232 // Not understood well just what each of these are, but I don't think this
2233 // contains a format menu
2234 }
2235}
2236#endif
2237
2238#if qStroika_Foundation_Common_Platform_Windows
2239/*
2240 ********************************************************************************
2241 ******************************** LedItDocManager *******************************
2242 ********************************************************************************
2243 */
2244// Some private, but externed, MFC 4.0 routines needed to subclass CDocManager... See below...
2245// LGP 960222
2246extern BOOL AFXAPI AfxFullPath (LPTSTR lpszPathOut, LPCTSTR lpszFileIn);
2247extern BOOL AFXAPI AfxResolveShortcut (CWnd* pWnd, LPCTSTR pszShortcutFile, LPTSTR pszPath, int cchPath);
2248extern void AFXAPI AfxGetModuleShortFileName (HINSTANCE hInst, CString& strShortName);
2249
2250LedItDocManager::LedItDocManager ()
2251 : CDocManager ()
2252{
2253}
2254
2255void LedItDocManager::OnFileNew ()
2256{
2257 // tmp hack - for now always pick the first - later this guy will own all refs
2258 // and just use RIGHT (namely LedDoc) one...
2259 CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead ();
2260 ASSERT (pTemplate != NULL);
2261 ASSERT_KINDOF (CDocTemplate, pTemplate);
2262 (void)pTemplate->OpenDocumentFile (NULL);
2263}
2264
2265CDocument* LedItDocManager::OpenDocumentFile (LPCTSTR lpszFileName)
2266{
2267 return OpenDocumentFile (lpszFileName, eUnknownFormat);
2268}
2269
2270inline SDKString GetLongPathName (const SDKString& pathName)
2271{
2272 TCHAR szPath[_MAX_PATH];
2273 Require (pathName.length () < _MAX_PATH);
2274 Characters::CString::Copy (szPath, std::size (szPath), pathName.c_str ());
2275 WIN32_FIND_DATA fileData;
2276 HANDLE hFind = ::FindFirstFile (szPath, &fileData);
2277 if (hFind != INVALID_HANDLE_VALUE) {
2278 TCHAR* lastSlash = ::_tcsrchr (szPath, '\\');
2279 if (lastSlash != NULL) {
2280 *lastSlash = '\0';
2281 }
2282 Characters::CString::Cat (szPath, std::size (szPath), _T ("\\"));
2283 Characters::CString::Cat (szPath, std::size (szPath), fileData.cFileName);
2284 szPath[_MAX_PATH - 1] = '\0';
2285 VERIFY (::FindClose (hFind));
2286 }
2287 return szPath;
2288}
2289CDocument* LedItDocManager::OpenDocumentFile (LPCTSTR lpszFileName, FileFormat format)
2290{
2291 // Lifted from CDocManager::OpenDocumentFile() with a few changes to not keep
2292 // separate lists of templates. Only reason I create multiple templates is to
2293 // get the popup in the open/save dialogs to appear.
2294 // Sigh!
2295 // LGP 960222
2296 // PLUS SEE BELOW - LGP 960522
2297 CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead ();
2298 ASSERT (pTemplate != NULL);
2299 ASSERT_KINDOF (CDocTemplate, pTemplate);
2300
2301 TCHAR szPath[_MAX_PATH];
2302 ASSERT (::_tcslen (lpszFileName) < _MAX_PATH);
2303 TCHAR szTemp[_MAX_PATH];
2304 if (lpszFileName[0] == '\"')
2305 ++lpszFileName;
2306 Characters::CString::Copy (szTemp, std::size (szTemp), lpszFileName);
2307 LPTSTR lpszLast = _tcsrchr (szTemp, '\"');
2308 if (lpszLast != NULL)
2309 *lpszLast = 0;
2310 AfxFullPath (szPath, szTemp);
2311 TCHAR szLinkName[_MAX_PATH];
2312 if (AfxResolveShortcut (AfxGetMainWnd (), szPath, szLinkName, _MAX_PATH))
2313 Characters::CString::Copy (szPath, std::size (szPath), szLinkName);
2314
2315 // Also, to fix SPR#0345, we must use this (or SHGetFileInfo) hack
2316 // to get the long-file-name version of the file name.
2317 Characters::CString::Copy (szPath, std::size (szPath), GetLongPathName (szPath).c_str ());
2318
2319 LedItDocument::sHiddenDocOpenArg = format;
2320 return (pTemplate->OpenDocumentFile (szPath));
2321}
2322
2323void LedItDocManager::RegisterShellFileTypes (BOOL bWin95)
2324{
2325 // Cloned from base CWinApp version, but we don't use Doc templates
2326
2327 CString strPathName, strTemp;
2328
2329 AfxGetModuleShortFileName (AfxGetInstanceHandle (), strPathName);
2330
2331 // Only do for .led file now???
2332 // In future maybe ask user if I should do .txt, etc??? And any others I support?
2333 RegisterShellFileType (bWin95, strPathName, 1, ".led", "LedIt.Document", "LedIt Document");
2334}
2335
2336void LedItDocManager::RegisterShellFileType (bool bWin95, CString strPathName, int iconIndexInFile, CString strFilterExt,
2337 CString strFileTypeId, CString strFileTypeName)
2338{
2339 static const TCHAR szShellOpenFmt[] = _T("%s\\shell\\open\\%s");
2340 static const TCHAR szShellPrintFmt[] = _T("%s\\shell\\print\\%s");
2341 static const TCHAR szShellPrintToFmt[] = _T("%s\\shell\\printto\\%s");
2342 static const TCHAR szDefaultIconFmt[] = _T("%s\\DefaultIcon");
2343 static const TCHAR szShellNewFmt[] = _T("%s\\ShellNew");
2344 static const TCHAR szIconIndexFmt[] = _T(",%d");
2345 static const TCHAR szCommand[] = _T("command");
2346 static const TCHAR szOpenArg[] = _T(" \"%1\"");
2347 static const TCHAR szPrintArg[] = _T(" /p \"%1\"");
2348 static const TCHAR szPrintToArg[] = _T(" /pt \"%1\" \"%2\" \"%3\" \"%4\"");
2349
2350 static const TCHAR szShellNewValueName[] = _T("NullFile");
2351 static const TCHAR szShellNewValue[] = _T("");
2352
2353 const int DEFAULT_ICON_INDEX = 0;
2354
2355 CString strOpenCommandLine = strPathName;
2356 CString strPrintCommandLine = strPathName;
2357 CString strPrintToCommandLine = strPathName;
2358 CString strDefaultIconCommandLine = strPathName;
2359
2360 if (bWin95) {
2361 CString strIconIndex;
2362 HICON hIcon = ::ExtractIcon (AfxGetInstanceHandle (), strPathName, iconIndexInFile);
2363 if (hIcon != NULL) {
2364 strIconIndex.Format (szIconIndexFmt, iconIndexInFile);
2365 ::DestroyIcon (hIcon);
2366 }
2367 else {
2368 strIconIndex.Format (szIconIndexFmt, DEFAULT_ICON_INDEX);
2369 }
2370 strDefaultIconCommandLine += strIconIndex;
2371 }
2372
2373 if (!strFileTypeId.IsEmpty ()) {
2374 CString strTemp;
2375
2376 // enough info to register it
2377 if (strFileTypeName.IsEmpty ()) {
2378 strFileTypeName = strFileTypeId; // use id name
2379 }
2380
2381 ASSERT (strFileTypeId.Find (' ') == -1); // no spaces allowed
2382
2383 // first register the type ID with our server
2384 if (!SetRegKey (strFileTypeId, strFileTypeName)) {
2385 return; // just skip it
2386 }
2387
2388 if (bWin95) {
2389 // path\DefaultIcon = path,1
2390 strTemp.Format (szDefaultIconFmt, (LPCTSTR)strFileTypeId);
2391 if (!SetRegKey (strTemp, strDefaultIconCommandLine)) {
2392 return; // just skip it
2393 }
2394 }
2395
2396 // We are an SDI application...
2397 // path\shell\open\command = path filename
2398 // path\shell\print\command = path /p filename
2399 // path\shell\printto\command = path /pt filename printer driver port
2400 strOpenCommandLine += szOpenArg;
2401 if (bWin95) {
2402 strPrintCommandLine += szPrintArg;
2403 strPrintToCommandLine += szPrintToArg;
2404 }
2405
2406 // path\shell\open\command = path filename
2407 strTemp.Format (szShellOpenFmt, (LPCTSTR)strFileTypeId, (LPCTSTR)szCommand);
2408 if (!SetRegKey (strTemp, strOpenCommandLine)) {
2409 return; // just skip it
2410 }
2411
2412 if (bWin95) {
2413 // path\shell\print\command = path /p filename
2414 strTemp.Format (szShellPrintFmt, (LPCTSTR)strFileTypeId, (LPCTSTR)szCommand);
2415 if (!SetRegKey (strTemp, strPrintCommandLine)) {
2416 return; // just skip it
2417 }
2418
2419 // path\shell\printto\command = path /pt filename printer driver port
2420 strTemp.Format (szShellPrintToFmt, (LPCTSTR)strFileTypeId, (LPCTSTR)szCommand);
2421 if (!SetRegKey (strTemp, strPrintToCommandLine)) {
2422 return; // just skip it
2423 }
2424 }
2425
2426 if (!strFilterExt.IsEmpty ()) {
2427 ASSERT (strFilterExt[0] == '.');
2428 LONG lSize = _MAX_PATH * 2;
2429 LONG lResult = ::RegQueryValue (HKEY_CLASSES_ROOT, strFilterExt, strTemp.GetBuffer (lSize), &lSize);
2430 strTemp.ReleaseBuffer ();
2431 if (lResult != ERROR_SUCCESS || strTemp.IsEmpty () || strTemp == strFileTypeId) {
2432 // no association for that suffix
2433 if (!SetRegKey (strFilterExt, strFileTypeId)) {
2434 return; // just skip it
2435 }
2436 if (bWin95) {
2437 strTemp.Format (szShellNewFmt, (LPCTSTR)strFilterExt);
2438 (void)SetRegKey (strTemp, szShellNewValue, szShellNewValueName);
2439 }
2440 }
2441 }
2442 }
2443}
2444
2445BOOL LedItDocManager::DoPromptFileName (CString& /*fileName*/, UINT /*nIDSTitle*/, DWORD /*lFlags*/, BOOL /*bOpenFileDialog*/, CDocTemplate* /*pTemplate*/)
2446{
2447 // don't call this directly...
2448 Assert (false);
2449 return false;
2450}
2451
2452void LedItDocManager::OnFileOpen ()
2453{
2454 CString fileName;
2455 FileFormat format = eUnknownFormat;
2456 if (LedItDocument::DoPromptOpenFileName (fileName, &format)) {
2457 OpenDocumentFile (fileName, format);
2458 }
2459}
2460#endif
#define AssertNotNull(p)
Definition Assertions.h:334
#define EnsureNotNull(p)
Definition Assertions.h:341
#define RequireNotNull(p)
Definition Assertions.h:348
#define AssertMember(p, c)
Definition Assertions.h:313
#define Verify(c)
Definition Assertions.h:420
basic_string< SDKChar > SDKString
Definition SDKString.h:38