OWLNext    7.0
Borland's Object Windows Library for the modern age
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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