1 /*******************************************************************************
2  * ccodemax.cpp
3  *
4  * This file is part of the CodeMax editor support code.
5  *
6  * Author: Christopher J. Cason.
7  *
8  * ---------------------------------------------------------------------------
9  * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
10  * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
11  *
12  * POV-Ray is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU Affero General Public License as
14  * published by the Free Software Foundation, either version 3 of the
15  * License, or (at your option) any later version.
16  *
17  * POV-Ray is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Affero General Public License for more details.
21  *
22  * You should have received a copy of the GNU Affero General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  * ---------------------------------------------------------------------------
25  * POV-Ray is based on the popular DKB raytracer version 2.12.
26  * DKBTrace was originally written by David K. Buck.
27  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
28  * ---------------------------------------------------------------------------
29  * $File: //depot/public/povray/3.x/windows/cmedit/ccodemax.cpp $
30  * $Revision: #1 $
31  * $Change: 6069 $
32  * $DateTime: 2013/11/06 11:59:40 $
33  * $Author: chrisc $
34  *******************************************************************************/
35 
36 #include "cmedit.h"
37 #include "ccodemax.h"
38 #include "settings.h"
39 #include "menusupport.h"
40 #include "eventhandlers.h"
41 #include "editorinterface.h"
42 #include "dialogs.h"
43 #include "..\pvedit.h"
44 
45 bool                    CCodeMax::SaveDialogActive ;
46 static char             LanguageNames [] [32] = {"", "C/C++", "Basic", "Java", "Pascal", "SQL", "POV-Ray", "HTML", "XML", "INI"} ;
47 
48 extern int              AutoReload ;
49 extern int              NotifyBase ;
50 extern bool             CreateBackups ;
51 extern bool             LastOverwrite ;
52 extern bool             UndoAfterSave ;
53 extern bool             MessagePaneVisible ;
54 extern HWND             hMainWindow ;
55 extern HWND             hTabWindow ;
56 extern HWND             hNotifyWindow ;
57 extern HMENU            hPopupMenu ;
58 extern HMENU            hInsertMenu ;
59 extern HINSTANCE        hInstance ;
60 extern CCodeMax         *Editor ;
61 extern CStdString       BinariesPath ;
62 extern CStdString       DocumentsPath;
63 extern CStdString       InitialDir ;
64 extern CStdString       IncludeFilename ;
65 extern CStdString       CommandLine ;
66 
67 typedef struct
68 {
69   WORD          cmd ;
70   CodemaxHotkey key ;
71 } DefHotkeyRec ;
72 
73 DefHotkeyRec DefHotKeys [] =
74 {
75   { CM_SAVE,                          HOTKEYF_CONTROL,                    'S',        0, 0 },
76   { CM_SAVEAS,                        HOTKEYF_CONTROL | HOTKEYF_SHIFT,    'A',        0, 0 },
77   { CM_SAVEALL,                       HOTKEYF_CONTROL | HOTKEYF_SHIFT,    'V',        0, 0 },
78   { CM_EXIT,                          HOTKEYF_ALT,                        'X',        0, 0 },
79   { CM_SHOWMESSAGES,                  HOTKEYF_ALT,                        'M',        0, 0 },
80   { CM_NEWFILE,                       HOTKEYF_CONTROL,                    'N',        0, 0 },
81   { CM_OPENFILE,                      HOTKEYF_CONTROL,                    'O',        0, 0 },
82   { CM_CLOSECURRENTFILE,              HOTKEYF_CONTROL,                    'W',        0, 0 },
83   { CM_PRINT,                         HOTKEYF_CONTROL,                    'P',        0, 0 },
84   { 0,                                0,                                  '\0',       0, 0 },
85 } ;
86 
CCodeMax(HWND parent)87 CCodeMax::CCodeMax (HWND parent)
88 {
89   RECT        rect ;
90 
91   m_Opened = false ;
92   m_Language = tlNone ;
93   m_Index = 0 ;
94   m_BackedUp = false ;
95   m_LButtonDown = false ;
96   m_RMBDownX = m_RMBDownY = 0 ;
97   m_RMBDownLine = m_RMBDownCol = -1 ;
98   m_Tag.LongName [0] = '\0' ;
99   m_Tag.ShortName [0] = '\0' ;
100 
101   GetClientRect (parent, &rect) ;
102   TabCtrl_AdjustRect (parent, FALSE, &rect) ;
103   m_hWnd = CreateWindowEx (0,
104                            "CodeMax",
105                            "",
106                            WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
107                            rect.left,
108                            rect.top,
109                            rect.right - rect.left + 1,
110                            rect.bottom - rect.top + 1,
111                            parent,
112                            (HMENU) this,
113                            hInstance,
114                            NULL) ;
115   m_OldWndProc = (WNDPROC) SetWindowLongPtr (m_hWnd, GWLP_WNDPROC, (LONG_PTR) StaticWndProc) ;
116 }
117 
~CCodeMax()118 CCodeMax::~CCodeMax ()
119 {
120   if (m_hWnd)
121     DestroyWindow (m_hWnd) ;
122 }
123 
WndProc(UINT message,WPARAM wParam,LPARAM lParam)124 LRESULT CCodeMax::WndProc (UINT message, WPARAM wParam, LPARAM lParam)
125 {
126   POINT                 point ;
127   CodemaxRange          range ;
128   CodemaxPos            pos ;
129 
130   if (message == WM_LBUTTONDOWN)
131   {
132     m_LButtonDown = true ;
133     LRESULT result = CallWindowProc (m_OldWndProc, m_hWnd, message, wParam, lParam) ;
134     if (GetSel (&range, false) == CODEMAX_SUCCESS)
135     {
136       int len = GetLineLength (range.Start.Line + 1) ;
137       if (range.Start.Col > len)
138         if (!IsMenuItemChecked (CM_CURSORBEYONDEOL))
139           SetCaretPos (range.Start.Line + 1, len + 1) ;
140     }
141     return (result) ;
142   }
143   if (message == WM_LBUTTONUP)
144   {
145     LRESULT result = CallWindowProc (m_OldWndProc, m_hWnd, message, wParam, lParam) ;
146     m_LButtonDown = false ;
147 
148     if (GetSel (&range, false) == CODEMAX_SUCCESS)
149     {
150       int len = GetLineLength (range.End.Line + 1) ;
151       if (range.End.Col > len && !IsMenuItemChecked (CM_CURSORBEYONDEOL))
152       {
153         range.End.Col = len ;
154         SetSel (&range, false) ;
155       }
156     }
157     return (result) ;
158   }
159   if (message == WM_RBUTTONDOWN)
160   {
161     m_RMBDownX = LOWORD (lParam) ;
162     m_RMBDownY = HIWORD (lParam) ;
163     if (GetSelFromPoint (m_RMBDownX, m_RMBDownY, &pos) == CODEMAX_SUCCESS)
164     {
165       m_RMBDownLine = pos.Line + 1 ;
166       m_RMBDownCol = pos.Col + 1 ;
167     }
168     else
169       m_RMBDownLine = m_RMBDownCol = -1 ;
170     // don't pass it on (so the caret doesn't move)
171     return (0) ;
172   }
173   if (message == WM_CONTEXTMENU)
174   {
175     if (Editor != this)
176       return (0) ;
177     GetCursorPos (&point) ;
178     PopupMenuPopup () ;
179     TrackPopupMenuEx (hPopupMenu, 0, point.x, point.y, hMainWindow, NULL) ;
180     m_RMBDownLine = m_RMBDownCol = -1 ;
181     return (0) ;
182   }
183   if (message == WM_CHAR && MessagePaneVisible && (char) wParam == 0x1b)
184   {
185     MessagePaneVisible = false ;
186     ShowMessagePane () ;
187     return (0) ;
188   }
189   if (message == WM_ERASEBKGND)
190     return (0) ;
191   return (CallWindowProc (m_OldWndProc, m_hWnd, message, wParam, lParam)) ;
192 }
193 
StaticWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)194 LRESULT CALLBACK CCodeMax::StaticWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
195 {
196   try
197   {
198     CCodeMax *e = (CCodeMax *) GetWindowLongPtr (hWnd, GWLP_ID) ;
199     ASSERT (hWnd == e->m_hWnd) ;
200     if (hWnd != e->m_hWnd)
201       return DefWindowProc (hWnd, message, wParam, lParam);
202     return (e->WndProc (message, wParam, lParam)) ;
203   }
204   catch (...)
205   {
206     ShowMessage ("ERROR: The editor code threw an exception handling message %08lx. Please report this as a bug.", message) ;
207     return DefWindowProc (hWnd, message, wParam, lParam);
208   }
209 }
210 
SetFileName(LPCTSTR Filename)211 void CCodeMax::SetFileName (LPCTSTR Filename)
212 {
213   if (m_Tag.LongName != NULL)
214     if (strcmp (Filename, m_Tag.LongName) == 0)
215       return ;
216   strcpy (m_Tag.LongName, Filename) ;
217   m_Opened = false ;
218 }
219 
SetOpened(bool IsOpened)220 void CCodeMax::SetOpened (bool IsOpened)
221 {
222   if (!IsOpened)
223   {
224     m_Opened = false ;
225     return ;
226   }
227   m_Opened = OpenFile (m_Tag.LongName) != 0 ;
228 }
229 
GetLanguageName(void)230 LPCTSTR CCodeMax::GetLanguageName (void)
231 {
232   GetLanguage (m_LanguageName) ;
233   for (int i = 0 ; i < sizeof (LanguageNames) / sizeof (LanguageNames [0]) ; i++)
234     if (_stricmp (m_LanguageName, LanguageNames [i]) == 0)
235       m_Language = TLanguage (i) ;
236   return (m_LanguageName) ;
237 }
238 
GetLanguage(void)239 TLanguage CCodeMax::GetLanguage (void)
240 {
241   GetLanguageName () ;
242   return (m_Language) ;
243 }
244 
GetScrollBars(void)245 TScrollStyle CCodeMax::GetScrollBars (void)
246 {
247   TScrollStyle          result = tssNone ;
248 
249   if (HasScrollBar (true))
250     result = tssHorizontal ;
251   if (HasScrollBar (false))
252     result = result == tssNone ? tssVertical : tssBoth ;
253   return (result) ;
254 }
255 
SetScrollBars(TScrollStyle style)256 void CCodeMax::SetScrollBars (TScrollStyle style)
257 {
258   switch (style)
259   {
260     case tssNone :
261          ShowScrollbar (false, false) ;
262          ShowScrollbar (true, false) ;
263          break ;
264 
265     case tssHorizontal :
266          ShowScrollbar (false, false) ;
267          ShowScrollbar (true, true) ;
268          break ;
269 
270     case tssVertical :
271          ShowScrollbar (false, true) ;
272          ShowScrollbar (true, false) ;
273          break ;
274 
275     case tssBoth :
276          ShowScrollbar (false, true) ;
277          ShowScrollbar (true, true) ;
278          break ;
279   }
280 }
281 
GetText(const CodemaxRange * pRange)282 CStdString CCodeMax::GetText (const CodemaxRange *pRange)
283 {
284   int         len = GetTextLength (pRange) ;
285   CStdString  result ;
286 
287   if (len != -1)
288   {
289     char *buffer = (char *) malloc (len + 1) ;
290     GetText (buffer, pRange) ;
291     result = buffer ;
292     free (buffer) ;
293     return (result) ;
294   }
295   return ("") ;
296 }
297 
GetLine(int nLine)298 CStdString CCodeMax::GetLine (int nLine)
299 {
300   int         len = GetLineLength (nLine) ;
301   CStdString  result ;
302 
303   if (len != -1)
304   {
305     char *buffer = (char *) malloc (len + 1) ;
306     GetLine (nLine, buffer) ;
307     result = buffer ;
308     free (buffer) ;
309     return (result) ;
310   }
311   return ("(error getting line)") ;
312 }
313 
GetWord(CodemaxPos * pPos)314 CStdString CCodeMax::GetWord (CodemaxPos *pPos)
315 {
316   int         len = GetWordLength (pPos) ;
317   CStdString  result ;
318 
319   if (len != -1)
320   {
321     char *buffer = (char *) malloc (len + 1) ;
322     GetWord (buffer, pPos) ;
323     result = buffer ;
324     free (buffer) ;
325     return (result) ;
326   }
327   return ("(error getting word)") ;
328 }
329 
SetDefaultHotKeys(void)330 void CCodeMax::SetDefaultHotKeys (void)
331 {
332   // we do it this way to avoid nuking any identical hotkeys
333   // that may have been added by the user.
334   for (DefHotkeyRec *p = DefHotKeys ; p->cmd ; p++)
335     if (LookupHotKey (&p->key) == -1)
336       RegisterHotKey (&p->key, p->cmd) ;
337 }
338 
SetHotKeys(char * HotKeys)339 LRESULT CCodeMax::SetHotKeys (char *HotKeys)
340 {
341   return (CMSetHotKeys ((unsigned char *) HotKeys)) ;
342 }
343 
SetMacro(int Index,char * Macro)344 LRESULT CCodeMax::SetMacro (int Index, char *Macro)
345 {
346   return (CMSetMacro (Index, (unsigned char *) Macro)) ;
347 }
348 
SetFindReplaceMRUList(LPCTSTR List,bool IsFind)349 void CCodeMax::SetFindReplaceMRUList (LPCTSTR List, bool IsFind)
350 {
351   CMSetFindReplaceMRUList (List, IsFind) ;
352 }
353 
GetHotKeys(char * HotKeys)354 int CCodeMax::GetHotKeys (char *HotKeys)
355 {
356   return (CMGetHotKeys ((unsigned char *) HotKeys)) ;
357 }
358 
GetMacro(int Index,char * Macro)359 int CCodeMax::GetMacro (int Index, char *Macro)
360 {
361   return (CMGetMacro (Index, (unsigned char *) Macro)) ;
362 }
363 
GetFindReplaceMRUList(bool IsFind)364 CStdString CCodeMax::GetFindReplaceMRUList (bool IsFind)
365 {
366   char        buffer [CODEMAX_FIND_REPLACE_MRU_BUFF_SIZE] ;
367 
368   CMGetFindReplaceMRUList (buffer, IsFind) ;
369   return (buffer) ;
370 }
371 
GetLineNo(void)372 int CCodeMax::GetLineNo (void)
373 {
374   CodemaxRange              range ;
375 
376   GetSel (&range, false) ;
377   return (++range.End.Line) ;
378 }
379 
SetLineNo(int LineNo)380 void CCodeMax::SetLineNo (int LineNo)
381 {
382   CodemaxRange              range ;
383 
384   if (LineNo == 0)
385     LineNo++ ;
386   GetSel (&range, false) ;
387   SetCaretPos (LineNo, range.Start.Col + 1) ;
388 }
389 
GetColNo(void)390 int CCodeMax::GetColNo (void)
391 {
392   CodemaxRange              range ;
393 
394   GetSel (&range, false) ;
395   return (++range.End.Col) ;
396 }
397 
SetColNo(int ColNo)398 void CCodeMax::SetColNo (int ColNo)
399 {
400   CodemaxRange              range ;
401 
402   if (ColNo == 0)
403     ColNo++ ;
404   GetSel (&range, false) ;
405   SetCaretPos (range.Start.Line + 1, ColNo) ;
406 }
407 
SetPosition(int LineNo,int ColNo)408 void CCodeMax::SetPosition (int LineNo, int ColNo)
409 {
410   CodemaxRange              range ;
411 
412   if (LineNo == 0)
413     LineNo++ ;
414   if (ColNo == 0)
415     ColNo++ ;
416   range.Start.Line = --LineNo ;
417   range.Start.Col = --ColNo ;
418   range.End = range.Start ;
419   SetSel (&range, true) ;
420 }
421 
GetPosition(CodemaxPos * Position)422 void CCodeMax::GetPosition (CodemaxPos *Position)
423 {
424   CodemaxRange              range ;
425 
426   GetSel (&range, false) ;
427   *Position = range.End ;
428 }
429 
SetPosition(const CodemaxPos * Position)430 void CCodeMax::SetPosition (const CodemaxPos *Position)
431 {
432   CodemaxRange              range ;
433 
434   range.Start = range.End = *Position ;
435   SetSel (&range, true) ;
436 }
437 
SetLanguage(TLanguage Language)438 void CCodeMax::SetLanguage (TLanguage Language)
439 {
440   strcpy (m_LanguageName, LanguageNames [Language]) ;
441   SetLanguage (m_LanguageName) ;
442 }
443 
444 //---------------------------------------------------------------------------
GetHotKeyString(CodemaxHotkey & cmHotKey)445 CStdString CCodeMax::GetHotKeyString (CodemaxHotkey &cmHotKey)
446 {
447   char        str [256] = "" ;
448   UINT        nVirtKey = cmHotKey.VirtKey1 ;
449   BYTE        byModifiers = cmHotKey.Modifier1 ;
450   BYTE        byOrigModifiers = byModifiers ;
451 
452   for (int i = 0 ; nVirtKey && (i < 2) ; i++)
453   {
454     if (i == 0 || (i != 0 && byModifiers != byOrigModifiers))
455     {
456       if ((byModifiers & HOTKEYF_CONTROL) == HOTKEYF_CONTROL)
457         strcat (str, "Ctrl + ") ;
458       if ((byModifiers & HOTKEYF_SHIFT) == HOTKEYF_SHIFT)
459         strcat (str, "Shift + ") ;
460       if ((byModifiers & HOTKEYF_ALT) == HOTKEYF_ALT)
461         strcat (str, "Alt + ") ;
462     }
463 
464     if (nVirtKey)
465     {
466       char    szTemp [2] ;
467       LPTSTR  pszChar ;
468 
469       switch (nVirtKey)
470       {
471         case VK_NUMLOCK:        pszChar = "Lock";           break;
472         case VK_BACK:           pszChar = "Backspace";      break;
473         case VK_INSERT:         pszChar = "Insert";         break;
474         case VK_DELETE:         pszChar = "Delete";         break;
475         case VK_HOME:           pszChar = "Home";           break;
476         case VK_END:            pszChar = "End";            break;
477         case VK_PRIOR:          pszChar = "Page Up";        break;
478         case VK_NEXT:           pszChar = "Page Down";      break;
479         case VK_LEFT:           pszChar = "Left";           break;
480         case VK_RIGHT:          pszChar = "Right";          break;
481         case VK_UP:             pszChar = "Up";             break;
482         case VK_DOWN:           pszChar = "Down";           break;
483         case VK_SCROLL:         pszChar = "Scroll Lock";    break;
484         case VK_TAB:            pszChar = "Tab";            break;
485         case VK_ESCAPE:         pszChar = "Esc";            break;
486         case VK_RETURN:         pszChar = "Enter";          break;
487         case VK_F1:             pszChar = "F1";             break;
488         case VK_F2:             pszChar = "F2";             break;
489         case VK_F3:             pszChar = "F3";             break;
490         case VK_F4:             pszChar = "F4";             break;
491         case VK_F5:             pszChar = "F5";             break;
492         case VK_F6:             pszChar = "F6";             break;
493         case VK_F7:             pszChar = "F7";             break;
494         case VK_F8:             pszChar = "F8";             break;
495         case VK_F9:             pszChar = "F9";             break;
496         case VK_F10:            pszChar = "F10";            break;
497         case VK_F11:            pszChar = "F11";            break;
498         case VK_F12:            pszChar = "F12";            break;
499         case VK_SPACE:          pszChar = "Space";          break;
500         case VK_ADD:            pszChar = "Plus";           break;
501         case 0x3b:              pszChar = "Plus";           break;
502         case 0xbd:              pszChar = "Minus";          break;
503         case VK_SUBTRACT:       pszChar = "Minus";          break;
504         case 0x3d:              pszChar = "Minus";          break;
505 
506         default:
507         {
508           if (nVirtKey >= 0x60 && nVirtKey <= 0x6f)
509             strcat (str, "Num ") ;
510           switch (nVirtKey)
511           {
512             case 0xc0:          { nVirtKey = '`'; break; }
513             case 0x30:          { nVirtKey = '0'; break; }
514             case 0x31:          { nVirtKey = '1'; break; }
515             case 0x32:          { nVirtKey = '2'; break; }
516             case 0x33:          { nVirtKey = '3'; break; }
517             case 0x34:          { nVirtKey = '4'; break; }
518             case 0x35:          { nVirtKey = '5'; break; }
519             case 0x36:          { nVirtKey = '6'; break; }
520             case 0x37:          { nVirtKey = '7'; break; }
521             case 0x38:          { nVirtKey = '8'; break; }
522             case 0x39:          { nVirtKey = '9'; break; }
523             case 0xbb:          { nVirtKey = '='; break; }
524             case 0xdb:          { nVirtKey = '['; break; }
525             case 0xdd:          { nVirtKey = ']'; break; }
526             case 0xdc:          { nVirtKey = '\\'; break; }
527             case 0xba:          { nVirtKey = ';'; break; }
528             case 0xde:          { nVirtKey = '\''; break; }
529             case 0xbc:          { nVirtKey = ','; break; }
530             case 0xbe:          { nVirtKey = '.'; break; }
531             case 0xbf:          { nVirtKey = '/'; break; }
532             case VK_NUMPAD0:    { nVirtKey = '0'; break; }
533             case VK_NUMPAD1:    { nVirtKey = '1'; break; }
534             case VK_NUMPAD2:    { nVirtKey = '2'; break; }
535             case VK_NUMPAD3:    { nVirtKey = '3'; break; }
536             case VK_NUMPAD4:    { nVirtKey = '4'; break; }
537             case VK_NUMPAD5:    { nVirtKey = '5'; break; }
538             case VK_NUMPAD6:    { nVirtKey = '6'; break; }
539             case VK_NUMPAD7:    { nVirtKey = '7'; break; }
540             case VK_NUMPAD8:    { nVirtKey = '8'; break; }
541             case VK_NUMPAD9:    { nVirtKey = '9'; break; }
542             case VK_MULTIPLY:   { nVirtKey = '*'; break; }
543             case VK_DECIMAL:    { nVirtKey = '.'; break; }
544             case VK_DIVIDE :    { nVirtKey = '/'; break; }
545           }
546           szTemp [0] = (char) nVirtKey ;
547           szTemp [1] = '\0' ;
548           pszChar = szTemp ;
549         }
550       }
551 
552       strcat (str, pszChar) ;
553 
554       nVirtKey = cmHotKey.VirtKey2 ;
555       byModifiers = cmHotKey.Modifiers2 ;
556 
557       if (nVirtKey && (i == 0))
558         strcat (str, ", ") ;
559     }
560   }
561   return (str) ;
562 }
563 
564 //------------------------------------------------------------------------------------------------------------------------
565 
SetLanguageBasedOnFileType(void)566 void CCodeMax::SetLanguageBasedOnFileType (void)
567 {
568   CStdString            ext = GetFileExt (m_Tag.ShortName) ;
569 
570   m_Language = tlNone ;
571   ext.MakeUpper () ;
572   if (ext == "C" || ext == "CPP" || ext == "H" || ext == "HPP"  || ext == "JS")
573     m_Language = tlCCpp ;
574   else if (ext == "JAVA")
575     m_Language = tlJava ;
576   else if (ext == "BAS")
577     m_Language = tlBasic ;
578   else if (ext == "PAS")
579     m_Language = tlPascal ;
580   else if (ext == "SQL" || ext == "DDL")
581     m_Language = tlSQL ;
582   else if (ext == "HTML" || ext == "HTM" || ext == "PHP" || ext == "PHP3" || ext == "PHP4"  || ext == "PHP5"  || ext == "ASP")
583     m_Language = tlHTML ;
584   else if (ext == "SGML" || ext == "XML")
585     m_Language = tlSGML ;
586   else if (ext == "POV" || ext == "INC" || ext == "MAC" || ext == "MCR")
587     m_Language = tlPOVRay ;
588   else if (ext == "INI")
589     m_Language = tlINI ;
590   SetLanguage (m_Language) ;
591 }
592 
593 //------------------------------------------------------------------------------------------------------------------------
594 
SetupEditor(const EditConfigStruct * ec,bool PropsChange,bool InitCM)595 void CCodeMax::SetupEditor (const EditConfigStruct *ec, bool PropsChange, bool InitCM)
596 {
597   //if (!PropsChange)
598   //{
599     SetAutoIndent (ec->AutoIndent) ;
600     SetTabSize (ec->TabSize) ;
601   //}
602   if (ec->HFont != NULL)
603     SetFont (ec->HFont) ;
604   SetFontOwnership (false) ;
605   EnableTabExpand (ec->TabExpand) ;
606   EnableColorSyntax (ec->SyntaxHighlighting) ;
607   EnableWhitespaceDisplay (ec->WhiteSpaceDisplay) ;
608   EnableSmoothScrolling (ec->SmoothScrolling) ;
609   EnableLineToolTips (ec->LineToolTips) ;
610   EnableLeftMargin (ec->LeftMarginVisible) ;
611   EnableCaseSensitive (ec->CaseSensitive) ;
612   EnablePreserveCase (ec->PreserveCase) ;
613   EnableWholeWord (ec->WholeWordEnabled) ;
614   EnableDragDrop (ec->DragDropEnabled) ;
615   EnableColumnSel (ec->ColumnSelEnabled) ;
616   EnableRegExp (ec->RegexpEnabled) ;
617   EnableOvertypeCaret (ec->OvertypeCaret) ;
618   EnableSelBounds (ec->SelBoundsEnabled) ;
619   SetUndoLimit (ec->UndoLimit) ;
620 
621   // set scroll bars before splitters
622   SetScrollBars (ec->ScrollBars) ;
623 
624   // splitters must be set up after scroll bars
625   EnableHSplitter (ec->HSplitterEnabled) ;
626   EnableVSplitter (ec->VSplitterEnabled) ;
627 
628   SetColors (&ec->Colours) ;
629   SetFontStyles (&ec->FontStyles) ;
630   if (InitCM)
631   {
632     RegisterCommand (CMD_NEXT_KEYWORD, "ExpandNextKeyword", "Expands the next keyword in the keyword list") ;
633     RegisterCommand (CMD_PREV_KEYWORD, "ExpandPrevKeyword", "Expands the previous keyword in the keyword list") ;
634     if (ec->HotKeyLen > 0 && ec->HotKeys != NULL)
635       SetHotKeys (ec->HotKeys) ;
636     SetDefaultHotKeys () ;
637     SetFindReplaceMRUList (ec->FindMRUList, true) ;
638     SetFindReplaceMRUList (ec->ReplaceMRUList, false) ;
639     for (int i = 0 ; i < CODEMAX_MACRO_LIMIT ; i++)
640       if (ec->Macros [i] != NULL)
641         SetMacro (i, ec->Macros [i]) ;
642   }
643 }
644 
645 //------------------------------------------------------------------------------------------------------------------------
646 
GetConfigFromInstance(EditConfigStruct * ec)647 void CCodeMax::GetConfigFromInstance (EditConfigStruct *ec)
648 {
649   ec->AutoIndent = GetAutoIndent () ;
650   ec->SyntaxHighlighting = IsColorSyntaxEnabled () ;
651   ec->WhiteSpaceDisplay = IsWhitespaceDisplayEnabled () ;
652   ec->TabExpand = IsTabExpandEnabled () ;
653   ec->LeftMarginVisible = IsLeftMarginEnabled () ;
654   ec->SmoothScrolling = IsSmoothScrollingEnabled () ;
655   ec->LineToolTips = IsLineToolTipsEnabled () ;
656   ec->CaseSensitive = IsCaseSensitiveEnabled () ;
657   ec->PreserveCase = IsPreserveCaseEnabled () ;
658   ec->WholeWordEnabled = IsWholeWordEnabled () ;
659   ec->DragDropEnabled = IsDragDropEnabled () ;
660   ec->HSplitterEnabled = IsHSplitterEnabled () ;
661   ec->VSplitterEnabled = IsVSplitterEnabled () ;
662   ec->ColumnSelEnabled = IsColumnSelEnabled () ;
663   ec->RegexpEnabled = IsRegExpEnabled () ;
664   ec->OvertypeCaret = IsOvertypeCaretEnabled () ;
665   ec->SelBoundsEnabled = IsSelBoundsEnabled () ;
666   ec->ScrollBars = GetScrollBars () ;
667   ec->TabSize = GetTabSize () ;
668   ec->UndoLimit = GetUndoLimit () ;
669   ec->HFont = GetFont () ;
670   GetColors (&ec->Colours) ;
671   GetFontStyles (&ec->FontStyles) ;
672 }
673 
674 //------------------------------------------------------------------------------------------------------------------------
675 
GetConfigFromCommonSettings(EditConfigStruct * ec)676 void CCodeMax::GetConfigFromCommonSettings (EditConfigStruct *ec)
677 {
678   ec->FindMRUList = CCodeMax::GetFindReplaceMRUList (true) ;
679   ec->ReplaceMRUList = CCodeMax::GetFindReplaceMRUList (false) ;
680   if (ec->HotKeys != NULL)
681     free (ec->HotKeys) ;
682   ec->HotKeys = NULL ;
683   if ((ec->HotKeyLen = CCodeMax::GetHotKeys (NULL)) > 0)
684   {
685     ec->HotKeys = (char *) malloc (ec->HotKeyLen) ;
686     if ((ec->HotKeyLen = CCodeMax::GetHotKeys (ec->HotKeys)) == 0)
687     {
688       free (ec->HotKeys) ;
689       ec->HotKeys = NULL ;
690       PutStatusMessage ("Failed to get key bindings from Editor DLL") ;
691     }
692   }
693   for (int i = 0 ; i < CODEMAX_MACRO_LIMIT ; i++)
694   {
695     free (ec->Macros [i]) ;
696     ec->Macros [i] = NULL ;
697     if ((ec->MacroLen [i] = CCodeMax::GetMacro (i, NULL)) <= 0)
698       continue ;
699     ec->Macros [i] = (char *) malloc (ec->MacroLen [i]) ;
700     CCodeMax::GetMacro (i, ec->Macros [i]) ;
701   }
702 }
703 
704 //------------------------------------------------------------------------------------------------------------------------
705 
AskFileName(EditTagStruct * t)706 bool CCodeMax::AskFileName (EditTagStruct *t)
707 {
708   char                  szFile [_MAX_PATH] = "" ;
709   CStdString            str ;
710   CStdString            ext ;
711   OPENFILENAME          ofn ;
712   EditTagStruct         tag ;
713 
714   memset(&tag, 0, sizeof(tag));
715   if (t == NULL)
716     t = &m_Tag ;
717   str = GetFilePath (t->LongName) ;
718   if (str == "")
719     str = InitialDir ;
720 
721   ZeroMemory (&ofn, sizeof (OPENFILENAME)) ;
722   ofn.lStructSize = sizeof (OPENFILENAME) ;
723   if (t->LongName [0] != 0)
724     strcpy (szFile, t->ShortName) ;
725   ofn.hwndOwner = hMainWindow ;
726   ofn.lpstrFile = szFile ;
727   ofn.nMaxFile = sizeof (szFile) ;
728   ofn.lpstrFilter = "POV-Ray Files (*.pov;*.inc;*.ini;*.mac;*.mcr)\0*.pov;*.inc;*.ini;*.mac;*.mcr\0"
729                     "POV-Ray Source (*.pov)\0*.pov\0"
730                     "Include Files (*.inc;*.mac;*.mcr)\0*.inc;*.mac;*.mcr\0"
731                     "INI files (*.ini)\0*.ini\0"
732                     "Text Files (*.txt)\0*.txt\0"
733                     "All Files (*.*)\0*.*\0" ;
734 
735   ext = GetFileExt (t->ShortName) ;
736   ext.MakeUpper () ;
737   if (ext == "")
738     ofn.nFilterIndex = 1 ;
739   else if (ext == "POV")
740     ofn.nFilterIndex = 2 ;
741   else if (ext == "INC")
742     ofn.nFilterIndex = 3 ;
743   else if (ext == "INI")
744     ofn.nFilterIndex = 4 ;
745   else if (ext == "TXT")
746     ofn.nFilterIndex = 5 ;
747   else
748     ofn.nFilterIndex = 6 ;
749 
750   ofn.lpstrFileTitle = NULL ;
751   ofn.nMaxFileTitle = 0 ;
752   ofn.lpstrInitialDir = str ;
753   ofn.lpstrDefExt = NULL ;
754   ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT ;
755 
756   SaveDialogActive = true ;
757   while (true)
758   {
759     if (GetSaveFileName (&ofn) != 0)
760     {
761       if (szFile [strlen (szFile) - 1] != '.')
762       {
763         if (GetFileExt (szFile) == "")
764         {
765           switch (ofn.nFilterIndex)
766           {
767             case 1 :
768             case 2 :
769                 strcat (szFile, ".pov") ;
770                 break ;
771 
772             case 3 :
773                 strcat (szFile, ".inc") ;
774                 break ;
775 
776             case 4 :
777                 strcat (szFile, ".ini") ;
778                 break ;
779 
780             case 5 :
781                 strcat (szFile, ".txt") ;
782                 break ;
783 
784             case 6 :
785                 break ;
786           }
787         }
788       }
789       else
790         szFile [strlen (szFile) - 1] = '\0' ;
791       MakeFileNames (&tag, szFile) ;
792       if (_stricmp(tag.LongName, t->LongName) != 0 && FindEditor (tag.LongName) != NULL)
793       {
794         ShowMessage ("This file is open in another editor tab") ;
795         continue ;
796       }
797       *t = tag ;
798       InitialDir = szFile ;
799       if (!ofn.nFileOffset || szFile [ofn.nFileOffset - 1])
800         InitialDir = GetFilePath (InitialDir) ;
801       SaveDialogActive = false ;
802       return (true) ;
803     }
804     SaveDialogActive = false ;
805     return (false) ;
806   }
807   return (false) ;
808 }
809 
810 //------------------------------------------------------------------------------------------------------------------------
811 
SaveEditorFile(void)812 TSaveType CCodeMax::SaveEditorFile (void)
813 {
814   char                  str [_MAX_PATH + 5] ;
815   char                  oldName [_MAX_PATH] ;
816   TCITEM                item ;
817   EditTagStruct         tag = m_Tag ;
818 
819   PutStatusMessage ("") ;
820   ClearErrorLine () ;
821   strcpy (oldName, m_Tag.LongName) ;
822   if (m_Tag.LongName [0] == '\0')
823     if (!AskFileName (&tag))
824       return (stCancel) ;
825   if (CreateBackups && !m_BackedUp)
826   {
827     if (FileExists (tag.LongName))
828     {
829       if ((GetFileAttributes (tag.LongName) & FILE_ATTRIBUTE_READONLY) != 0)
830       {
831         MessageBox (hMainWindow, "Cannot overwrite read-only file", tag.ShortName, MB_ICONEXCLAMATION | MB_OK) ;
832         return (stError) ;
833       }
834       sprintf (str, "%s.bak", tag.LongName) ;
835       if (FileExists (str) && !DeleteFile (str))
836       {
837         ShowErrorMessage (GetBaseName (str), "Failed to delete old backup file") ;
838         return (stError) ;
839       }
840       if (!MoveFile (tag.LongName, str))
841       {
842         ShowErrorMessage (tag.ShortName, "Failed to rename original file to .bak") ;
843         return (stError) ;
844       }
845       m_BackedUp = true ;
846     }
847   }
848   if (SaveFile (tag.LongName, !UndoAfterSave) == CODEMAX_SUCCESS)
849   {
850     if (strcmp (tag.LongName, oldName) != 0)
851     {
852       m_Tag = tag ;
853       item.mask = TCIF_TEXT ;
854       item.dwState = item.dwStateMask = 0 ;
855       item.pszText = tag.ShortName ;
856       TabCtrl_SetItem (hTabWindow, m_Index + 1, &item) ;
857       if (_stricmp (tag.LongName, oldName) != 0)
858       {
859         AddToRecent (EncodeFilename(tag.LongName)) ;
860         SetLanguageBasedOnFileType () ;
861         UpdateRecent () ;
862 
863         // pretend the tab has changed so the window caption is updated
864         SendMessage (hNotifyWindow, WM_COMMAND, NotifyBase + povwin::NotifyTabChange, GetFlags ()) ;
865       }
866     }
867     UpdateFileTime () ;
868     PutStatusMessage ("File saved") ;
869     return (stSaved) ;
870   }
871   ShowErrorMessage (m_Tag.ShortName, "Failed to save file") ;
872   return (stError) ;
873 }
874 
875 //------------------------------------------------------------------------------------------------------------------------
876 
TrySave(bool ContinueOption)877 TSaveType CCodeMax::TrySave (bool ContinueOption)
878 {
879   int         flags = MB_ICONEXCLAMATION | MB_DEFBUTTON1 ;
880   char        str [_MAX_FNAME + 64] ;
881 
882   switch (SaveEditorFile ())
883   {
884     case stSaved :
885          return (stSaved) ;
886 
887     case stCancel :
888          return (stCancel) ;
889 
890     default :
891          if (ContinueOption)
892            flags |= HaveWin2kOrLater () ? MB_CANCELTRYCONTINUE : MB_ABORTRETRYIGNORE ;
893          else
894            flags |= MB_RETRYCANCEL ;
895          sprintf (str, "Failed to save file '%s'", m_Tag.ShortName) ;
896          switch (MessageBox (hMainWindow, str, "POV-Ray editor error", flags))
897          {
898            case IDABORT :
899            case IDCANCEL :
900                 return (stCancel) ;
901 
902            case IDRETRY :
903            case IDTRYAGAIN :
904                 return (stRetry) ;
905 
906            case IDIGNORE :
907            case IDCONTINUE :
908                 return (stContinue) ;
909          }
910          return (stDiscard) ;
911   }
912 }
913 
914 //------------------------------------------------------------------------------------------------------------------------
915 
UpdateFileTime(void)916 void CCodeMax::UpdateFileTime (void)
917 {
918   GetFileTimeFromDisk (m_Tag.LongName, m_Tag.TimeSaved) ;
919 }
920 
921 // IsCodeUpToDate() will check to see the file on disk is newer than the window contents.
922 // If Stale is TRUE, then the code is not up to date if the file on disk is newer.
923 // If Stale is FALSE, then the code is not up to date if the file on disk is newer or older
IsCodeUpToDate(bool Stale)924 bool CCodeMax::IsCodeUpToDate (bool Stale)
925 {
926   int                   compare ;
927   bool                  upToDate = true ;
928   FILETIME              time ;
929 
930   if (m_Tag.LongName [0] != '\0')
931   {
932     GetFileTimeFromDisk (m_Tag.LongName, time) ;
933     compare = CompareFileTime (&time, &m_Tag.TimeSaved) ;
934     upToDate = Stale ? (compare <= 0) : (compare == 0) ;
935   }
936   return (upToDate) ;
937 }
938 
939 //------------------------------------------------------------------------------------------------------------------------
940 
GetCurrentKeyword(void)941 CStdString CCodeMax::GetCurrentKeyword (void)
942 {
943   int         col = GetColNo () - 1 ;
944   CStdString  ln = GetLine (GetLineNo ()) ;
945   const char  *line = ln ;
946   const char  *s = line + col ;
947 
948   // special case - if the cursor is immediately after the end of a word,
949   // and it's on whitespace or a non-alpha, then we go back one column
950   if (col > 0 && !isalpha (*s) && *s != '_')
951     if (isalnum (line [col - 1]) || line [col - 1] == '_' || line [col - 1] == '#')
952       s-- ;
953 
954   // backtrack to the start of the word
955   while ((isalnum (*s) || *s == '_' || *s == '#') && s > line)
956     s-- ;
957 
958   // now we need to track forward
959   while (*s && !isalnum (*s) && *s != '_' && *s != '#')
960     s++ ;
961 
962   // return if the line is blank
963   if (*s == '\0')
964     return ("") ;
965 
966   // now find the end of the word
967   const char *start = s ;
968   while (*s && (isalnum (*s) || *s == '_' || *s == '#'))
969     s++ ;
970   return (ln.Mid (start - line, s - start)) ;
971 }
972 
973 //------------------------------------------------------------------------------------------------------------------------
974 
PopupMenuPopup(void)975 void CCodeMax::PopupMenuPopup (void)
976 {
977   int                   line ;
978   int                   col ;
979 
980   if (GetSubMenu (hPopupMenu, 0) != hInsertMenu)
981     InsertMenu (hPopupMenu, 0, MF_BYPOSITION | MF_POPUP, (UINT_PTR) hInsertMenu, "Insert") ;
982   SetMenuState () ;
983   SetMenuItemText (CM_OPENFILEUNDERCURSOR, "Open Include File/Insert Command Line") ;
984   EnableMenuItem (CM_OPENFILEUNDERCURSOR, false) ;
985   if ((line = m_RMBDownLine) == -1 || (col = m_RMBDownCol) == -1)
986     return ;
987   IncludeFilename = LocateIncludeFilename (line, col) ;
988   if (IncludeFilename != "")
989   {
990     CStdString str = IncludeFilename ;
991     if (str.length () > 32)
992       str = str.Left (29) + "..." ;
993     SetMenuItemText (CM_OPENFILEUNDERCURSOR, CStdString ("Open \"") + str + "\"") ;
994     EnableMenuItem (CM_OPENFILEUNDERCURSOR, true) ;
995   }
996   else
997   {
998     CommandLine = LocateCommandLine (line) ;
999     if (CommandLine != "")
1000     {
1001       CStdString str = CommandLine ;
1002       if (str.length () > 32)
1003         str = str.Left (29) + "..." ;
1004       SetMenuItemText (CM_OPENFILEUNDERCURSOR, CStdString ("Cop&y \"") + str + "\" to Command-Line") ;
1005       EnableMenuItem (CM_OPENFILEUNDERCURSOR, true) ;
1006     }
1007   }
1008 }
1009 
1010 //------------------------------------------------------------------------------------------------------------------------
1011 
LocateIncludeFilename(int line,int col)1012 CStdString CCodeMax::LocateIncludeFilename (int line, int col)
1013 {
1014   int                   pos ;
1015   int                   len ;
1016   CStdString            str = "" ;
1017   CStdString            name ;
1018 
1019   // N.B. line and col as passed in are 1-based
1020   if (line <= 0 || col <= 0)
1021     return (str) ;
1022   str = GetLine (line) ;
1023   if ((len = (int) str.length ()) == 0)
1024     return (str) ;
1025   col-- ;
1026   if (col >= len)
1027     col = len - 1 ;
1028   if ((pos = str.Find ('"')) >= col)
1029     col = pos + 1 ;
1030   for (pos = col ; pos < len ; pos++)
1031     if (str [pos] == '"')
1032       break ;
1033   if (pos >= len)
1034     return ("") ;
1035   str = str.Left (pos) ;
1036   for (pos = pos - 1 ; pos > 0 ; pos--)
1037     if (str [pos] == '"')
1038       break ;
1039   if (pos == 0)
1040     return ("") ;
1041   return (str.Mid (pos + 1)) ;
1042 }
1043 
1044 //------------------------------------------------------------------------------------------------------------------------
1045 
LocateCommandLine(int line)1046 CStdString CCodeMax::LocateCommandLine (int line)
1047 {
1048   int                   pos ;
1049   CStdString            str ;
1050   CStdString            tmpstr ;
1051 
1052   // N.B. line and col as passed in are 1-based
1053   if (line <= 0)
1054     return ("") ;
1055   str = GetLine (line) ;
1056   if (str.length () < 3)
1057     return ("") ;
1058   if ((pos = str.Find ("//")) == -1)
1059     return ("") ;
1060   str.Delete (0, pos + 2) ;
1061   tmpstr = str = str.Trim () ;
1062   tmpstr.MakeLower () ;
1063   if ((pos = tmpstr.Find ("cmd:")) != -1)
1064   {
1065     str.Delete (0, pos + 4) ;
1066     return (str.Trim ()) ;
1067   }
1068   if (str [0] != '+' && str [0] != '-')
1069     return ("") ;
1070   if (!isalpha (str [1]))
1071     return ("") ;
1072   return (str) ;
1073 }
1074 
1075