mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-23 20:47:25 -08:00
feature<Launcher>: close tabs by context menu; collect garbage after repository closed
This commit is contained in:
parent
a9f138076e
commit
1a46551a77
14 changed files with 145 additions and 103 deletions
|
@ -90,6 +90,14 @@ namespace SourceGit {
|
|||
Current.MainWindow.Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open repository.
|
||||
/// </summary>
|
||||
/// <param name="repo"></param>
|
||||
public static void Open(Git.Repository repo) {
|
||||
(Current.MainWindow as UI.Launcher).Open(repo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deactivated event.
|
||||
/// </summary>
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace SourceGit.Git {
|
|||
public class Repository {
|
||||
|
||||
#region HOOKS
|
||||
public static Action<Repository> OnOpen = null;
|
||||
[XmlIgnore] public Action<string> OnNavigateCommit = null;
|
||||
[XmlIgnore] public Action OnWorkingCopyChanged = null;
|
||||
[XmlIgnore] public Action OnTagChanged = null;
|
||||
|
@ -23,6 +22,7 @@ namespace SourceGit.Git {
|
|||
[XmlIgnore] public Action OnBranchChanged = null;
|
||||
[XmlIgnore] public Action OnCommitsChanged = null;
|
||||
[XmlIgnore] public Action OnSubmoduleChanged = null;
|
||||
[XmlIgnore] public Action OnClosing = null;
|
||||
#endregion
|
||||
|
||||
#region PROPERTIES_SAVED
|
||||
|
@ -294,14 +294,14 @@ namespace SourceGit.Git {
|
|||
featurePrefix = GetConfig("gitflow.prefix.feature");
|
||||
releasePrefix = GetConfig("gitflow.prefix.release");
|
||||
hotfixPrefix = GetConfig("gitflow.prefix.hotfix");
|
||||
|
||||
OnOpen?.Invoke(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close repository.
|
||||
/// </summary>
|
||||
public void Close() {
|
||||
OnClosing?.Invoke();
|
||||
|
||||
OnBranchChanged = null;
|
||||
OnCommitsChanged = null;
|
||||
OnTagChanged = null;
|
||||
|
@ -309,6 +309,7 @@ namespace SourceGit.Git {
|
|||
OnWorkingCopyChanged = null;
|
||||
OnNavigateCommit = null;
|
||||
OnSubmoduleChanged = null;
|
||||
OnClosing = null;
|
||||
|
||||
cachedBranches.Clear();
|
||||
cachedRemotes.Clear();
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<Geometry x:Key="Icon.Submodule">M557.696 545.347L789.873 402.66c23.998-14.999 31.297-46.496 16.398-70.493-14.798-23.798-45.995-31.197-69.993-16.699L506.501 456.555 277.123 315.37c-24.098-14.798-55.595-7.3-70.493 16.799-14.799 24.097-7.3 55.594 16.798 70.493l231.778 142.586V819.12c0 28.297 22.897 51.195 51.195 51.195 28.297 0 51.195-22.898 51.195-51.195V545.347h0.1zM506.5 0l443.356 255.975v511.95L506.501 1023.9 63.144 767.925v-511.95L506.5 0z</Geometry>
|
||||
<Geometry x:Key="Icon.LFS">M169.984 470.016l0 84.010667 86.016 0 0-84.010667-86.016 0zM86.016 598.016l0-171.989333 852.010667 0 0 171.989333-852.010667 0zM256 297.984l0-84.010667-86.016 0 0 84.010667 86.016 0zM86.016 169.984l852.010667 0 0 171.989333-852.010667 0 0-171.989333zM169.984 726.016l0 84.010667 86.016 0 0-84.010667-86.016 0zM86.016 854.016l0-171.989333 852.010667 0 0 171.989333-852.010667 0z</Geometry>
|
||||
<Geometry x:Key="Icon.User">M 841.758 299.375 c 0 165.25 -134 299.375 -299.375 299.375 S 243.009 464.75 243.009 299.375 S 377.009 0 542.383 0 c 165.25 0 299.375 134 299.375 299.375 Z m 0 0 M 789.383 612.75 c -69.75 55.125 -156.25 85.625 -247.125 85.625 c -91.875 0 -179.25 -31.25 -249.25 -87.375 C 108.384 678.875 25.8838 915.75 25.8838 1024 h 1027.75 c 0 -107.25 -83.125 -342.5 -264.25 -411.25 Z m 0 0</Geometry>
|
||||
<Geometry x:Key="Icon.Home">M1024 590.432 512 193.024 0 590.432 0 428.416 512 30.976 1024 428.416ZM896 576 896 960 640 960 640 704 384 704 384 960 128 960 128 576 512 288Z</Geometry>
|
||||
|
||||
<Geometry x:Key="Icon.ScrollLeft">M753.613 996.727L269.38 511.505 754.602 27.272z</Geometry>
|
||||
<Geometry x:Key="Icon.ScrollRight">M270.387 27.273L754.62 512.495 269.398 996.728z</Geometry>
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
xmlns:local="clr-namespace:SourceGit.UI"
|
||||
xmlns:converters="clr-namespace:SourceGit.Converters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
Unloaded="Cleanup">
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<RoutedUICommand x:Key="OpenSearchBarCommand" Text="OpenSearchBar"/>
|
||||
<RoutedUICommand x:Key="HideSearchBarCommand" Text="HideSearchBar"/>
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace SourceGit.UI {
|
|||
/// </summary>
|
||||
/// <param name="repo">Opened repository.</param>
|
||||
public Dashboard(Git.Repository opened) {
|
||||
opened.OnClosing = Cleanup;
|
||||
opened.OnWorkingCopyChanged = UpdateLocalChanges;
|
||||
opened.OnTagChanged = UpdateTags;
|
||||
opened.OnStashChanged = UpdateStashes;
|
||||
|
@ -78,6 +79,22 @@ namespace SourceGit.UI {
|
|||
UpdateSubmodules();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup
|
||||
/// </summary>
|
||||
public void Cleanup() {
|
||||
repo = null;
|
||||
localBranchTree.ItemsSource = null;
|
||||
remoteBranchTree.ItemsSource = null;
|
||||
tagList.ItemsSource = null;
|
||||
cachedLocalBranches.Clear();
|
||||
cachedRemotes.Clear();
|
||||
|
||||
histories.Cleanup();
|
||||
commits.Cleanup();
|
||||
stashes.Cleanup();
|
||||
}
|
||||
|
||||
#region DATA_UPDATE
|
||||
private void UpdateHistories() {
|
||||
Dispatcher.Invoke(() => {
|
||||
|
@ -287,14 +304,6 @@ namespace SourceGit.UI {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void Cleanup(object sender, RoutedEventArgs e) {
|
||||
localBranchTree.ItemsSource = null;
|
||||
remoteBranchTree.ItemsSource = null;
|
||||
tagList.ItemsSource = null;
|
||||
cachedLocalBranches.Clear();
|
||||
cachedRemotes.Clear();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region TOOLBAR
|
||||
|
@ -1021,7 +1030,7 @@ namespace SourceGit.UI {
|
|||
sub.Name = Path.GetFileName(path);
|
||||
sub.Parent = repo;
|
||||
|
||||
if (!sub.BringUpTab()) sub.Open();
|
||||
App.Open(sub);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -71,6 +71,9 @@ namespace SourceGit.UI {
|
|||
/// </summary>
|
||||
public void Reset() {
|
||||
mask.Visibility = Visibility.Visible;
|
||||
lineChanges = null;
|
||||
foreach (var editor in editors) editorContainer.Children.Remove(editor);
|
||||
editors.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
xmlns:sourcegit="clr-namespace:SourceGit"
|
||||
xmlns:converters="clr-namespace:SourceGit.Converters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
Unloaded="Cleanup">
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid x:Name="layout" Background="{StaticResource Brush.BG1}">
|
||||
<!-- List Panel (SearchBar + DataGrid) -->
|
||||
<Grid x:Name="commitListPanel" Background="{StaticResource Brush.BG2}" ClipToBounds="True">
|
||||
|
|
|
@ -78,6 +78,15 @@ namespace SourceGit.UI {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup
|
||||
/// </summary>
|
||||
public void Cleanup() {
|
||||
commitGraph.Children.Clear();
|
||||
commitList.ItemsSource = null;
|
||||
cachedCommits.Clear();
|
||||
}
|
||||
|
||||
#region DATA
|
||||
public void SetCommits(List<Git.Commit> commits) {
|
||||
cachedCommits = commits;
|
||||
|
@ -184,12 +193,6 @@ namespace SourceGit.UI {
|
|||
SetLoadingEnabled(false);
|
||||
});
|
||||
}
|
||||
|
||||
private void Cleanup(object sender, RoutedEventArgs e) {
|
||||
commitGraph.Children.Clear();
|
||||
commitList.ItemsSource = null;
|
||||
cachedCommits.Clear();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SEARCH_BAR
|
||||
|
@ -516,7 +519,7 @@ namespace SourceGit.UI {
|
|||
|
||||
// Reset
|
||||
var reset = new MenuItem();
|
||||
reset.Header = $"Reset '{current.Name}' To Here";
|
||||
reset.Header = $"Reset '{current.Name}' to Here";
|
||||
reset.Visibility = commit.IsHEAD ? Visibility.Collapsed : Visibility.Visible;
|
||||
reset.Click += (o, e) => {
|
||||
Reset.Show(Repo, commit);
|
||||
|
@ -526,7 +529,7 @@ namespace SourceGit.UI {
|
|||
|
||||
// Rebase or interactive rebase
|
||||
var rebase = new MenuItem();
|
||||
rebase.Header = commit.IsMerged ? $"Interactive Rebase '{current.Name}' From Here" : $"Rebase '{current.Name}' To Here";
|
||||
rebase.Header = commit.IsMerged ? $"Interactive Rebase '{current.Name}' from Here" : $"Rebase '{current.Name}' to Here";
|
||||
rebase.Visibility = commit.IsHEAD ? Visibility.Collapsed : Visibility.Visible;
|
||||
rebase.Click += (o, e) => {
|
||||
if (commit.IsMerged) {
|
||||
|
@ -587,7 +590,7 @@ namespace SourceGit.UI {
|
|||
|
||||
// Save as patch
|
||||
var patch = new MenuItem();
|
||||
patch.Header = "Save As Patch";
|
||||
patch.Header = "Save as Patch";
|
||||
patch.Click += (o, e) => {
|
||||
FolderDailog.Open("Save patch to ...", saveTo => {
|
||||
Repo.RunCommand($"format-patch {commit.SHA} -1 -o \"{saveTo}\"", null);
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
Data="M 0,0 L 0,6 6,6 C 6,6 0,6 0,0 Z"
|
||||
Fill="Transparent"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="8,0" VerticalAlignment="Center">
|
||||
<StackPanel Orientation="Horizontal" Margin="12,0" VerticalAlignment="Center">
|
||||
<Path Grid.Column="0" Width="14" Height="14" x:Name="Icon" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Git}"/>
|
||||
|
||||
<ContentPresenter
|
||||
|
@ -119,15 +119,8 @@
|
|||
TextElement.Foreground="{DynamicResource Brush.FG}"
|
||||
TextElement.FontWeight="Bold"
|
||||
ContentSource="Header"
|
||||
Margin="8,0"
|
||||
Margin="8,0,0,0"
|
||||
RecognizesAccessKey="True" />
|
||||
|
||||
<Button x:Name="Closer" Background="Transparent" Grid.Column="2" Click="CloseRepo" Visibility="Hidden">
|
||||
<Button.ToolTip>
|
||||
<ToolTip Content="CLOSE" FontWeight="Normal"/>
|
||||
</Button.ToolTip>
|
||||
<Path Width="8" Height="8" Style="{StaticResource Style.Icon}" Data="{StaticResource Icon.Close}"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
|
@ -139,16 +132,8 @@
|
|||
<Setter TargetName="CornerRight" Property="Fill" Value="{StaticResource Brush.BG1}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="AllowDrop" Value="False">
|
||||
<Setter TargetName="Icon" Property="Fill" Value="#FFF05133"/>
|
||||
<Setter TargetName="Closer" Property="Visibility" Value="Collapsed"/>
|
||||
<Setter TargetName="Icon" Property="Data" Value="{StaticResource Icon.Home}"/>
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="AllowDrop" Value="True"/>
|
||||
<Condition Property="IsMouseOver" Value="True"/>
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="Closer" Property="Visibility" Value="Visible"/>
|
||||
</MultiTrigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsSelected" Value="False"/>
|
||||
|
@ -166,6 +151,7 @@
|
|||
|
||||
<EventSetter Event="MouseMove" Handler="TabsMouseMove"/>
|
||||
<EventSetter Event="Drop" Handler="TabsDrop"/>
|
||||
<EventSetter Event="ContextMenuOpening" Handler="TabsContextMenuOpening"/>
|
||||
</Style>
|
||||
</TabControl.ItemContainerStyle>
|
||||
|
||||
|
|
|
@ -36,26 +36,9 @@ namespace SourceGit.UI {
|
|||
/// Constructor
|
||||
/// </summary>
|
||||
public Launcher() {
|
||||
Git.Repository.OnOpen = repo => {
|
||||
Dispatcher.Invoke(() => {
|
||||
var page = new Dashboard(repo);
|
||||
var tab = new Tab() {
|
||||
Title = repo.Parent == null ? repo.Name : $"{repo.Parent.Name} : {repo.Name}",
|
||||
Tooltip = repo.Path,
|
||||
AllowDragDrop = true,
|
||||
Repo = repo,
|
||||
Page = page,
|
||||
};
|
||||
|
||||
repo.SetPopupManager(page.popupManager);
|
||||
Tabs.Add(tab);
|
||||
openedTabs.SelectedItem = tab;
|
||||
});
|
||||
};
|
||||
|
||||
Tabs.Add(new Tab() {
|
||||
Title = "SOURCE GIT",
|
||||
Tooltip = "Welcome Page",
|
||||
Title = "HOME",
|
||||
Tooltip = "Repositories Manager",
|
||||
AllowDragDrop = false,
|
||||
Page = new Manager(),
|
||||
});
|
||||
|
@ -64,21 +47,87 @@ namespace SourceGit.UI {
|
|||
openedTabs.SelectedItem = Tabs[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open repository
|
||||
/// </summary>
|
||||
/// <param name="repo"></param>
|
||||
public void Open(Git.Repository repo) {
|
||||
for (int i = 1; i < Tabs.Count; i++) {
|
||||
var opened = Tabs[i];
|
||||
if (opened.Repo.Path == repo.Path) {
|
||||
openedTabs.SelectedItem = opened;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
repo.Open();
|
||||
|
||||
var page = new Dashboard(repo);
|
||||
var tab = new Tab() {
|
||||
Title = repo.Parent == null ? repo.Name : $"{repo.Parent.Name} : {repo.Name}",
|
||||
Tooltip = repo.Path,
|
||||
AllowDragDrop = true,
|
||||
Repo = repo,
|
||||
Page = page,
|
||||
};
|
||||
|
||||
repo.SetPopupManager(page.popupManager);
|
||||
Tabs.Add(tab);
|
||||
openedTabs.SelectedItem = tab;
|
||||
}
|
||||
|
||||
#region LAYOUT_CONTENT
|
||||
/// <summary>
|
||||
/// Close repository tab.
|
||||
/// Context menu for tab items.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void CloseRepo(object sender, RoutedEventArgs e) {
|
||||
var tab = (sender as Button).DataContext as Tab;
|
||||
if (tab == null || tab.Repo == null) return;
|
||||
private void TabsContextMenuOpening(object sender, ContextMenuEventArgs ev) {
|
||||
var tab = (sender as TabItem).DataContext as Tab;
|
||||
if (tab == null) {
|
||||
ev.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Tabs.Remove(tab);
|
||||
tab.Page = null;
|
||||
tab.Repo.RemovePopup();
|
||||
tab.Repo.Close();
|
||||
tab.Repo = null;
|
||||
var repo = tab.Repo;
|
||||
if (repo == null) {
|
||||
ev.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var close = new MenuItem();
|
||||
close.Header = "Close";
|
||||
close.Click += (o, e) => {
|
||||
Tabs.Remove(tab);
|
||||
|
||||
tab.Page = null;
|
||||
tab.Repo.RemovePopup();
|
||||
tab.Repo.Close();
|
||||
tab.Repo = null;
|
||||
};
|
||||
|
||||
var copyPath = new MenuItem();
|
||||
copyPath.Header = "Copy Path";
|
||||
copyPath.Click += (o, e) => {
|
||||
Clipboard.SetText(repo.Path);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
var refresh = new MenuItem();
|
||||
refresh.Header = "Refresh";
|
||||
refresh.Click += (o, e) => {
|
||||
repo.AssertCommand(null);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
var menu = new ContextMenu();
|
||||
menu.Items.Add(close);
|
||||
menu.Items.Add(new Separator());
|
||||
menu.Items.Add(copyPath);
|
||||
menu.Items.Add(refresh);
|
||||
menu.IsOpen = true;
|
||||
|
||||
ev.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -189,29 +238,4 @@ namespace SourceGit.UI {
|
|||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for repository.
|
||||
/// </summary>
|
||||
public static class RepositoryTabBindings {
|
||||
|
||||
/// <summary>
|
||||
/// Bring up tab of repository if it was opened before.
|
||||
/// </summary>
|
||||
/// <param name="repo"></param>
|
||||
/// <returns></returns>
|
||||
public static bool BringUpTab(this Git.Repository repo) {
|
||||
var main = App.Current.MainWindow as Launcher;
|
||||
|
||||
for (int i = 1; i < main.Tabs.Count; i++) {
|
||||
var opened = main.Tabs[i];
|
||||
if (opened.Repo.Path == repo.Path) {
|
||||
main.openedTabs.SelectedItem = opened;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -429,7 +429,7 @@ namespace SourceGit.UI {
|
|||
}
|
||||
|
||||
var repo = App.Preference.AddRepository(path, "");
|
||||
if (!repo.BringUpTab()) repo.Open();
|
||||
App.Open(repo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
xmlns:git="clr-namespace:SourceGit.Git"
|
||||
xmlns:converters="clr-namespace:SourceGit.Converters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
Unloaded="Cleanup">
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid Background="{StaticResource Brush.BG3}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300"/>
|
||||
|
|
|
@ -34,9 +34,7 @@ namespace SourceGit.UI {
|
|||
/// <summary>
|
||||
/// Cleanup
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void Cleanup(object sender, RoutedEventArgs e) {
|
||||
public void Cleanup() {
|
||||
stashList.ItemsSource = null;
|
||||
changeList.ItemsSource = null;
|
||||
diff.Reset();
|
||||
|
|
|
@ -112,6 +112,18 @@ namespace SourceGit.UI {
|
|||
Validation.ClearInvalid(txtCommitMsg.GetBindingExpression(TextBox.TextProperty));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup
|
||||
/// </summary>
|
||||
public void Cleanup() {
|
||||
Repo = null;
|
||||
unstagedList.ItemsSource = null;
|
||||
unstagedList.ItemsSource = null;
|
||||
stageList.ItemsSource = null;
|
||||
stageTree.ItemsSource = null;
|
||||
diffViewer.Reset();
|
||||
}
|
||||
|
||||
#region UNSTAGED
|
||||
private void UnstagedTreeMultiSelectionChanged(object sender, RoutedEventArgs e) {
|
||||
mergePanel.Visibility = Visibility.Collapsed;
|
||||
|
|
Loading…
Reference in a new issue