OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
tracewnd.cpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// ObjectWindows
3// Copyright (c) 1998 by Yura Bidus, All Rights Reserved
4//
5/// \file
6/// Implementation of the private TTraceWindow class.
7//----------------------------------------------------------------------------
8
9#include <owl/pch.h>
10#pragma hdrstop
11
12#include "tracewnd.h"
13#include <owl/opensave.h>
14#include <owl/inputdia.h>
15#include <owl/panespli.h>
16#include <owl/profile.h>
17#include <owl/edit.h>
18#include <owl/listbox.h>
19#include <owl/checklst.h>
20#include <owl/validate.h>
21
22using namespace std;
23using namespace std::filesystem;
24
25namespace owl {
27
28auto GetDiagIniFullFileName_(LPCSTR filename) -> tstring; // Private function defined in "diaginit.cpp".
29
30//-------------------------------------------------------------------------------------------------
31
32class TTraceWindow::TGroupList
33 : public TCheckList
34{
35public:
36
37 TGroupList(TWindow* parent, int id)
38 : TCheckList(parent, id, 0, 0, 0, 0)
39 {}
40
41 void AddItem(const tstring& text, bool checked, TDiagBase* group)
42 {
43 const auto i = new TCheckListItem(text, checked ? BF_CHECKED : BF_UNCHECKED);
44 i->SetData(reinterpret_cast<UINT_PTR>(group));
46 }
47
48 auto GetData(int index) -> TDiagBase*
49 {
50 PRECONDITION(GetItem(index));
51 return reinterpret_cast<TDiagBase*>(GetItem(index)->GetData());
52 }
53
54 void SetItemText(int index, const tstring& text)
55 {
56 PRECONDITION(GetItem(index));
57 GetItem(index)->SetText(text);
58 }
59
60private:
61
62 void EvLButtonDown(uint modKeys, const TPoint& point)
63 {
65 const auto index = GetCaretIndex();
66 const auto i = GetItem(index);
67 if (i && i->IsEnabled() && point.x < CheckList_BoxWidth)
68 SetGroupState(index, i->IsChecked());
69 }
70
71 void EvChar(uint key, uint repeatCount, uint flags)
72 {
74 const auto index = GetCaretIndex();
75 const auto i = GetItem(index);
76 if (i && i->IsEnabled() && key == _T(' '))
77 SetGroupState(index, i->IsChecked());
78 }
79
80 void SetGroupState(int index, bool enabled)
81 {
82 const auto group = GetData(index);
83 if (!group) return;
84 group->Enable(enabled);
85
86 // Save level into "OWL.INI".
87 //
88 auto s = tostringstream{};
89 s << (group->IsEnabled() ? 1 : 0) << _T(' ') << group->GetLevel();
90 TProfile ini(_T("Diagnostics"), GetDiagIniFullFileName_(OWL_INI));
91 ini.WriteString(to_tstring(group->GetName()), s.str());
92 }
93
94 DECLARE_RESPONSE_TABLE(TGroupList);
95};
96
97DEFINE_RESPONSE_TABLE1(TTraceWindow::TGroupList, TCheckList)
101
102//-------------------------------------------------------------------------------------------------
103
104namespace {
105
106enum
107{
108 Cm_SaveTrace = 100,
109 Cm_Top,
115};
116
117enum
118{
119 Idc_TraceEdit = 200,
122};
123
124} // namespace
125
126TTraceWindow* TTraceWindow::Instance = nullptr;
127
128DEFINE_RESPONSE_TABLE1(TTraceWindow, TFrameWindow)
133 EV_COMMAND(Cm_EditSelectAll, CmEditSelectAll),
137 EV_COMMAND(Cm_PreviousPane, CmPreviousPane),
142
144{
145 if (shouldCreateIfNeccessary && !Instance)
146 Instance = new TTraceWindow{};
147 return Instance;
148}
149
151{
152 if (Instance)
153 delete Instance;
154}
155
157{
159
160 // Don't process trace messages from the Diagnostic Window itself.
161 //
162 if (Active) return;
163
164 TraceText += group->GetDiagModule()->GetName();
165 TraceText += _T(": ");
166 TraceText += msg;
167 TraceDirty = true;
168}
169
171{
173 if (TraceDirty)
174 UpdateTraceText();
175 return more;
176}
177
179{
181
182 const auto title = tstring{_T("Diagnostic Window - ")} +
185
186 //
187 // Build the menu in code to not force a linked in RC file:
188 //
189 TMenu menu{NoAutoDelete};
191 menu.AppendMenu(MF_POPUP, traceMenu, _T("&Trace"));
192 traceMenu.AppendMenu(MF_STRING, Cm_SaveTrace, _T("&Save messages...\tCtrl+S"));
193 traceMenu.AppendMenu(MF_SEPARATOR);
194 traceMenu.AppendMenu(MF_STRING, Cm_Top, _T("Always On &Top"));
195
197 menu.AppendMenu(MF_POPUP, editMenu, _T("&Edit"));
198 editMenu.AppendMenu(MF_STRING, CM_EDITCOPY, _T("&Copy\tCtrl+C"));
199 editMenu.AppendMenu(MF_STRING, Cm_EditClear, _T("C&lear"));
200 editMenu.AppendMenu(MF_SEPARATOR);
201 editMenu.AppendMenu(MF_STRING, Cm_EditSelectAll, _T("Select &all\tCtrl+A"));
202
204 menu.AppendMenu(MF_POPUP, traceGroupMenu, _T("&Group"));
205 traceGroupMenu.AppendMenu(MF_STRING, Cm_SetLevel, _T("Set level...\tEnter"));
206
207 SetMenu(menu);
208 DrawMenuBar();
209
210 const ACCEL accelerators[6]
211 {
218 };
219 SethAccel(CreateAcceleratorTable(const_cast<LPACCEL>(accelerators), static_cast<int>(COUNTOF(accelerators))));
220
221 TraceMessages.LimitText(0);
222
223 Panels.SplitPane(&TraceMessages, nullptr, psNone);
224 Panels.SplitPane(&TraceMessages, &TraceModules, psHorizontal, 0.50f);
225 Panels.SplitPane(&TraceModules, &TraceGroups, psVertical, 0.50f);
226
228 TraceMessages.SetWindowFont(font, false);
229 TraceModules.SetWindowFont(font, false);
230 TraceGroups.SetWindowFont(font, false);
231
232 AddModules(TModule::NextModule(nullptr));
233 OldHook = TDiagBase::SetGlobalHook(this);
234}
235
237{
239 SaveWindowState();
241}
242
243TTraceWindow::TTraceWindow()
244 : TFrameWindow(nullptr, _T("Diagnostic Window")),
245 OldHook{},
246 Panels{*new TPaneSplitter{this}},
247 TraceMessages{*new TEdit{this, Idc_TraceEdit, _T(""), 0, 0, 0, 0, 0, true}},
248 TraceGroups{*new TGroupList(this, Idc_GroupListBox)},
249 TraceModules{*new TListBox(this, Idc_ModuleListBox, 0, 0, 0, 0)},
250 TraceDirty{false},
251 Active{true},
252 TracePath{to_tstring(current_path())},
253 TraceText{}
254{
255 Instance = this;
256 SetClientWindow(&Panels);
257
260 TraceModules.ModifyExStyle(0, WS_EX_CLIENTEDGE);
262
263 RestoreWindowState();
264}
265
266TTraceWindow::~TTraceWindow()
267{
268 Destroy();
269 Instance = nullptr;
270}
271
272void TTraceWindow::CmSave()
273{
274 auto data = TFileSaveDialog::TData{};
275 data.SetFilter(_T("Text Files (*.txt)|*.txt|All Files (*.*)|*.*|"));
277 data.InitialDir = const_cast<tchar*>(TracePath.c_str());
278
279 auto f = to_tstring(path{TracePath} / _T("Trace-000.txt"));
280 const auto n = f.size();
281 auto i = size_t{0};
282 while (exists(f))
283 {
284 ++i;
285 if (i > 999)
286 break;
287 const auto makeDigit = [](size_t i) { return static_cast<tchar>('0' + (i % 10)); };
288 f[n - 5] = makeDigit(i / 1);
289 f[n - 6] = makeDigit(i / 10);
290 f[n - 7] = makeDigit(i / 100);
291 }
292 _tcscpy_s(data.FileName, data.MaxPath, to_tstring(path{f}.filename()).c_str());
293
294 TFileSaveDialog dlg{this, data};
295 if (dlg.Execute() == IDOK)
296 {
297 const auto& s = TraceMessages.GetText();
298 tofstream{data.FileName} << s;
299 TracePath = to_tstring(path{data.FileName}.parent_path());
300 }
301}
302
303void TTraceWindow::CmTop()
304{
305 Attr.ExStyle ^= WS_EX_TOPMOST; // toggle the bit
306 const auto topMost = (Attr.ExStyle & WS_EX_TOPMOST) != 0;
308 auto ini = TProfile{_T("TraceWindow"), GetDiagIniFullFileName_(OWL_INI)};
309 ini.WriteInt(_T("TopMost"), topMost ? 1 : 0);
310}
311
312void TTraceWindow::CeTop(TCommandEnabler& tce)
313{
314 tce.SetCheck((Attr.ExStyle & WS_EX_TOPMOST) != 0);
315}
316
317void TTraceWindow::CmEditClear()
318{
319 TraceMessages.SetWindowText(_T(""));
320}
321
322void TTraceWindow::CmEditSelectAll()
323{
324 TraceMessages.SetSelection(0, -1);
325 TraceMessages.SetFocus();
326}
327
328void TTraceWindow::CmSetLevel()
329{
330 const auto i = TraceGroups.GetSelIndex();
331 if (i == LB_ERR) return;
332 const auto group = reinterpret_cast<TDiagBase*>(TraceGroups.GetData(i));
333 auto s = tostringstream{};
334 s << group->GetLevel();
335 const auto levelString = s.str();
336
337 auto prompt = tstring{_T("Set level for ")};
338 prompt += FormatLink(group->GetDiagModule());
339 prompt += _T("::");
340 prompt += to_tstring(group->GetName());
341
342 const auto m = TModule::FindResModule(IDD_INPUTDIALOG, TResId{RT_DIALOG});
343 TInputDialog dlg{&TraceGroups, _T("Diagnostic Window"), prompt, levelString, m, new TRangeValidator{INT_MIN, INT_MAX}};
344 if (dlg.Execute())
345 {
346 auto level = 0;
347 tistringstream{dlg.GetBuffer()} >> level;
348 group->SetLevel(level);
349 TraceGroups.SetItemText(i, FormatGroup(group).c_str());
350
351 // Save the state to the configuration file.
352 //
353 auto ini = TProfile{_T("Diagnostics"), GetDiagIniFullFileName_(OWL_INI)};
354 auto s = tostringstream{};
355 s << (group->IsEnabled() ? 1 : 0) << _T(' ') << level;
356 ini.WriteString(to_tstring(group->GetName()), s.str());
357 }
358}
359
360void TTraceWindow::CeSetLevel(TCommandEnabler& tce)
361{
362 tce.Enable(TraceGroups.GetSelIndex() != LB_ERR);
363}
364
365void TTraceWindow::CmNextPane()
366{
367 const auto w = GetFocus();
368 if (w == TraceMessages.GetHandle())
369 TraceModules.SetFocus();
370 else if (w == TraceModules.GetHandle())
371 TraceGroups.SetFocus();
372 else
373 TraceMessages.SetFocus();
374}
375
376void TTraceWindow::CmPreviousPane()
377{
378 const auto w = GetFocus();
379 if (w == TraceMessages.GetHandle())
380 TraceGroups.SetFocus();
381 else if (w == TraceModules.GetHandle())
382 TraceMessages.SetFocus();
383 else
384 TraceModules.SetFocus();
385}
386
387void TTraceWindow::EvActivate(uint active, bool minimized, HWND hWndOther)
388{
390 Active = active;
391}
392
393void TTraceWindow::LbnSelChangeModule()
394{
395 const auto i = TraceModules.GetSelIndex();
396 if (i == LB_ERR) return;
397 const auto module = reinterpret_cast<TModule*>(TraceModules.GetItemData(i));
398 TraceGroups.SetRedraw(false);
399 TraceGroups.ClearList();
401 if (group->GetDiagModule() == module)
402 TraceGroups.AddItem(FormatGroup(group), group->IsEnabled(), group);
403 TraceGroups.SetRedraw(true);
404 TraceGroups.Invalidate();
405}
406
407void TTraceWindow::SaveWindowState()
408{
409 auto ini = TProfile{_T("TraceWindow"), GetDiagIniFullFileName_(OWL_INI)};
410 auto s = tostringstream{};
411 const auto ws = _T(' ');
412 s << Attr.X << ws << Attr.Y << ws << (Attr.X + Attr.W) << ws << (Attr.Y + Attr.H);
413 ini.WriteString(_T("Position"), s.str());
414 ini.WriteString(_T("Path"), TracePath.c_str());
415}
416
417void TTraceWindow::RestoreWindowState()
418{
419 auto ini = TProfile{_T("TraceWindow"), GetDiagIniFullFileName_(OWL_INI)};
420 auto is = tistringstream{ini.GetString(_T("Position"), _T("-1 -1 -1 -1"))};
421 auto r = TRect{};
422 is >> r.left >> r.top >> r.right >> r.bottom;
423 if (!r.IsEmpty())
424 {
425 Attr.X = r.left;
426 Attr.Y = r.top;
427 Attr.W = r.Width();
428 Attr.H = r.Height();
429 }
430 bool topMost = ini.GetInt(_T("TopMost"), 0) == 1;
431 if (topMost)
433 TracePath = ini.GetString(_T("Path"), TracePath);
434}
435
436void TTraceWindow::AddModules(TModule* module)
437{
438 for (auto m = module; m; m = TModule::NextModule(m))
439 {
440 const auto i = TraceModules.AddString(FormatLink(m));
441 TraceModules.SetItemData(i, reinterpret_cast<LPARAM>(m));
442 }
443 for (auto g = TDiagBase::GetDiagGroup(nullptr); g; g = TDiagBase::GetDiagGroup(g))
444 if (g->GetDiagModule() == module)
445 TraceGroups.AddItem(FormatGroup(g), g->IsEnabled(), g);
446}
447
448void TTraceWindow::UpdateTraceText()
449{
450 if (!IsWindow()) return;
451 const auto tmp = TraceText;
452 TraceText = _T("");
453 TraceDirty = false;
454 const auto n = TraceMessages.GetWindowTextLength();
455 TraceMessages.SetSelection(n, -1);
456 TraceMessages.Insert(tmp);
457}
458
459auto TTraceWindow::FormatGroup(TDiagBase* group) -> tstring
460{
461 const auto n = to_tstring(group->GetName());
462 auto ini = TProfile{_T("Diagnostics Descriptions"), GetDiagIniFullFileName_(OWL_INI)};
463 const auto d = ini.GetString(n, n); // Replace name by description, if present.
464 auto s = tostringstream{};
465 s << d << _T(" (") << group->GetLevel() << _T(')');
466 return s.str();
467}
468
469auto TTraceWindow::FormatLink(TModule* module) -> tstring
470{
471 return module->GetName();
472}
473
474} // OWL namespace
Definition of class TCheckList, an ownerdrawn listbox to select multiple items.
#define PRECONDITION(condition)
Definition checks.h:227
TFrameWindow * GetMainWindow()
Return the current main window.
Definition applicat.h:592
void EvLButtonDown(uint modKeys, const TPoint &point)
Toggles the checked state when the mouse is clicked in the checkbox.
Definition checklst.cpp:296
int AddItem(TCheckListItem *item)
Adds the item into the checklist.
Definition checklst.cpp:210
TCheckListItem * GetItem(int idx)
Returns the item at the specified index.
Definition checklst.cpp:479
void EvChar(uint key, uint repeatCount, uint flags)
Toggles the checked state when the space key is pressed.
Definition checklst.cpp:280
TCheckList(TWindow *parent, int id, int x, int y, int w, int h, TCheckListItem *=0, int numItems=0, TModule *=0)
Creates a checklist.
Definition checklst.cpp:107
void ClearList() override
Definition checklst.cpp:348
UINT_PTR GetData()
Returns the user-defined data for this item.
Definition checklst.h:448
void SetText(const tstring &text)
Copies the text string.
Definition checklst.h:354
Encapsulates the system font used for a specific GUI element, e.g. icon, caption, menu,...
Definition gdiobjec.h:380
@ sfiMessage
Represents NONCLIENTMETRICS::lfMessageFont.
Definition gdiobjec.h:394
static TDiagBase * GetDiagGroup(TDiagBase *curr=nullptr)
Definition checks.cpp:235
static TDiagBaseHook * SetGlobalHook(TDiagBaseHook *hook=nullptr)
Definition checks.cpp:173
A TEdit is an interface object that represents an edit control interface element.
Definition edit.h:34
Derived from TWindow, TFrameWindow controls such window-specific behavior as keyboard navigation and ...
Definition framewin.h:96
auto IdleAction(long idleCount) -> bool override
Overrides TWindow's virtual function.
Definition framewin.cpp:293
virtual bool SetMenu(HMENU newMenu)
Overrides TWindow's non-virtual SetMenu function, thus allowing derived classes the opportunity to im...
Definition framewin.cpp:471
void CleanupWindow() override
Cleans up any associated icons.
virtual TWindow * SetClientWindow(TWindow *clientWnd)
Sets the client window to the specified window.
Definition framewin.cpp:603
void SetupWindow() override
Calls TWindow::SetUpWindow to create windows in a child list.
An interface object that represents a corresponding list box element.
Definition listbox.h:43
virtual int SetItemData(int index, LPARAM itemData)
Sets the custom value associated with the list box item at the specified index position.
Definition listbox.h:282
virtual int AddString(LPCTSTR str)
Adds str to the list box, returning its position in the list (0 is the first position).
Definition listbox.h:344
int GetCaretIndex() const
Returns the index of the currently focused list-box item.
Definition listbox.h:257
virtual int GetSelIndex() const
For single-selection list boxes.
Definition listbox.cpp:538
The TMenu class encapsulates window menus.
Definition menu.h:77
TPaneSplitter is a class that acts as a container for child windows (called panes) and splitters (pan...
Definition panespli.h:52
virtual bool SplitPane(TWindow *target, TWindow *newPane, TSplitDirection splitDir, float percent=0.50f)
Splits given pane, 'target', with 'newPane', in either the vertical or horizontal direction.
TPopupMenu creates an empty pop-up menu to add to an existing window or pop-up menu.
Definition menu.h:189
int GetText(TCHAR *str, int maxChars) const
Retrieves the static control's text, stores it in the str argument of maxChars size,...
Definition static.h:211
static void DestroyInstance()
Definition tracewnd.cpp:150
void Output(TDiagBase *group, LPCTSTR str) override
Definition tracewnd.cpp:156
auto IdleAction(long) -> bool override
Definition tracewnd.cpp:170
void CleanupWindow() override
Definition tracewnd.cpp:236
void SetupWindow() override
Definition tracewnd.cpp:178
HWND SetFocus()
Sets the keyboard focus to current window and activates the window that receives the focus by sending...
Definition window.h:2151
TApplication * GetApplication() const
Gets a pointer to the TApplication object associated with this.
Definition window.h:1855
TWindow()
Protected constructor for use by immediate virtually derived classes.
Definition window.cpp:392
void DrawMenuBar()
DrawMenuBar redraws the menu bar.
Definition window.h:3313
bool SetWindowPos(HWND hWndInsertAfter, const TRect &rect, uint flags)
Changes the size of the window pointed to by rect.
Definition window.h:2809
virtual void Destroy(int retVal=0)
Destroys an MS-Windows element associated with the TWindow.
Definition window.cpp:2160
void SetWindowFont(HFONT font, bool redraw=true)
Sets the font that a control uses to draw text.
Definition window.h:3476
void SetRedraw(bool redraw)
Sends a WM_SETREDRAW message to a window so that changes can be redrawn (redraw = true) or to prevent...
Definition window.h:2182
bool IsWindow() const
Returns true if an HWND is being used.
Definition window.h:2040
void EvActivate(uint active, bool minimized, HWND hWndOther)
Default message handler for WM_ACTIVATE.
Definition window.h:3578
bool ModifyStyle(uint32 offBits, uint32 onBits, uint swpFlags=0)
Modifies the style bits of the window.
Definition window.cpp:3591
void SethAccel(HACCEL)
Definition window.cpp:4394
LPCTSTR GetCaption() const
Returns the Title member of TWindow.
Definition window.h:1900
void SetWindowText(LPCTSTR str)
Sets the window's text to the given string (by copying).
Definition window.h:2669
bool ModifyExStyle(uint32 offBits, uint32 onBits, uint swpFlags=0)
Modifies the style bits of the window.
Definition window.cpp:3599
static HWND GetFocus()
Gets a handle to the window that has the focus.
Definition window.h:2139
virtual void Invalidate(bool erase=true)
Invalidates (mark for painting) the entire client area of a window.
Definition window.h:2822
HWND GetHandle() const
Returns the handle of the window.
Definition window.h:2020
int GetWindowTextLength() const
Returns the length, in characters, of the specified window's title.
Definition window.h:2641
#define _T(x)
Definition cygwin.h:51
Definition of class TEdit.
#define DECLARE_RESPONSE_TABLE(cls)
Definition eventhan.h:436
#define DEFINE_RESPONSE_TABLE1(cls, base)
Macro to define a response table for a class with one base.
Definition eventhan.h:492
@ NoAutoDelete
Definition gdibase.h:70
virtual void LimitText(int)
Limit the amount of new text that can be entered in the edit control.
Definition edit.h:611
void Insert(LPCTSTR str)
Inserts the text supplied in str into the edit control at the current text insertion point (cursor po...
Definition edit.h:553
virtual bool SetSelection(int startPos, int endPos)
Select the characters in the range "startPos .. endPos".
Definition edit.h:430
static TModule * FindResModule(TResId id, TResId type)
Global search for resources.
Definition module.cpp:429
static TModule * NextModule(TModule *module=nullptr)
Definition module.cpp:290
Definition of TInputDialog class.
Definition of class TListBox and TlistBoxData.
Object Windows Library (OWLNext Core)
Definition animctrl.h:22
std::ofstream tofstream
Definition strmdefs.h:44
std::ostringstream tostringstream
Definition strmdefs.h:36
EV_WM_CHAR
Definition checklst.cpp:196
@ psNone
Unspecified split.
Definition splitter.h:33
@ psHorizontal
Horizontal split.
Definition splitter.h:31
@ psVertical
Vertical split.
Definition splitter.h:32
tstring GetDiagIniFullFileName_(LPCSTR filename_)
Definition diaginit.cpp:78
@ BF_UNCHECKED
Item is unchecked.
Definition checkbox.h:31
@ BF_CHECKED
Item is checked.
Definition checkbox.h:29
char tchar
Definition defs.h:77
std::istringstream tistringstream
Definition strmdefs.h:37
OWL_DIAGINFO
Definition animctrl.cpp:14
const int CheckList_BoxWidth
Definition checklst.h:33
END_RESPONSE_TABLE
Definition button.cpp:26
std::string tstring
Definition defs.h:79
EV_WM_ACTIVATE
Definition tracewnd.cpp:140
unsigned int uint
Definition number.h:25
EV_WM_LBUTTONDOWN
Definition checklst.cpp:195
auto to_tstring(const T &v) -> tstring
Definition defs.h:82
Definition of TOpenSave abstract, TFileOpen, TFileSave common Dialog classes.
#define OWL_INI
Definition defs.h:170
#define COUNTOF(s)
Array element count Important: Only use this with an argument of array type.
Definition defs.h:376
Definition of TProfile class.
Definition of private class TTraceWindow.
#define EV_COMMAND_ENABLE(id, method)
Response table entry for enabling a command.
Definition windowev.h:193
#define EV_LBN_SELCHANGE(id, method)
Definition windowev.h:492
#define EV_LBN_DBLCLK(id, method)
Definition windowev.h:488
#define EV_COMMAND(id, method)
Response table entry for a menu/accelerator/push button message.
Definition windowev.h:171
#define WS_EX_CLIENTEDGE
Definition wsysinc.h:33