1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 // ViewDialog.cpp : implementation file
25 #include "log_analyser.h"
26 #include "ViewDialog.h"
27 #include "log_analyserDlg.h"
37 static char THIS_FILE
[] = __FILE__
;
41 extern CString LogDateString
;
42 static UINT WM_FINDREPLACE
= ::RegisterWindowMessage(FINDMSGSTRING
);
46 void CListCtrlEx::initIt()
48 DWORD dwStyle
= GetWindowLong(m_hWnd
, GWL_STYLE
);
49 SetWindowLong( m_hWnd
, GWL_STYLE
, dwStyle
| LVS_OWNERDRAWFIXED
);
54 * Keyboard handler in list box
56 afx_msg
void CListCtrlEx::OnKeyDown( UINT nChar
, UINT nRepCnt
, UINT nFlags
)
58 // Transmit to List Ctrl AND to main window
59 CListCtrl::OnKeyDown( nChar
, nRepCnt
, nFlags
);
60 ((CLog_analyserDlg
*)(_ViewDialog
->GetParent()))->OnKeyDown( nChar
, nRepCnt
, nFlags
);
64 // Adapted from http://zeus.eed.usv.ro/misc/doc/prog/c/mfc/listview/sel_row.html
65 void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct
)
67 CDC
* pDC
= CDC::FromHandle(lpDrawItemStruct
->hDC
);
68 CRect
rcItem(lpDrawItemStruct
->rcItem
);
69 int nItem
= lpDrawItemStruct
->itemID
;
70 CImageList
* pImageList
;
73 int nSavedDC
= pDC
->SaveDC();
75 // Get item image and state info
77 lvi
.mask
= LVIF_IMAGE
| LVIF_STATE
;
80 lvi
.stateMask
= 0xFFFF; // get all state flags
83 BOOL bHighlight
=((lvi
.state
& LVIS_DROPHILITED
)
84 || ( (lvi
.state
& LVIS_SELECTED
)
85 && ((GetFocus() == this)
86 || (GetStyle() & LVS_SHOWSELALWAYS
)
91 // Get rectangles for drawing
92 CRect rcBounds
, rcLabel
, rcIcon
;
93 GetItemRect(nItem
, rcBounds
, LVIR_BOUNDS
);
94 GetItemRect(nItem
, rcLabel
, LVIR_LABEL
);
95 GetItemRect(nItem
, rcIcon
, LVIR_ICON
);
96 CRect
rcCol( rcBounds
);
99 CString sLabel
= GetItemText( nItem
, 0 );
101 // Labels are offset by a certain amount
102 // This offset is related to the width of a space character
103 int offset
= pDC
->GetTextExtent(_T(" "), 1 ).cx
*2;
107 GetClientRect(&rcWnd
);
108 rcHighlight
= rcBounds
;
109 rcHighlight
.left
= rcLabel
.left
;
110 rcHighlight
.right
= rcWnd
.right
;
112 // Draw the background color
114 pDC
->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT
));
115 pDC
->FillRect( rcHighlight
, &CBrush(_ViewDialog
->getBkColorForLine( nItem
, bHighlight
!=0 )) );
118 rcCol
.right
= rcCol
.left
+ GetColumnWidth(0);
120 rgn
.CreateRectRgnIndirect(&rcCol
);
121 pDC
->SelectClipRgn(&rgn
);
125 if (lvi
.state
& LVIS_STATEIMAGEMASK
)
127 int nImage
= ((lvi
.state
& LVIS_STATEIMAGEMASK
)>>12) - 1;
128 pImageList
= GetImageList(LVSIL_STATE
);
131 pImageList
->Draw(pDC
, nImage
,
132 CPoint(rcCol
.left
, rcCol
.top
), ILD_TRANSPARENT
);
136 // Draw normal and overlay icon
137 pImageList
= GetImageList(LVSIL_SMALL
);
140 UINT nOvlImageMask
=lvi
.state
& LVIS_OVERLAYMASK
;
141 pImageList
->Draw(pDC
, lvi
.iImage
,
142 CPoint(rcIcon
.left
, rcIcon
.top
),
143 ILD_TRANSPARENT
| nOvlImageMask
);
148 // Draw item label - Column 0
149 rcLabel
.left
+= offset
/2;
150 rcLabel
.right
-= offset
;
152 pDC
->SetTextColor( _ViewDialog
->getTextColorForLine( nItem
, bHighlight
!=0 ) );
153 pDC
->DrawText(sLabel
,-1,rcLabel
,DT_LEFT
| DT_SINGLELINE
| DT_NOPREFIX
| DT_NOCLIP
154 | DT_VCENTER
/*| DT_END_ELLIPSIS*/);
157 // Draw labels for remaining columns
159 lvc
.mask
= LVCF_FMT
| LVCF_WIDTH
;
161 rcBounds
.right
= rcHighlight
.right
> rcBounds
.right
? rcHighlight
.right
:
163 rgn
.CreateRectRgnIndirect(&rcBounds
);
164 pDC
->SelectClipRgn(&rgn
);
166 for(int nColumn
= 1; GetColumn(nColumn
, &lvc
); nColumn
++)
168 rcCol
.left
= rcCol
.right
;
169 rcCol
.right
+= lvc
.cx
;
171 sLabel
= GetItemText(nItem
, nColumn
);
172 if (sLabel
.GetLength() == 0)
175 // Get the text justification
176 UINT nJustify
= DT_LEFT
;
177 switch(lvc
.fmt
& LVCFMT_JUSTIFYMASK
)
183 nJustify
= DT_CENTER
;
190 rcLabel
.left
+= offset
;
191 rcLabel
.right
-= offset
;
193 pDC
->DrawText(sLabel
, -1, rcLabel
, nJustify
| DT_SINGLELINE
|
194 DT_NOPREFIX
| DT_VCENTER
| DT_END_ELLIPSIS
);
197 // Draw focus rectangle if item has focus
198 if (lvi
.state
& LVIS_FOCUSED
&& (GetFocus() == this))
200 pDC
->DrawFocusRect(rcHighlight
);
205 pDC
->RestoreDC( nSavedDC
);
209 void CListCtrlEx::RepaintSelectedItems()
211 CRect rcBounds
, rcLabel
;
213 // Invalidate focused item so it can repaint
214 int nItem
= GetNextItem(-1, LVNI_FOCUSED
);
218 GetItemRect(nItem
, rcBounds
, LVIR_BOUNDS
);
219 GetItemRect(nItem
, rcLabel
, LVIR_LABEL
);
220 rcBounds
.left
= rcLabel
.left
;
222 InvalidateRect(rcBounds
, FALSE
);
225 // Invalidate selected items depending on LVS_SHOWSELALWAYS
226 if(!(GetStyle() & LVS_SHOWSELALWAYS
))
228 for(nItem
= GetNextItem(-1, LVNI_SELECTED
);
229 nItem
!= -1; nItem
= GetNextItem(nItem
, LVNI_SELECTED
))
231 GetItemRect(nItem
, rcBounds
, LVIR_BOUNDS
);
232 GetItemRect(nItem
, rcLabel
, LVIR_LABEL
);
233 rcBounds
.left
= rcLabel
.left
;
235 InvalidateRect(rcBounds
, FALSE
);
243 /*void CListCtrlEx::OnKillFocus(CWnd* pNewWnd)
245 CListCtrl::OnKillFocus(pNewWnd);
247 // check if we are losing focus to label edit box
248 if(pNewWnd != NULL && pNewWnd->GetParent() == this)
251 // repaint items that should change appearance
252 if((GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
253 RepaintSelectedItems();
256 void CListCtrlEx::OnSetFocus(CWnd* pOldWnd)
258 CListCtrl::OnSetFocus(pOldWnd);
260 // check if we are getting focus from label edit box
261 if(pOldWnd!=NULL && pOldWnd->GetParent()==this)
264 // repaint items that should change appearance
265 if((GetStyle() & LVS_TYPEMASK)==LVS_REPORT)
266 RepaintSelectedItems();
270 BEGIN_MESSAGE_MAP(CListCtrlEx
, CListCtrl
)
271 //{{AFX_MSG_MAP(CListCtrlEx)
277 /////////////////////////////////////////////////////////////////////////////
278 // CViewDialog dialog
281 CViewDialog::CViewDialog(CWnd
* pParent
/*=NULL*/)
282 : CDialog(CViewDialog::IDD
, pParent
)
284 //{{AFX_DATA_INIT(CViewDialog)
290 void CViewDialog::DoDataExchange(CDataExchange
* pDX
)
292 CDialog::DoDataExchange(pDX
);
293 //{{AFX_DATA_MAP(CViewDialog)
294 DDX_Control(pDX
, IDC_LIST1
, m_ListCtrl
);
295 DDX_Text(pDX
, IDC_Service
, m_Caption
);
301 * Load, using the current filters
303 void CViewDialog::reload()
305 SessionDatePassed
= false;
307 if ( LogSessionStartDate
.IsEmpty() || (LogSessionStartDate
== _T("Beginning")) )
309 SessionDatePassed
= true;
312 ((CButton
*)GetDlgItem( IDC_BUTTON1
))->ShowWindow( SW_SHOW
);
313 ((CButton
*)GetDlgItem( IDC_BUTTON2
))->ShowWindow( SW_SHOW
);
314 m_Caption
.Format( _T("%s (%u file%s) %u+ %u- (%s)"), Seriesname
, Filenames
.size(), Filenames
.size()>1?"s":"", PosFilter
.size(), NegFilter
.size(), LogSessionStartDate
.IsEmpty()?"all":CString("session ")+LogSessionStartDate
);
319 time( &CurrentTime
);
321 // Translate bookmarks (phase 1)
322 CurrentBookmark
= -1;
323 vector
<int> bookmarksAbsoluteLines
;
324 if ( ! Bookmarks
.empty() )
326 getBookmarksAbsoluteLines( bookmarksAbsoluteLines
);
330 loadFileOrSeries( bookmarksAbsoluteLines
);
338 * Code from IDisplayer::dateToHumanString() (NeL misc)
340 string
timeToStr( const time_t& date
)
342 static char cstime
[25];
343 struct tm
*tms
= localtime(&date
);
345 strftime (cstime
, 25, "%Y/%m/%d %H:%M:%S", tms
);
347 smprintf(cstime
, 25, "bad date %d", (unsigned int)date
);
353 * Reload with old filter to get bookmarks absolute line numbers (not called if there's no bookmark)
355 void CViewDialog::getBookmarksAbsoluteLines( vector
<int>& bookmarksAbsoluteLines
)
358 unsigned int currentAbsoluteLineNum
= 0, currentLineNum
= 0;
359 for ( unsigned int i
=0; i
!=Filenames
.size(); ++i
)
361 CString
& filename
= Filenames
[i
];
365 if (ifs
.open(NLMISC::tStrToUtf8(filename
)))
371 ifs
.getline(line
, 1024);
373 if ( SessionDatePassed
)
375 // Stop if the session is finished
376 if ( (! LogSessionStartDate
.IsEmpty()) && (strstr( line
, nlTStrToUtf8(LogDateString
))) )
382 if ( passFilter( line
, PreviousPosFilter
, PreviousNegFilter
) )
384 // Translate bookmarks (phase 1: filtered -> absolute)
385 vector
<int>::iterator ibl
;
386 ibl
= find( Bookmarks
.begin(), Bookmarks
.end(), currentLineNum
);
387 if ( ibl
!= Bookmarks
.end() )
389 bookmarksAbsoluteLines
.push_back( currentAbsoluteLineNum
);
395 ++currentAbsoluteLineNum
;
399 // Look for the session beginning
400 if ( strstr( line
, nlTStrToUtf8(LogSessionStartDate
)) != NULL
)
402 SessionDatePassed
= true;
412 * Auto-detect file corruption (version for any NeL log file)
414 bool detectLineCorruption( const char *cLine
)
416 string line
= string(cLine
);
417 if ( ! line
.empty() )
419 bool corrupted
= false;
422 // Some line may begin with no date, this is normal, we don't state them as corruption
424 // Search for year not at beginning. Ex: "2003/" (it does not work when the year is different from the current one!)
425 p
= line
.substr( 1 ).find( timeToStr( CurrentTime
).substr( 0, 5 ) );
426 if ( p
!= string::npos
)
428 ++p
; // because searched from pos 1
430 // Search for date/time
431 if ( (line
.size()>p
+20) && (line
[p
+10]==' ') && (line
[p
+13]==':')
432 && (line
[p
+16]==':') && (line
[p
+19]==' ') )
434 // Search for the five next blank characters. The fifth is followed by ": ".
435 // (Date Time LogType ThreadId Machine/Service SourceFile Line : User-defined log line)
436 unsigned int nbBlank
= 0;
437 string::size_type sp
;
438 for ( sp
=p
+20; sp
!=line
.size(); ++sp
)
445 if ( (nbBlank
==5) && (line
[sp
+1]==':') && (line
[sp
+2]==' ') )
456 bool HasCorruptedLines
;
462 std::string
CViewDialog::corruptedLinesString( const std::vector
<unsigned int>& corruptedLines
)
465 if ( ! corruptedLines
.empty() )
467 res
= NLMISC::toString(" -> %u corrupted lines:", (uint
)corruptedLines
.size());
469 vector
<unsigned int>::const_iterator ivc
;
470 for ( ivc
=corruptedLines
.begin(); ivc
!=corruptedLines
.end(); ++ivc
)
472 res
+= NLMISC::toString("\r\n line %u : %s...", *ivc
, NLMISC::tStrToUtf8(Buffer
[*ivc
].Left(20)).c_str());
474 HasCorruptedLines
= true;
481 * Load a log file or series
483 void CViewDialog::loadFileOrSeries( const vector
<int>& bookmarksAbsoluteLines
)
485 // Header for 'files loaded' display
486 string actualFilenames
= "Files loaded";
487 if ( LogSessionStartDate
.IsEmpty() )
488 actualFilenames
+= ":\r\n";
490 actualFilenames
+= " for Session of " + NLMISC::tStrToUtf8(LogSessionStartDate
) + ":\r\n";
491 bool corruptionDetectionEnabled
= (((CButton
*)(((CLog_analyserDlg
*)GetParent())->GetDlgItem( IDC_DetectCorruptedLines
)))->GetCheck() == 1);
492 HasCorruptedLines
= false;
493 vector
<unsigned int> corruptedLines
;
496 unsigned int currentAbsoluteLineNum
= 0, currentLineNum
= 0;
497 for ( unsigned int i
=0; i
!=Filenames
.size(); ++i
)
499 CString
& filename
= Filenames
[i
];
500 ifstream
ifs( filename
);
504 while ( ! ifs
.eof() )
506 ifs
.getline( line
, 1024 );
507 line
[1023] = '\0'; // force valid end of line
508 if ( SessionDatePassed
)
510 // Stop if the session is finished
511 if ( (! LogSessionStartDate
.IsEmpty()) && (strstr( line
, nlTStrToUtf8(LogDateString
) )) )
513 actualFilenames
+= NLMISC::tStrToUtf8(filename
) + corruptedLinesString(corruptedLines
) + "\r\n";
514 corruptedLines
.clear();
519 if ( passFilter( line
, PosFilter
, NegFilter
) )
521 // Auto-detect line corruption
522 if ( corruptionDetectionEnabled
&& detectLineCorruption( line
) )
523 corruptedLines
.push_back( currentLineNum
);
525 // Translate bookmarks (phase 2: absolute -> filtered)
526 if ( ! bookmarksAbsoluteLines
.empty() )
528 vector
<int>::const_iterator ibal
;
529 ibal
= find( bookmarksAbsoluteLines
.begin(), bookmarksAbsoluteLines
.end(), currentAbsoluteLineNum
);
530 if ( ibal
!= bookmarksAbsoluteLines
.end() )
532 Bookmarks
.push_back( currentLineNum
);
536 // Add line to list box
541 ++currentAbsoluteLineNum
;
545 // Look for the session beginning
546 if ( strstr( line
, nlTStrToUtf8(LogSessionStartDate
) ) != NULL
)
548 SessionDatePassed
= true;
553 if ( SessionDatePassed
)
555 actualFilenames
+= NLMISC::tStrToUtf8(filename
) + corruptedLinesString(corruptedLines
) + "\r\n";
556 corruptedLines
.clear();
562 s
.Format(_T( "<Cannot open file %s>\r\n"), filename
);
563 actualFilenames
+= NLMISC::tStrToUtf8(s
);
568 if ( HasCorruptedLines
)
570 actualFilenames
+= "(When corrupted lines are present, it is possible that some other lines are missing)\r\n\
571 Select the line number and press Ctrl-G to scroll to the corrupted line.\r\n\
572 At any time, press Ctrl-L in this edit box to return to this list of files and corrupted lines.";
574 ((CLog_analyserDlg
*)GetParent())->displayCurrentLine( actualFilenames
.c_str() );
575 ((CLog_analyserDlg
*)GetParent())->memorizeFileList( actualFilenames
.c_str() );
580 * Set the filters (and backup the previous ones for bookmark translation)
582 void CViewDialog::setFilters( const std::vector
<CString
>& posFilter
, const std::vector
<CString
>& negFilter
)
584 PreviousPosFilter
= PosFilter
;
585 PreviousNegFilter
= NegFilter
;
586 PosFilter
= posFilter
;
587 NegFilter
= negFilter
;
592 * Returns true if the string must be logged, according to the current filters
594 bool CViewDialog::passFilter( const char *text
, const std::vector
<CString
>& posFilter
, const std::vector
<CString
>& negFilter
) const
596 bool yes
= posFilter
.empty();
599 vector
<CString
>::const_iterator ilf
;
601 // 1. Positive filter
602 for ( ilf
=posFilter
.begin(); ilf
!=posFilter
.end(); ++ilf
)
604 found
= (strstr(text
, nlTStrToUtf8(*ilf
)) != NULL
);
607 yes
= true; // positive filter passed (no need to check another one)
610 // else try the next one
614 return false; // positive filter not passed
617 // 2. Negative filter
618 for ( ilf
=negFilter
.begin(); ilf
!=negFilter
.end(); ++ilf
)
620 found
= (strstr(text
, nlTStrToUtf8(*ilf
)) != NULL
);
623 return false; // negative filter not passed (no need to check another one)
626 return true; // negative filter passed
633 void CViewDialog::reloadTrace()
636 ((CButton
*)GetDlgItem( IDC_BUTTON1
))->ShowWindow( SW_HIDE
);
637 ((CButton
*)GetDlgItem( IDC_BUTTON2
))->ShowWindow( SW_HIDE
);
638 if ( LogSessionStartDate
.IsEmpty() )
640 SessionDatePassed
= true;
641 if ( PosFilter
.empty() )
642 m_Caption
= "Trace of " + Seriesname
+ " (all)";
644 m_Caption
= "Trace of " + PosFilter
[0] + " (all)";
648 if ( LogSessionStartDate
== "Beginning" )
650 SessionDatePassed
= true;
652 if ( PosFilter
.empty() )
653 m_Caption
= "Trace of " + Seriesname
+ " (session " + LogSessionStartDate
+ ")" ;
655 m_Caption
= "Trace of " + PosFilter
[0] + " (session " + LogSessionStartDate
+ ")" ;
661 ifstream
ifs( Seriesname
);
665 while ( ! ifs
.eof() )
667 ifs
.getline( line
, 1024 );
668 if ( SessionDatePassed
)
670 // Stop if the session is finished
671 if ((!LogSessionStartDate
.IsEmpty()) && (strstr(line
, nlTStrToUtf8(LogDateString
))))
674 // Read if it's a TRACE
675 char *pc
= strstr( line
, "TRACE" );
678 std::string tposFilter0
= NLMISC::tStrToUtf8(PosFilter
[0]);
679 if (PosFilter
.empty() || (strncmp(pc
- PosFilter
[0].GetLength(), tposFilter0
.c_str(), tposFilter0
.size()) == 0))
681 ((CLog_analyserDlg
*)GetParent())->insertTraceLine( Index
, pc
+6 );
687 // Look for the session beginning
688 if (strstr(line
, nlTStrToUtf8(LogSessionStartDate
)) != NULL
)
690 SessionDatePassed
= true;
695 addLine( "<After adding all the views" );
696 addLine( "you need, click Compute Traces" );
697 addLine( "to generate all the views>" );
701 addLine( "<Cannot open log file>" );
708 BEGIN_MESSAGE_MAP(CViewDialog
, CDialog
)
709 //{{AFX_MSG_MAP(CViewDialog)
710 ON_BN_CLICKED(IDC_BUTTON1
, OnButtonFilter
)
711 ON_NOTIFY(LVN_GETDISPINFO
, IDC_LIST1
, OnGetdispinfoList1
)
712 ON_NOTIFY(LVN_ITEMCHANGED
, IDC_LIST1
, OnItemchangedList1
)
713 ON_NOTIFY(NM_SETFOCUS
, IDC_LIST1
, OnSetfocusList1
)
714 ON_BN_CLICKED(IDC_BUTTON2
, OnButtonFind
)
716 ON_REGISTERED_MESSAGE( WM_FINDREPLACE
, OnFindReplace
)
720 /////////////////////////////////////////////////////////////////////////////
721 // CViewDialog message handlers
727 void CViewDialog::OnSetfocusList1(NMHDR
* pNMHDR
, LRESULT
* pResult
)
729 // Force to display the current item when the current view changes
730 if ( getSelectionIndex() != -1 )
733 ((CLog_analyserDlg
*)GetParent())->setCurrentView( Index
);
735 m_ListCtrl
.RepaintSelectedItems();
742 void CViewDialog::OnItemchangedList1(NMHDR
* pNMHDR
, LRESULT
* pResult
)
744 NM_LISTVIEW
* pNMListView
= (NM_LISTVIEW
*)pNMHDR
;
746 // Display the current item when it changes
747 if ( pNMListView
->iItem
!= -1 )
750 ((CLog_analyserDlg
*)GetParent())->setCurrentView( Index
);
752 m_ListCtrl
.RepaintSelectedItems();
760 void CViewDialog::resizeView( int nbViews
, int top
, int left
)
763 GetParent()->GetClientRect( &parentRect
);
765 int width
= (int)((parentRect
.right
-32)*WidthR
);
767 viewRect
.left
= left
;
769 viewRect
.right
= viewRect
.left
+ width
;
770 viewRect
.bottom
= parentRect
.bottom
-10;
771 MoveWindow( &viewRect
, TRUE
);
773 m_ListCtrl
.MoveWindow( 5, 32, width
-5, viewRect
.bottom
-top
-42 );
775 lvc
.mask
= LVCF_WIDTH
;
777 m_ListCtrl
.SetColumn( 0, &lvc
);
778 //m_ListCtrl.SetColumnWidth( 0, LVSCW_AUTOSIZE ); // worse
780 GetDlgItem( IDC_DragBar
)->MoveWindow( 0, 0, 32, viewRect
.bottom
-top
);
785 * Return the nb of lines
787 int CViewDialog::getNbLines() const
789 return (int)Buffer
.size();
794 * Return the nb of visible lines
796 int CViewDialog::getNbVisibleLines() const
798 return m_ListCtrl
.GetCountPerPage();
803 * Fill from getNbLines() to maxNbLines with blank lines
805 void CViewDialog::fillGaps( int maxNbLines
)
807 int nbLines
= getNbLines();
808 for ( int i
=0; i
!=maxNbLines
-nbLines
; ++i
)
816 * Commit the lines previously added
818 void CViewDialog::commitAddedLines()
820 m_ListCtrl
.SetItemCount( (int)Buffer
.size() );
821 m_ListCtrl
.SetColumnWidth( 0, LVSCW_AUTOSIZE
);
828 void CViewDialog::scrollTo( int index
)
830 int deltaIndex
= index
- m_ListCtrl
.GetTopIndex();
832 if ( m_ListCtrl
.GetItemRect( 0, &rect
, LVIR_BOUNDS
) )
834 int itemH
= rect
.bottom
-rect
.top
;
835 m_ListCtrl
.Scroll( CSize( 0, deltaIndex
*itemH
) );
838 //m_ListCtrl.EnsureVisible( index, false );
845 void CViewDialog::select( int index
)
848 itstate
.mask
= LVIF_STATE
;
850 int sm
= getSelectionIndex();
853 m_ListCtrl
.SetItemState( sm
, &itstate
);
858 itstate
.state
= LVIS_SELECTED
| /*LVIS_DROPHILITED |*/ LVIS_FOCUSED
;
859 m_ListCtrl
.SetItemState( index
, &itstate
);
860 m_ListCtrl
.SetSelectionMark( index
);
866 * Return the index of the top of the listbox
868 int CViewDialog::getScrollIndex() const
870 return m_ListCtrl
.GetTopIndex();
875 * Add the current scroll index to the bookmark list, or delete it if already inside the list
877 void CViewDialog::addBookmark()
879 int bkIndex
= getSelectionIndex();
880 vector
<int>::iterator ibk
= find( Bookmarks
.begin(), Bookmarks
.end(), bkIndex
);
881 if ( ibk
== Bookmarks
.end() )
884 Bookmarks
.push_back( bkIndex
);
885 std::sort( Bookmarks
.begin(), Bookmarks
.end() ); // not very fast but not many items
886 ((CLog_analyserDlg
*)(GetParent()))->displayCurrentLine( "Bookmark set" );
891 Bookmarks
.erase( ibk
);
894 // Refresh the listbox view to display the right bookmark color
895 ((CLog_analyserDlg
*)(GetParent()))->SetFocus();
896 m_ListCtrl
.SetFocus();
901 * Scroll the listbox to the next stored bookmkark
903 void CViewDialog::recallNextBookmark()
905 if ( Bookmarks
.empty() )
908 // Precondition: the vector is sorted
909 int origIndex
= (CurrentBookmark
==-1) ? getScrollIndex() : CurrentBookmark
, destIndex
;
911 while ( (i
< Bookmarks
.size()) && (Bookmarks
[i
] <= origIndex
) )
913 if ( i
== Bookmarks
.size() )
915 // Origin index > all the bookmarks => go back to the first one
916 destIndex
= Bookmarks
[0];
920 // Go to the next bookmark
921 destIndex
= Bookmarks
[i
];
924 CurrentBookmark
= destIndex
; // because scrollTo does not scroll if we are at the bottom of the list
925 scrollTo( destIndex
);
926 //select( destIndex );
933 void CViewDialog::addText( const CString
& lines
)
935 int pos
, lineStartPos
=0;
936 for ( pos
=0; pos
<lines
.GetLength(); ++pos
)
938 if ( lines
[pos
] == '\n' )
940 addLine( lines
.Mid( lineStartPos
, pos
-lineStartPos
) );
945 if ( lineStartPos
> pos
)
946 addLine( lines
.Mid( lineStartPos
, pos
-lineStartPos
) );
953 void CViewDialog::clear()
956 m_ListCtrl
.DeleteAllItems();
963 void CViewDialog::OnButtonFilter()
965 if ( ((CLog_analyserDlg
*)GetParent())->FilterDialog
.DoModal() == IDOK
)
967 setFilters( ((CLog_analyserDlg
*)GetParent())->FilterDialog
.getPosFilter(), ((CLog_analyserDlg
*)GetParent())->FilterDialog
.getNegFilter() );
969 if ( ! ((CLog_analyserDlg
*)GetParent())->Trace
)
976 BOOL
CViewDialog::OnInitDialog()
978 CDialog::OnInitDialog();
980 m_ListCtrl
.GetHeaderCtrl()->ModifyStyle( 0, HDS_HIDDEN
);
981 m_ListCtrl
.InsertColumn(0, _T(""));
982 m_ListCtrl
.setViewDialog( this );
988 FindMatchCase
= false;
989 FindDownwards
= true;
991 CurrentBookmark
= -1;
997 * Return the text color
999 COLORREF
CViewDialog::getTextColorForLine( int index
, bool selected
)
1002 return ::GetSysColor(COLOR_HIGHLIGHTTEXT
);
1005 if ( Buffer
[index
].Find( _T("DBG") ) != -1 )
1006 return RGB(0x80,0x80,0x80);
1007 else if ( Buffer
[index
].Find( _T("WRN") ) != -1 )
1008 return RGB(0x80,0,0);
1009 else if ( (Buffer
[index
].Find( _T("ERR") ) != -1) || (Buffer
[index
].Find( _T("AST") ) != -1) )
1010 return RGB(0xFF,0,0);
1011 else // INF and others
1018 * Return the background color
1020 COLORREF
CViewDialog::getBkColorForLine( int index
, bool selected
)
1023 while ( (i
< Bookmarks
.size()) && (Bookmarks
[i
]<index
) )
1025 if ( (i
< Bookmarks
.size()) && (index
== Bookmarks
[i
]) )
1027 return (::GetSysColor(COLOR_HIGHLIGHT
) + RGB(0xC0,0x90,0x90)) / 2; // selected bookmark
1029 return RGB(0xC0,0x90,0x90); // bookmark
1032 return ::GetSysColor(COLOR_HIGHLIGHT
); // selected
1034 return GetSysColor(COLOR_WINDOW
); // normal
1041 void formatLogStr( CString
& str
, bool displayHeaders
)
1043 if ( ! displayHeaders
)
1045 int pos
= str
.Find( _T(" : ") );
1048 str
.Delete( 0, pos
+ 3 );
1055 * Process string before displaying it in the view
1057 void CViewDialog::OnGetdispinfoList1(NMHDR
* pNMHDR
, LRESULT
* pResult
)
1059 LV_DISPINFO
* pDispInfo
= (LV_DISPINFO
*)pNMHDR
;
1060 LV_ITEM
* pItem
= &(pDispInfo
)->item
;
1062 int iItemIndx
= pItem
->iItem
;
1063 if (pItem
->mask
& LVIF_TEXT
) //valid text buffer?
1065 CString str
= Buffer
[iItemIndx
];
1066 formatLogStr( str
, ((CButton
*)(((CLog_analyserDlg
*)GetParent())->GetDlgItem( IDC_DispLineHeaders
)))->GetCheck() == 1 );
1067 lstrcpy( pItem
->pszText
, str
);
1076 void CViewDialog::displayString()
1080 POSITION pos
= m_ListCtrl
.GetFirstSelectedItemPosition();
1081 while ( pos
!= NULL
)
1083 int index
= m_ListCtrl
.GetNextSelectedItem( pos
);
1084 CString str
= Buffer
[index
];
1085 formatLogStr( str
, ((CButton
*)(((CLog_analyserDlg
*)GetParent())->GetDlgItem( IDC_DispLineHeaders
)))->GetCheck() == 1 );
1090 ((CLog_analyserDlg
*)GetParent())->displayCurrentLine( s
);
1097 void CViewDialog::OnButtonFind()
1099 if ( FindDialog
) // spawn only 1 window
1102 m_ListCtrl
.ModifyStyle( 0, LVS_SHOWSELALWAYS
);
1104 DWORD frDown
= FindDownwards
? FR_DOWN
: 0;
1105 DWORD frMatchCase
= FindMatchCase
? FR_MATCHCASE
: 0;
1106 FindDialog
= new CFindReplaceDialog();
1107 FindDialog
->Create( true, FindStr
, NULL
, frDown
| frMatchCase
| FR_HIDEWHOLEWORD
, this );
1111 bool matchString( const CString
& str
, const CString
& substr
, bool matchCase
, int& matchPos
)
1115 matchPos
= str
.Find( substr
);
1116 return matchPos
!= -1;
1120 CString str2
= str
, substr2
= substr
;
1122 substr2
.MakeUpper();
1123 matchPos
= str2
.Find( substr2
);
1124 return matchPos
!= -1;
1132 afx_msg LRESULT
CViewDialog::OnFindReplace(WPARAM wParam
, LPARAM lParam
)
1135 if ( FindDialog
->IsTerminating() )
1138 m_ListCtrl
.ModifyStyle( LVS_SHOWSELALWAYS
, 0 );
1144 if ( FindDialog
->FindNext() )
1146 FindMatchCase
= (FindDialog
->MatchCase() != 0);
1147 FindDownwards
= (FindDialog
->SearchDown() != 0);
1148 FindStr
= FindDialog
->GetFindString();
1150 int lineIndex
, matchPos
;
1151 if ( FindDialog
->SearchDown() )
1153 BeginFindIndex
= (getSelectionIndex() == -1) ? 0 : getSelectionIndex() + 1;
1154 for ( lineIndex
=BeginFindIndex
; lineIndex
!=(int)Buffer
.size(); ++lineIndex
)
1156 if ( matchString( Buffer
[lineIndex
], FindStr
, FindDialog
->MatchCase()!=0, matchPos
) )
1158 scrollTo( lineIndex
);
1159 select( lineIndex
);
1160 //BeginFindIndex = getSelectionIndex()+1;
1163 s
.Format( _T("Found '%s' (downwards from line %d) at line %d:\r\n%s"), FindStr
, BeginFindIndex
, lineIndex
, Buffer
[lineIndex
] );
1164 ((CLog_analyserDlg
*)GetParent())->displayCurrentLine( s
);
1165 ((CLog_analyserDlg
*)GetParent())->selectText( 1, matchPos
, FindStr
.GetLength() );
1166 //BeginFindIndex = lineIndex+1;
1173 BeginFindIndex
= (getSelectionIndex() == -1) ? 0 : getSelectionIndex() - 1;
1174 for ( lineIndex
=BeginFindIndex
; lineIndex
>=0; --lineIndex
)
1176 if ( matchString( Buffer
[lineIndex
], FindStr
, FindDialog
->MatchCase()!=0, matchPos
) )
1178 scrollTo( lineIndex
);
1179 select( lineIndex
);
1180 //BeginFindIndex = getSelectionIndex()-1;
1183 s
.Format( _T("Found '%s' (upwards from line %d) at line %d:\r\n%s"), FindStr
, BeginFindIndex
, lineIndex
, Buffer
[lineIndex
] );
1184 ((CLog_analyserDlg
*)GetParent())->displayCurrentLine( s
);
1185 ((CLog_analyserDlg
*)GetParent())->selectText( 1, matchPos
, FindStr
.GetLength() );
1186 //BeginFindIndex = lineIndex-1;
1192 s
.Format( _T("Not found (%s from line %d)"), FindDialog
->SearchDown() ? _T("downwards") : _T("upwards"), BeginFindIndex
);
1194 //BeginFindIndex = 0;
1202 void CViewDialog::OnLButtonDown(UINT nFlags
, CPoint point
)
1204 if ( (Index
> 0) && (ChildWindowFromPoint( point
) == GetDlgItem( IDC_DragBar
)) )
1206 ((CLog_analyserDlg
*)GetParent())->beginResizeView( Index
);
1210 //PostMessage(WM_NCHITTEST,HTCAPTION,MAKELPARAM(point.x,point.y));
1211 CDialog::OnLButtonDown(nFlags
, point
);