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