Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / tools / misc / log_analyser / ViewDialog.cpp
blob3a5a725a45462691ce25eb63ff449da16e7ebda6
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
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
24 #include "stdafx.h"
25 #include "log_analyser.h"
26 #include "ViewDialog.h"
27 #include "log_analyserDlg.h"
29 #include <fstream>
30 #include <algorithm>
31 using namespace std;
34 #ifdef _DEBUG
35 #define new DEBUG_NEW
36 #undef THIS_FILE
37 static char THIS_FILE[] = __FILE__;
38 #endif
41 extern CString LogDateString;
42 static UINT WM_FINDREPLACE = ::RegisterWindowMessage(FINDMSGSTRING);
43 time_t CurrentTime;
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;
72 // Save dc state
73 int nSavedDC = pDC->SaveDC();
75 // Get item image and state info
76 LV_ITEM lvi;
77 lvi.mask = LVIF_IMAGE | LVIF_STATE;
78 lvi.iItem = nItem;
79 lvi.iSubItem = 0;
80 lvi.stateMask = 0xFFFF; // get all state flags
81 GetItem(&lvi);
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;
105 CRect rcHighlight;
106 CRect rcWnd;
107 GetClientRect(&rcWnd);
108 rcHighlight = rcBounds;
109 rcHighlight.left = rcLabel.left;
110 rcHighlight.right = rcWnd.right;
112 // Draw the background color
113 if( bHighlight )
114 pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
115 pDC->FillRect( rcHighlight, &CBrush(_ViewDialog->getBkColorForLine( nItem, bHighlight!=0 )) );
117 // Set clip region
118 rcCol.right = rcCol.left + GetColumnWidth(0);
119 CRgn rgn;
120 rgn.CreateRectRgnIndirect(&rcCol);
121 pDC->SelectClipRgn(&rgn);
122 rgn.DeleteObject();
124 // Draw state icon
125 if (lvi.state & LVIS_STATEIMAGEMASK)
127 int nImage = ((lvi.state & LVIS_STATEIMAGEMASK)>>12) - 1;
128 pImageList = GetImageList(LVSIL_STATE);
129 if (pImageList)
131 pImageList->Draw(pDC, nImage,
132 CPoint(rcCol.left, rcCol.top), ILD_TRANSPARENT);
136 // Draw normal and overlay icon
137 pImageList = GetImageList(LVSIL_SMALL);
138 if (pImageList)
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
158 LV_COLUMN lvc;
159 lvc.mask = LVCF_FMT | LVCF_WIDTH;
161 rcBounds.right = rcHighlight.right > rcBounds.right ? rcHighlight.right :
162 rcBounds.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)
173 continue;
175 // Get the text justification
176 UINT nJustify = DT_LEFT;
177 switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
179 case LVCFMT_RIGHT:
180 nJustify = DT_RIGHT;
181 break;
182 case LVCFMT_CENTER:
183 nJustify = DT_CENTER;
184 break;
185 default:
186 break;
189 rcLabel = rcCol;
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);
204 // Restore dc
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);
216 if(nItem != -1)
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);
239 UpdateWindow();
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)
249 return;
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)
262 return;
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)
272 ON_WM_KEYDOWN()
273 //}}AFX_MSG_MAP
274 END_MESSAGE_MAP()
277 /////////////////////////////////////////////////////////////////////////////
278 // CViewDialog dialog
281 CViewDialog::CViewDialog(CWnd* pParent /*=NULL*/)
282 : CDialog(CViewDialog::IDD, pParent)
284 //{{AFX_DATA_INIT(CViewDialog)
285 m_Caption = _T("");
286 //}}AFX_DATA_INIT
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);
296 //}}AFX_DATA_MAP
301 * Load, using the current filters
303 void CViewDialog::reload()
305 SessionDatePassed = false;
306 CWaitCursor wc;
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 );
315 UpdateData( false );
316 clear();
317 setRedraw( false );
319 time( &CurrentTime );
321 // Translate bookmarks (phase 1)
322 CurrentBookmark = -1;
323 vector<int> bookmarksAbsoluteLines;
324 if ( ! Bookmarks.empty() )
326 getBookmarksAbsoluteLines( bookmarksAbsoluteLines );
327 Bookmarks.clear();
330 loadFileOrSeries( bookmarksAbsoluteLines );
331 commitAddedLines();
333 setRedraw( true );
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);
344 if (tms)
345 strftime (cstime, 25, "%Y/%m/%d %H:%M:%S", tms);
346 else
347 smprintf(cstime, 25, "bad date %d", (unsigned int)date);
348 return cstime;
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 )
357 // Read the files
358 unsigned int currentAbsoluteLineNum = 0, currentLineNum = 0;
359 for ( unsigned int i=0; i!=Filenames.size(); ++i )
361 CString& filename = Filenames[i];
363 NLMISC::CIFile ifs;
365 if (ifs.open(NLMISC::tStrToUtf8(filename)))
367 char line [1024];
369 while (!ifs.eof())
371 ifs.getline(line, 1024);
373 if ( SessionDatePassed )
375 // Stop if the session is finished
376 if ( (! LogSessionStartDate.IsEmpty()) && (strstr( line, nlTStrToUtf8(LogDateString))) )
378 return;
381 // Test the filters
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 );
392 ++currentLineNum;
395 ++currentAbsoluteLineNum;
397 else
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;
420 string::size_type p;
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 )
440 if ( line[sp]==' ')
441 ++nbBlank;
442 if ( nbBlank==5 )
443 break;
445 if ( (nbBlank==5) && (line[sp+1]==':') && (line[sp+2]==' ') )
447 return true;
452 return false;
456 bool HasCorruptedLines;
462 std::string CViewDialog::corruptedLinesString( const std::vector<unsigned int>& corruptedLines )
464 string res;
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;
476 return res;
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";
489 else
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;
495 // Read the files
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 );
501 if ( ! ifs.fail() )
503 char line [1024];
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();
515 goto endOfLoading;
518 // Test the filters
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
537 addLine( line );
538 ++currentLineNum;
541 ++currentAbsoluteLineNum;
543 else
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();
559 else
561 CString s;
562 s.Format(_T( "<Cannot open file %s>\r\n"), filename);
563 actualFilenames += NLMISC::tStrToUtf8(s);
567 endOfLoading:
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();
598 bool found;
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);
605 if ( found )
607 yes = true; // positive filter passed (no need to check another one)
608 break;
610 // else try the next one
612 if ( ! yes )
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);
621 if ( found )
623 return false; // negative filter not passed (no need to check another one)
626 return true; // negative filter passed
631 * Load trace
633 void CViewDialog::reloadTrace()
635 CWaitCursor wc;
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)";
643 else
644 m_Caption = "Trace of " + PosFilter[0] + " (all)";
646 else
648 if ( LogSessionStartDate == "Beginning" )
650 SessionDatePassed = true;
652 if ( PosFilter.empty() )
653 m_Caption = "Trace of " + Seriesname + " (session " + LogSessionStartDate + ")" ;
654 else
655 m_Caption = "Trace of " + PosFilter[0] + " (session " + LogSessionStartDate + ")" ;
658 UpdateData( false );
659 clear();
661 ifstream ifs( Seriesname );
662 if ( ! ifs.fail() )
664 char line [1024];
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))))
672 break;
674 // Read if it's a TRACE
675 char *pc = strstr( line, "TRACE" );
676 if ( pc != NULL )
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 );
685 else
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>" );
699 else
701 addLine( "<Cannot open log file>" );
704 commitAddedLines();
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)
715 ON_WM_LBUTTONDOWN()
716 ON_REGISTERED_MESSAGE( WM_FINDREPLACE, OnFindReplace )
717 //}}AFX_MSG_MAP
718 END_MESSAGE_MAP()
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 )
731 displayString();
733 ((CLog_analyserDlg*)GetParent())->setCurrentView( Index );
735 m_ListCtrl.RepaintSelectedItems();
736 *pResult = 0;
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 )
748 displayString();
750 ((CLog_analyserDlg*)GetParent())->setCurrentView( Index );
752 m_ListCtrl.RepaintSelectedItems();
753 *pResult = 0;
758 * Resize
760 void CViewDialog::resizeView( int nbViews, int top, int left )
762 RECT parentRect;
763 GetParent()->GetClientRect( &parentRect );
765 int width = (int)((parentRect.right-32)*WidthR);
766 RECT viewRect;
767 viewRect.left = left;
768 viewRect.top = top;
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 );
774 LVCOLUMN lvc;
775 lvc.mask = LVCF_WIDTH;
776 lvc.cx = width-24;
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 )
810 addLine( "" );
816 * Commit the lines previously added
818 void CViewDialog::commitAddedLines()
820 m_ListCtrl.SetItemCount( (int)Buffer.size() );
821 m_ListCtrl.SetColumnWidth( 0, LVSCW_AUTOSIZE );
826 * Scroll
828 void CViewDialog::scrollTo( int index )
830 int deltaIndex = index - m_ListCtrl.GetTopIndex();
831 RECT rect;
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 );
843 * Select
845 void CViewDialog::select( int index )
847 LVITEM itstate;
848 itstate.mask = LVIF_STATE;
849 itstate.state = 0;
850 int sm = getSelectionIndex();
851 if ( sm != -1 )
853 m_ListCtrl.SetItemState( sm, &itstate );
856 if ( index != -1 )
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() )
883 // Add
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" );
888 else
890 // Remove
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() )
906 return;
908 // Precondition: the vector is sorted
909 int origIndex = (CurrentBookmark==-1) ? getScrollIndex() : CurrentBookmark, destIndex;
910 unsigned int i = 0;
911 while ( (i < Bookmarks.size()) && (Bookmarks[i] <= origIndex) )
912 ++i;
913 if ( i == Bookmarks.size() )
915 // Origin index > all the bookmarks => go back to the first one
916 destIndex = Bookmarks[0];
918 else
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 );
931 * Add several lines
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 ) );
941 ++pos; // skip '\n'
942 lineStartPos = pos;
945 if ( lineStartPos > pos )
946 addLine( lines.Mid( lineStartPos, pos-lineStartPos ) );
951 * Clear
953 void CViewDialog::clear()
955 Buffer.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 )
971 reload();
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 );
983 m_ListCtrl.initIt();
985 Index = -1;
986 BeginFindIndex = -1;
987 FindDialog = NULL;
988 FindMatchCase = false;
989 FindDownwards = true;
990 WidthR = 0.0f;
991 CurrentBookmark = -1;
992 return TRUE;
997 * Return the text color
999 COLORREF CViewDialog::getTextColorForLine( int index, bool selected )
1001 if ( selected )
1002 return ::GetSysColor(COLOR_HIGHLIGHTTEXT);
1003 else
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
1012 return RGB(0,0,0);
1018 * Return the background color
1020 COLORREF CViewDialog::getBkColorForLine( int index, bool selected )
1022 unsigned int i = 0;
1023 while ( (i < Bookmarks.size()) && (Bookmarks[i]<index) )
1024 ++i;
1025 if ( (i < Bookmarks.size()) && (index == Bookmarks[i]) )
1026 if ( selected )
1027 return (::GetSysColor(COLOR_HIGHLIGHT) + RGB(0xC0,0x90,0x90)) / 2; // selected bookmark
1028 else
1029 return RGB(0xC0,0x90,0x90); // bookmark
1030 else
1031 if ( selected )
1032 return ::GetSysColor(COLOR_HIGHLIGHT); // selected
1033 else
1034 return GetSysColor(COLOR_WINDOW); // normal
1041 void formatLogStr( CString& str, bool displayHeaders )
1043 if ( ! displayHeaders )
1045 int pos = str.Find( _T(" : ") );
1046 if ( pos != -1 )
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 );
1069 *pResult = 0;
1074 * Display string
1076 void CViewDialog::displayString()
1078 // Build the string
1079 CString s;
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 );
1086 s += str + "\r\n";
1089 // Display it
1090 ((CLog_analyserDlg*)GetParent())->displayCurrentLine( s );
1095 * Search string
1097 void CViewDialog::OnButtonFind()
1099 if ( FindDialog ) // spawn only 1 window
1100 return;
1102 m_ListCtrl.ModifyStyle( 0, LVS_SHOWSELALWAYS );
1103 select( -1 );
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 )
1113 if ( matchCase )
1115 matchPos = str.Find( substr );
1116 return matchPos != -1;
1118 else
1120 CString str2 = str, substr2 = substr;
1121 str2.MakeUpper();
1122 substr2.MakeUpper();
1123 matchPos = str2.Find( substr2 );
1124 return matchPos != -1;
1132 afx_msg LRESULT CViewDialog::OnFindReplace(WPARAM wParam, LPARAM lParam)
1134 // Test 'Cancel'
1135 if ( FindDialog->IsTerminating() )
1137 FindDialog = NULL;
1138 m_ListCtrl.ModifyStyle( LVS_SHOWSELALWAYS, 0 );
1139 select( -1 );
1140 return 0;
1143 // Test 'Find'
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;
1161 //displayString();
1162 CString s;
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;
1167 return 1;
1171 else
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;
1181 //displayString();
1182 CString s;
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;
1187 return 1;
1191 CString s;
1192 s.Format( _T("Not found (%s from line %d)"), FindDialog->SearchDown() ? _T("downwards") : _T("upwards"), BeginFindIndex );
1193 AfxMessageBox( s );
1194 //BeginFindIndex = 0;
1195 return 0;
1198 return 0;
1202 void CViewDialog::OnLButtonDown(UINT nFlags, CPoint point)
1204 if ( (Index > 0) && (ChildWindowFromPoint( point ) == GetDlgItem( IDC_DragBar )) )
1206 ((CLog_analyserDlg*)GetParent())->beginResizeView( Index );
1208 else
1210 //PostMessage(WM_NCHITTEST,HTCAPTION,MAKELPARAM(point.x,point.y));
1211 CDialog::OnLButtonDown(nFlags, point);