/******************************************************************** * Module: main.cpp. This is part of Visual-MinGW. * * Purpose: Main module. * * Authors: Manu B. * * License: Visual-MinGW is a C/C++ Integrated Development Environment. * Copyright (C) 2001 Manu. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * (See license.htm for more details.) * * Revisions: * Manu B. 12/15/01 CFileList created. * ********************************************************************/ #include #include #include #include #include "process.h" #include "project.h" #include "main.h" #include "rsrc.h" #define MSG_MODIFIED "Modified" CCriticalSection CriticalSection; extern CMessageBox MsgBox; CFindReplaceDlg EditorDlg; void Main_CmdTest(HWND hwnd); /* Globals */ char * g_env_path = NULL; char * g_vm_path = NULL; CWinApp winApp; CProject Project; CChrono Chrono; // File filters & flags. DWORD singleFileOpen = OFN_EXPLORER | OFN_FILEMUSTEXIST; DWORD multipleFileOpen = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT; DWORD fileSave = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; char * defFilter = "All Sources\0*.c;*.cpp;*.cxx;*.h;*.hpp;*.hxx;*.rc;*.mingw;*.prj\0" "C Files\0*.c;*.cpp;*.cxx;*.rc\0" "Headers\0*.h;*.hpp;*.hxx\0" "Ini file\0*.ini\0" "All Files (*.*)\0*.*\0\0"; char * prjFilter = "Project Files (*.prj)\0*.prj\0All Files (*.*)\0*.*\0\0"; char * prjDefExt = "prj"; char * srcFilter = "All Sources\0*.c;*.cpp;*.cxx;*.h;*.hpp;*.hxx;*.rc\0" "C Files\0*.c;*.cpp;*.cxx;*.rc\0" "Headers\0*.h;*.hpp;*.hxx\0" "All Files (*.*)\0*.*\0\0"; char * srcDefExt = "cpp"; /* For tests */ CChooseFontDlg CChooseFont; void Main_CmdTest(HWND){ winApp.Process.AddTask( "sh.exe", IN_PIPE || OUTERR_PIPE, LVOUT_ERROR); winApp.Process.Run(); /* CChooseFont.Create(&winApp);*/ return; } /******************************************************************** * Class: CFileDlg. * * Purpose: A CFileDlgBase for Open/Save dlg boxes. * * Revisions: * ********************************************************************/ CFileDlg::CFileDlg(){ } CFileDlg::~CFileDlg(){ } bool CFileDlg::Open(CWindow * pWindow, char * pszFileName, DWORD nMaxFile, int fileflag){ switch(fileflag){ // Project file. case PRJ_FILE: SetData(prjFilter, prjDefExt, singleFileOpen); break; // Add multiple files to project. case ADD_SRC_FILE: Reset(); SetTitle("Add files to project"); nMaxFile = 2048; SetFilterIndex(1); SetData(srcFilter, srcDefExt, multipleFileOpen); break; default: // SRC_FILE SetData(defFilter, srcDefExt, singleFileOpen); SetFilterIndex(1); break; } return OpenFileName(pWindow, pszFileName, nMaxFile); } bool CFileDlg::Save(CWindow * pWindow, char * pszFileName, DWORD nMaxFile, int fileflag){ Reset(); switch(fileflag){ case SRC_FILE: SetData(defFilter, srcDefExt, fileSave); SetFilterIndex(1); break; default: // PRJ_FILE SetData(prjFilter, prjDefExt, fileSave); break; } return SaveFileName(pWindow, pszFileName, nMaxFile); } /******************************************************************** * Class: CPreferencesDlg. * * Purpose: * * Revisions: * ********************************************************************/ CPreferencesDlg::CPreferencesDlg(){ } CPreferencesDlg::~CPreferencesDlg(){ } int CPreferencesDlg::Create(void){ return CreateModal(&winApp, IDD_PREFERENCES, (LPARAM) this); } LRESULT CALLBACK CPreferencesDlg::CDlgProc(UINT Message, WPARAM wParam, LPARAM lParam){ switch(Message){ case WM_INITDIALOG: return OnInitDialog((HWND) wParam, lParam); case WM_NOTIFY: OnNotify((int) wParam, (LPNMHDR) lParam); break; case WM_COMMAND: OnCommand(HIWORD(wParam), LOWORD(wParam), (HWND) lParam); break; case WM_CLOSE: EndDlg(0); break; } return FALSE; } BOOL CPreferencesDlg::OnInitDialog(HWND, LPARAM){ // Tab control handle and TCITEM. _hWndTab = ::GetDlgItem(_hWnd, IDC_PREF_TABS); tcitem.mask = TCIF_TEXT | TCIF_PARAM; // Insert tabs. HWND hwndChild = EnvDlg.Create(this, IDD_ENVIRON, NULL, (long) NULL); tcitem.pszText = "Environment"; tcitem.lParam = (long) &EnvDlg; ::SendMessage(_hWndTab, TCM_INSERTITEM, 0, (LPARAM)&tcitem); SetChildPosition(hwndChild); /* tcitem.pszText = "General"; tcitem.lParam = (long) NULL; ::SendMessage(_hWndTab, TCM_INSERTITEM, 1, (LPARAM)&tcitem); tcitem.pszText = "Find in files"; tcitem.lParam = (long) NULL; ::SendMessage(_hWndTab, TCM_INSERTITEM, 2, (LPARAM)&tcitem);*/ // Show the dialog and default pane. Show(); EnvDlg.Show(); EnvDlg.SetFocus(); return TRUE; } BOOL CPreferencesDlg::OnCommand(WORD, WORD wID, HWND){ switch (wID){ case IDOK: EnvDlg.OnCommand(0, wID, 0); EndDlg(IDOK); return TRUE; case IDCANCEL: EndDlg(IDCANCEL); return FALSE; case IDAPPLY: EnvDlg.OnCommand(0, wID, 0); return TRUE; } return FALSE; } BOOL CPreferencesDlg::EndDlg(int nResult){ EnvDlg.EndDlg(0); EnvDlg.bIsVisible = false; if (_hWnd){ BOOL result = ::EndDialog(_hWnd, nResult); _hWnd = 0; return result; } return false; } /******************************************************************** * Class: CEnvDlg. * * Purpose: * * Revisions: * ********************************************************************/ CEnvDlg::CEnvDlg(){ } CEnvDlg::~CEnvDlg(){ } LRESULT CALLBACK CEnvDlg::CDlgProc(UINT Message, WPARAM wParam, LPARAM lParam){ switch(Message){ case WM_INITDIALOG: return OnInitDialog((HWND) wParam, lParam); case WM_COMMAND: OnCommand(HIWORD(wParam), LOWORD(wParam), (HWND) lParam); break; } return FALSE; } BOOL CEnvDlg::OnInitDialog(HWND, LPARAM){ bIsVisible = false; bModified = false; /* Get control handles */ hApply = ::GetDlgItem(_pParent->_hWnd, IDAPPLY); hSetCcBin = GetItem(IDC_SET_CCBIN); hCcBinDir = GetItem(IDC_CCBIN); hBrowseCc = GetItem(IDC_BROWSE_CC); hSetCmdBin = GetItem(IDC_SET_CMDBIN); hCmdBinDir = GetItem(IDC_CMDBIN); hBrowseCmd = GetItem(IDC_BROWSE_CMD); hAutoexec = GetItem(IDC_AUTOEXEC); hEnvView = GetItem(IDC_ENV_VIEW); if (winApp.bSetCcEnv) ::SendMessage(hSetCcBin, BM_SETCHECK, BST_CHECKED, 0); if (winApp.bSetCmdEnv) ::SendMessage(hSetCmdBin, BM_SETCHECK, BST_CHECKED, 0); if (winApp.bSetDefEnv) ::SendMessage(hAutoexec, BM_SETCHECK, BST_CHECKED, 0); SetItemText(hCcBinDir, winApp.szCcBinDir); SetItemText(hCmdBinDir, winApp.szCmdBinDir); SetEnvText(); /* hCcIncDir = GetItem(IDC_CC_INCDIR); SetItemText(hCcIncDir, winApp.includeDir);*/ bIsVisible = true; return TRUE; } BOOL CEnvDlg::OnCommand(WORD wNotifyCode, WORD wID, HWND){ char directory[MAX_PATH]; switch (wID){ case IDC_BROWSE_CC: if (winApp.ShellDlg.BrowseForFolder(&winApp, directory, "Browse", BIF_RETURNONLYFSDIRS)){ SetItemText(hCcBinDir, directory); } return TRUE; case IDC_BROWSE_CMD: if (winApp.ShellDlg.BrowseForFolder(&winApp, directory, "Browse", BIF_RETURNONLYFSDIRS)){ SetItemText(hCmdBinDir, directory); } return TRUE; case IDOK: winApp.bSetCcEnv = (BST_CHECKED==::SendMessage(hSetCcBin, BM_GETCHECK, 0, 0)); winApp.bSetCmdEnv = (BST_CHECKED==::SendMessage(hSetCmdBin, BM_GETCHECK, 0, 0)); winApp.bSetDefEnv = (BST_CHECKED==::SendMessage(hAutoexec, BM_GETCHECK, 0, 0)); GetItemText(hCcBinDir, winApp.szCcBinDir, MAX_PATH); GetItemText(hCmdBinDir, winApp.szCmdBinDir, MAX_PATH); // GetItemText(hCcIncDir, winApp.includeDir, MAX_PATH); if (bModified) winApp.SetEnv(); return TRUE; case IDCANCEL: return FALSE; case IDAPPLY: if (bModified){ winApp.bSetCcEnv = (BST_CHECKED==::SendMessage(hSetCcBin, BM_GETCHECK, 0, 0)); winApp.bSetCmdEnv = (BST_CHECKED==::SendMessage(hSetCmdBin, BM_GETCHECK, 0, 0)); winApp.bSetDefEnv = (BST_CHECKED==::SendMessage(hAutoexec, BM_GETCHECK, 0, 0)); GetItemText(hCcBinDir, winApp.szCcBinDir, MAX_PATH); GetItemText(hCmdBinDir, winApp.szCmdBinDir, MAX_PATH); winApp.SetEnv(); SetEnvText(); bModified = false; ::EnableWindow(hApply, false); } return TRUE; default: if (bIsVisible && !bModified){ switch(wNotifyCode){ case EN_CHANGE: case BN_CLICKED: bModified = true; ::EnableWindow(hApply, true); return TRUE; } } break; } return FALSE; } void CEnvDlg::SetEnvText(void){ if (g_vm_path){ char * text = (char *) malloc(strlen(g_vm_path)+20); // 10 lines max. char * start = text; char * parse = g_vm_path; while (*parse){ if (*parse == ';'){ // Change ';' into CR/LF. *text = '\r'; text++; *text = '\n'; text++; parse++; }else if (*parse == '='){ // Rewind buffer. text = start; parse++; }else{ // Copy one char. *text = *parse; text++; parse++; } } *text = '\0'; SetItemText(hEnvView, start); free(start); } } /******************************************************************** * Class: CGrepDlg. * * Purpose: * * Revisions: * ********************************************************************/ CGrepDlg::CGrepDlg(){ *findWhat = '\0'; *gDir = '\0'; } CGrepDlg::~CGrepDlg(){ } int CGrepDlg::Create(void){ return CreateModal(&winApp, IDD_GREP, (LPARAM) this); } LRESULT CALLBACK CGrepDlg::CDlgProc(UINT Message, WPARAM wParam, LPARAM lParam){ switch(Message){ case WM_INITDIALOG: return OnInitDialog((HWND) wParam, lParam); case WM_COMMAND: OnCommand(HIWORD(wParam), LOWORD(wParam), (HWND) lParam); break; case WM_CLOSE: EndDlg(0); break; } return FALSE; } BOOL CGrepDlg::OnInitDialog(HWND, LPARAM){ hFindWhat = GetItem(IDC_FINDWHAT); hgDir = GetItem(IDC_GFILTER); SetItemText(hFindWhat, findWhat); SetItemText(hgDir, gDir); // Show the dialog and default pane. Show(); return TRUE; } BOOL CGrepDlg::OnCommand(WORD, WORD wID, HWND){ switch (wID){ case IDOK: GetItemText(hFindWhat, findWhat, sizeof(findWhat)); GetItemText(hgDir, gDir, sizeof(gDir)); FindInFiles(findWhat, gDir); return TRUE; case IDCANCEL: EndDlg(IDCANCEL); return FALSE; } return FALSE; } void CGrepDlg::FindInFiles(char * findWhat, char * fileFilter){ if (!findWhat || !fileFilter || winApp.Process.isRunning()) return; winApp.Report.Clear(); winApp.Report.Append("Grep search...", LVOUT_NORMAL); winApp.Process.AddTask("grep -G -n -H ", OUTERR_PIPE, LVOUT_ERROR); winApp.Process.CmdCat(findWhat); winApp.Process.CmdCat(" "); winApp.Process.CmdCat(fileFilter); winApp.Process.Run(); } /******************************************************************** * Functions: WinMain procedure. * * Purpose: Runs the application. * * Revisions: * ********************************************************************/ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ return winApp.Run(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } /******************************************************************** * Class: CWinApp. * * Purpose: Manages the all application. * * Revisions: * ********************************************************************/ CWinApp::CWinApp(){ *iniFileName = '\0'; hmod = NULL; *openFilesDir ='\0'; *projectDir = '\0'; *includeDir = '\0'; bSetCcEnv = false; bSetCmdEnv = false; bSetDefEnv = false; *szCcBinDir = '\0'; *szCmdBinDir = '\0'; firstRun = false; // Child windows dimensions. deltaY = 0; tbarHeight = 26; sbarHeight = 20; tvWidth = 140; lvHeight = 120; hSplitter = 4; vSplitter = 4; } CWinApp::~CWinApp(){ } bool CWinApp::CustomInit(void){ /* Get PATH environment variable */ char * env_path = getenv("PATH"); if (env_path) g_env_path = strdup(env_path); SetName("Visual MinGW", APP_VERSION); MsgBox.SetCaption("Visual MinGW"); IsWinNT(); ReadIniFile("visual-mingw.ini"); hAccel = LoadAccelerators(_hInst, "ACCELS"); hmod = LoadLibrary("SciLexer.DLL"); if (!hmod){ MsgBox.DisplayFatal("Unable to load SciLexer.DLL"); return false; } return true; } bool CWinApp::Release(void){ WriteIniFile(); if (hmod) FreeLibrary(hmod); if (g_env_path) free(g_env_path); return true; } bool CWinApp::ReadIniFile(char * fileName){ ParseCmdLine(iniFileName); strcat(iniFileName, fileName); if (!IniFile.Load(iniFileName)){ /* Create an empty file and fill it */ firstRun = true; MsgBox.DisplayWarning("Visual-MinGW first run !\n" "Step 1: User interface initialization.\n" "Please report bugs to Visual-MinGW home page.\n" "See the Readme text for more information."); FILE * file = fopen(iniFileName, "wb"); if (!file) return false; SaveIniFile(file); fclose(file); return false; } // [General] section IniFile.GetString(openFilesDir, "FilesDirectory", "General" ); IniFile.GetString(projectDir, "ProjectDirectory" ); bSetDefEnv = IniFile.GetInt( "SetDefEnv" ); bSetCmdEnv = IniFile.GetInt( "SetBinDir" ); IniFile.GetString(szCmdBinDir, "BinDir" ); // [Compiler] section IniFile.GetString(includeDir, "IncludeDir", "Compiler" ); bSetCcEnv = IniFile.GetInt( "SetBinDir" ); IniFile.GetString(szCcBinDir, "BinDir" ); SetEnv(); return true; } void CWinApp::SaveIniFile(FILE * file){ // [General] fprintf (file, "\t; Generated automatically by Visual-MinGW.\n"); fprintf (file, "\t ; http://visual-mingw.sourceforge.net/\n"); fprintf (file, "[General]\nSignature = 40"); fprintf (file, "\nFilesDirectory = %s", openFilesDir); fprintf (file, "\nProjectDirectory = %s", projectDir); fprintf (file, "\nTvWidth = %d", tvWidth); fprintf (file, "\nLvHeight = %d", lvHeight); fprintf (file, "\nSetDefEnv = %d", bSetDefEnv); fprintf (file, "\nSetBinDir = %d", bSetCmdEnv); fprintf (file, "\nBinDir = %s", szCmdBinDir); // [Compiler] fprintf (file, "\n\n[Compiler]\nIncludeDir = %s", includeDir); fprintf (file, "\nSetBinDir = %d", bSetCcEnv); fprintf (file, "\nBinDir = %s", szCcBinDir); } bool CWinApp::WriteIniFile(void){ if (*iniFileName == '\0') return false; FILE * file = fopen(iniFileName, "wb"); if (!file) return false; SaveIniFile(file); fclose(file); IniFile.Close(); return true; } bool CWinApp::SetEnv(void){ // Free previous variable. //getenv("PATH="); // Malloc a buffer. int len = 0; if (bSetCcEnv) len += strlen(winApp.szCcBinDir); if (bSetCmdEnv) len += strlen(winApp.szCmdBinDir); if (bSetDefEnv && g_env_path) len += strlen(g_env_path); g_vm_path = (char *) malloc(len+8); // Copy the environment variable. strcpy(g_vm_path, "PATH="); if (bSetCcEnv && *winApp.szCcBinDir){ strcat(g_vm_path, winApp.szCcBinDir); strcat(g_vm_path, ";"); } if (bSetCmdEnv && *winApp.szCmdBinDir){ strcat(g_vm_path, winApp.szCmdBinDir); strcat(g_vm_path, ";"); } if (bSetDefEnv && g_env_path) strcat(g_vm_path, g_env_path); len = strlen(g_vm_path) - 1; if (g_vm_path[len] == ';') g_vm_path[len] = '\0'; if (putenv(g_vm_path) == -1){ free(g_vm_path); g_vm_path = NULL; return false; } return true; } /******************************************************************** * CWinApp: Create each application's window. ********************************************************************/ bool CWinApp::CreateUI(void){ InitCommonControls(); // Custom values. wc.style = 0; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = NULL; wc.hbrBackground = //NULL; (HBRUSH)(COLOR_INACTIVEBORDER + 1); wc.lpszMenuName = MAKEINTRESOURCE(ID_MENU); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!MainRegisterEx("main_class")) { MsgBox.DisplayFatal("Can't Register Main Window"); return false; } // Custom values. wc.hbrBackground = NULL; wc.lpszMenuName = 0; if(!ChildRegisterEx("child_class")) { MsgBox.DisplayFatal("Can't Register MDI Class"); return false; } // Use a CreateWindowEx like procedure. HWND hwnd = CreateEx( this, // Owner class. 0, mainClass, appName, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, NULL); if(!hwnd) { MsgBox.DisplayFatal("Can't create Main window"); return false; } MsgBox.SetParent(hwnd); // SW_SHOWMAXIMIZED. ::ShowWindow(hwnd, SW_SHOWMAXIMIZED); ::UpdateWindow(hwnd); if (firstRun) FirstRunTest(); firstRun = false; return true; } void CWinApp::FirstRunTest(void){ MsgBox.DisplayWarning("Visual-MinGW first run !\n" "Step 2: You will now set your environment variables.\n" "\"Use default environment variables\" should be checked.\n" "Then Visual-MinGW will try to launch the compiler."); PreferencesDlg.Create(); MsgBox.DisplayWarning("Visual-MinGW first run !\n" "Step 3: Installation checking.\n" "Try to launch rm and gcc.\n" "See \"Main\" or \"Log\" report views for results.\n"); winApp.Report.Clear(); winApp.Report.Append("Testing for first run...", LVOUT_NORMAL); // Put the command line and the run flag in the command stack. winApp.Process.AddTask("gcc -v", OUTERR_PIPE, LVOUT_NORMAL); winApp.Process.AddTask("rm --version", OUTERR_PIPE, LVOUT_NORMAL); winApp.Process.Run(); return; } void CWinApp::CreateToolbar(void){ Toolbar.CreateEx( this, 0, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NORESIZE); Toolbar.AddBitmap(IDB_TOOLBAR, 15); TBBUTTON tbButtons [] = { { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0}, { 0, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}, { 1, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}, { 2, IDM_SAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0}, { 3, IDM_CUT, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}, { 4, IDM_COPY, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}, { 5, IDM_PASTE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0, 0}, 0, 0}, { 6, IDM_UNDO, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0}, { 7, IDM_REDO, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0, 0}, 0, 0} }; int numbutton = sizeof tbButtons/sizeof tbButtons[0]; Toolbar.AddButtons(&tbButtons[0], numbutton); } void CWinApp::CreateSplitter(void){ MainSplitter.Init(&ChildSplitter, &Report, SPLSTYLE_HORZ, lvHeight, SPLMODE_2); ChildSplitter.Init(&Manager, &MdiClient, SPLSTYLE_VERT, tvWidth, SPLMODE_1); // File Manager. Manager.Create(this); // MDI client. CreateMDI(); // ListView. Report.Create(this); } void CWinApp::CreateMDI(void){ MdiClient.Init(3, ID_FIRSTCHILD); MdiClient.CreateEx( this, WS_EX_CLIENTEDGE, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL ); } HWND CWinApp::CreateChild(char * caption, LPVOID lParam){ CChildView * mdiChild = new CChildView; HWND hwnd = mdiChild->CreateEx( &MdiClient, // MUST be an MdiClient *. WS_EX_MDICHILD, MDIS_ALLCHILDSTYLES | WS_CHILD | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_MAXIMIZE, caption, 0, lParam); if (!hwnd) delete mdiChild; return hwnd; } void CWinApp::CreateStatusBar(void){ Sbar.CreateEx( this, 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBARS_SIZEGRIP); int sbWidths[] = {60, 120, -1}; int numparts = sizeof sbWidths/sizeof sbWidths[0]; Sbar.SetParts(numparts, &sbWidths[0]); } void CWinApp::SendCaretPos(int caretPos) { // To display the "Line : xxxx" message, we use our standard msgBuf[256]. sprintf(msgBuf, "Line : %d", caretPos); Sbar.SendMessage(SB_SETTEXT, 0, (LPARAM) msgBuf); return; } /******************************************************************** * CWinApp: Message handling procedures. ********************************************************************/ LRESULT CALLBACK CWinApp::CMainWndProc(UINT Message, WPARAM wParam, LPARAM lParam){ switch(Message){ case WM_CREATE: return OnCreate((LPCREATESTRUCT) lParam); case WM_PAINT: return OnPaint((HDC) wParam); case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam)); case WM_DESTROY: return OnDestroy(); case WM_COMMAND: return OnCommand(wParam, lParam); case WM_CLOSE: return OnClose(); case WM_NOTIFY: return OnNotify((int) wParam, (LPNMHDR) lParam); case WM_LBUTTONDOWN: return OnLButtonDown((short) LOWORD(lParam), (short) HIWORD(lParam), wParam); case WM_MOUSEMOVE: return OnMouseMove((short) LOWORD(lParam), (short) HIWORD(lParam), wParam); case WM_LBUTTONUP: return OnLButtonUp((short) LOWORD(lParam), (short) HIWORD(lParam), wParam); case WM_SETCURSOR: OnSetCursor((HWND) wParam, (UINT) LOWORD(lParam), (UINT) HIWORD(lParam)); return DefWindowProc(_hWnd, Message, wParam, lParam); default: return DefFrameProc(_hWnd, MdiClient.GetId(), Message, wParam, lParam); } return 0; } BOOL CWinApp::OnCreate(LPCREATESTRUCT){ // Toolbar. CreateToolbar(); // Splitter. CreateSplitter(); // Statusbar. CreateStatusBar(); return TRUE; } BOOL CWinApp::OnPaint(HDC){ PAINTSTRUCT ps; BeginPaint(_hWnd, &ps); EndPaint(_hWnd, &ps); return 0; } BOOL CWinApp::OnSize(UINT, int width, int height){ // TreeView and MDI Client delta-height. deltaY = height-sbarHeight-lvHeight-vSplitter-tbarHeight; if (deltaY>3){ Toolbar.SetPosition(0, 0, 0, width, tbarHeight, 0); MainSplitter.SetPosition(0, 0, tbarHeight, width, height-tbarHeight-sbarHeight, 0); Sbar.SetPosition(0, 0, height-sbarHeight, width, sbarHeight, 0); } InvalidateRect(_hWnd, NULL, false); return 0; } BOOL CWinApp::OnDestroy(void){ PostQuitMessage(0); return 0; } BOOL CWinApp::OnClose(void){ if (IDCANCEL == Manager.SaveAll(IDASK)) // Ask to save. return TRUE; // Cancelled by user. ::DestroyWindow(_hWnd); return 0; } BOOL CWinApp::OnNotify(int idCtrl, LPNMHDR notify){ Manager.OnNotify(idCtrl, notify); Report.OnNotify(idCtrl, notify); return 0; } BOOL CWinApp::OnLButtonDown(short xPos, short yPos, UINT){ MainSplitter.OnLButtonDown(_hWnd, xPos, yPos); ChildSplitter.OnLButtonDown(_hWnd, xPos, yPos); return 0; } BOOL CWinApp::OnMouseMove(short xPos, short yPos, UINT){ MainSplitter.OnMouseMove(_hWnd, xPos, yPos); ChildSplitter.OnMouseMove(_hWnd, xPos, yPos); return 0; } BOOL CWinApp::OnLButtonUp(short xPos, short yPos, UINT){ MainSplitter.OnLButtonUp(_hWnd, xPos, yPos); ChildSplitter.OnLButtonUp(_hWnd, xPos, yPos); return 0; } BOOL CWinApp::OnSetCursor(HWND, UINT nHittest, UINT){ if (nHittest == HTCLIENT) { if (MainSplitter.OnSetCursor(_hWnd, 0)){ return 0; }else if (ChildSplitter.OnSetCursor(_hWnd, 0)){ return 0; }else{ ::SetCursor(::LoadCursor(NULL, IDC_ARROW)); } } return 0; } /******************************************************************** * CWinApp: Dispatch command messages. ********************************************************************/ BOOL CWinApp::OnCommand(WPARAM wParam, LPARAM lParam){ int wID = LOWORD(wParam); switch (wID){ /* File Menu */ case IDM_NEW: Manager.FilesView.New(); break; case IDM_OPEN: Manager.OpenFileDialog(); break; case IDM_NEW_PROJECT: Manager.NewProjectDialog(); break; case IDM_OPEN_PROJECT: Manager.OpenProjectDialog(); break; case IDM_SAVE_PROJECT: Manager.SaveProjectFiles(IDYES); break; case IDM_CLOSE_PROJECT: Manager.CloseProject(); break; case IDM_PREFERENCES: PreferencesDlg.Create(); break; case IDM_QUIT: PostMessage(_hWnd, WM_CLOSE, 0, 0); break; /* Find Menu */ case IDM_GREP: GrepDlg.Create(); break; /* Window Menu */ case IDM_CASCADE: PostMessage(MdiClient.GetId(), WM_MDICASCADE, 0, 0); break; case IDM_TILEHORZ: PostMessage(MdiClient.GetId(), WM_MDITILE, MDITILE_HORIZONTAL, 0); break; case IDM_TILEVERT: PostMessage(MdiClient.GetId(), WM_MDITILE, MDITILE_VERTICAL, 0); break; case IDM_ARRANGE: PostMessage(MdiClient.GetId(), WM_MDIICONARRANGE, 0, 0); break; /* Project Menu */ case IDM_NEW_MODULE: Project.NewModuleDlg(); break; case IDM_ADD: Project.AddFiles(); break; case IDM_REMOVE_FILE: Manager.RemoveProjectFile(); break; case IDM_REMOVE_MODULE: Manager.RemoveProjectModule(); break; case IDM_OPTION: Project.OptionsDlg(); break; case IDM_ZIP_SRCS: Project.ZipSrcs(); break; case IDM_EXPLORE: Project.Explore(_hWnd); break; /* Build Menu */ case IDM_BUILD: Project.Build(); break; case IDM_REBUILDALL: Project.RebuildAll(); break; case IDM_RUN_TARGET: Project.RunTarget(); break; case IDM_MKCLEAN: Project.MakeClean(); break; case IDM_MKF_BUILD: Project.BuildMakefile(); break; case IDM_RUN_CMD: winApp.Process.CommandDlg.Create(); break; case IDM_TEST: Main_CmdTest(_hWnd); break; default:{ if (wID >= ID_FIRSTCHILD){ DefFrameProc(_hWnd, MdiClient.GetId(), WM_COMMAND, wParam, lParam); }else{ HWND hChildWindow = (HWND) MdiClient.SendMessage(WM_MDIGETACTIVE); if (hChildWindow) ::SendMessage(hChildWindow, WM_COMMAND, wParam, lParam); } } } return TRUE; } /******************************************************************** * CWinApp: Handles child messages. ********************************************************************/ LRESULT CALLBACK CWinApp::CChildWndProc(CWindow * pWnd, UINT Message, WPARAM wParam, LPARAM lParam){ CChildView * childView = (CChildView *) pWnd; HWND hwndChild = childView->_hWnd; switch(Message){ case WM_CREATE: childView->OnCreate((LPCREATESTRUCT) lParam); break; case WM_SIZE: childView->OnSize(wParam, LOWORD(lParam), HIWORD(lParam)); break; case WM_COMMAND: childView->OnCommand(wParam, lParam); break; case WM_DESTROY: childView->OnDestroy(); break; case WM_CLOSE: if (childView->OnClose()){ MdiClient.SendMessage(WM_MDIDESTROY,(WPARAM) hwndChild, 0); } return true; case WM_NOTIFY: childView->OnNotify((int) wParam, (LPNMHDR) lParam); break; case WM_SETFOCUS: childView->OnSetFocus((HWND) wParam); break; case WM_MDIACTIVATE: childView->OnActivate((HWND) wParam, (HWND) lParam); break; } return DefMDIChildProc(hwndChild, Message, wParam, lParam); } /******************************************************************** * Class: CChildView. * * Purpose: MDI child window class. * * Revisions: * ********************************************************************/ CChildView::CChildView(){ modified = false; } CChildView::~CChildView(){ } bool CChildView::OnCreate(LPCREATESTRUCT){ CFileItem * file = (CFileItem *) GetLong(GWL_USERDATA); // Create Scintilla Editor Control. HWND hwnd = Editor.CreateEx( this, 0, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL); if (!hwnd) return false; // @@TODO need to manage creation failure. // Set window handles file->pMdiChild = this; // Load a file if there is one to load. Editor.LoadFile(file); return true; } bool CChildView::OnSize(UINT wParam, int width, int height){ if(wParam != SIZE_MINIMIZED){ Editor.SetPosition(0, 0, 0, width, height, 0); } return true; } BOOL CChildView::OnClose(void){ if (modified){ int decision = MsgBox.AskToSave(true); switch (decision){ case IDCANCEL: return FALSE; case IDYES: CmdSave(); break; } } return TRUE; } BOOL CChildView::OnDestroy(void){ CFileItem * file = (CFileItem*) GetLong(GWL_USERDATA); if (file){ if (!file->isInProject){ // A simple file. winApp.Manager.FilesView.CloseFile(file); }else{ // A project one. file->pMdiChild = NULL; //modified = false; } } return 0; } BOOL CChildView::OnNotify(int, LPNMHDR notify){ SCNotification * notification = (SCNotification *) notify; // Notify Message from Current Editor Control. if (notify->hwndFrom == Editor._hWnd){ switch (notify->code){ case SCN_UPDATEUI: Editor.GetCurrentPos(); winApp.SendCaretPos(Editor.caretPos); break; case SCN_SAVEPOINTREACHED: modified = false; winApp.Sbar.WriteString("", 1); break; case SCN_SAVEPOINTLEFT: modified = true; winApp.Sbar.WriteString(MSG_MODIFIED, 1); break; case SCN_MARGINCLICK: if (notification->margin == 2) Editor.MarginClick(notification->position, notification->modifiers); break; } } return 0; } BOOL CChildView::OnSetFocus(HWND){ CFileItem * file = (CFileItem*) GetLong(GWL_USERDATA); if (!file) return false; // Select corresponding TreeView item. CTreeView * pTreeView = file->pTreeView; if(!pTreeView) return false; pTreeView->SendMessage(TVM_SELECTITEM, (WPARAM)TVGN_CARET, (LPARAM)file->_hItem); // Set Focus on Editor Control. Editor.SetFocus(); // Display "Modified" message or nothing in the Status Bar. winApp.SendCaretPos(Editor.caretPos); if(modified) winApp.Sbar.SendMessage(SB_SETTEXT, 1, (LPARAM) MSG_MODIFIED); else winApp.Sbar.SendMessage(SB_SETTEXT, 1, (LPARAM) ""); int selectedTab = winApp.Manager.SendMessage(TCM_GETCURSEL); if (file->isInProject == true && selectedTab != PROJECT_TAB){ winApp.Manager.SendMessage(TCM_SETCURFOCUS, PROJECT_TAB); }else if (file->isInProject == false && selectedTab != FILES_TAB){ winApp.Manager.SendMessage(TCM_SETCURFOCUS, FILES_TAB); } return 0; } BOOL CChildView::OnActivate(HWND, HWND hwndChildAct){ HMENU hMenu; HMENU hFileMenu; BOOL EnableFlag; HWND hwndMain = winApp._hWnd; hMenu = GetMenu(hwndMain); if(_hWnd == hwndChildAct){ EnableFlag = TRUE; //being activated }else{ EnableFlag = FALSE; //being de-activated } // Menu items. EnableMenuItem(hMenu, 1, MF_BYPOSITION | (EnableFlag ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(hMenu, 3, MF_BYPOSITION | (EnableFlag ? MF_ENABLED : MF_GRAYED)); // Sub-menu items. hFileMenu = GetSubMenu(hMenu, 0); EnableMenuItem(hFileMenu, IDM_SAVE, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(hFileMenu, IDM_SAVEAS, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED)); hFileMenu = GetSubMenu(hMenu, 2); EnableMenuItem(hFileMenu, IDM_FIND, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(hFileMenu, IDM_REPLACE, MF_BYCOMMAND | (EnableFlag ? MF_ENABLED : MF_GRAYED)); DrawMenuBar(hwndMain); return 0; } void CChildView::CmdSave(void){ CFileItem * file = (CFileItem*) GetLong(GWL_USERDATA); if (!file) return; /* Untitled file ? */ if (file->nFileOffset == 0){ CmdSaveAs(); return; } if (!file->isInProject){ // A simple file. Editor.SaveFile(file->szFileName); }else{ // A project one. Project.szDirBuffer[Project.nFileOffset - 1] = '\\'; strcpy(&Project.szDirBuffer[Project.nFileOffset], file->szFileName); Editor.SaveFile(Project.szDirBuffer); Project.szDirBuffer[Project.nFileOffset - 1] = '\0'; } } void CChildView::CmdSaveAs(void){ CFileItem * file = (CFileItem*) GetLong(GWL_USERDATA); if (!file) return; char fileName[MAX_PATH]; if (!winApp.FileDlg.Save(&winApp, fileName, MAX_PATH, SRC_FILE)) //@@ return; // canceled by user ::SetWindowText(_hWnd, fileName); strcpy(file->szFileName, fileName); Editor.SaveFile(file->szFileName); //@@ TODO we need to check for errors } BOOL CChildView::OnCommand(WPARAM wParam, LPARAM){ CFileItem * file = (CFileItem*) GetLong(GWL_USERDATA); if(!file) return false; switch (LOWORD(wParam)){ case IDM_SAVE: CmdSave(); break; case IDM_SAVEAS: CmdSaveAs(); break; case IDM_SAVEALL: winApp.Manager.SaveAll(IDYES); // Silent. break; /* case IDM_CLOSE: PostMessage(pWnd, WM_CLOSE, 0, 0); break; */ // To Scintilla control. case IDM_FIND: EditorDlg.Find(&Editor); break; case IDM_REPLACE: EditorDlg.Replace(&Editor); break; case IDM_CUT: Editor.SendMessage(SCI_CUT); break; case IDM_COPY: Editor.SendMessage(SCI_COPY); break; case IDM_PASTE: Editor.SendMessage(SCI_PASTE); break; case IDM_UNDO: Editor.SendMessage(SCI_UNDO); break; case IDM_REDO: Editor.SendMessage(SCI_REDO); break; case IDM_SELECTALL: Editor.SendMessage(SCI_SELECTALL); break; } return TRUE; } /******************************************************************** * Class: CManager. * * Purpose: * * Revisions: * ********************************************************************/ CManager::CManager(){ } CManager::~CManager(){ } void CManager::OpenFileDialog(void){ CFileItem * file = new CFileItem; /* Show the "Open file" dialog */ winApp.FileDlg.Reset(); winApp.FileDlg.SetInitialDir(winApp.openFilesDir); if(!winApp.FileDlg.Open(&winApp, file->szFileName, MAX_PATH, SRC_FILE)){ delete file; return; // canceled by user } /* Get file information */ file->nFileExtension = winApp.FileDlg.GetFileExtension(); file->nFileOffset = winApp.FileDlg.GetFileOffset(); GetFileType(file); // Copy file directory. strncpy(winApp.openFilesDir, file->szFileName, (file->nFileOffset - 1)); winApp.openFilesDir[file->nFileOffset-1] = '\0'; /* Load the file */ if(!OpenFile(file)){ delete file; MsgBox.DisplayString("This file is already opened."); } } bool CManager::OpenFile(CFileItem * file){ if (!file) return false; if (!file->isInProject){ if (!FilesView.OpenFile(file)) return false; }else{ if (!ProjectView.OpenFile(file)) return false; } return true; } bool CManager::NewProjectDialog(void){ if(IDYES == Project.CloseDecision()) CloseProject(); char fileName[MAX_PATH]; WORD fileOffset; *fileName = '\0'; if (!winApp.FileDlg.Save(&winApp, fileName, MAX_PATH, PRJ_FILE)){ return false; // canceled by user } // Copy prj file's directory. fileOffset = winApp.FileDlg.GetFileOffset(); ProjectView.CreateRoot("Project"); if (!Project.New(fileName, fileOffset)){ ProjectView.DestroyRoot(); ProjectView.DestroyList(); return false; } return true; } bool CManager::OpenProjectDialog(void){ if(IDYES == Project.CloseDecision()) CloseProject(); char fileName[MAX_PATH]; WORD offset; *fileName = '\0'; // Load default values. winApp.FileDlg.Reset(); winApp.FileDlg.SetInitialDir(winApp.projectDir); if (!winApp.FileDlg.Open(&winApp, fileName, MAX_PATH, PRJ_FILE)){ return false; // canceled by user } // Copy project file's directory. offset = winApp.FileDlg.GetFileOffset(); // Initialize project tree view. ProjectView.CreateRoot(fileName+offset); if (!Project.Open(fileName, offset)){ ProjectView.DestroyRoot(); ProjectView.DestroyList(); return false; } return true; } bool CManager::CloseProject(void){ return ProjectView.Close(); } void CManager::RemoveProjectFile(void){ ProjectView.RemoveFile(); } void CManager::RemoveProjectModule(void){ ProjectView.RemoveModule(); } int CManager::SaveProjectFiles(int decision){ return ProjectView.SaveAll(decision); } int CManager::SaveAll(int decision){ /* Save open files ? */ decision = FilesView.SaveAll(decision); /* Save project files ? */ decision = ProjectView.SaveAll(decision); return decision; } void CManager::CreateImageList(void){ // Create an empty image list. ImgList.Create(16, 16, ILC_COLORDDB|ILC_MASK, 8, 1); // Load treeview bmp and add it to the image list. CBitmap tvBitmap; tvBitmap.Load(this, IDB_TREEVIEW); ImgList.AddMasked(&tvBitmap, RGB(255,0,255)); // We no longer need treeview bmp. tvBitmap.Destroy(); } void CManager::Create(CWindow * pParent){ // Create the Tab Control. CreateEx( pParent, WS_EX_CLIENTEDGE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TCS_BOTTOM | TCS_FOCUSNEVER); // Give it the default font, create tabs, select first one and show the control. SendMessage(WM_SETFONT, (long) GetStockObject(DEFAULT_GUI_FONT), 0); InsertItem(FILES_TAB, TCIF_TEXT, 0, 0, "Files", 16, 0, 0); InsertItem(PROJECT_TAB, TCIF_TEXT, 0, 0, "Project", 16, 0, 0); Show(); // Create an Image list and then the Project TreeView. CreateImageList(); ProjectView.Create(this, &ImgList); SetItem_Param(PROJECT_TAB, (long) &ProjectView); FilesView.Create(this, &ImgList); SetItem_Param(FILES_TAB, (long) &FilesView); } bool CManager::SetPosition(HWND, int x, int y, int width, int height, UINT){ /* Overwrites CTabCtrl::SetPosition() so that all child windows are also resized */ // Tab Control. ::SetWindowPos(_hWnd, 0, x, y, width, height, 0); // Child windows. RECT Rect; ::GetClientRect(_hWnd, &Rect); ProjectView.SetPosition(0, Rect.top +5, Rect.left +5, Rect.right-10, Rect.bottom-30, 0); FilesView.SetPosition(0, Rect.top +5, Rect.left +5, Rect.right-10, Rect.bottom-30, 0); return true; } BOOL CManager::OnNotify(int, LPNMHDR notify){ // Dispatch messages. switch (notify->code){ // Tab Control. case TCN_SELCHANGING: OnSelChanging(notify); break; case TCN_SELCHANGE: OnSelChange(notify); break; // TreeView. case TVN_SELCHANGED: Tv_OnSelchanged((LPNMTREEVIEW) notify); break; } return TRUE; } void CManager::OnSelChanging(LPNMHDR notify){ if (_hWnd == notify->hwndFrom){ CTreeView * pTreeView = (CTreeView *) GetItem_Param(GetCurSel()); if (pTreeView){ pTreeView->Hide(); } } } void CManager::OnSelChange(LPNMHDR notify){ if (_hWnd == notify->hwndFrom){ CTreeView * pTreeView = (CTreeView *) GetItem_Param(GetCurSel()); if (pTreeView){ pTreeView->Show(); } } } void CManager::Tv_OnSelchanged(LPNMTREEVIEW notify){ // Get lParam of current tree item. CFileItem * file = (CFileItem *) notify->itemNew.lParam; if (file){ CChildView * pMdiChild = (CChildView *) file->pMdiChild; if(pMdiChild){ // An editor, focus it. ::SetFocus((HWND) pMdiChild->_hWnd); }else{ // No editor, the item is part of a project. Project.SwitchCurrentDir(); winApp.CreateChild(file->szFileName, file); } } } /******************************************************************** * Class: CFilesView. * * Purpose: Open files TreeView. * * Revisions: * ********************************************************************/ CFilesView::CFilesView(){ hRoot = NULL; } CFilesView::~CFilesView(){ } void CFilesView::New(void){ CFileItem * file = new CFileItem; if(!winApp.Manager.OpenFile(file)){ delete file; MsgBox.DisplayString("Untitled file already exist."); } } bool CFilesView::OpenFile(CFileItem * file){ if (!file) return false; int listAction; char * fileName = file->szFileName + file->nFileOffset; /* Untitled file ? */ if (file->nFileOffset == 0){ //@@TODO add a counter to get Untitled01, 02, etc... strcpy(file->szFileName, "Untitled"); } /* Check if this file is already opened */ listAction = InsertSorted_New(file); if (listAction == FILE_FOUND){ /* Focus the editor window */ CFileItem * currentFile = (CFileItem *) GetCurrent(); if (currentFile){ CMDIChild * pMdiChild = currentFile->pMdiChild; if (pMdiChild) pMdiChild->SetFocus(); } return false; } /* Create the editor window */ if (!winApp.CreateChild(file->szFileName, file)){ MsgBox.DisplayFatal("Can't create child window"); return false; } // Note: A WM_SETFOCUS message will be send to the child window. /* Append the file to the list */ InsertLast(file); /* Create a Tree View item */ file->_hItem = CreateItem( hRoot, //@@ use a GetRootItem() ? TVI_LAST, file->type, fileName, (LPARAM) file); file->pTreeView = this; return true; } void CFilesView::CloseFile(CFileItem * file){ SendMessage(TVM_DELETEITEM, 0, (LPARAM) file->_hItem); Destroy(file); } int CFilesView::SaveAll(int decision){ if (decision == IDNO || decision == IDCANCEL) return decision; CFileItem * file = (CFileItem*) First(); while (file){ if (file->pMdiChild){ CChildView * childView = (CChildView *) file->pMdiChild; /* Modified ? */ if (childView->modified){ /* Ask ? */ if (decision == IDASK){ decision = MsgBox.AskToSave(true); // Cancel button. if (decision != IDYES) return decision; // IDNO or IDCANCEL. } childView->CmdSave(); } } file = (CFileItem*) Next(); } return decision; } HWND CFilesView::Create(CWindow * pParent, CImageList * imgList){ // Create TreeView. CreateEx( pParent, WS_EX_CLIENTEDGE, WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TVS_EDITLABELS | TVS_HASLINES | TVS_HASBUTTONS, 0, (void*) 12); // Assign the image list to the treeview control. SendMessage(TVM_SETIMAGELIST, (long)TVSIL_NORMAL, (long) imgList->GetId()); hRoot = CreateItem(TVI_ROOT, TVI_LAST, WORKSPACE, "Workspace", 0); return _hWnd; } /******************************************************************** * Class: CProjectView. * * Purpose: Project TreeView. * * Revisions: * ********************************************************************/ CProjectView::CProjectView(){ hRoot = NULL; } CProjectView::~CProjectView(){ } CFileItem * CProjectView::NewFile(char * name){ CFileItem * current = (CFileItem *) GetCurrent(); CFileItem * srcFile = new CFileItem; // Copy directory name. if (current){ strncpy(srcFile->szFileName, current->szFileName, current->nFileOffset); srcFile->nFileOffset = current->nFileOffset; }else{ // No files in the project yet, use makefile directory. strcpy(srcFile->szFileName, Project.Makefile.mkfDir); srcFile->nFileOffset = strlen(srcFile->szFileName)+1; } srcFile->szFileName[srcFile->nFileOffset - 1] = '\\'; // Append file name. strcpy(&srcFile->szFileName[srcFile->nFileOffset], name); //MsgBox.DisplayString(srcFile->szFileName); if (::CheckFile(srcFile)){ ::GetFileType(srcFile); srcFile->isInProject = true; HANDLE hFile; hFile = ::CreateFile(srcFile->szFileName, 0, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_ARCHIVE, NULL); if (hFile != INVALID_HANDLE_VALUE){ CloseHandle(hFile); // Try to add new file to the project. if(OpenFile(srcFile)){ Project.modified = true; return srcFile; } } } delete srcFile; return NULL; } bool CProjectView::OpenFile(CFileItem * file){ if (!file) return false; int listAction; char * fileName = file->szFileName + file->nFileOffset; /* Check if this file is already opened */ listAction = InsertSorted_New(file); if (listAction == FILE_FOUND){ /* Focus the editor window */ CFileItem * currentFile = (CFileItem *) GetCurrent(); if (currentFile){ CMDIChild * pMdiChild = currentFile->pMdiChild; if (!pMdiChild){ /* Create a child window */ Project.SwitchCurrentDir(); winApp.CreateChild(file->szFileName, file); }else{ pMdiChild->SetFocus(); } } return false; } file->_hDirItem = hRoot; CreateSubDirItem(file); if (listAction == EMPTY_LIST){ InsertFirst(file); }else if (listAction == INSERT_FIRST){ InsertFirst(file); }else if (listAction == INSERT_LAST){ InsertLast(file); }else if (listAction == INSERT_BEFORE){ InsertBefore(file); }else if (listAction == INSERT_AFTER){ InsertAfter(file); } /* Create the file icon */ file->_hItem = CreateItem( file->_hDirItem, TVI_SORT, file->type, fileName, (LPARAM) file); file->pTreeView = this; /* Create an editor view */ if (file->show){ winApp.CreateChild(file->szFileName, file); } return true; } bool CProjectView::Close(){ if (Project.NoProject()) return false; int decision = IDASK; decision = SaveAll(decision); if (decision == IDCANCEL) return false; // Parse the list while there's a next node. CFileItem * srcFile = (CFileItem *) First(); while(srcFile){ DestroyFile(srcFile, decision); srcFile = (CFileItem *) Next(); } Project.loaded = false; DestroyRoot(); DestroyList(); winApp.Report.Clear(); return true; } void CProjectView::RemoveFile(void){ if (Project.NoProject()) return; CFileItem * srcFile = (CFileItem *) GetSelectedItemParam(); if (srcFile){ if (srcFile->pMdiChild) DestroyFile(srcFile); TreeView_DeleteItem(_hWnd, srcFile->_hItem); if (!TreeView_GetChild(_hWnd, srcFile->_hDirItem)) TreeView_DeleteItem(_hWnd, srcFile->_hDirItem); /* else TreeView_SelectItem(_hWnd, srcFile->_hDirItem);*/ Destroy(srcFile); // we need to save prj file before exit. //@@ Project.CloseFile, modified & buildMakefile should be private. Project.modified = true; Project.buildMakefile = true; }else{ MsgBox.DisplayWarning("No project file selected"); } } void CProjectView::RemoveModule(void){ if (Project.NoProject()) return; CFileItem * srcFile = (CFileItem *) GetSelectedItemParam(); CFileItem * otherFile; if (srcFile){ if (srcFile->prev){ otherFile = (CFileItem *) srcFile->prev; if (otherFile->nFileExtension != 0){ if (0 == strnicmp(srcFile->szFileName, otherFile->szFileName, otherFile->nFileExtension)){ if (otherFile->pMdiChild) DestroyFile(otherFile); TreeView_DeleteItem(_hWnd, otherFile->_hItem); Destroy(otherFile); } } } if (srcFile->next){ otherFile = (CFileItem *) srcFile->next; if (otherFile->nFileExtension != 0){ if (0 == strnicmp(srcFile->szFileName, otherFile->szFileName, otherFile->nFileExtension)){ if (otherFile->pMdiChild) DestroyFile(otherFile); TreeView_DeleteItem(_hWnd, otherFile->_hItem); Destroy(otherFile); } } } if (srcFile->pMdiChild) DestroyFile(srcFile); TreeView_DeleteItem(_hWnd, srcFile->_hItem); Destroy(srcFile); // we need to save prj file before exit. //@@ Project.CloseFile, modified & buildMakefile should be private. Project.modified = true; Project.buildMakefile = true; }else{ MsgBox.DisplayWarning("No project file selected"); } } int CProjectView::DestroyFile(CFileItem * file, int decision){ if (file && file->pMdiChild){ CChildView * pMdiChild = (CChildView *) file->pMdiChild; if (pMdiChild->modified && decision != IDNO){ // Ask ? if (decision == IDASK){ decision = MsgBox.AskToSave(true); // (Cancel button) if (decision == IDCANCEL) return decision; } pMdiChild->CmdSave(); } if (pMdiChild->_hWnd) // have an editor window, so destroy it. winApp.MdiClient.SendMessage(WM_MDIDESTROY, (WPARAM)pMdiChild->_hWnd, 0); } return decision; } int CProjectView::SaveAll(int decision){ if (!Project.loaded) return 0; if (decision == IDNO || decision == IDCANCEL) return decision; CFileItem * file = (CFileItem*) First(); while (file){ if (file->pMdiChild){ CChildView * childView = (CChildView *) file->pMdiChild; /* Modified ? */ if (childView->modified){ /* Ask ? */ if (decision == IDASK){ decision = MsgBox.AskToSave(true); // Cancel button. if (decision != IDYES) return decision; // IDNO or IDCANCEL. } childView->CmdSave(); } } file = (CFileItem*) Next(); } if (Project.modified) return Project.SavePrjFile(decision); return decision; } bool CProjectView::CreateSubDirItem(CFileItem * file){ /* Initialize _hDirItem and get a pointer to current file */ file->_hDirItem = hRoot; CFileItem * currentFile = (CFileItem *) GetCurrent(); /* See if our new file is in the same directory than current file */ if (currentFile){ // There's some files in the list. if (file->nFileOffset == currentFile->nFileOffset){ // Same directory length, we may have found the directory. if (0 == strnicmp(file->szFileName, currentFile->szFileName, currentFile->nFileOffset)){ /* We have found the directory, then copy _hDirItem */ file->_hDirItem = currentFile->_hDirItem; return true; } } } /* We need to parse the tree view and create directory icons */ char * parse = file->szFileName; if (*parse == '.' && *(parse+1) == '\\'){ /* This is a valid relative path */ char dir[MAX_PATH]; strcpy(dir, file->szFileName); parse = dir+2; char * dirStart; HTREEITEM hParent = hRoot; HTREEITEM hFound; if (*parse){ for ( ; ; ){ /* Found each backslash */ dirStart = parse; parse = strchr(parse, '\\'); if (!parse) break; // No more backslash. else if (parse == dirStart) return false; // Avoids an endless loop. *parse = '\0'; /* Find the directory */ hFound = FindDirItem(hParent, dirStart); if (!hFound){ /* Append a new directory icon */ hParent = CreateDirItem(hParent, dirStart); } parse++; } } file->_hDirItem = hParent; } return true; } HTREEITEM CProjectView::FindDirItem(HTREEITEM hItem, char * dir){ char buffer[_MAX_DIR]; HTREEITEM hNext = TreeView_GetChild(_hWnd, hItem); while (hNext){ _TvItem.hItem = hNext; _TvItem.mask = TVIF_HANDLE | TVIF_TEXT; _TvItem.pszText = buffer; _TvItem.cchTextMax = _MAX_DIR; if (TreeView_GetItem(_hWnd, &_TvItem)){ if (!stricmp(dir, buffer)) return hNext; } hNext = TreeView_GetNextSibling(_hWnd, hNext); } return NULL; } HWND CProjectView::Create(CWindow * pParent, CImageList * imgList){ // Create TreeView. CreateEx( pParent, WS_EX_CLIENTEDGE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TVS_EDITLABELS | TVS_HASLINES | TVS_HASBUTTONS); // Assign the image list to the treeview control. SendMessage(TVM_SETIMAGELIST, (long)TVSIL_NORMAL, (long) imgList->GetId()); return _hWnd; } void CProjectView::CreateRoot(char * projectName){ _pParent->SendMessage(TCM_SETCURFOCUS, 1, 0); // Create Root Item. hRoot = CreateItem(TVI_ROOT, TVI_LAST, PROJECT, projectName, 0); SendMessage(TVM_EXPAND, (long) TVE_EXPAND, (long) hRoot); } void CProjectView::DestroyRoot(void){ TreeView_DeleteItem(_hWnd, hRoot); hRoot = 0; _pParent->SendMessage(TCM_SETCURFOCUS, 0, 0); } HTREEITEM CProjectView::CreateDirItem(HTREEITEM hParent, char * dir){ return CreateItem(hParent, TVI_SORT, DIR, dir, 0); } CFileItem * CProjectView::FindFile(char * szFileName){ if (!szFileName || !*szFileName) return NULL; char * currentFile; bool stripDir = true; if (*szFileName == '.') stripDir = false; // Get the current node. CFileItem * currentNode = (CFileItem *) GetCurrent(); if(!currentNode) return NULL; // The list is empty. currentFile = GetFileName(currentNode, stripDir); int cmpResult = stricmp(szFileName, currentFile); // Compare names to know if we must parse Up // or Down from current node. if (cmpResult == 0){ return currentNode; // Found ! } // Search Up ----------------------------------------------------------------- else if (cmpResult == -1){ // Parse the list while there's a previous node. while (Prev()){ currentNode = (CFileItem *) GetCurrent(); currentFile = GetFileName(currentNode, stripDir); if(!stricmp(szFileName, currentFile)) return currentNode; // Found ! } } // Search Down -------------------------------------------------------------- else if (cmpResult == 1){ // Parse the list while there's a next node. while (Next()){ currentNode = (CFileItem *) GetCurrent(); currentFile = GetFileName(currentNode, stripDir); if(!stricmp(szFileName, currentFile)) return currentNode; // Found ! } } return NULL; } char * CProjectView::GetFileName(CFileItem * currentNode, bool flag){ char * fileName = currentNode->szFileName; if (flag == true){ fileName += currentNode->nFileOffset; } return fileName; } /******************************************************************** * Class: CReport. * * Purpose: * * Revisions: * ********************************************************************/ CReport::CReport(){ } CReport::~CReport(){ } void CReport::Create(CWindow * pParent){ // Create the Tab Control. CreateEx( pParent, WS_EX_CLIENTEDGE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS /*| TCS_BOTTOM*/ | TCS_MULTILINE | TCS_VERTICAL | TCS_FOCUSNEVER); // Give it a smart font, create tabs, select first one and show the control. SendMessage(WM_SETFONT, (long) GetStockObject(DEFAULT_GUI_FONT), 0); InsertItem(REPORT_MAIN_TAB, TCIF_TEXT, 0, 0, "Main", 16, 0, 0); InsertItem(REPORT_LOG_TAB, TCIF_TEXT, 0, 0, "Log", 16, 0, 0); Show(); // Create an Image list and then the Project TreeView. MainList.Create(this); SetItem_Param(REPORT_MAIN_TAB, (long) &MainList); LogList.Create(this); SetItem_Param(REPORT_LOG_TAB, (long) &LogList); } bool CReport::SetPosition(HWND, int x, int y, int width, int height, UINT){ /* Overwrites CTabCtrl::SetPosition() so that all child windows are also resized */ // Tab Control. ::SetWindowPos(_hWnd, 0, x, y, width, height, 0); // Get tab's display area. RECT area; area.left = 0; area.top = 0; area.right = width; area.bottom = height; ::SendMessage(_hWnd, TCM_ADJUSTRECT, FALSE, (LPARAM) &area); area.right -= area.left; area.bottom -= area.top; /* WS_EX_CLIENTEDGE correction */ area.top -= 2; area.right -= 2; // Borders. area.left += 3; area.top += 3; area.right -= 6; area.bottom -= 6; // Child windows. MainList.SetPosition(0, area.left, area.top, area.right, area.bottom, 0); LogList.SetPosition(0, area.left, area.top, area.right, area.bottom, 0); return true; } BOOL CReport::OnNotify(int, LPNMHDR notify){ // Dispatch messages. switch (notify->code){ // Tab Control. case TCN_SELCHANGING: OnSelChanging(notify); break; case TCN_SELCHANGE: OnSelChange(notify); break; // Main list. case NM_DBLCLK: MainList.Lv_OnDbClick((LPNMLISTVIEW) notify); break; } return TRUE; } void CReport::OnSelChanging(LPNMHDR notify){ if (_hWnd == notify->hwndFrom){ CWindow * pWindow = (CWindow *) GetItem_Param(GetCurSel()); if (pWindow){ pWindow->Hide(); } } } void CReport::OnSelChange(LPNMHDR notify){ if (_hWnd == notify->hwndFrom){ CWindow * pWindow = (CWindow *) GetItem_Param(GetCurSel()); if (pWindow){ pWindow->Show(); } } } void CReport::Clear(void){ MainList.Clear(); LogList.Clear(); } bool CReport::Append(char * line, WORD outputFlag){ LogList.Append(line, outputFlag); MainList.Append(line, outputFlag); return true; } /******************************************************************** * Class: CMainList. * * Purpose: * * Revisions: * ********************************************************************/ CMainList::CMainList(){ } CMainList::~CMainList(){ } void CMainList::Create(CWindow * pParent){ CreateEx( pParent, WS_EX_CLIENTEDGE, WS_VISIBLE | WS_CHILD| WS_CLIPCHILDREN | WS_CLIPSIBLINGS | LVS_REPORT); SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_GRIDLINES, LVS_EX_GRIDLINES); SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); // Insert columns. LVCOLUMN lvc; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; lvc.iSubItem = 0; lvc.cx = 35; lvc.pszText = "Line"; SendMessage(LVM_INSERTCOLUMN, 0, (LPARAM) &lvc); lvc.iSubItem = 1; lvc.cx = 70; lvc.pszText = "Unit"; SendMessage(LVM_INSERTCOLUMN, 1, (LPARAM) &lvc); lvc.iSubItem = 2; lvc.cx = 640; lvc.pszText = "Message"; SendMessage(LVM_INSERTCOLUMN, 2, (LPARAM) &lvc); } void CMainList::Lv_OnDbClick(LPNMLISTVIEW lpnmlv){ if (_hWnd == lpnmlv->hdr.hwndFrom){ char lineBuff[256]; *lineBuff = '\0'; char * c = lineBuff; LV_ITEM lvi; lvi.mask = LVIF_TEXT; lvi.iItem = lpnmlv->iItem; lvi.iSubItem = 0; lvi.pszText = lineBuff; lvi.cchTextMax = 256; lvi.lParam = 0; if (!SendMessage(LVM_GETITEMTEXT, lpnmlv->iItem, (long) &lvi)) return; while(*c){ if (!isdigit(*c)) return; c++; } int line = atoi(lineBuff); //MsgBox.DisplayLong((long) line); lvi.iSubItem = 1; if (!SendMessage(LVM_GETITEMTEXT, lpnmlv->iItem, (long) &lvi)) return; CFileItem * item = winApp.Manager.ProjectView.FindFile(lineBuff); if (item && item->isInProject){ CChildView * pMdiChild = (CChildView *) item->pMdiChild; if(pMdiChild){ // An editor, focus it. ::SetFocus((HWND) pMdiChild->_hWnd); }else{ // No editor, the item is part of a project. Project.SwitchCurrentDir(); winApp.CreateChild(item->szFileName, item); } pMdiChild = (CChildView *) item->pMdiChild; if (pMdiChild) pMdiChild->Editor.GotoLine(line-1); } } } bool CMainList::Append(char * line, WORD outputFlag){ int row; *szLine = '\0'; *szUnit = '\0'; *szMsg = '\0'; if (outputFlag == LVOUT_ERROR){ if (!SplitErrorLine(line)) return false; }else if (outputFlag == LVOUT_NORMAL){ strcpy (szMsg, line); }else{ strcpy (szMsg, "Unrecognized outputFlag"); } // Fill in List View columns, first is column 0. LV_ITEM lvi; lvi.mask = LVIF_TEXT; // | LVIF_PARAM; lvi.iItem = 0x7FFF; lvi.iSubItem = 0; lvi.pszText = szLine; lvi.cchTextMax = strlen(lvi.pszText)+1; lvi.lParam = 0; row = SendMessage(LVM_INSERTITEM, 0, (LPARAM) &lvi); // Continue with column 1. lvi.iSubItem = 1; lvi.pszText = szUnit; lvi.cchTextMax = strlen(lvi.pszText)+1; SendMessage(LVM_SETITEMTEXT, (WPARAM)row, (LPARAM)&lvi); // Continue with column 2. lvi.iSubItem = 2; lvi.pszText = szMsg; lvi.cchTextMax = strlen(lvi.pszText)+1; SendMessage(LVM_SETITEMTEXT, (WPARAM)row, (LPARAM)&lvi); // Save last row position lastRow = row+1; return true; } bool CMainList::SplitErrorLine(char * line){ char * chr = line; char * col; // line => [unit]:[line_n°]: [error message] // or => [unit]: [error message] if (!*line) return false; /* Unit */ col = szUnit; for ( ; ; ){ if (!*chr){ /* Not an error line */ //strcpy(szMsg, szUnit); *szUnit = '\0'; return false; }else if (*chr == ':'){ if (*(chr+1) == '\\'){ *col = *chr; col++; chr++; continue; }else{ chr++; break; } } *col = *chr; col++; chr++; } *col = '\0'; /* Line number ? */ col = szLine; if (*chr && isdigit(*chr)){ //@@ *chr=0 ? while (*chr && *chr != ':'){ *col = *chr; col++; chr++; } *col = '\0'; chr++; } /* Message */ col = szMsg; if (isspace(*chr)){ /**col = '>'; col++; *col = ' '; col++;*/ chr++; } while (*chr){ *col = *chr; col++; chr++; } *col = '\0'; return true; } /******************************************************************** * Class: CLogList. * * Purpose: * * Revisions: * ********************************************************************/ CLogList::CLogList(){ } CLogList::~CLogList(){ } void CLogList::Create(CWindow * pParent){ CreateEx( pParent, WS_EX_CLIENTEDGE, WS_CHILD| WS_CLIPCHILDREN | WS_CLIPSIBLINGS | LVS_REPORT | LVS_NOCOLUMNHEADER); SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); // Insert columns. LVCOLUMN lvc; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; lvc.iSubItem = 0; lvc.cx = 100; lvc.pszText = "Message"; SendMessage(LVM_INSERTCOLUMN, 0, (LPARAM) &lvc); } bool CLogList::SetPosition(HWND hInsertAfter, int x, int y, int width, int height, UINT uFlags){ ::SendMessage(_hWnd, WM_SETREDRAW, FALSE, 0); ::SetWindowPos(_hWnd, hInsertAfter, x, y, width, height, uFlags); ::SendMessage(_hWnd, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM((int) width-22, 0)); ::SendMessage(_hWnd, WM_SETREDRAW, TRUE, 0); return true; } bool CLogList::Append(char * line, WORD /*outputFlag*/){ int row; *szMsg = '\0'; /* if (outputFlag != LVOUT_ERROR) return false; */ // Fill in List View columns, first is column 0. LV_ITEM lvi; lvi.mask = LVIF_TEXT; // | LVIF_PARAM; lvi.iItem = 0x7FFF; lvi.iSubItem = 0; lvi.pszText = line; lvi.cchTextMax = strlen(lvi.pszText)+1; lvi.lParam = 0; row = SendMessage(LVM_INSERTITEM, 0, (LPARAM) &lvi); // Save last row position lastRow = row+1; return true; } /******************************************************************** * Class: CFileItem. * * Purpose: Linked List Node for file parameters. * * Revisions: * ********************************************************************/ CFileItem::CFileItem(){ type = U_FILE; *szFileName = '\0'; szFileName[MAX_PATH - 1] = '\0'; // security. nFileOffset = 0; nFileExtension = 0; pTreeView = NULL; _hDirItem = 0; _hItem = 0; pMdiChild = NULL; show = 0; isInProject = false; } CFileItem::~CFileItem(){ } /******************************************************************** * Class: CFileList. * * Purpose: A CList with a dedicated Compare() procedure. * * Revisions: * ********************************************************************/ CFileList::CFileList(){ } CFileList::~CFileList(){ } int CFileList::Compare(CNode *node1, CNode *node2){ return stricmp(((CFileItem *)node1)->szFileName, ((CFileItem *)node2)->szFileName); }