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