diff --git a/src/Models/Preference.cs b/src/Models/Preference.cs index 66071940..bc5cb4b6 100644 --- a/src/Models/Preference.cs +++ b/src/Models/Preference.cs @@ -208,6 +208,7 @@ namespace SourceGit.Models { public WindowInfo Window { get; set; } = new WindowInfo(); public List Groups { get; set; } = new List(); public List Repositories { get; set; } = new List(); + public List Recents { get; set; } = new List(); public RestoreTabs Restore { get; set; } = new RestoreTabs(); #endregion @@ -355,5 +356,36 @@ namespace SourceGit.Models { if (removedIdx >= 0) Repositories.RemoveAt(removedIdx); } #endregion + + #region RECENTS + public void AddRecent(string path) { + if (Recents.Count == 0) { + Recents.Add(path); + return; + } + + for (int i = 0; i < Recents.Count; i++) { + if (Recents[i] == path) { + if (i != 0) { + Recents.RemoveAt(i); + Recents.Insert(0, path); + } + + return; + } + } + + Recents.Insert(0, path); + } + + public void RemoveRecent(string path) { + for (int i = 0; i < Recents.Count; i++) { + if (Recents[i] == path) { + Recents.RemoveAt(i); + return; + } + } + } + #endregion } } \ No newline at end of file diff --git a/src/Resources/Locales/en_US.xaml b/src/Resources/Locales/en_US.xaml index ee6eac93..a9c38d00 100644 --- a/src/Resources/Locales/en_US.xaml +++ b/src/Resources/Locales/en_US.xaml @@ -1,500 +1,502 @@ - - START - SURE - SAVE - CLOSE - CANCEL - CLICK TO GO - Reveal in File Explorer - Save As ... - Save File to ... - Copy Path - {0} Bytes - FILTER - Optional. - SELECT FOLDER - CHANGE THEME - - URL : - Git Repository URL - Parent Folder : - Relative foler to store this module. Optional. - - ABOUT - SourceGit - OPEN SOURCE GIT CLIENT - - Patch - Apply Patch - Patch File : - Select .patch file to apply - Whitespace : - Ignore whitespace changes - No Warn - Turns off the trailing whitespace warning - Warn - Outputs warnings for a few such errors, but applies - Error - Raise errors and refuses to apply the patch - Error All - Similar to 'error', but shows more - - Archive ... - Archive - Revision : - Save Archive To : - Select archive file path - - Blame - Right click to see commit info - COMMIT SHA - AUTHOR - MODIFY TIME - - SUBMODULES - Add Submodule - Fetch nested submodules - Open Submodule Repository - Copy Relative Path - Delete Submodule - - Cherry-Pick This Commit - Cherry Pick - Commit : - Commit all changes - - Clone Remote Repository - Repository URL : - Git Repository URL - Parent Folder : - Folder to contain this repository - Local Name : - Repository name. Optional. - Remote Name : - Remote name. Optional. - Extra Parameters : - Additional arguments to clone repository. Optional. - - INFORMATION - AUTHOR - COMMITTER - SHA - PARENTS - REFS - MESSAGE - CHANGED - CHANGES - Search Files ... - FILES - - Configure - User : - User name for this repository - Email : - Email address - Proxy : - HTTP proxy used by this repository - - Create Branch - Create Local Branch - Based On : - New Branch Name : - Enter branch name. - Local Changes : - Stash & Reapply - Discard - Check out after created - Git do not hold any branch until you do first commit. - - Create Tag - New Tag At : - Tag Name : - Recommanded format :v1.0.0-alpha - Tag Message : - Optional. - - Open In File Browser - Open Git Bash - Search Commit - Configure this repository - WORKSPACE - LOCAL BRANCHES - NEW BRANCH - REMOTES - ADD REMOTE - TAGS - NEW TAG - SUBMODULES - ADD SUBMODULE - UPDATE SUBMODULE - SUBTREES - ADD/LINK SUBTREE - RESOLVE - CONTINUE - ABORT - - GIT FLOW - Initialize Git-Flow - Production Branch : - Development Branch : - Feature : - Release : - Hotfix : - Feature Prefix : - Release Prefix : - Hotfix Prefix : - Version Tag Prefix : - Start Feature ... - Start Release ... - Start Hotfix ... - GIT FLOW - Start Feature - GIT FLOW - Start Release - GIT FLOW - Start Hotfix - Enter name - GIT FLOW - Finish Feature - GIT FLOW - Finish Release - GIT FLOW - Finish Hotfix - {0} branch name is required. - {0} branch name contains invalid characters. - {0} prefix is required. - {0} contains invalid characters. - Development branch is same with production! - Keep branch - - Bookmark - Open - Open Container Folder - - Push '{0}' - Discard all changes - Fast-Forward to '{0}' - Pull '{0}' - Pull '{0}' into '{1}' - Checkout '{0}' - Merge '{0}' into '{1}' - Rebase '{0}' on '{1}' - Git Flow - Finish '{0}' - Rename '{0}' - Delete '{0}' - Tracking ... - Copy Branch Name - Unset Upstream - - Fetch '{0}' - Edit '{0}' - Delete '{0}' - Copy Remote URL - - Reset '{0}' to Here - Rebase '{0}' to Here - Cherry-Pick This Commit - Reword - Squash Into Parent - Revert Commit - Save as Patch ... - Copy Commit SHA - Copy Commit Info - - Push '{0}' - Delete '{0}' - Copy Tag Name - - Apply - Pop - Drop - - Unstage - Stage... - Discard... - Stash... - Unstage {0} files - Stage {0} files... - Discard {0} files... - Stash {0} files... - Save As Patch... - - Confirm To Delete Branch - Branch : - - Confirm To Delete Remote - Remote : - - Confirm To Delete Tag - Tag : - Delete from remote repositories - - Confirm To Delete Submodule - Submodule Path : - - Next Difference - Previous Difference - Toggle One-Side/Two-Sides - Open With Merge Tool - SELECT FILE TO VIEW CHANGES - NO CHANGES OR ONLY EOL CHANGES - BINARY DIFF - OLD : - NEW : - LFS OBJECT CHANGE - Copy - - Confirm To Discard Changes - Changes : - You can't undo this action!!! - All local changes in working copy. - Total {0} changes will be discard - - Fetch - Fetch Remote Changes - Remote : - Fetch all remotes - Prune remote dead branches - - File History - - CHANGE DISPLAY MODE - Show as Grid - Show as List - Show as Tree - - SELECT FOLDER - SELECTED : - - Histories - SEARCH SHA/SUBJECT/AUTHOR. PRESS ENTER TO SEARCH, ESC TO QUIT - CLEAR - Switch Curve/Polyline Graph Mode - Switch Horizontal/Vertical Layout - SELECTED {0} COMMITS - HISTORIES GUIDE - 1. Select single commit to view detail - 2. Select two commits to show differences - 3. Select more than 2 commits to count - 4. Open context menu to see more options - - Initialize Repository - Path : - Invalid repository detected. Run `git init` under this path? - - Source Git - PREFERENCE - ABOUT - ERROR - - NEW PAGE - *Repositories - WELCOME PAGE - Close Tab - Close Other Tabs - Close Tabs to the Right - Bookmark - - Merge Branch - Source Branch : - Into : - Merge Option : - - SourceGit - Open Local Repository - Clone Remote Repository - Bookmarks - Histories - Add Folder - Add Sub-Folder - Rename - Delete - - Pull - Pull (Fetch & Merge) - Remote : - Branch : - Into : - Use rebase instead of merge - Stash & reapply local changes - - Push - Push Changes To Remote - Local Branch : - Remote : - Remote Branch : - Push all tags - Force push - - Push Tag To Remote - Tag : - Remote : - - Rebase Current Branch - Rebase : - On : - Stash & reapply local changes - - Add Remote - Edit Remote - Name : - Remote name - Repository URL : - Remote git repository URL - - Rename Branch - Branch : - New Name : - Unique name for this branch - - Reset Current Branch To Revision - Current Branch : - Move To : - Reset Mode : - - Confirm To Revert Commit - Commit : - Commit revert changes - - Preference - GENERAL SETTING - Language - Window Font - Content Font - Avatar Server - Check for update - Fetch remotes automatically (need restart) - Restore windows - Enable crash report (maybe include related path) - Use Windows Terminal to open Git terminal - GIT SETTING - Install Path - Input path for git.exe - Git version - Default Clone Dir - Default path to clone repo into - User Name - Global git user name - User Email - Global git user email - Enable Auto CRLF - MERGE TOOL - Merger - Install Path - Input path for merge tool - Select Git Executable File - Select {0} Install Path - - Stash - Stash Local Changes - Message : - Optional. Name of this stash - Include untracked files - - Stashes - STASHES - CHANGES - - COMMIT : {0} -> {1} - - UPDATE AVAILABLE - {0} is available! - Publish Time - Base On Commit - Is Pre-release - DOWNLOAD - - Changes - UNSTAGED - STAGE - STAGE ALL - STAGED - UNSTAGE - UNSTAGE ALL - CONFLICTS DETECTED - USE THEIRS - USE MINE - OPEN MERGE - Enter commit message - MESSAGE HISTORIES - Amend - COMMIT - COMMIT & PUSH - NO RECENT INPUT MESSAGES - RECENT INPUT MESSAGES - - Cherry-Pick merge request detected! Press 'Abort' to restore original HEAD - Rebase merge request detected! Press 'Abort' to restore original HEAD - Revert merge request detected! Press 'Abort' to restore original HEAD - Merge request detected! Press 'Abort' to restore original HEAD - - NOTICE - Restart required to apply changes in preference. Restart now? - - Add/Link SubTree - Source URL : - Branch/Commit : - Local Relative Path : - Squash commits? - - Edit SubTree - Source URL : - Local Relative Path : - - Unlink SubTree - Local Relative Path : - This will only remove links. - - Pull Changes Of SubTree - Push Changes Of SubTree - Local Relative Path : - Remote : - Branch : - Squash commits? - - Edit ... - Unlink ... - Pull ... - Push ... - - HOTKEYS - KEY - DESCRIPTION - Create a new page - Close current active page - Switch to next page - Switch to page at given index - Toggle search bar if possible - Reload current repository if possible - Stage or unstage selected files - - Reword Commit Message - On : - Message : - - Squash HEAD Into Parent - HEAD : - To : - Reword : - - Git has NOT been configured. Please to go [Preference] and configure it first. - Path[{0}] not exists! - Can NOT locate bash.exe. Make sure bash.exe exists under the same folder with git.exe - BINARY FILE NOT SUPPORTED!!! - BLAME ON THIS FILE IS NOT SUPPORTED!!! - GIT_DIR for this repository NOT FOUND! - Initialize Git-flow failed! - Bad git-flow branch type! - EXISTS and FULL ACCESS CONTROL needed - Remote git URL not supported - Bad local repository name - Remote name can NOT be null - Bad name for remote. Regex: ^[\\w\\-\\.]+$ - Duplicated remote name! - Branch name can NOT be null - Bad name for branch. Regex: ^[\\w\\-/\\.]+$ - Duplicated branch name! - Tag name can NOT be null - Bad name for tag. Regex: ^[\\w\\-\\.]+$ - Duplicated tag name! - Commit message can NOT be empty - Invalid path for patch file - Invalid relative path - Invalid path for archive file - This field is required + + START + SURE + SAVE + CLOSE + CANCEL + CLICK TO GO + Reveal in File Explorer + Save As ... + Save File to ... + Copy Path + {0} Bytes + FILTER + Optional. + SELECT FOLDER + CHANGE THEME + + URL : + Git Repository URL + Parent Folder : + Relative foler to store this module. Optional. + + ABOUT + SourceGit - OPEN SOURCE GIT CLIENT + + Patch + Apply Patch + Patch File : + Select .patch file to apply + Whitespace : + Ignore whitespace changes + No Warn + Turns off the trailing whitespace warning + Warn + Outputs warnings for a few such errors, but applies + Error + Raise errors and refuses to apply the patch + Error All + Similar to 'error', but shows more + + Archive ... + Archive + Revision : + Save Archive To : + Select archive file path + + Blame + Right click to see commit info + COMMIT SHA + AUTHOR + MODIFY TIME + + SUBMODULES + Add Submodule + Fetch nested submodules + Open Submodule Repository + Copy Relative Path + Delete Submodule + + Cherry-Pick This Commit + Cherry Pick + Commit : + Commit all changes + + Clone Remote Repository + Repository URL : + Git Repository URL + Parent Folder : + Folder to contain this repository + Local Name : + Repository name. Optional. + Remote Name : + Remote name. Optional. + Extra Parameters : + Additional arguments to clone repository. Optional. + + INFORMATION + AUTHOR + COMMITTER + SHA + PARENTS + REFS + MESSAGE + CHANGED + CHANGES + Search Files ... + FILES + + Configure + User : + User name for this repository + Email : + Email address + Proxy : + HTTP proxy used by this repository + + Create Branch + Create Local Branch + Based On : + New Branch Name : + Enter branch name. + Local Changes : + Stash & Reapply + Discard + Check out after created + Git do not hold any branch until you do first commit. + + Create Tag + New Tag At : + Tag Name : + Recommanded format :v1.0.0-alpha + Tag Message : + Optional. + + Open In File Browser + Open Git Bash + Search Commit + Configure this repository + WORKSPACE + LOCAL BRANCHES + NEW BRANCH + REMOTES + ADD REMOTE + TAGS + NEW TAG + SUBMODULES + ADD SUBMODULE + UPDATE SUBMODULE + SUBTREES + ADD/LINK SUBTREE + RESOLVE + CONTINUE + ABORT + + GIT FLOW + Initialize Git-Flow + Production Branch : + Development Branch : + Feature : + Release : + Hotfix : + Feature Prefix : + Release Prefix : + Hotfix Prefix : + Version Tag Prefix : + Start Feature ... + Start Release ... + Start Hotfix ... + GIT FLOW - Start Feature + GIT FLOW - Start Release + GIT FLOW - Start Hotfix + Enter name + GIT FLOW - Finish Feature + GIT FLOW - Finish Release + GIT FLOW - Finish Hotfix + {0} branch name is required. + {0} branch name contains invalid characters. + {0} prefix is required. + {0} contains invalid characters. + Development branch is same with production! + Keep branch + + Bookmark + Open + Open Container Folder + + Push '{0}' + Discard all changes + Fast-Forward to '{0}' + Pull '{0}' + Pull '{0}' into '{1}' + Checkout '{0}' + Merge '{0}' into '{1}' + Rebase '{0}' on '{1}' + Git Flow - Finish '{0}' + Rename '{0}' + Delete '{0}' + Tracking ... + Copy Branch Name + Unset Upstream + + Fetch '{0}' + Edit '{0}' + Delete '{0}' + Copy Remote URL + + Reset '{0}' to Here + Rebase '{0}' to Here + Cherry-Pick This Commit + Reword + Squash Into Parent + Revert Commit + Save as Patch ... + Copy Commit SHA + Copy Commit Info + + Push '{0}' + Delete '{0}' + Copy Tag Name + + Apply + Pop + Drop + + Unstage + Stage... + Discard... + Stash... + Unstage {0} files + Stage {0} files... + Discard {0} files... + Stash {0} files... + Save As Patch... + + Confirm To Delete Branch + Branch : + + Confirm To Delete Remote + Remote : + + Confirm To Delete Tag + Tag : + Delete from remote repositories + + Confirm To Delete Submodule + Submodule Path : + + Next Difference + Previous Difference + Toggle One-Side/Two-Sides + Open With Merge Tool + SELECT FILE TO VIEW CHANGES + NO CHANGES OR ONLY EOL CHANGES + BINARY DIFF + OLD : + NEW : + LFS OBJECT CHANGE + Copy + + Confirm To Discard Changes + Changes : + You can't undo this action!!! + All local changes in working copy. + Total {0} changes will be discard + + Fetch + Fetch Remote Changes + Remote : + Fetch all remotes + Prune remote dead branches + + File History + + CHANGE DISPLAY MODE + Show as Grid + Show as List + Show as Tree + + SELECT FOLDER + SELECTED : + + Histories + SEARCH SHA/SUBJECT/AUTHOR. PRESS ENTER TO SEARCH, ESC TO QUIT + CLEAR + Switch Curve/Polyline Graph Mode + Switch Horizontal/Vertical Layout + SELECTED {0} COMMITS + HISTORIES GUIDE + 1. Select single commit to view detail + 2. Select two commits to show differences + 3. Select more than 2 commits to count + 4. Open context menu to see more options + + Initialize Repository + Path : + Invalid repository detected. Run `git init` under this path? + + Source Git + PREFERENCE + ABOUT + ERROR + + NEW PAGE + *Repositories + WELCOME PAGE + Close Tab + Close Other Tabs + Close Tabs to the Right + Bookmark + + Merge Branch + Source Branch : + Into : + Merge Option : + + SourceGit + Open Local Repository + Clone Remote Repository + DRAG-DROP YOUR FOLDER + START + RECENT OPENED + REPOSITORIES + Add Folder + Add Sub-Folder + Rename + Delete + + Pull + Pull (Fetch & Merge) + Remote : + Branch : + Into : + Use rebase instead of merge + Stash & reapply local changes + + Push + Push Changes To Remote + Local Branch : + Remote : + Remote Branch : + Push all tags + Force push + + Push Tag To Remote + Tag : + Remote : + + Rebase Current Branch + Rebase : + On : + Stash & reapply local changes + + Add Remote + Edit Remote + Name : + Remote name + Repository URL : + Remote git repository URL + + Rename Branch + Branch : + New Name : + Unique name for this branch + + Reset Current Branch To Revision + Current Branch : + Move To : + Reset Mode : + + Confirm To Revert Commit + Commit : + Commit revert changes + + Preference + GENERAL SETTING + Language + Window Font + Content Font + Avatar Server + Check for update + Fetch remotes automatically (need restart) + Restore windows + Enable crash report (maybe include related path) + Use Windows Terminal to open Git terminal + GIT SETTING + Install Path + Input path for git.exe + Git version + Default Clone Dir + Default path to clone repo into + User Name + Global git user name + User Email + Global git user email + Enable Auto CRLF + MERGE TOOL + Merger + Install Path + Input path for merge tool + Select Git Executable File + Select {0} Install Path + + Stash + Stash Local Changes + Message : + Optional. Name of this stash + Include untracked files + + Stashes + STASHES + CHANGES + + COMMIT : {0} -> {1} + + UPDATE AVAILABLE + {0} is available! + Publish Time + Base On Commit + Is Pre-release + DOWNLOAD + + Changes + UNSTAGED + STAGE + STAGE ALL + STAGED + UNSTAGE + UNSTAGE ALL + CONFLICTS DETECTED + USE THEIRS + USE MINE + OPEN MERGE + Enter commit message + MESSAGE HISTORIES + Amend + COMMIT + COMMIT & PUSH + NO RECENT INPUT MESSAGES + RECENT INPUT MESSAGES + + Cherry-Pick merge request detected! Press 'Abort' to restore original HEAD + Rebase merge request detected! Press 'Abort' to restore original HEAD + Revert merge request detected! Press 'Abort' to restore original HEAD + Merge request detected! Press 'Abort' to restore original HEAD + + NOTICE + Restart required to apply changes in preference. Restart now? + + Add/Link SubTree + Source URL : + Branch/Commit : + Local Relative Path : + Squash commits? + + Edit SubTree + Source URL : + Local Relative Path : + + Unlink SubTree + Local Relative Path : + This will only remove links. + + Pull Changes Of SubTree + Push Changes Of SubTree + Local Relative Path : + Remote : + Branch : + Squash commits? + + Edit ... + Unlink ... + Pull ... + Push ... + + HOTKEYS + KEY + DESCRIPTION + Create a new page + Close current active page + Switch to next page + Switch to page at given index + Toggle search bar if possible + Reload current repository if possible + Stage or unstage selected files + + Reword Commit Message + On : + Message : + + Squash HEAD Into Parent + HEAD : + To : + Reword : + + Git has NOT been configured. Please to go [Preference] and configure it first. + Path[{0}] not exists! + Can NOT locate bash.exe. Make sure bash.exe exists under the same folder with git.exe + BINARY FILE NOT SUPPORTED!!! + BLAME ON THIS FILE IS NOT SUPPORTED!!! + GIT_DIR for this repository NOT FOUND! + Initialize Git-flow failed! + Bad git-flow branch type! + EXISTS and FULL ACCESS CONTROL needed + Remote git URL not supported + Bad local repository name + Remote name can NOT be null + Bad name for remote. Regex: ^[\\w\\-\\.]+$ + Duplicated remote name! + Branch name can NOT be null + Bad name for branch. Regex: ^[\\w\\-/\\.]+$ + Duplicated branch name! + Tag name can NOT be null + Bad name for tag. Regex: ^[\\w\\-\\.]+$ + Duplicated tag name! + Commit message can NOT be empty + Invalid path for patch file + Invalid relative path + Invalid path for archive file + This field is required \ No newline at end of file diff --git a/src/Resources/Locales/zh_CN.xaml b/src/Resources/Locales/zh_CN.xaml index 89561ac1..71e1b3c1 100644 --- a/src/Resources/Locales/zh_CN.xaml +++ b/src/Resources/Locales/zh_CN.xaml @@ -1,499 +1,501 @@ - - 开 始 - 确 定 - 保 存 - 关闭 - 取 消 - 点击前往 - 在文件浏览器中查看 - 另存为... - 复制路径 - {0} 字节 - 过滤 - 选填 - 选择文件夹 - 切换主题 - - 仓库地址 : - 远程仓库地址 - 本地目录 : - 本地存放的父级目录,选填. - - 关于软件 - SourceGit - 开源Git图形客户端 - - 补丁 - 应用补丁 - 补丁文件 : - 选择补丁文件 - 空白符号处理 : - 忽略空白符号 - 忽略 - 关闭所有警告 - 警告 - 应用补丁,输出关于空白符的警告 - 错误 - 输出错误,并终止应用补丁 - 更多错误 - 与【错误】级别相似,但输出内容更多 - - 存档 ... - 存档 - 指定的提交: - 存档文件路径: - 选择存档文件的存放路径 - - 逐行追溯 - 右键点击查看所选行修改记录 - 提交指纹 - 修改者 - 修改时间 - - 子模块 - 添加子模块 - 拉取子孙模块 - 打开仓库 - 复制路径 - 删除子模块 - - 挑选此提交 - 挑选提交 - 提交ID : - 提交变化 - - 克隆远程仓库 - 远程仓库 : - 远程仓库地址 - 父级目录 : - 选择存放本仓库的父级文件夹路径 - 本地仓库名 : - 本地仓库目录的名字,选填 - 远程名 : - 远程的名字,选填 - 额外参数 : - 其他克隆参数,选填 - - 基本信息 - 修改者 - 提交者 - 提交指纹 - 父提交 - 相关引用 - 提交信息 - 变更列表 - 变更对比 - 查找文件... - 文件列表 - - 仓库配置 - 用户 : - 应用于本仓库的用户名 - 邮箱 : - 邮箱地址 - 代理 : - HTTP网络代理 - - 新建分支 - 创建本地分支 - 新分支基于 : - 新分支名 : - 填写分支名称 - 未提交更改 : - 贮藏并自动恢复 - 忽略 - 完成后切换到新分支 - 对于空仓库,只有提交一次有效数据,Git 才会创建第一个分支 - - 新建标签 - 标签位于 : - 标签名 : - 推荐格式 :v1.0.0-alpha - 标签描述 : - 选填 - - 在文件浏览器中打开 - 打开GIT终端 - 查找提交 - 配置本仓库 - 工作区 - 本地分支 - 新建分支 - 远程列表 - 添加远程 - 标签列表 - 新建标签 - 子模块列表 - 添加子模块 - 更新子模块 - 子树列表 - 添加子树 - 解决冲突 - 下一步 - 终止冲突解决 - - GIT工作流 - 初始化GIT工作流 - 发布分支 : - 开发分支 : - 特性分支 : - 版本分支 : - 修复分支 : - 特性分支名前缀 : - 版本分支名前缀 : - 修复分支名前缀 : - 版本标签前缀 : - 开始特性分支... - 开始版本分支... - 开始修复分支... - 开始特性分支 - 开始版本分支 - 开始修复分支 - 输入分支名 - 结束特性分支 - 结束版本分支 - 结束修复分支 - {0}分支名未填写! - {0}分支名包含非法字符! - {0}前缀未填写! - {0}前缀包含非法字符! - 开发分支与发布分支不可相同! - 保留分支 - - 书签 - 打开 - 在浏览器中查看 - - 推送 '{0}' - 放弃所有更改 - 快进到 '{0}' - 拉回 '{0}' - 拉回 '{0}' 内容至 '{1}' - 检出 '{0}' - 合并 '{0}' 到 '{1}' - 变基 '{0}' 分支至 '{1}' - GIT工作流 - 完成 '{0}' - 重命名 '{0}' - 删除 '{0}' - 切换上游分支... - 复制分支名 - 取消追踪 - - 拉取 '{0}' 更新 - 编辑 '{0}' - 删除 '{0}' - 复制远程地址 - - 重置 '{0}' 到此处 - 变基 '{0}' 到此处 - 挑选此提交 - 编辑提交信息 - 合并此提交到上一个提交 - 回滚此提交 - 另存为补丁 ... - 复制提交指纹 - 复制提交信息 - - 推送 '{0}' - 删除 '{0}' - 复制标签名 - - 应用 - 应用并删除 - 删除 - - 从暂存中移除 - 暂存... - 放弃更改... - 贮藏... - 从暂存中移除 {0} 个文件 - 暂存 {0} 个文件... - 放弃 {0} 个文件的更改... - 贮藏选中的 {0} 个文件... - 另存为补丁... - - 确定要删除此分支吗? - 分支名 : - - 确定要移除该远程吗? - 远程名 : - - 确定要移除该标签吗? - 标签名 : - 同时删除远程仓库中的此标签 - - 确定要移除该子模块吗? - 子模块路径 : - - 下一个差异 - 上一个差异 - 切换显示模式 - 使用外部合并工具查看 - 请选择需要对比的文件 - 没有变更或仅有换行符差异 - 二进制文件 - 原始大小 : - 当前大小 : - LFS对象变更 - 复制 - - 放弃更改确认 - 需要放弃的变更 : - 本操作不支持回退,请确认后继续!!! - 所有本地址未提交的修改 - 总计{0}项选中更改 - - 拉取 - 拉取远程仓库内容 - 远程仓库 : - 拉取所有的远程仓库 - 自动清理远程已删除分支 - - 文件历史 - - 切换变更显示模式 - 网格模式 - 列表模式 - 树形模式 - - 选择目录... - 当前选择 : - - 历史记录 - 查询提交指纹、信息、作者。回车键开始,ESC键取消 - 清空 - 切换曲线/折线显示 - 切换横向/纵向显示 - 已选中 {0} 项提交 - 操作说明 - 1. 单选时,显示选中提交的详细信息 - 2. 双选时,按选中顺序对比两个提交 - 3. 多选时,仅统计选中行数 - 4. 右键用于操作选中的某个提交 - - 初始化新仓库 - 路径 : - 点击【确定】将在此目录执行`git init`操作 - - Source Git - 偏好设置 - 关于 - 出错了 - - 新建空白页 - 新标签页 - 起始页 - 关闭标签页 - 关闭其他标签页 - 关闭右侧标签页 - 设置书签 - - 合并分支 - 合并分支 : - 目标分支 : - 合并方式 : - - 欢迎使用本软件 - 打开本地仓库 - 克隆远程仓库 - 收藏/书签 - 最近使用 - 新建分组 - 新建子分组 - 重命名 - 删除 - - 拉回 - 拉回(拉取并合并) - 远程 : - 拉取分支 : - 本地分支 : - 使用变基方式合并分支 - 自动贮藏并恢复本地变更 - - 推送 - 推送到远程仓库 - 本地分支 : - 远程仓库 : - 远程分支 : - 同时推送标签 - 启用强制推送 - - 推送标签到远程仓库 - 标签 : - 远程仓库 : - - 变基操作 - 分支 : - 目标提交 : - 自动贮藏并恢复本地变更 - - 添加远程仓库 - 编辑远程仓库 - 远程名 : - 唯一远程名 - 仓库地址 : - 远程仓库的地址 - - 分支重命名 - 分支 : - 新的名称 : - 新的分支名不能与现有分支名相同 - - 重置当前分支到指定版本 - 当前分支 : - 提交 : - 重置模式 : - - 确定要回滚吗? - 目标提交 : - 回滚后提交更改 - - 偏好设置 - 通用配置 - 显示语言 - 系统字体 - 文本字体 - 头像服务 - 启用检测更新 - 启用定时自动拉取远程更新(重启生效) - 启动时恢复上次打开的仓库 - 开启崩溃上报(可能涉及上报相关路径) - 使用 Windows Terminal 打开 Git 终端 - GIT配置 - 安装路径 - 填写git.exe所在位置 - Git 版本 - 默认克隆路径 - 默认的仓库本地存放位置 - 用户名 - 默认GIT用户名 - 邮箱 - 默认GIT用户邮箱 - 自动换行转换 - 外部合并工具 - 工具 - 安装路径 - 填写工具可执行文件所在位置 - 选择git.exe所在位置 - 选择{0}所在位置 - - 贮藏 - 贮藏本地变更 - 信息 : - 选填,用于命名此贮藏 - 包含未跟踪的文件 - - 贮藏列表 - 贮藏列表 - 查看变更 - - 对比提交 : {0} -> {1} - - 检测更新 - {0}已发布! - 发布时间 - GIT版本 - 预览版 - 下 载 - - 本地更改 - 未暂存 - 暂存选中 - 暂存所有 - 已暂存 - 从暂存区移除选中 - 从暂存区移除所有 - 检测到冲突 - 使用THEIRS - 使用MINE - 打开合并工具 - 填写提交信息 - 历史提交信息 - 修补 - 提交 - 提交并推送 - 没有提交信息记录 - 最近输入的提交信息 - - 检测到挑选提交冲突! - 检测到变基冲突! - 检测到回滚提交冲突! - 检测到分支合并冲突! - - 系统提示 - 本次配置变更需要在重启后生效,是否立即重启? - - 添加子树 - 远程地址: - 分支或提交ID: - 本地相对路径: - 合并提交为单一提交 - - 编辑子树信息 - 远程地址: - 本地相对路径: - - 删除子树 - 本地相对路径: - 本操作仅将子树信息删除,相关文件及提交不会更改 - - 拉取子树更新 - 推送子树更新到远程 - 本地相对路径: - 远程地址: - 远程分支: - 合并提交为单一提交 - - 编辑子树 ... - 删除子树 ... - 拉取子树更新 - 推送子树变更 - - 快捷键 - 快捷键 - 功能说明 - 新建标签页 - 关闭当前浏览标签页 - 切换到下一个标签页 - 切换到指定位置的标签页 - 打开/隐藏搜索框(仅在仓库页起效) - 重新加载当前仓库信息(仅在仓库页起效) - 暂存或从暂存中移除当前选中 - - 编辑提交信息 - 提交: - 提交信息: - - 合并HEAD到上一个提交 - 当前提交 : - 合并到 : - 修改提交信息: - - GIT尚未配置。请打开【偏好设置】配置GIT路径。 - 路径({0})不存在或不可读取! - 无法找到bash.exe,请确保其在git.exe同目录中! - 二进制文件不支持该操作!!! - 选中文件不支持该操作!!! - 获取仓库GIT_DIR失败! - 初始化GIT FLOW失败! - 不支持的GIT FLOW分支! - 目录不存在或不可写!!! - 非法的远程仓库地址! - 非法的本地仓库地址! - 远程仓库地址不可为空 - 远程仓库地址包含非法字符!仅支持字母、数字、下划线、横线或英文点号! - 远程仓库名已存在! - 分支名不可为空 - 分支名包含非法字符!仅支持字母、数字、下划线、横线或英文点号! - 分支名已存在! - 标签名不可为空! - 标签名包含非法字符!仅支持字母、数字、下划线、横线或英文点号! - 标签名已存在! - 提交信息未填写! - 补丁文件不存在或不可访问! - 非法的子路径! - 非法的存档文件路径! - 内容未填写! + + 开 始 + 确 定 + 保 存 + 关闭 + 取 消 + 点击前往 + 在文件浏览器中查看 + 另存为... + 复制路径 + {0} 字节 + 过滤 + 选填 + 选择文件夹 + 切换主题 + + 仓库地址 : + 远程仓库地址 + 本地目录 : + 本地存放的父级目录,选填. + + 关于软件 + SourceGit - 开源Git图形客户端 + + 补丁 + 应用补丁 + 补丁文件 : + 选择补丁文件 + 空白符号处理 : + 忽略空白符号 + 忽略 + 关闭所有警告 + 警告 + 应用补丁,输出关于空白符的警告 + 错误 + 输出错误,并终止应用补丁 + 更多错误 + 与【错误】级别相似,但输出内容更多 + + 存档 ... + 存档 + 指定的提交: + 存档文件路径: + 选择存档文件的存放路径 + + 逐行追溯 + 右键点击查看所选行修改记录 + 提交指纹 + 修改者 + 修改时间 + + 子模块 + 添加子模块 + 拉取子孙模块 + 打开仓库 + 复制路径 + 删除子模块 + + 挑选此提交 + 挑选提交 + 提交ID : + 提交变化 + + 克隆远程仓库 + 远程仓库 : + 远程仓库地址 + 父级目录 : + 选择存放本仓库的父级文件夹路径 + 本地仓库名 : + 本地仓库目录的名字,选填 + 远程名 : + 远程的名字,选填 + 额外参数 : + 其他克隆参数,选填 + + 基本信息 + 修改者 + 提交者 + 提交指纹 + 父提交 + 相关引用 + 提交信息 + 变更列表 + 变更对比 + 查找文件... + 文件列表 + + 仓库配置 + 用户 : + 应用于本仓库的用户名 + 邮箱 : + 邮箱地址 + 代理 : + HTTP网络代理 + + 新建分支 + 创建本地分支 + 新分支基于 : + 新分支名 : + 填写分支名称 + 未提交更改 : + 贮藏并自动恢复 + 忽略 + 完成后切换到新分支 + 对于空仓库,只有提交一次有效数据,Git 才会创建第一个分支 + + 新建标签 + 标签位于 : + 标签名 : + 推荐格式 :v1.0.0-alpha + 标签描述 : + 选填 + + 在文件浏览器中打开 + 打开GIT终端 + 查找提交 + 配置本仓库 + 工作区 + 本地分支 + 新建分支 + 远程列表 + 添加远程 + 标签列表 + 新建标签 + 子模块列表 + 添加子模块 + 更新子模块 + 子树列表 + 添加子树 + 解决冲突 + 下一步 + 终止冲突解决 + + GIT工作流 + 初始化GIT工作流 + 发布分支 : + 开发分支 : + 特性分支 : + 版本分支 : + 修复分支 : + 特性分支名前缀 : + 版本分支名前缀 : + 修复分支名前缀 : + 版本标签前缀 : + 开始特性分支... + 开始版本分支... + 开始修复分支... + 开始特性分支 + 开始版本分支 + 开始修复分支 + 输入分支名 + 结束特性分支 + 结束版本分支 + 结束修复分支 + {0}分支名未填写! + {0}分支名包含非法字符! + {0}前缀未填写! + {0}前缀包含非法字符! + 开发分支与发布分支不可相同! + 保留分支 + + 书签 + 打开 + 在浏览器中查看 + + 推送 '{0}' + 放弃所有更改 + 快进到 '{0}' + 拉回 '{0}' + 拉回 '{0}' 内容至 '{1}' + 检出 '{0}' + 合并 '{0}' 到 '{1}' + 变基 '{0}' 分支至 '{1}' + GIT工作流 - 完成 '{0}' + 重命名 '{0}' + 删除 '{0}' + 切换上游分支... + 复制分支名 + 取消追踪 + + 拉取 '{0}' 更新 + 编辑 '{0}' + 删除 '{0}' + 复制远程地址 + + 重置 '{0}' 到此处 + 变基 '{0}' 到此处 + 挑选此提交 + 编辑提交信息 + 合并此提交到上一个提交 + 回滚此提交 + 另存为补丁 ... + 复制提交指纹 + 复制提交信息 + + 推送 '{0}' + 删除 '{0}' + 复制标签名 + + 应用 + 应用并删除 + 删除 + + 从暂存中移除 + 暂存... + 放弃更改... + 贮藏... + 从暂存中移除 {0} 个文件 + 暂存 {0} 个文件... + 放弃 {0} 个文件的更改... + 贮藏选中的 {0} 个文件... + 另存为补丁... + + 确定要删除此分支吗? + 分支名 : + + 确定要移除该远程吗? + 远程名 : + + 确定要移除该标签吗? + 标签名 : + 同时删除远程仓库中的此标签 + + 确定要移除该子模块吗? + 子模块路径 : + + 下一个差异 + 上一个差异 + 切换显示模式 + 使用外部合并工具查看 + 请选择需要对比的文件 + 没有变更或仅有换行符差异 + 二进制文件 + 原始大小 : + 当前大小 : + LFS对象变更 + 复制 + + 放弃更改确认 + 需要放弃的变更 : + 本操作不支持回退,请确认后继续!!! + 所有本地址未提交的修改 + 总计{0}项选中更改 + + 拉取 + 拉取远程仓库内容 + 远程仓库 : + 拉取所有的远程仓库 + 自动清理远程已删除分支 + + 文件历史 + + 切换变更显示模式 + 网格模式 + 列表模式 + 树形模式 + + 选择目录... + 当前选择 : + + 历史记录 + 查询提交指纹、信息、作者。回车键开始,ESC键取消 + 清空 + 切换曲线/折线显示 + 切换横向/纵向显示 + 已选中 {0} 项提交 + 操作说明 + 1. 单选时,显示选中提交的详细信息 + 2. 双选时,按选中顺序对比两个提交 + 3. 多选时,仅统计选中行数 + 4. 右键用于操作选中的某个提交 + + 初始化新仓库 + 路径 : + 点击【确定】将在此目录执行`git init`操作 + + Source Git + 偏好设置 + 关于 + 出错了 + + 新建空白页 + 新标签页 + 起始页 + 关闭标签页 + 关闭其他标签页 + 关闭右侧标签页 + 设置书签 + + 合并分支 + 合并分支 : + 目标分支 : + 合并方式 : + + 欢迎使用本软件 + 打开本地仓库 + 克隆远程仓库 + 支持拖放操作 + 开始使用 + 最近使用 + 收藏/书签 + 新建分组 + 新建子分组 + 重命名 + 删除 + + 拉回 + 拉回(拉取并合并) + 远程 : + 拉取分支 : + 本地分支 : + 使用变基方式合并分支 + 自动贮藏并恢复本地变更 + + 推送 + 推送到远程仓库 + 本地分支 : + 远程仓库 : + 远程分支 : + 同时推送标签 + 启用强制推送 + + 推送标签到远程仓库 + 标签 : + 远程仓库 : + + 变基操作 + 分支 : + 目标提交 : + 自动贮藏并恢复本地变更 + + 添加远程仓库 + 编辑远程仓库 + 远程名 : + 唯一远程名 + 仓库地址 : + 远程仓库的地址 + + 分支重命名 + 分支 : + 新的名称 : + 新的分支名不能与现有分支名相同 + + 重置当前分支到指定版本 + 当前分支 : + 提交 : + 重置模式 : + + 确定要回滚吗? + 目标提交 : + 回滚后提交更改 + + 偏好设置 + 通用配置 + 显示语言 + 系统字体 + 文本字体 + 头像服务 + 启用检测更新 + 启用定时自动拉取远程更新(重启生效) + 启动时恢复上次打开的仓库 + 开启崩溃上报(可能涉及上报相关路径) + 使用 Windows Terminal 打开 Git 终端 + GIT配置 + 安装路径 + 填写git.exe所在位置 + Git 版本 + 默认克隆路径 + 默认的仓库本地存放位置 + 用户名 + 默认GIT用户名 + 邮箱 + 默认GIT用户邮箱 + 自动换行转换 + 外部合并工具 + 工具 + 安装路径 + 填写工具可执行文件所在位置 + 选择git.exe所在位置 + 选择{0}所在位置 + + 贮藏 + 贮藏本地变更 + 信息 : + 选填,用于命名此贮藏 + 包含未跟踪的文件 + + 贮藏列表 + 贮藏列表 + 查看变更 + + 对比提交 : {0} -> {1} + + 检测更新 + {0}已发布! + 发布时间 + GIT版本 + 预览版 + 下 载 + + 本地更改 + 未暂存 + 暂存选中 + 暂存所有 + 已暂存 + 从暂存区移除选中 + 从暂存区移除所有 + 检测到冲突 + 使用THEIRS + 使用MINE + 打开合并工具 + 填写提交信息 + 历史提交信息 + 修补 + 提交 + 提交并推送 + 没有提交信息记录 + 最近输入的提交信息 + + 检测到挑选提交冲突! + 检测到变基冲突! + 检测到回滚提交冲突! + 检测到分支合并冲突! + + 系统提示 + 本次配置变更需要在重启后生效,是否立即重启? + + 添加子树 + 远程地址: + 分支或提交ID: + 本地相对路径: + 合并提交为单一提交 + + 编辑子树信息 + 远程地址: + 本地相对路径: + + 删除子树 + 本地相对路径: + 本操作仅将子树信息删除,相关文件及提交不会更改 + + 拉取子树更新 + 推送子树更新到远程 + 本地相对路径: + 远程地址: + 远程分支: + 合并提交为单一提交 + + 编辑子树 ... + 删除子树 ... + 拉取子树更新 + 推送子树变更 + + 快捷键 + 快捷键 + 功能说明 + 新建标签页 + 关闭当前浏览标签页 + 切换到下一个标签页 + 切换到指定位置的标签页 + 打开/隐藏搜索框(仅在仓库页起效) + 重新加载当前仓库信息(仅在仓库页起效) + 暂存或从暂存中移除当前选中 + + 编辑提交信息 + 提交: + 提交信息: + + 合并HEAD到上一个提交 + 当前提交 : + 合并到 : + 修改提交信息: + + GIT尚未配置。请打开【偏好设置】配置GIT路径。 + 路径({0})不存在或不可读取! + 无法找到bash.exe,请确保其在git.exe同目录中! + 二进制文件不支持该操作!!! + 选中文件不支持该操作!!! + 获取仓库GIT_DIR失败! + 初始化GIT FLOW失败! + 不支持的GIT FLOW分支! + 目录不存在或不可写!!! + 非法的远程仓库地址! + 非法的本地仓库地址! + 远程仓库地址不可为空 + 远程仓库地址包含非法字符!仅支持字母、数字、下划线、横线或英文点号! + 远程仓库名已存在! + 分支名不可为空 + 分支名包含非法字符!仅支持字母、数字、下划线、横线或英文点号! + 分支名已存在! + 标签名不可为空! + 标签名包含非法字符!仅支持字母、数字、下划线、横线或英文点号! + 标签名已存在! + 提交信息未填写! + 补丁文件不存在或不可访问! + 非法的子路径! + 非法的存档文件路径! + 内容未填写! \ No newline at end of file diff --git a/src/Views/Widgets/Dashboard.xaml.cs b/src/Views/Widgets/Dashboard.xaml.cs index de2334cf..3a6b7c22 100644 --- a/src/Views/Widgets/Dashboard.xaml.cs +++ b/src/Views/Widgets/Dashboard.xaml.cs @@ -315,6 +315,7 @@ namespace SourceGit.Views.Widgets { Models.Exception.Raise(App.Text("MissingBash")); return; } + if (Models.Preference.Instance.General.UseWindowsTerminal) { Process.Start(new ProcessStartInfo { WorkingDirectory = repo.Path, @@ -329,6 +330,7 @@ namespace SourceGit.Views.Widgets { UseShellExecute = true, }); } + e.Handled = true; } diff --git a/src/Views/Widgets/Welcome.xaml b/src/Views/Widgets/Welcome.xaml index 1e052073..095e054e 100644 --- a/src/Views/Widgets/Welcome.xaml +++ b/src/Views/Widgets/Welcome.xaml @@ -7,164 +7,165 @@ xmlns:widgets="clr-namespace:SourceGit.Views.Widgets" mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="800"> - + - + + - - - + + + + + - - - - - - - - - - - - - + + + - - - + + + + + + + + + + + + - + - - + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + - + + - - - - - - - - - + + + + + - - - - - - - - - - - + + + @@ -199,33 +200,45 @@ IsHitTestVisible="True" Visibility="Collapsed"/> - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/src/Views/Widgets/Welcome.xaml.cs b/src/Views/Widgets/Welcome.xaml.cs index 30ea8923..fac0fdd5 100644 --- a/src/Views/Widgets/Welcome.xaml.cs +++ b/src/Views/Widgets/Welcome.xaml.cs @@ -14,117 +14,130 @@ namespace SourceGit.Views.Widgets { /// 新标签页 /// public partial class Welcome : UserControl, Controls.IPopupContainer { - + /// /// 树节点数据 /// public class Node : Controls.BindableBase { - public string Id { - get; - set; - } - public string ParentId { - get; - set; - } - + public string Id { get; set; } + public string ParentId { get; set; } + private string name; public string Name { get => name; set => SetProperty(ref name, value); } - - public bool IsGroup { - get; - set; - } - + + public bool IsGroup { get; set; } + private bool isEditing = false; public bool IsEditing { get => isEditing; set => SetProperty(ref isEditing, value); } - - public bool IsExpanded { - get; - set; - } + + public bool IsExpanded { get; set; } private int bookmark = 0; public int Bookmark { get => bookmark; set => SetProperty(ref bookmark, value); } - - public List Children { - get; - set; - } + + public List Children { get; set; } } - + /// /// 仓库节点编辑事件参数 /// public event Action OnNodeEdited; - private bool clearBookmark = false; - public Welcome() { InitializeComponent(); UpdateTree(); + UpdateRecents(); } - + #region POPUP_CONTAINER public void Show(Controls.PopupWidget widget) { popup.Show(widget); } - + public void ShowAndStart(Controls.PopupWidget widget) { popup.ShowAndStart(widget); } - + public void UpdateProgress(string message) { popup.UpdateProgress(message); } #endregion - + #region FUNC_EVENTS private void OnOpenClicked(object sender, RoutedEventArgs e) { var dialog = new Controls.FolderDialog(); - - if (dialog.ShowDialog() == true) { - CheckAndOpen(dialog.SelectedPath); - } + if (dialog.ShowDialog() == true) CheckAndOpen(dialog.SelectedPath); } - + private void OnCloneClicked(object sender, RoutedEventArgs e) { - if (MakeSureReady()) { - new Popups.Clone().Show(); - } + if (MakeSureReady()) new Popups.Clone().Show(); } - + + private void OnRecentContextMenuOpening(object sender, ContextMenuEventArgs e) { + var repo = (sender as DataGridRow).DataContext as Models.Repository; + if (repo != null) { + var remove = new MenuItem(); + remove.Header = App.Text("Welcome.Delete"); + remove.Click += (o, ev) => { + Models.Preference.Instance.RemoveRecent(repo.Path); + UpdateRecents(); + ev.Handled = true; + }; + + var menu = new ContextMenu(); + menu.Items.Add(remove); + menu.IsOpen = true; + e.Handled = true; + } + } + + private void OnRecentDoubleClick(object sender, MouseButtonEventArgs e) { + var repo = (sender as DataGridRow).DataContext as Models.Repository; + if (repo != null) CheckAndOpen(repo.Path); + e.Handled = true; + } + + private void OnRecentLostFocus(object sender, RoutedEventArgs e) { + list.UnselectAll(); + e.Handled = true; + } + + private void OnTreeLostFocus(object sender, RoutedEventArgs e) { + var child = FocusManager.GetFocusedElement(body); + if (child == null) return; + + if (!tree.IsAncestorOf(child as UIElement)) tree.UnselectAll(); + e.Handled = true; + } + private void OnTreeNodeStatusChange(object sender, RoutedEventArgs e) { var node = (sender as Controls.TreeItem).DataContext as Node; - if (node != null) { var group = Models.Preference.Instance.FindGroup(node.Id); group.IsExpanded = node.IsExpanded; e.Handled = true; } } - + private void OnTreeNodeDoubleClick(object sender, MouseButtonEventArgs e) { var node = (sender as Controls.TreeItem).DataContext as Node; - if (node != null && !node.IsGroup) { CheckAndOpen(node.Id); e.Handled = true; } } - + private void OnTreeContextMenuOpening(object sender, ContextMenuEventArgs e) { - var item = treeHistory.FindItem(e.OriginalSource as DependencyObject); - + var item = tree.FindItem(e.OriginalSource as DependencyObject); if (item == null) { var addFolder = new MenuItem(); addFolder.Header = App.Text("Welcome.NewFolder"); @@ -133,20 +146,16 @@ namespace SourceGit.Views.Widgets { UpdateTree(group.Id); ev.Handled = true; }; + var menu = new ContextMenu(); menu.Items.Add(addFolder); menu.IsOpen = true; e.Handled = true; - } - else { + } else { var node = item.DataContext as Node; - - if (node == null) { - return; - } - + if (node == null) return; + var menu = new ContextMenu(); - if (!node.IsGroup) { var open = new MenuItem(); open.Header = App.Text("RepoCM.Open"); @@ -154,71 +163,74 @@ namespace SourceGit.Views.Widgets { CheckAndOpen(node.Id); ev.Handled = true; }; + var explore = new MenuItem(); explore.Header = App.Text("RepoCM.Explore"); explore.Click += (o, ev) => { Process.Start("explorer", node.Id); ev.Handled = true; }; + var iconBookmark = FindResource("Icon.Bookmark") as Geometry; var bookmark = new MenuItem(); bookmark.Header = App.Text("RepoCM.Bookmark"); - for (int i = 0; i < Controls.Bookmark.COLORS.Length; i++) { var icon = new System.Windows.Shapes.Path(); icon.Data = iconBookmark; icon.Fill = Controls.Bookmark.COLORS[i]; icon.Width = 8; + var mark = new MenuItem(); mark.Icon = icon; mark.Header = $"{i}"; + var refIdx = i; mark.Click += (o, ev) => { var repo = Models.Preference.Instance.FindRepository(node.Id); - if (repo != null) { repo.Bookmark = refIdx; - UpdateTree(); + node.Bookmark = refIdx; + UpdateRecents(); + OnNodeEdited?.Invoke(node); } - ev.Handled = true; }; + bookmark.Items.Add(mark); } - + menu.Items.Add(open); menu.Items.Add(explore); menu.Items.Add(bookmark); - } - else { + } else { var addSubFolder = new MenuItem(); addSubFolder.Header = App.Text("Welcome.NewSubFolder"); addSubFolder.Click += (o, ev) => { var parent = Models.Preference.Instance.FindGroup(node.Id); - - if (parent != null) { - parent.IsExpanded = true; - } - + if (parent != null) parent.IsExpanded = true; + var group = Models.Preference.Instance.AddGroup("New Group", node.Id); UpdateTree(group.Id); ev.Handled = true; }; + menu.Items.Add(addSubFolder); } - + var rename = new MenuItem(); rename.Header = App.Text("Welcome.Rename"); rename.Click += (o, ev) => { UpdateTree(node.Id); ev.Handled = true; }; + var delete = new MenuItem(); delete.Header = App.Text("Welcome.Delete"); delete.Click += (o, ev) => { DeleteNode(node); ev.Handled = true; }; + menu.Items.Add(rename); menu.Items.Add(delete); menu.IsOpen = true; @@ -226,188 +238,109 @@ namespace SourceGit.Views.Widgets { } } #endregion - - #region DRAP_DROP_EVENTS - private void OnPageMouseDown(object sender, MouseButtonEventArgs e) { - var itemHistory = treeHistory.FindItem(e.OriginalSource as DependencyObject); - - if (itemHistory == null) { - treeHistory.UnselectAll(); - } - - var itemBookmark = treeBookmarks.FindItem(e.OriginalSource as DependencyObject); - - if (itemBookmark == null) { - treeBookmarks.UnselectAll(); - } - clearBookmark = false; - } - - private void OnPageMouseMove(object sender, MouseEventArgs e) { - if (e.LeftButton != MouseButtonState.Pressed) { - return; - } - - var item = treeHistory.FindItem(e.OriginalSource as DependencyObject); - - if (item == null) { - return; - } - - treeHistory.UnselectAll(); - var adorner = new Controls.DragDropAdorner(item); - DragDrop.DoDragDrop(item, item.DataContext, DragDropEffects.Move); - adorner.Remove(); - } - - private void OnPageDrop(object sender, DragEventArgs e) { - bool rebuild = false; - - if (e.Data.GetDataPresent(DataFormats.FileDrop)) { - if (!MakeSureReady()) { - return; - } - - var paths = e.Data.GetData(DataFormats.FileDrop) as string[]; - - foreach (var path in paths) { - var dir = new Commands.QueryGitDir(path).Result(); - - if (dir != null) { - var root = new Commands.GetRepositoryRootPath(path).Result(); - Models.Preference.Instance.AddRepository(root, dir, ""); - CheckAndOpen(path); - rebuild = true; - } - } - } - else if (e.Data.GetDataPresent(typeof(Node))) { - var node = e.Data.GetData(typeof(Node)) as Node; - - if (node.IsGroup) { - e.Handled = true; - return; - } - else { - var repo = Models.Preference.Instance.FindRepository(node.Id); - - if (repo != null && repo.Bookmark != 0 && clearBookmark) { - repo.Bookmark = 0; - } - clearBookmark = false; - rebuild = true; - } - } - - if (rebuild) { - UpdateTree(); - } - - e.Handled = true; - } - - private void OnTreeBookmarksDragEnter(object sender, DragEventArgs e) { + #region DRAP_DROP_EVENTS + private void OnPageDragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent(typeof(Node))) { dropArea.Visibility = Visibility.Visible; } } - - private void OnTreeBookmarksDragLeave(object sender, DragEventArgs e) { + + private void OnPageDragLeave(object sender, DragEventArgs e) { dropArea.Visibility = Visibility.Hidden; } - - private void OnTreeBookmarksDragOver(object sender, DragEventArgs e) { - if (!e.Data.GetDataPresent(DataFormats.FileDrop) && !e.Data.GetDataPresent(typeof(Node))) { - return; - } - - var item = treeBookmarks.FindItem(e.OriginalSource as DependencyObject); - - if (item == null) { - return; - } - - var node = item.DataContext as Node; - - if (node.IsGroup && !item.IsExpanded) { - item.IsExpanded = true; - } - clearBookmark = true; - + private void OnPageDrop(object sender, DragEventArgs e) { + dropArea.Visibility = Visibility.Hidden; + } + + private void OnTreeMouseMove(object sender, MouseEventArgs e) { + if (e.LeftButton != MouseButtonState.Pressed) return; + + var item = tree.FindItem(e.OriginalSource as DependencyObject); + if (item == null) return; + + tree.UnselectAll(); + + var adorner = new Controls.DragDropAdorner(item); + DragDrop.DoDragDrop(item, item.DataContext, DragDropEffects.Move); + adorner.Remove(); + } + + private void OnTreeDragOver(object sender, DragEventArgs e) { + if (!e.Data.GetDataPresent(DataFormats.FileDrop) && !e.Data.GetDataPresent(typeof(Node))) return; + + var item = tree.FindItem(e.OriginalSource as DependencyObject); + if (item == null) return; + + var node = item.DataContext as Node; + if (node.IsGroup && !item.IsExpanded) item.IsExpanded = true; e.Handled = true; } - - private void OnTreeBookmarksDrop(object sender, DragEventArgs e) { - bool rebuild = false; - var parent = ""; - clearBookmark = false; + private void OnTreeDrop(object sender, DragEventArgs e) { + bool rebuild = false; dropArea.Visibility = Visibility.Hidden; - var to = treeBookmarks.FindItem(e.OriginalSource as DependencyObject); - + + var parent = ""; + var to = tree.FindItem(e.OriginalSource as DependencyObject); if (to != null) { var dst = to.DataContext as Node; parent = dst.IsGroup ? dst.Id : dst.ParentId; } - + if (e.Data.GetDataPresent(DataFormats.FileDrop)) { - if (!MakeSureReady()) { - return; - } - + if (!MakeSureReady()) return; + var paths = e.Data.GetData(DataFormats.FileDrop) as string[]; - foreach (var path in paths) { var dir = new Commands.QueryGitDir(path).Result(); - if (dir != null) { var root = new Commands.GetRepositoryRootPath(path).Result(); - Models.Preference.Instance.AddRepository(root, dir, parent).Bookmark = 1; // 默认添加的标签; - // CheckAndOpen(path); + Models.Preference.Instance.AddRepository(root, dir, parent); rebuild = true; } } - } - else if (e.Data.GetDataPresent(typeof(Node))) { - var node = e.Data.GetData(typeof(Node)) as Node; - - if (node.IsGroup) { - if (!Models.Preference.Instance.IsSubGroup(node.Id, parent)) { - Models.Preference.Instance.FindGroup(node.Id).Parent = parent; + } else if (e.Data.GetDataPresent(typeof(Node))) { + var src = e.Data.GetData(typeof(Node)) as Node; + if (src.IsGroup) { + if (!Models.Preference.Instance.IsSubGroup(src.Id, parent)) { + Models.Preference.Instance.FindGroup(src.Id).Parent = parent; rebuild = true; } - } - else { - var repo = Models.Preference.Instance.FindRepository(node.Id); - - if (repo != null) { - repo.GroupId = parent; - - if (repo.Bookmark == 0) { - repo.Bookmark = 1; - } - } - + } else { + Models.Preference.Instance.FindRepository(src.Id).GroupId = parent; rebuild = true; } } - - if (rebuild) { - UpdateTree(); - } - + + if (rebuild) UpdateTree(); e.Handled = true; } #endregion - + #region DATA + private void UpdateRecents() { + var repos = new List(); + var dirty = new List(); + + foreach (var path in Models.Preference.Instance.Recents) { + var repo = Models.Preference.Instance.FindRepository(path); + if (repo != null) { + repos.Add(repo); + } else { + dirty.Add(path); + } + } + + foreach (var path in dirty) Models.Preference.Instance.RemoveRecent(path); + list.ItemsSource = repos; + } + private void UpdateTree(string editingNodeId = null) { var groupNodes = new Dictionary(); - var nodesHistory = new List(); - var nodesBookmarks = new List(); - + var nodes = new List(); + foreach (var group in Models.Preference.Instance.Groups) { Node node = new Node() { Id = group.Id, @@ -419,18 +352,20 @@ namespace SourceGit.Views.Widgets { Bookmark = 0, Children = new List(), }; + groupNodes.Add(node.Id, node); } - + + nodes.Clear(); + foreach (var kv in groupNodes) { if (groupNodes.ContainsKey(kv.Value.ParentId)) { groupNodes[kv.Value.ParentId].Children.Add(kv.Value); - } - else { - nodesBookmarks.Add(kv.Value); + } else { + nodes.Add(kv.Value); } } - + foreach (var repo in Models.Preference.Instance.Repositories) { Node node = new Node() { Id = repo.Path, @@ -442,138 +377,111 @@ namespace SourceGit.Views.Widgets { Bookmark = repo.Bookmark, Children = new List(), }; - nodesHistory.Add(node); - - if (repo.Bookmark != 0) { - if (groupNodes.ContainsKey(repo.GroupId)) { - groupNodes[repo.GroupId].Children.Add(node); - } - else { - nodesBookmarks.Add(node); - } + + if (groupNodes.ContainsKey(repo.GroupId)) { + groupNodes[repo.GroupId].Children.Add(node); + } else { + nodes.Add(node); } - - OnNodeEdited?.Invoke(node); } - - treeHistory.ItemsSource = nodesHistory; - treeBookmarks.ItemsSource = nodesBookmarks; + + tree.ItemsSource = nodes; } - + private void DeleteNode(Node node) { if (node.IsGroup) { Models.Preference.Instance.RemoveGroup(node.Id); - } - else { + } else { Models.Preference.Instance.RemoveRepository(node.Id); } - - UpdateTree(); + + UpdateTree(); + UpdateRecents(); } - + private bool MakeSureReady() { if (!Models.Preference.Instance.IsReady) { Models.Exception.Raise(App.Text("NotConfigured")); return false; } - return true; } - + private void CheckAndOpen(string path) { - if (!MakeSureReady()) { - return; - } - + if (!MakeSureReady()) return; + if (!Directory.Exists(path)) { Models.Exception.Raise(App.Text("PathNotFound", path)); return; } - + var root = new Commands.GetRepositoryRootPath(path).Result(); - if (root == null) { new Popups.Init(path).Show(); return; } - + var gitDir = new Commands.QueryGitDir(root).Result(); var repo = Models.Preference.Instance.AddRepository(root, gitDir, ""); Models.Watcher.Open(repo); - treeHistory.UnselectAll(); - treeBookmarks.UnselectAll(); + Models.Preference.Instance.AddRecent(repo.Path); } - + public void UpdateNodes(string id, int bookmark, IEnumerable nodes = null) { - if (nodes == null) { - nodes = treeHistory.ItemsSource.OfType(); - } - + if (nodes == null) nodes = tree.ItemsSource.OfType(); foreach (var node in nodes) { if (!node.IsGroup) { if (node.Id == id) { - Models.Preference.Instance.FindRepository(node.Id).Bookmark = bookmark; - UpdateTree(); + node.Bookmark = bookmark; break; } - } - else if (node.Children.Count > 0) { + } else if (node.Children.Count > 0) { UpdateNodes(id, bookmark, node.Children); } } } #endregion - + #region RENAME_NODES private void RenameStart(object sender, RoutedEventArgs e) { var edit = sender as Controls.TextEdit; - - if (edit == null || !edit.IsVisible) { - return; - } - + if (edit == null || !edit.IsVisible) return; + edit.SelectAll(); edit.Focus(); } - + private void RenameKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Escape) { UpdateTree(); e.Handled = true; - } - else if (e.Key == Key.Enter) { + } else if (e.Key == Key.Enter) { RenameEnd(sender, e); e.Handled = true; } } - + private void RenameEnd(object sender, RoutedEventArgs e) { var edit = sender as Controls.TextEdit; - - if (edit == null) { - return; - } - + if (edit == null) return; + if (string.IsNullOrWhiteSpace(edit.Text)) { UpdateTree(); e.Handled = false; return; } - + var node = edit.DataContext as Node; - if (node != null) { node.Name = edit.Text; node.IsEditing = false; - if (node.IsGroup) { Models.Preference.Instance.RenameGroup(node.Id, edit.Text); - } - else { - Models.Preference.Instance.RenameRepository(node.Id, node.Name); + } else { + Models.Preference.Instance.RenameRepository(node.Id, node.Name); + UpdateRecents(); OnNodeEdited?.Invoke(node); } - e.Handled = false; } }