Can dynamically set show/hide checkboxes in GitStatusListCtrl
[TortoiseGit.git] / src / Git / GitStatusListCtrl.h
blobf4634e8aa17434f4716338a6a0cd06f06ed97c60
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2013 - TortoiseGit
4 // Copyright (C) 2003-2008 - TortoiseSVN
5 // Copyright (C) 2010-2012 Sven Strickroth <email@cs-ware.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the 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 General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software Foundation,
19 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #pragma once
22 #include "TGitPath.h"
23 #include "GitStatus.h"
24 #include "GitRev.h"
25 #include "GitConfig.h"
26 #include "Colors.h"
27 #include "LoglistCommonResource.h"
28 #include "HintListCtrl.h"
30 #define GIT_WC_ENTRY_WORKING_SIZE_UNKNOWN (-1)
32 // these defines must be in the order the columns are inserted!
33 #define GITSLC_COLFILENAME 0x000000002
34 #define GITSLC_COLEXT 0x000000004
35 #define GITSLC_COLSTATUS 0x000000008
36 //#define SVNSLC_COLAUTHOR 0x000000040
37 //#define SVNSLC_COLREVISION 0x000000080
38 //#define SVNSLC_COLDATE 0x000000100
39 #define GITSLC_COLADD 0x000000010
40 #define GITSLC_COLDEL 0x000000020
41 #define GITSLC_COLMODIFICATIONDATE 0x000000040
42 #define GITSLC_COLSIZE 0x000000080
43 #define GITSLC_NUMCOLUMNS 8
45 //#define SVNSLC_COLURL 0x000000200
46 //#define SVNSLC_COLCOPYFROM 0x000020000
48 #define GITSLC_SHOWUNVERSIONED CTGitPath::LOGACTIONS_UNVER
49 #define GITSLC_SHOWNORMAL 0x00000000
50 #define GITSLC_SHOWMODIFIED (CTGitPath::LOGACTIONS_MODIFIED)
51 #define GITSLC_SHOWADDED (CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_COPY)
52 #define GITSLC_SHOWREMOVED CTGitPath::LOGACTIONS_DELETED
53 #define GITSLC_SHOWCONFLICTED CTGitPath::LOGACTIONS_UNMERGED
54 #define GITSLC_SHOWMISSING 0x00000000
55 #define GITSLC_SHOWREPLACED CTGitPath::LOGACTIONS_REPLACED
56 #define GITSLC_SHOWMERGED CTGitPath::LOGACTIONS_MERGED
57 #define GITSLC_SHOWIGNORED CTGitPath::LOGACTIONS_IGNORE
58 #define GITSLC_SHOWOBSTRUCTED 0x00000000
59 #define GITSLC_SHOWEXTERNAL 0x00000000
60 #define GITSLC_SHOWINCOMPLETE 0x00000000
61 #define GITSLC_SHOWINEXTERNALS 0x00000000
62 #define GITSLC_SHOWREMOVEDANDPRESENT 0x00000000
63 #define GITSLC_SHOWLOCKS 0x00000000
64 #define GITSLC_SHOWDIRECTFILES 0x00000000
65 #define GITSLC_SHOWDIRECTFOLDER 0x00000000
66 #define GITSLC_SHOWEXTERNALFROMDIFFERENTREPO 0x00000000
67 #define GITSLC_SHOWSWITCHED 0x00000000
68 #define GITSLC_SHOWINCHANGELIST 0x00000000
70 #define GITSLC_SHOWDIRECTS (GITSLC_SHOWDIRECTFILES | GITSLC_SHOWDIRECTFOLDER)
72 #define GITSLC_SHOWFILES 0x01000000
73 #define GITSLC_SHOWSUBMODULES 0x02000000
74 #define GITSLC_SHOWEVERYTHING 0xffffffff
76 #define GITSLC_SHOWVERSIONED (CTGitPath::LOGACTIONS_FORWORD|GITSLC_SHOWNORMAL|GITSLC_SHOWMODIFIED|\
77 GITSLC_SHOWADDED|GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
78 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
79 GITSLC_SHOWEXTERNAL|GITSLC_SHOWINCOMPLETE|GITSLC_SHOWINEXTERNALS|\
80 GITSLC_SHOWEXTERNALFROMDIFFERENTREPO)
82 #define GITSLC_SHOWVERSIONEDBUTNORMAL (GITSLC_SHOWMODIFIED|GITSLC_SHOWADDED|\
83 GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
84 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
85 GITSLC_SHOWEXTERNAL|GITSLC_SHOWINCOMPLETE|GITSLC_SHOWINEXTERNALS|\
86 GITSLC_SHOWEXTERNALFROMDIFFERENTREPO)
88 #define GITSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS (GITSLC_SHOWMODIFIED|\
89 GITSLC_SHOWADDED|GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
90 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
91 GITSLC_SHOWINCOMPLETE|GITSLC_SHOWEXTERNAL|GITSLC_SHOWINEXTERNALS)
93 #define GITSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALS (GITSLC_SHOWMODIFIED|\
94 GITSLC_SHOWADDED|GITSLC_SHOWREMOVED|GITSLC_SHOWCONFLICTED|GITSLC_SHOWMISSING|\
95 GITSLC_SHOWREPLACED|GITSLC_SHOWMERGED|GITSLC_SHOWIGNORED|GITSLC_SHOWOBSTRUCTED|\
96 GITSLC_SHOWINCOMPLETE)
98 #define GITSLC_SHOWALL (GITSLC_SHOWVERSIONED|GITSLC_SHOWUNVERSIONED)
100 #define GITSLC_POPALL 0xFFFFFFFFFFFFFFFF
101 #define GITSLC_POPCOMPAREWITHBASE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARE)
102 #define GITSLC_POPCOMPARE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPAREWC)
103 #define GITSLC_POPGNUDIFF CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_GNUDIFF1)
104 #define GITSLC_POPREVERT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_REVERT)
105 #define GITSLC_POPSHOWLOG CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LOG)
106 #define GITSLC_POPSHOWLOGSUBMODULE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LOGSUBMODULE)
107 #define GITSLC_POPSHOWLOGOLDNAME CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_LOGOLDNAME)
108 #define GITSLC_POPOPEN CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_OPEN)
109 #define GITSLC_POPDELETE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_DELETE)
110 #define GITSLC_POPADD CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_ADD)
111 #define GITSLC_POPIGNORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_IGNORE)
112 #define GITSLC_POPCONFLICT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_EDITCONFLICT)
113 #define GITSLC_POPRESOLVE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_RESOLVECONFLICT)
114 #define GITSLC_POPEXPLORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_EXPLORE)
115 #define GITSLC_POPCOMMIT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMMIT)
116 #define GITSLC_POPCHANGELISTS CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_CHECKGROUP)
117 #define GITSLC_POPBLAME CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_BLAME)
118 #define GITSLC_POPSAVEAS CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_SAVEAS)
119 #define GITSLC_POPCOMPARETWOFILES CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_COMPARETWO)
120 #define GITSLC_POPRESTORE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_POPRESTORE)
121 #define GITSLC_POPASSUMEVALID CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_ASSUMEVALID)
122 #define GITSLC_POPSKIPWORKTREE CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_SKIPWORKTREE)
123 #define GITSLC_POPEXPORT CGitStatusListCtrl::GetContextMenuBit(CGitStatusListCtrl::IDGITLC_EXPORT)
125 #define GITSLC_IGNORECHANGELIST _T("ignore-on-commit")
127 // This gives up to 64 standard properties and menu entries
128 #define GITSLC_MAXCOLUMNCOUNT 0xff
130 #define OVL_RESTORE 1
132 typedef int (__cdecl *GENERICCOMPAREFN)(const void * elem1, const void * elem2);
133 typedef CComCritSecLock<CComCriticalSection> Locker;
135 class CGitStatusListCtrlDropTarget;
138 * \ingroup TortoiseProc
139 * Helper class for CGitStatusListCtrl that represents
140 * the columns visible and their order as well as
141 * persisting that data in the registry.
143 * It assigns logical index values to the (potential) columns:
144 * 0 .. GitSLC_NUMCOLUMNS-1 contain the standard attributes
146 * The column vector contains the columns that are actually
147 * available in the control.
150 class ColumnManager
152 public:
154 /// construction / destruction
156 ColumnManager (CListCtrl* control) : control (control), m_dwDefaultColumns(0) {};
157 ~ColumnManager() {};
159 DWORD m_dwDefaultColumns;
160 /// registry access
162 void ReadSettings (DWORD defaultColumns, DWORD hideColumns, const CString& containerName, int ReadSettings, int *withlist=NULL);
163 void WriteSettings() const;
165 /// read column definitions
167 int GetColumnCount() const; ///< total number of columns
168 bool IsVisible (int column) const;
169 int GetInvisibleCount() const;
170 bool IsRelevant (int column) const;
171 CString GetName (int column) const;
172 int SetNames(UINT * buff, int size);
173 int GetWidth (int column, bool useDefaults = false) const;
174 int GetVisibleWidth (int column, bool useDefaults) const;
176 /// switch columns on and off
178 void SetVisible (int column, bool visible);
180 /// tracking column modifications
182 void ColumnMoved (int column, int position);
183 void ColumnResized (int column);
185 /// call these to update the user-prop list
186 /// (will also auto-insert /-remove new list columns)
188 /// don't clutter the context menu with irrelevant prop info
190 void RemoveUnusedProps();
192 /// bring everything back to its "natural" order
194 void ResetColumns (DWORD defaultColumns);
196 void OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult)
198 LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);
199 if ( (header != NULL)
200 && (header->iItem >= 0)
201 && (header->iItem < GetColumnCount()))
203 ColumnResized (header->iItem);
205 *pResult = 0;
208 void OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult)
210 LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);
211 *pResult = TRUE;
212 if ( (header != NULL)
213 && (header->iItem >= 0)
214 && (header->iItem < GetColumnCount())
215 // only allow the reordering if the column was not moved left of the first
216 // visible item - otherwise the 'invisible' columns are not at the far left
217 // anymore and we get all kinds of redrawing problems.
218 && (header->pitem)
219 && (header->pitem->iOrder >= GetInvisibleCount()))
221 ColumnMoved (header->iItem, header->pitem->iOrder);
225 void OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult)
227 LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
228 *pResult = 0;
229 if ((phdr->iItem < 0)||(phdr->iItem >= itemName.size()))
230 return;
232 if (IsVisible (phdr->iItem))
234 return;
236 *pResult = 1;
239 int OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)
241 LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
242 *pResult = 0;
243 if ((phdr->iItem < 0)||(phdr->iItem >= itemName.size()))
245 return 0;
248 // visible columns may be modified
250 if (IsVisible (phdr->iItem))
252 return 0;
255 // columns already marked as "invisible" internally may be (re-)sized to 0
257 if ( (phdr->pitem != NULL)
258 && (phdr->pitem->mask == HDI_WIDTH)
259 && (phdr->pitem->cxy == 0))
261 return 0;
264 if ( (phdr->pitem != NULL)
265 && (phdr->pitem->mask != HDI_WIDTH))
267 return 0;
270 *pResult = 1;
271 return 1;
273 void OnContextMenuHeader(CWnd * pWnd, CPoint point, bool isGroundEnable=false)
275 CHeaderCtrl * pHeaderCtrl = (CHeaderCtrl *)pWnd;
276 if ((point.x == -1) && (point.y == -1))
278 CRect rect;
279 pHeaderCtrl->GetItemRect(0, &rect);
280 pHeaderCtrl->ClientToScreen(&rect);
281 point = rect.CenterPoint();
284 CMenu popup;
285 if (popup.CreatePopupMenu())
287 int columnCount = GetColumnCount();
289 CString temp;
290 UINT uCheckedFlags = MF_STRING | MF_ENABLED | MF_CHECKED;
291 UINT uUnCheckedFlags = MF_STRING | MF_ENABLED;
293 // build control menu
295 //temp.LoadString(IDS_STATUSLIST_SHOWGROUPS);
296 //popup.AppendMenu(isGroundEnable? uCheckedFlags : uUnCheckedFlags, columnCount, temp);
298 temp.LoadString(IDS_STATUSLIST_RESETCOLUMNORDER);
299 popup.AppendMenu(uUnCheckedFlags, columnCount+2, temp);
300 popup.AppendMenu(MF_SEPARATOR);
302 // standard columns
303 AddMenuItem(&popup);
305 // user-prop columns:
306 // find relevant ones and sort 'em
308 std::map<CString, int> sortedProps;
309 for (int i = (int)itemName.size(); i < columnCount; ++i)
310 if (IsRelevant(i))
311 sortedProps[GetName(i)] = i;
313 if (!sortedProps.empty())
315 // add 'em to the menu
317 popup.AppendMenu(MF_SEPARATOR);
319 typedef std::map<CString, int>::const_iterator CIT;
320 for ( CIT iter = sortedProps.begin(), end = sortedProps.end()
321 ; iter != end
322 ; ++iter)
324 popup.AppendMenu ( IsVisible(iter->second)
325 ? uCheckedFlags
326 : uUnCheckedFlags
327 , iter->second
328 , iter->first);
332 // show menu & let user pick an entry
334 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, pWnd, 0);
335 if ((cmd >= 1)&&(cmd < columnCount))
337 SetVisible (cmd, !IsVisible(cmd));
339 else if (cmd == columnCount)
341 pWnd->GetParent()->SendMessage(LVM_ENABLEGROUPVIEW, !isGroundEnable, NULL);
342 //EnableGroupView(!isGroundEnable);
344 else if (cmd == columnCount+1)
346 RemoveUnusedProps();
348 else if (cmd == columnCount+2)
350 ResetColumns (m_dwDefaultColumns);
355 void AddMenuItem(CMenu *pop)
357 UINT uCheckedFlags = MF_STRING | MF_ENABLED | MF_CHECKED;
358 UINT uUnCheckedFlags = MF_STRING | MF_ENABLED;
360 for (int i = 1; i < itemName.size(); ++i)
362 if(IsRelevant(i))
363 pop->AppendMenu ( IsVisible(i)
364 ? uCheckedFlags
365 : uUnCheckedFlags
367 , GetName(i));
370 private:
372 /// initialization utilities
374 void ParseWidths (const CString& widths);
375 void SetStandardColumnVisibility (DWORD visibility);
376 void ParseColumnOrder (const CString& widths);
378 /// map internal column order onto visible column order
379 /// (all invisibles in front)
381 std::vector<int> GetGridColumnOrder();
382 void ApplyColumnOrder();
384 /// utilities used when writing data to the registry
386 DWORD GetSelectedStandardColumns() const;
387 CString GetWidthString() const;
388 CString GetColumnOrderString() const;
390 /// our parent control and its data
392 CListCtrl* control;
394 /// where to store in the registry
396 CString registryPrefix;
398 /// all columns in their "natural" order
400 struct ColumnInfo
402 int index; ///< is a user prop when < GitSLC_USERPROPCOLOFFSET
403 int width;
404 bool visible;
405 bool relevant; ///< set to @a visible, if no *shown* item has that property
408 std::vector<ColumnInfo> columns;
410 /// user-defined properties
412 std::set<CString> itemProps;
414 /// global column ordering including unused user props
416 std::vector<int> columnOrder;
418 std::vector<int> itemName;
423 * \ingroup TortoiseProc
424 * Simple utility class that defines the sort column order.
426 class CSorter
428 public:
430 CSorter ( ColumnManager* columnManager
431 , int sortedColumn
432 , bool ascending);
434 bool operator() ( const CTGitPath* entry1
435 , const CTGitPath* entry2) const;
437 static int A2L(const CString &str)
439 if(str==_T("-"))
440 return -1;
441 else
442 return _ttol(str);
445 private:
447 ColumnManager* columnManager;
448 int sortedColumn;
449 bool ascending;
453 * \ingroup SVN
454 * A List control, based on the MFC CListCtrl which shows a list of
455 * files with their Subversion status. The control also provides a context
456 * menu to do some Subversion tasks on the selected files.
458 * This is the main control used in many dialogs to show a list of files to
459 * work on.
461 class CGitStatusListCtrl :
462 public CListCtrl
464 public:
465 enum
467 IDGITLC_REVERT = 1,
468 IDGITLC_COMPARE,
469 IDGITLC_OPEN,
470 IDGITLC_DELETE,
471 IDGITLC_IGNORE,
472 IDGITLC_GNUDIFF1 ,
473 IDGITLC_LOG ,
474 IDGITLC_LOGOLDNAME,
475 IDGITLC_LOGSUBMODULE,
476 IDGITLC_EDITCONFLICT ,
477 IDGITLC_IGNOREMASK ,
478 IDGITLC_ADD ,
479 IDGITLC_RESOLVECONFLICT ,
480 IDGITLC_OPENWITH ,
481 IDGITLC_EXPLORE ,
482 IDGITLC_RESOLVETHEIRS ,
483 IDGITLC_RESOLVEMINE ,
484 IDGITLC_REMOVE ,
485 IDGITLC_COMMIT ,
486 IDGITLC_COPY ,
487 IDGITLC_COPYEXT ,
488 IDGITLC_REMOVEFROMCS ,
489 IDGITLC_CREATECS ,
490 IDGITLC_CREATEIGNORECS ,
491 IDGITLC_CHECKGROUP ,
492 IDGITLC_UNCHECKGROUP ,
493 IDGITLC_COMPAREWC ,
494 IDGITLC_BLAME ,
495 IDGITLC_SAVEAS ,
496 IDGITLC_REVERTTOREV ,
497 IDGITLC_REVERTTOPARENT ,
498 IDGITLC_VIEWREV ,
499 IDGITLC_FINDENTRY ,
500 IDGITLC_COMPARETWO ,
501 IDGITLC_GNUDIFF2 ,
502 IDGITLC_COMPARETWOFILES ,
503 IDGITLC_POPRESTORE ,
504 IDGITLC_CREATERESTORE ,
505 IDGITLC_RESTOREPATH ,
506 IDGITLC_ASSUMEVALID ,
507 IDGITLC_SKIPWORKTREE ,
508 IDGITLC_EXPORT ,
509 // the IDSVNLC_MOVETOCS *must* be the last index, because it contains a dynamic submenu where
510 // the submenu items get command ID's sequent to this number
511 IDGITLC_MOVETOCS ,
513 int GetColumnIndex(int colmask);
514 static inline unsigned __int64 GetContextMenuBit(int i){ return ((unsigned __int64 )0x1)<<i ;}
516 * Sent to the parent window (using ::SendMessage) after a context menu
517 * command has finished if the item count has changed.
519 static const UINT GITSLNM_ITEMCOUNTCHANGED;
521 * Sent to the parent window (using ::SendMessage) when the control needs
522 * to be refreshed. Since this is done usually in the parent window using
523 * a thread, this message is used to tell the parent to do exactly that.
525 static const UINT GITSLNM_NEEDSREFRESH;
528 * Sent to the parent window (using ::SendMessage) when the user drops
529 * files on the control. The LPARAM is a pointer to a TCHAR string
530 * containing the dropped path.
532 static const UINT GITSLNM_ADDFILE;
535 * Sent to the parent window (using ::SendMessage) when the user checks/unchecks
536 * one or more items in the control. The WPARAM contains the number of
537 * checked items in the control.
539 static const UINT GITSLNM_CHECKCHANGED;
541 static const UINT GITSLNM_ITEMCHANGED;
543 CGitStatusListCtrl(void);
544 ~CGitStatusListCtrl(void);
546 CString m_Rev1;
547 CString m_Rev2;
550 * \ingroup TortoiseProc
551 * Helper class for CGitStatusListCtrl which represents
552 * the data for each file shown.
554 #if 0
555 class FileEntry
557 public:
558 FileEntry() : status(git_wc_status_unversioned)
559 // , copyfrom_rev(GIT_REV_ZERO)
560 , last_commit_date(0)
561 , last_commit_rev(GIT_REV_ZERO)
562 // , remoterev(GIT_REV_ZERO)
563 , textstatus(git_wc_status_unversioned)
564 , propstatus(git_wc_status_unversioned)
565 // , remotestatus(git_wc_status_unversioned)
566 // , remotetextstatus(git_wc_status_unversioned)
567 // , remotepropstatus(git_wc_status_unversioned)
568 , copied(false)
569 , switched(false)
570 , checked(false)
571 , inunversionedfolder(false)
572 , inexternal(false)
573 , differentrepo(false)
574 , direct(false)
575 , isfolder(false)
576 , isNested(false)
577 , Revision(GIT_REV_ZERO)
578 , isConflicted(false)
579 // , present_props()
580 , needslock(false)
581 /// , working_size(SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN)
582 , keeplocal(false)
583 // , depth(git_depth_unknown)
586 const CTGitPath& GetPath() const
588 return path;
590 const bool IsChecked() const
592 return checked;
594 CString GetRelativeGitPath() const
596 if (path.IsEquivalentTo(basepath))
597 return path.GetGitPathString();
598 return path.GetGitPathString().Mid(basepath.GetGitPathString().GetLength()+1);
600 // const bool IsLocked() const
601 // {
602 // return !(lock_token.IsEmpty() && lock_remotetoken.IsEmpty());
603 // }
604 // const bool HasNeedsLock() const
605 // {
606 // return needslock;
607 // }
608 const bool IsFolder() const
610 return isfolder;
612 const bool IsInExternal() const
614 return inexternal;
616 const bool IsNested() const
618 return isNested;
620 const bool IsFromDifferentRepository() const
622 return differentrepo;
624 CString GetDisplayName() const
626 CString const& chopped = path.GetDisplayString(&basepath);
627 if (!chopped.IsEmpty())
629 return chopped;
631 else
633 // "Display name" must not be empty.
634 return path.GetFileOrDirectoryName();
637 CString GetChangeList() const
639 return changelist;
641 // CString GetURL() const
642 // {
643 // return url;
644 // }
645 public:
646 git_wc_status_kind status; ///< local status
647 git_wc_status_kind textstatus; ///< local text status
648 git_wc_status_kind propstatus; ///< local property status
650 private:
651 CTGitPath path; ///< full path of the file
652 CTGitPath basepath; ///< common ancestor path of all files
654 CString changelist; ///< the name of the changelist the item belongs to
656 CString last_commit_author; ///< the author which last committed this item
657 CTime last_commit_date; ///< the date when this item was last committed
658 git_revnum_t last_commit_rev; ///< the revision where this item was last committed
660 git_revnum_t remoterev; ///< the revision in HEAD of the repository
661 bool copied; ///< if the file/folder is added-with-history
662 bool switched; ///< if the file/folder is switched to another url
663 bool checked; ///< if the file is checked in the list control
664 bool inunversionedfolder; ///< if the file is inside an unversioned folder
665 bool inexternal; ///< if the item is in an external folder
666 bool differentrepo; ///< if the item is from a different repository than the rest
667 bool direct; ///< directly included (TRUE) or just a child of a folder
668 bool isfolder; ///< TRUE if entry refers to a folder
669 bool isNested; ///< TRUE if the folder from a different repository and/or path
670 bool isConflicted; ///< TRUE if a file entry is conflicted, i.e. if it has the conflicted paths set
671 bool needslock; ///< TRUE if the Git:needs-lock property is set
672 git_revnum_t Revision; ///< the base revision
673 // PropertyList present_props; ///< cacheable properties present in BASE
674 bool keeplocal; ///< Whether a local copy of this entry should be kept in the working copy after a deletion has been committed
675 git_depth_t depth; ///< the depth of this entry
676 friend class CGitStatusListCtrl;
677 friend class CGitStatusListCtrlDropTarget;
678 friend class CSorter;
680 #endif
683 * Initializes the control, sets up the columns.
684 * \param dwColumns mask of columns to show. Use the GitSLC_COLxxx defines.
685 * \param sColumnInfoContainer Name of a registry key
686 * where the position and visibility of each column
687 * is saved and used from. If the registry key
688 * doesn't exist, the default order is used
689 * and dwColumns tells which columns are visible.
690 * \param dwContextMenus mask of context menus to be active, not all make sense for every use of this control.
691 * Use the GitSLC_POPxxx defines.
692 * \param bHasCheckboxes TRUE if the control should show check boxes on the left of each file entry.
693 * \param bHasWC TRUE if the reporisty is not a bare repository (hides wc related items on the contextmenu)
695 void Init(DWORD dwColumns, const CString& sColumnInfoContainer, unsigned __int64 dwContextMenus = ((GITSLC_POPALL ^ GITSLC_POPCOMMIT) ^ GITSLC_POPRESTORE), bool bHasCheckboxes = true, bool bHasWC = true, DWORD allowedColumns = 0xffffffff);
697 * Sets a background image for the list control.
698 * The image is shown in the right bottom corner.
699 * \param nID the resource ID of the bitmap to use as the background
701 bool SetBackgroundImage(UINT nID);
703 * Makes the 'ignore' context menu only ignore the files and not add the
704 * folder which gets the Git:ignore property changed to the list.
705 * This is needed e.g. for the Add-dialog, where the modified folder
706 * showing up would break the resulting "add" command.
708 void SetIgnoreRemoveOnly(bool bRemoveOnly = true) {m_bIgnoreRemoveOnly = bRemoveOnly;}
710 * The unversioned items are by default shown after all other files in the list.
711 * If that behavior should be changed, set this value to false.
713 void PutUnversionedLast(bool bLast) {m_bUnversionedLast = bLast;}
715 * Fetches the Subversion status of all files and stores the information
716 * about them in an internal array.
717 * \param sFilePath path to a file which contains a list of files and/or folders for which to
718 * fetch the status, separated by newlines.
719 * \param bUpdate TRUE if the remote status is requested too.
720 * \return TRUE on success.
722 BOOL GetStatus ( const CTGitPathList* pathList=NULL
723 , bool bUpdate = false
724 , bool bShowIgnores = false
725 , bool bShowUnRev=false);
728 * Populates the list control with the previously (with GetStatus) gathered status information.
729 * \param dwShow mask of file types to show. Use the GitSLC_SHOWxxx defines.
730 * \param dwCheck mask of file types to check. Use GitLC_SHOWxxx defines. Default (0) means 'use the entry's stored check status'
732 void Show(unsigned int dwShow, unsigned int dwCheck = 0, bool bShowFolders = true,BOOL updateStatusList=FALSE, bool UseStoredCheckStatus=false);
733 void Show(unsigned int dwShow, const CTGitPathList& checkedList, bool bShowFolders = true);
736 * Copies the selected entries in the control to the clipboard. The entries
737 * are separated by newlines.
738 * \param dwCols the columns to copy. Each column is separated by a tab.
740 bool CopySelectedEntriesToClipboard(DWORD dwCols);
743 * If during the call to GetStatus() some Git:externals are found from different
744 * repositories than the first one checked, then this method returns TRUE.
746 BOOL HasExternalsFromDifferentRepos() const {return m_bHasExternalsFromDifferentRepos;}
749 * If during the call to GetStatus() some Git:externals are found then this method returns TRUE.
751 BOOL HasExternals() const {return m_bHasExternals;}
754 * If unversioned files are found (but not necessarily shown) TRUE is returned.
756 BOOL HasUnversionedItems() {return m_bHasUnversionedItems;}
759 * If there are any locks in the working copy, TRUE is returned
761 BOOL HasLocks() const {return m_bHasLocks;}
764 * If there are any change lists defined in the working copy, TRUE is returned
766 BOOL HasChangeLists() const {return m_bHasChangeLists;}
769 * Returns the file entry data for the list control index.
771 //CGitStatusListCtrl::FileEntry * GetListEntry(UINT_PTR index);
774 * Returns the file entry data for the specified path.
775 * \note The entry might not be shown in the list control.
777 //CGitStatusListCtrl::FileEntry * GetListEntry(const CTGitPath& path);
780 * Returns the index of the list control entry with the specified path,
781 * or -1 if the path is not in the list control.
783 int GetIndex(const CTGitPath& path);
786 * Returns the file entry data for the specified path in the list control.
788 //CGitStatusListCtrl::FileEntry * GetVisibleListEntry(const CTGitPath& path);
791 * Returns a String containing some statistics like number of modified, normal, deleted,...
792 * files.
794 CString GetStatisticsString(bool simple=false);
797 * Set a static control which will be updated automatically with
798 * the number of selected and total files shown in the list control.
800 void SetStatLabel(CWnd * pStatLabel){m_pStatLabel = pStatLabel;};
803 * Set a tri-state checkbox which is updated automatically if the
804 * user checks/unchecks file entries in the list control to indicate
805 * if all files are checked, none are checked or some are checked.
807 void SetSelectButton(CButton * pButton) {m_pSelectButton = pButton;}
810 * Set a button which is de-/activated automatically. The button is
811 * only set active if at least one item is selected.
813 void SetConfirmButton(CButton * pButton) {m_pConfirmButton = pButton;}
816 * Select/unselect all entries in the list control.
817 * \param bSelect TRUE to check, FALSE to uncheck.
819 void SelectAll(bool bSelect, bool bIncludeNoCommits = false);
822 * Checks or unchecks all specified items
823 * \param dwCheck GITLC_SHOWxxx defines
824 * \param check if true matching items will be selected, false unchecks matching items
826 void Check(DWORD dwCheck, bool check = true);
828 /** Set a checkbox on an entry in the listbox
829 * Keeps the listctrl checked state and the FileEntry's checked flag in sync
831 void SetEntryCheck(CTGitPath* pEntry, int listboxIndex, bool bCheck);
833 /** Write a list of the checked items' paths into a path list
835 void WriteCheckedNamesToPathList(CTGitPathList& pathList);
837 /** fills in \a lMin and \a lMax with the lowest/highest revision of all
838 * files/folders in the working copy.
839 * \param bShownOnly if true, the min/max revisions are calculated only for shown items
840 * \param bCheckedOnly if true, the min/max revisions are calculated only for items
841 * which are checked.
842 * \remark Since an item can only be checked if it is visible/shown in the list control
843 * bShownOnly is automatically set to true if bCheckedOnly is true
845 void GetMinMaxRevisions(git_revnum_t& rMin, git_revnum_t& rMax, bool bShownOnly, bool bCheckedOnly);
848 * Returns the parent directory of all entries in the control.
849 * if \a bStrict is set to false, then the paths passed to the control
850 * to fetch the status (in GetStatus()) are used if possible.
852 CString GetCommonDirectory(bool bStrict);
855 * Returns the parent url of all entries in the control.
856 * if \a bStrict is set to false, then the paths passed to the control
857 * to fetch the status (in GetStatus()) are used if possible.
859 CTGitPath GetCommonURL(bool bStrict);
862 * Sets a pointer to a boolean variable which is checked periodically
863 * during the status fetching. As soon as the variable changes to true,
864 * the operations stops.
866 void SetCancelBool(bool * pbCanceled) {m_pbCanceled = pbCanceled;}
869 * Sets the string shown in the control while the status is fetched.
870 * If not set, it defaults to "please wait..."
872 void SetBusyString(const CString& str) {m_sBusy = str;}
873 void SetBusyString(UINT id) {m_sBusy.LoadString(id);}
876 * Sets the string shown in the control if no items are shown. This
877 * can happen for example if there's nothing modified and the unversioned
878 * files aren't shown either, so there's nothing to commit.
879 * If not set, it defaults to "file list is empty".
881 void SetEmptyString(const CString& str) {m_sEmpty = str;}
882 void SetEmptyString(UINT id) {m_sEmpty.LoadString(id);}
885 * Returns the number of selected items
887 LONG GetSelected(){return m_nSelected;};
890 * Enables dropping of files on the control.
892 bool EnableFileDrop();
895 * Checks if the path already exists in the list.
897 bool HasPath(const CTGitPath& path);
899 * Checks if the path is shown/visible in the list control.
901 bool IsPathShown(const CTGitPath& path);
903 * Forces the children to be checked when the parent folder is checked,
904 * and the parent folder to be unchecked if one of its children is unchecked.
906 void CheckChildrenWithParent(bool bCheck) {m_bCheckChildrenWithParent = bCheck;}
909 * Allows checking the items if change lists are present. If set to false,
910 * items are not checked if at least one changelist is available.
912 void CheckIfChangelistsArePresent(bool bCheck) {m_bCheckIfGroupsExist = bCheck;}
914 * Returns the currently used show flags passed to the Show() method.
916 DWORD GetShowFlags() {return m_dwShow;}
918 public:
919 CString GetLastErrorMessage() {return m_sLastError;}
921 void Block(BOOL block, BOOL blockUI) {m_bBlock = block; m_bBlockUI = blockUI;}
923 LONG GetUnversionedCount() { return m_nShownUnversioned; }
924 LONG GetModifiedCount() { return m_nShownModified; }
925 LONG GetAddedCount() { return m_nShownAdded; }
926 LONG GetDeletedCount() { return m_nShownDeleted; }
927 LONG GetConflictedCount() { return m_nShownConflicted; }
928 LONG GetFileCount() { return m_nShownFiles; }
929 LONG GetSubmoduleCount() { return m_nShownSubmodules; }
931 LONG m_nTargetCount; ///< number of targets in the file passed to GetStatus()
933 CString m_sURL; ///< the URL of the target or "(multiple targets)"
935 GitRev m_HeadRev; ///< the HEAD revision of the repository if bUpdate was TRUE
937 bool m_amend; ///< if true show the changes to the revision before the last commit
939 CString m_sUUID; ///< the UUID of the associated repository
941 bool m_bIsRevertTheirMy; ///< at rebase case, Their and My version is revert.
943 CWnd *m_hwndLogicalParent;
945 DECLARE_MESSAGE_MAP()
947 public:
948 void SetBusy(bool b) {m_bBusy = b; Invalidate();}
949 void SetHasCheckboxes(bool bHasCheckboxes)
951 m_bHasCheckboxes = bHasCheckboxes;
952 DWORD exStyle = GetExtendedStyle();
953 if (bHasCheckboxes)
954 exStyle |= LVS_EX_CHECKBOXES;
955 else
956 exStyle &= ~LVS_EX_CHECKBOXES;
957 SetExtendedStyle(exStyle);
960 private:
961 void SaveColumnWidths(bool bSaveToRegistry = false);
962 //void AddEntry(FileEntry * entry, WORD langID, int listIndex); ///< add an entry to the control
963 void RemoveListEntry(int index); ///< removes an entry from the listcontrol and both arrays
964 bool BuildStatistics(); ///< build the statistics and correct the case of files/folders
965 void StartDiff(int fileindex); ///< start the external diff program
966 void StartDiffWC(int fileindex); ///< start the external diff program
967 void StartDiffTwo(int fileindex);
969 enum
971 ALTERNATIVEEDITOR,
972 OPEN,
973 OPEN_WITH,
975 void OpenFile(CTGitPath *path,int mode);
977 /// Process one line of the command file supplied to GetStatus
978 bool FetchStatusForSingleTarget(GitConfig& config, GitStatus& status, const CTGitPath& target,
979 bool bFetchStatusFromRepository, CStringA& strCurrentRepositoryUUID, CTGitPathList& arExtPaths,
980 bool bAllDirect, git_depth_t depth = git_depth_infinity, bool bShowIgnores = false);
982 /// Create 'status' data for each item in an unversioned folder
983 void AddUnversionedFolder(const CTGitPath& strFolderName, const CTGitPath& strBasePath, GitConfig * config);
985 /// Read the all the other status items which result from a single GetFirstStatus call
986 void ReadRemainingItemsStatus(GitStatus& status, const CTGitPath& strBasePath, CStringA& strCurrentRepositoryUUID, CTGitPathList& arExtPaths, GitConfig * config, bool bAllDirect);
988 /// Clear the status vector (contains custodial pointers)
989 void ClearStatusArray();
991 /// Sort predicate function - Compare the paths of two entries without regard to case
992 //static bool EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2);
994 /// Predicate used to build a list of only the versioned entries of the FileEntry array
995 //static bool IsEntryVersioned(const FileEntry* pEntry1);
997 /// Look up the relevant show flags for a particular Git status value
998 DWORD GetShowFlagsFromGitStatus(git_wc_status_kind status);
1000 /// Adjust the checkbox-state on all descendants of a specific item
1001 //void SetCheckOnAllDescendentsOf(const FileEntry* parentEntry, bool bCheck);
1003 /// Build a path list of all the selected items in the list (NOTE - SELECTED, not CHECKED)
1004 void FillListOfSelectedItemPaths(CTGitPathList& pathList, bool bNoIgnored = false);
1006 /// Enables/Disables group view and adds all groups to the list control.
1007 /// If bForce is true, then group view is enabled and the 'null' group is added.
1008 bool PrepareGroups(bool bForce = false);
1009 /// Returns the group number to which the group header belongs
1010 /// If the point is not over a group header, -1 is returned
1011 int GetGroupFromPoint(POINT * ppt);
1012 /// Returns the number of change lists the selection has
1013 size_t GetNumberOfChangelistsInSelection();
1015 /// Puts the item to the corresponding group
1016 bool SetItemGroup(int item, int groupindex);
1018 void CheckEntry(int index, int nListItems);
1019 void UncheckEntry(int index, int nListItems);
1021 /// sends an GitSLNM_CHECKCHANGED notification to the parent
1022 void NotifyCheck();
1023 CWnd * GetLogicalParent() { return m_hwndLogicalParent != NULL ? m_hwndLogicalParent : this->GetParent(); }
1025 int CellRectFromPoint(CPoint& point, RECT *cellrect, int *col) const;
1027 void OnContextMenuList(CWnd * pWnd, CPoint point);
1028 void OnContextMenuGroup(CWnd * pWnd, CPoint point);
1029 void OnContextMenuHeader(CWnd * pWnd, CPoint point);
1031 virtual void PreSubclassWindow();
1032 virtual BOOL PreTranslateMessage(MSG* pMsg);
1033 virtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO* pTI) const;
1034 afx_msg void OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult);
1035 afx_msg BOOL OnToolTipText(UINT id, NMHDR *pNMHDR, LRESULT *pResult);
1036 afx_msg void OnHdnItemclick(NMHDR *pNMHDR, LRESULT *pResult);
1037 afx_msg void OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);
1038 afx_msg BOOL OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);
1039 afx_msg void OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult);
1040 afx_msg void OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult);
1041 afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
1043 void CreateChangeList(const CString& name);
1045 afx_msg void OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult);
1046 afx_msg void OnLvnGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult);
1047 afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);
1048 afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
1049 afx_msg UINT OnGetDlgCode();
1050 afx_msg void OnNMReturn(NMHDR *pNMHDR, LRESULT *pResult);
1051 afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
1052 afx_msg void OnPaint();
1053 afx_msg void OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult);
1054 afx_msg void OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);
1055 afx_msg void OnDestroy();
1058 void FilesExport();
1059 void FileSaveAs(CTGitPath *path);
1060 int RevertSelectedItemToVersion(bool parent = false);
1062 private:
1063 bool * m_pbCanceled;
1064 bool m_bAscending; ///< sort direction
1065 int m_nSortedColumn; ///< which column to sort
1066 bool m_bHasCheckboxes;
1067 bool m_bHasWC;
1068 bool m_bUnversionedLast;
1069 bool m_bHasExternalsFromDifferentRepos;
1070 bool m_bHasExternals;
1071 BOOL m_bHasUnversionedItems;
1072 bool m_bHasLocks;
1073 bool m_bHasChangeLists;
1074 //typedef std::vector<FileEntry*> FileEntryVector;
1075 //FileEntryVector m_arStatusArray;
1076 std::vector<CTGitPath*> m_arStatusArray;
1077 std::vector<size_t> m_arListArray;
1078 std::map<CString, int> m_changelists;
1079 bool m_bHasIgnoreGroup;
1080 //CTGitPathList m_ConflictFileList;
1081 CTGitPathList m_StatusFileList;
1082 CTGitPathList m_UnRevFileList;
1083 CTGitPathList m_IgnoreFileList;
1084 //CTGitPathList m_StatusUrlList;
1085 CString m_sLastError;
1087 LONG m_nUnversioned;
1088 LONG m_nNormal;
1089 LONG m_nModified;
1090 LONG m_nAdded;
1091 LONG m_nDeleted;
1092 LONG m_nConflicted;
1093 LONG m_nTotal;
1094 LONG m_nSelected;
1095 LONG m_nLineAdded;
1096 LONG m_nLineDeleted;
1097 LONG m_nRenamed;
1099 LONG m_nShownUnversioned;
1100 LONG m_nShownModified;
1101 LONG m_nShownAdded;
1102 LONG m_nShownDeleted;
1103 LONG m_nShownConflicted;
1104 LONG m_nShownFiles;
1105 LONG m_nShownSubmodules;
1107 DWORD m_dwDefaultColumns;
1108 DWORD m_dwShow;
1109 bool m_bShowFolders;
1110 bool m_bShowIgnores;
1111 bool m_bUpdate;
1112 unsigned __int64 m_dwContextMenus;
1113 BOOL m_bBlock;
1114 BOOL m_bBlockUI;
1115 bool m_bBusy;
1116 bool m_bEmpty;
1117 bool m_bIgnoreRemoveOnly;
1118 bool m_bCheckIfGroupsExist;
1119 bool m_bFileDropsEnabled;
1120 bool m_bOwnDrag;
1122 int m_nIconFolder;
1123 int m_nRestoreOvl;
1125 CWnd * m_pStatLabel;
1126 CButton * m_pSelectButton;
1127 CButton * m_pConfirmButton;
1128 CColors m_Colors;
1130 CString m_sEmpty;
1131 CString m_sBusy;
1132 CString m_sNoPropValueText;
1134 bool m_bCheckChildrenWithParent;
1135 CGitStatusListCtrlDropTarget * m_pDropTarget;
1137 ColumnManager m_ColumnManager;
1139 std::map<CString,bool> m_mapFilenameToChecked; ///< Remember de-/selected items
1140 CComCriticalSection m_critSec;
1142 friend class CGitStatusListCtrlDropTarget;
1143 public:
1144 enum
1146 FILELIST_MODIFY= 0x1,
1147 FILELIST_UNVER = 0x2,
1148 FILELIST_IGNORE =0x4
1150 public:
1151 int UpdateFileList(git_revnum_t hash,CTGitPathList *List=NULL);
1152 int UpdateFileList(int mask, bool once=true,CTGitPathList *List=NULL);
1153 int UpdateUnRevFileList(CTGitPathList &list);
1154 int UpdateUnRevFileList(CTGitPathList *List=NULL);
1155 int UpdateIgnoreFileList(CTGitPathList *List=NULL);
1157 int UpdateWithGitPathList(CTGitPathList &list);
1159 void AddEntry(CTGitPath* path, WORD langID, int ListIndex);
1160 void Clear();
1161 int m_FileLoaded;
1162 git_revnum_t m_CurrentVersion;
1163 bool m_bDoNotAutoselectSubmodules;
1164 std::map<CString, CString> m_restorepaths;
1167 #if 0
1168 class CGitStatusListCtrlDropTarget : public CIDropTarget
1170 public:
1171 CGitStatusListCtrlDropTarget(CGitStatusListCtrl * pGitStatusListCtrl):CIDropTarget(pGitStatusListCtrl->m_hWnd){m_pGitStatusListCtrl = pGitStatusListCtrl;}
1173 virtual bool OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD * /*pdwEffect*/, POINTL pt);
1174 virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect);
1175 private:
1176 CGitStatusListCtrl * m_pGitStatusListCtrl;
1178 #endif