KiCad PCB EDA Suite
Loading...
Searching...
No Matches
local_history_pane.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include "local_history_pane.h"
25#include "kicad_manager_frame.h"
26
27#include <git2.h>
28#include <project.h>
29#include <wx/filename.h>
30#include <wx/intl.h>
31#include <wx/menu.h>
32#include <wx/settings.h>
33
34wxDEFINE_EVENT( EVT_LOCAL_HISTORY_REFRESH, wxCommandEvent );
35
37 wxPanel( aParent ),
38 m_frame( aParent ),
39 m_list( nullptr ),
40 m_refreshTimer( this )
41{
42 m_list = new wxListCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL );
43 m_list->AppendColumn( _( "Title" ) );
44 m_list->AppendColumn( _( "Time" ) );
45 m_list->SetColumnWidth( 0, FromDIP( 200 ) );
46 m_list->SetColumnWidth( 1, FromDIP( 150 ) );
47
48 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
49 sizer->Add( m_list, 1, wxEXPAND );
50 SetSizer( sizer );
51
52 m_list->Bind( wxEVT_MOTION, &LOCAL_HISTORY_PANE::OnMotion, this );
53 m_list->Bind( wxEVT_LIST_ITEM_RIGHT_CLICK, &LOCAL_HISTORY_PANE::OnRightClick, this );
54 Bind( wxEVT_TIMER, &LOCAL_HISTORY_PANE::OnRefreshTimer, this, m_refreshTimer.GetId() );
55 Bind( EVT_LOCAL_HISTORY_REFRESH, &LOCAL_HISTORY_PANE::OnRefreshEvent, this );
56
57 m_refreshTimer.Start( 10000 );
58}
59
64
65void LOCAL_HISTORY_PANE::RefreshHistory( const wxString& aProjectPath )
66{
67 if( !IsShownOnScreen() )
68 return;
69
70 m_list->DeleteAllItems();
71 m_commits.clear();
72
73 wxFileName hist( aProjectPath, wxS( ".history" ) );
74
75 git_repository* repo = nullptr;
76 if( git_repository_open( &repo, hist.GetFullPath().mb_str().data() ) != 0 )
77 return;
78
79 git_revwalk* walk = nullptr;
80 if( git_revwalk_new( &walk, repo ) != 0 )
81 {
82 git_repository_free( repo );
83 return;
84 }
85
86 if( git_revwalk_push_head( walk ) != 0 )
87 {
88 git_revwalk_free( walk );
89 git_repository_free( repo );
90 return;
91 }
92
93 wxDateTime now = wxDateTime::Now();
94
95 git_oid oid;
96 while( git_revwalk_next( &oid, walk ) == 0 )
97 {
98 git_commit* commit = nullptr;
99 if( git_commit_lookup( &commit, repo, &oid ) != 0 )
100 continue;
101
103 info.hash = wxString::FromUTF8( git_oid_tostr_s( &oid ) );
104 info.summary = wxString::FromUTF8( git_commit_summary( commit ) );
105 info.message = wxString::FromUTF8( git_commit_message( commit ) );
106 info.date = wxDateTime( static_cast<time_t>( git_commit_time( commit ) ) );
107
108 // Calculate relative time
109 wxTimeSpan elapsed = now - info.date;
110 wxString timeStr;
111
112 if( elapsed.GetMinutes() < 1 )
113 {
114 timeStr = _( "Moments ago" );
115 }
116 else if( elapsed.GetMinutes() < 91 )
117 {
118 int minutes = elapsed.GetMinutes();
119 timeStr = wxString::Format( _( "%d minutes ago" ), minutes );
120 }
121 else if( elapsed.GetHours() < 24 )
122 {
123 int hours = elapsed.GetHours();
124 timeStr = wxString::Format( _( "%d hours ago" ), hours );
125 }
126 else
127 {
128 timeStr = info.date.Format();
129 }
130
131 wxString title = info.message.BeforeFirst( '\n' );
132 long row = m_list->InsertItem( m_list->GetItemCount(), title );
133 m_list->SetItem( row, 1, timeStr );
134
135 // Tint by foreground colour so light and dark themes both stay readable.
136 if( info.summary.StartsWith( wxS( "Autosave" ) ) )
137 m_list->SetItemTextColour( row, wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
138 else if( info.summary.StartsWith( wxS( "Backup" ) ) )
139 m_list->SetItemTextColour( row, wxColour( 80, 120, 200 ) );
140
141 m_commits.emplace_back( std::move( info ) );
142 git_commit_free( commit );
143 }
144
145 git_revwalk_free( walk );
146 git_repository_free( repo );
147}
148
149void LOCAL_HISTORY_PANE::OnMotion( wxMouseEvent& aEvent )
150{
151 int flags = 0;
152 long item = m_list->HitTest( aEvent.GetPosition(), flags );
153
154 if( item >= 0 && item < static_cast<long>( m_commits.size() ) )
155 {
156 const LOCAL_COMMIT_INFO& info = m_commits[item];
157 wxString tip = info.message;
158
159 if( !tip.EndsWith( wxS( "\n" ) ) )
160 tip << wxS( "\n" );
161
162 tip << wxS( "\n" ) << info.date.FormatISOCombined();
163
164 if( m_list->GetToolTipText() != tip )
165 m_list->SetToolTip( tip );
166 }
167 else
168 {
169 m_list->UnsetToolTip();
170 }
171
172 aEvent.Skip();
173}
174
175void LOCAL_HISTORY_PANE::OnRightClick( wxListEvent& aEvent )
176{
177 long item = aEvent.GetIndex();
178
179 if( item < 0 || item >= static_cast<long>( m_commits.size() ) )
180 return;
181
182 wxMenu menu;
183 wxMenuItem* restore = menu.Append( wxID_ANY, _( "Restore Commit" ) );
184 menu.Bind( wxEVT_MENU,
185 [this, item]( wxCommandEvent& )
186 {
187 m_frame->RestoreCommitFromHistory( m_commits[item].hash );
188 },
189 restore->GetId() );
190 PopupMenu( &menu );
191}
192
193
194void LOCAL_HISTORY_PANE::OnRefreshEvent( wxCommandEvent& aEvent )
195{
196 wxString projectPath = aEvent.GetString();
197
198 if( projectPath.IsEmpty() )
199 projectPath = m_frame->Prj().GetProjectPath();
200
201 RefreshHistory( projectPath );
202}
203
204
205void LOCAL_HISTORY_PANE::OnRefreshTimer( wxTimerEvent& aEvent )
206{
207 // Refresh the history to show updates from autosave
208 RefreshHistory( m_frame->Prj().GetProjectPath() );
209}
The main KiCad project manager frame.
LOCAL_HISTORY_PANE(KICAD_MANAGER_FRAME *aParent)
void OnRefreshTimer(wxTimerEvent &aEvent)
void OnRightClick(wxListEvent &aEvent)
KICAD_MANAGER_FRAME * m_frame
void RefreshHistory(const wxString &aProjectPath)
void OnRefreshEvent(wxCommandEvent &aEvent)
std::vector< LOCAL_COMMIT_INFO > m_commits
void OnMotion(wxMouseEvent &aEvent)
#define _(s)
wxDEFINE_EVENT(EVT_LOCAL_HISTORY_REFRESH, wxCommandEvent)