📄 textview.cpp
字号:
// TextView.cpp : implementation file
//
#include "stdafx.h"
#include "Quincy.h"
#include "debugger.h"
#include "TextView.h"
#include "QuincyView.h"
#include "TextDocument.h"
#include "Compiler.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTextView
static const int margin = 1; // margin for breakpoint and program counter carets
static const char breakpointchar = '>'; // breakpoint margin displaycharacter
IMPLEMENT_DYNCREATE(CTextView, CEditorView)
CTextView::CTextView()
{
}
CTextView::~CTextView()
{
}
BEGIN_MESSAGE_MAP(CTextView, CEditorView)
//{{AFX_MSG_MAP(CTextView)
ON_COMMAND(ID_BUILD, OnBuild)
ON_COMMAND(ID_BUILDALL, OnBuildall)
ON_COMMAND(ID_COMPILE, OnCompile)
ON_COMMAND(ID_EXECUTE, OnRun)
ON_COMMAND(ID_DEBUG_BREAKPOINT, OnDebugBreakpoint)
ON_COMMAND(ID_DEBUG_STEP, OnDebugStep)
ON_COMMAND(ID_DEBUG_STEPTOCURSOR, OnDebugSteptocursor)
ON_UPDATE_COMMAND_UI(ID_BUILD, OnUpdateBuild)
ON_UPDATE_COMMAND_UI(ID_BUILDALL, OnUpdateBuildAll)
ON_UPDATE_COMMAND_UI(ID_COMPILE, OnUpdateCompile)
ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_ALL, OnUpdateFileSaveAll)
ON_COMMAND(ID_DEBUG_STEPOUTOFFUNCTION, OnDebugStepoutoffunction)
ON_WM_CHAR()
ON_WM_TIMER()
ON_WM_LBUTTONDBLCLK()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTextView diagnostics
#ifdef _DEBUG
void CTextView::AssertValid() const
{
CEditorView::AssertValid();
}
void CTextView::Dump(CDumpContext& dc) const
{
CEditorView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CTextView message handlers
void CTextView::OnBuildall()
{
// ----- if a project document is open, send build command to its view
CQuincyView* pView = theApp.GetProjectView();
if (pView != 0)
pView->SendMessage(WM_COMMAND, ID_BUILDALL, 0);
}
void CTextView::OnBuild()
{
// ----- if a project document is open, send build command to its view
CQuincyView* pView = theApp.GetProjectView();
if (pView != 0)
pView->SendMessage(WM_COMMAND, ID_BUILD, 0);
else
DoCompile(true, false);
}
bool CTextView::DoCompile(bool bDoLink, bool bDoExecute, bool bDoStep)
{
CDocument* pDoc = GetDocument();
ASSERT(pDoc != 0);
CString& rstrPath = const_cast<CString&>(pDoc->GetPathName());
if (pDoc->IsModified())
pDoc->OnSaveDocument(rstrPath);
theApp.SaveAllDocuments(true);
// ----- make a copy of the file spec without the extension;
bool isCpp = rstrPath.Right(4).CompareNoCase(".cpp") == 0;
CString strSpec = rstrPath.Left(rstrPath.GetLength()-(isCpp ? 4 : 2));
CString strExeSpec = strSpec + ".exe";
// ---- queue the source and object files for compile/link
theApp.GetCompiler().ClearArrays();
theApp.GetCompiler().AddSourceFile(rstrPath);
if (bDoLink)
theApp.GetCompiler().AddObjectFile(theApp.GetCompiler().MakeObjectFileName(strSpec));
theApp.GetCompiler().ClearErrorLog();
theApp.GetCompiler().BuildTarget(strExeSpec,
(bDoExecute ? (bDoStep ? Compiler::step : Compiler::run) : Compiler::none));
return true;
}
void CTextView::OnCompile()
{
DoCompile(false, false);
}
void CTextView::OnDebugStep()
{
// ----- if a project document is open, send step command to its view
CQuincyView* pView = theApp.GetProjectView();
if (pView != 0)
pView->PostMessage(WM_COMMAND, ID_DEBUG_STEP, 0);
else if (!theApp.StepProgram())
if (!BuildIfNeeded(true))
theApp.DebugProgram(m_strExe, true);
}
void CTextView::OnDebugStepoutoffunction()
{
theApp.StepOut();
}
void CTextView::OnRun()
{
// ----- if a project document is open, send execute command to its view
CQuincyView* pView = theApp.GetProjectView();
if (pView != 0)
pView->DoRun();
else if (!theApp.ExecuteRunningProgram())
if (!BuildIfNeeded(false))
theApp.StartProgram(m_strExe);
}
// --- returns true if build is started meaning delay the execution
// also returns true if no exe and user opts not to build, meaning no execution
// otherwise returns false meaning execution may proceed
bool CTextView::BuildIfNeeded(bool bStep)
{
CDocument* pDoc = GetDocument();
ASSERT(pDoc != 0);
CString& rstrPath = const_cast<CString&>(pDoc->GetPathName());
// ----- make a copy of the file spec with the .EXE extension;
bool isCpp = rstrPath.Right(4).CompareNoCase(".cpp") == 0;
m_strExe = rstrPath.Left(rstrPath.GetLength()-(isCpp ? 4 : 2)) + ".exe";
int rtn;
if (_access(m_strExe, 0) != 0) {
CString strMsg = theApp.GetFileName(m_strExe) + " does not exist. Build?";
if (AfxMessageBox(strMsg, MB_YESNO | MB_ICONQUESTION) == IDYES)
DoCompile(true, true, bStep);
return true;
}
if (pDoc->IsModified()) {
CString strMsg = theApp.GetFileName(rstrPath) + " has been modified. Build?";
if ((rtn = AfxMessageBox(strMsg, MB_YESNOCANCEL | MB_ICONQUESTION)) == IDYES) {
DoCompile(true, true, bStep);
return true;
}
else if (rtn == IDCANCEL)
return true;
}
else if (theApp.CompareFileTimes(rstrPath, m_strExe) > 0) {
CString strMsg = theApp.GetFileName(m_strExe) + " out of date. Rebuild?";
if ((rtn = AfxMessageBox(strMsg, MB_YESNOCANCEL | MB_ICONQUESTION)) == IDYES) {
DoCompile(true, true, bStep);
return true;
}
}
return false;
}
// ----- return the document file specification
CString CTextView::SourceCodeFileName()
{
CTextDocument* pDoc = (CTextDocument*)GetDocument();
return pDoc == 0 ? CString() : pDoc->GetPathName();
}
// ----- called to set or clear a breakpoint in this source code file
void CTextView::OnDebugBreakpoint()
{
// ---- get the name of the source code file
CString strFile = GetDocument()->GetPathName();
// ----- get the current line number from the source code file
int nLineno = CurrentLineNumber(); // current line number
theApp.ToggleBreakpoint(strFile, nLineno);
DrawMargins();
}
// --- write a 16 X 15 bitmap into the editor's left margin
// nLine is the window's vertical pixel position
void CTextView::WriteMarginBitmap(int nRow, CBitmap& bm)
{
CDC* pCDC = GetDC();
CDC dcMem;
dcMem.CreateCompatibleDC(pCDC);
CBitmap* pOld = static_cast<CBitmap*>(dcMem.SelectObject(&bm));
dcMem.SetMapMode(pCDC->GetMapMode());
pCDC->BitBlt(0, nRow, 16, 15, &dcMem, 0, 0, SRCCOPY);
dcMem.SelectObject(pOld);
}
// ---- compute the window's zero-based client area pixel position number
// from the one-based text line number
inline int CTextView::RelativeRow(int nLineno)
{
ASSERT(nLineno > 0);
int lno = nLineno - TopLine(); // zero-based line number
int top = TopRow() % m_fontheight;
int y = lno * m_fontheight - top;
return y;
}
void CTextView::OnDraw(CDC* pDC)
{
CEditorView::OnDraw(pDC);
DrawMargins();
}
void CTextView::DrawMargins()
{
PadMargin();
// ---- get the name of the source code file
CString strFile = theApp.GetFileName(SourceCodeFileName());
if (strFile.IsEmpty())
return;
// ----- compute top and bottom lines of the client window
int nLine = TopLine(); // one-based line number
RECT rc;
GetClientRect(&rc);
int nBottomLine = nLine + rc.bottom / m_fontheight; // one-based line number
// --- set flag if this file is the current debugged source code file
bool bSrc = false;
Debugger* pDebugger = theApp.GetDebugger(false);
if (pDebugger != 0) {
const CString* pCurrentSrcFile = pDebugger->CurrentSrcFile();
CString str = theApp.GetFileName(*pCurrentSrcFile);
if (pCurrentSrcFile != 0) {
bSrc = strFile.CompareNoCase(str) == 0;
}
}
// ---- iterate the lines, displaying
// breakpoint margin carets and the program counter cursor bar
do {
bool bPC = (bSrc && nLine == theApp.GetDebugger()->CurrentLineNo()) != false;
if (theApp.IsBreakpoint(strFile, nLine)) {
if (bPC)
SetPCBreakpointDisplay(nLine);
else
SetBreakpointDisplay(nLine, true);
}
else if (bPC)
SetProgramCounterDisplay(nLine, true);
} while (nLine++ < nBottomLine);
}
// ---- set or clear a breakpoint bitmap in the margin
// ------ nLineno is the one-based file line number
void CTextView::SetBreakpointDisplay(int nLineno, bool bOnOff)
{
int nRelativeRow = RelativeRow(nLineno);
CBitmap bm;
bm.LoadBitmap(bOnOff ? IDB_BITMAP4 : IDB_BITMAP3);
WriteMarginBitmap(nRelativeRow, bm);
bm.DeleteObject();
}
// ---- set a breakpoint and pc bitmap in the margin
// ------ nLineno is the one-based file line number
void CTextView::SetPCBreakpointDisplay(int nLineno)
{
int nRelativeRow = RelativeRow(nLineno);
CBitmap bm;
bm.LoadBitmap(IDB_BITMAP5);
WriteMarginBitmap(nRelativeRow, bm);
bm.DeleteObject();
}
// ---- set or clear the program counter cursor in the margin
// ------ nLineno is the zero-based file line number
void CTextView::SetProgramCounterDisplay(int nLineno, bool bOnOff)
{
int nRelativeRow = RelativeRow(nLineno);
CBitmap bm;
bm.LoadBitmap(bOnOff ? IDB_BITMAP2 : IDB_BITMAP3);
WriteMarginBitmap(nRelativeRow, bm);
bm.DeleteObject();
}
void CTextView::OnDebugSteptocursor()
{
if (!theApp.TestProgramChanged()) {
int nLineNo = CurrentLineNumber();
CString strFile = SourceCodeFileName();
if (!theApp.StepTo(strFile, nLineNo))
OnRun();
}
}
void CTextView::OnUpdateBuild(CCmdUI* pCmdUI)
{
pCmdUI->Enable(CanBuild() && (theApp.IsProjectFileLoaded() || IsSourceFile()));
}
void CTextView::OnUpdateBuildAll(CCmdUI* pCmdUI)
{
pCmdUI->Enable(CanBuild() && theApp.IsProjectFileLoaded());
}
void CTextView::OnUpdateCompile(CCmdUI* pCmdUI)
{
pCmdUI->Enable(CanBuild() && IsSourceFile());
}
bool CTextView::CanBuild()
{
Debugger* pDebugger = theApp.GetDebugger(false);
return !theApp.CompileRunning() && pDebugger == 0 && theApp.CanCompile();
}
bool CTextView::IsSourceFile()
{
CTextDocument* pDoc = (CTextDocument*)GetDocument();
ASSERT(pDoc != 0);
return pDoc->IsSourceFile();
}
void CTextView::OnUpdateFileSaveAll(CCmdUI* pCmdUI)
{
pCmdUI->Enable(true);
}
void CTextView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
if (point.x < m_margin)
OnDebugBreakpoint();
else
CEditorView::OnLButtonDblClk(nFlags, point);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -