diff --git a/main2.pb b/main2.pb index 11ddbb7..d3ffbf9 100644 --- a/main2.pb +++ b/main2.pb @@ -1,5 +1,10 @@ EnableExplicit +CompilerIf #PB_Compiler_Thread=0 + MessageRequester("Compiler","You must to enable Create Threadsafe executable in Compiler Options",#PB_MessageRequester_Error|#PB_MessageRequester_Ok) + End +CompilerEndIf + ; ============================================================================= ;-MODULE TRANSLATE ; ============================================================================= @@ -11,7 +16,7 @@ EndDeclareModule Module Translate ; =============================================== - ; Système Multilingue Minimaliste pour PureBasic + ; Système Multilingue ; =============================================== Global NewMap Translations.s() @@ -463,7 +468,7 @@ Enumeration GadgetsIDs #GID_FrmProxy #GID_ChkProxy - + ; HTTP #GID_LblHttpSrv #GID_EdHttpSrv @@ -483,7 +488,7 @@ Enumeration GadgetsIDs #GID_EdHttpsUser #GID_LblHttpsPass #GID_EdHttpsPass - + #GID_BtnApplyProxy EndEnumeration @@ -491,6 +496,38 @@ EndEnumeration ; ----------------------------------------------------------------------------- ; SMALL HELPERS / AIDES UTILITAIRES ; ----------------------------------------------------------------------------- + +; Compte le nombre d’items cochés (#PB_ListIcon_Checked) dans un ListIcon +Procedure.i _ListCountChecked(gadget.i) + Protected i, c + For i = 0 To CountGadgetItems(gadget) - 1 + If GetGadgetItemState(gadget, i) & #PB_ListIcon_Checked + c + 1 + EndIf + Next + ProcedureReturn c +EndProcedure + +; Compte le nombre d’items sélectionnés (#PB_ListIcon_Selected) dans un ListIcon +Procedure.i _ListCountSelected(gadget.i) + Protected i, c + For i = 0 To CountGadgetItems(gadget) - 1 + If GetGadgetItemState(gadget, i) & #PB_ListIcon_Selected + c + 1 + EndIf + Next + ProcedureReturn c +EndProcedure + +; Petit helper pour activer/désactiver sans se tromper +Procedure _SetEnabled(gadget.i, enabled.i) + If enabled + DisableGadget(gadget, 0) + Else + DisableGadget(gadget, 1) + EndIf +EndProcedure + Macro RightOf(g) : GadgetX(g) + GadgetWidth(g) : EndMacro Macro BottomOf(g) : GadgetY(g) + GadgetHeight(g) : EndMacro @@ -605,15 +642,15 @@ Procedure ApplyToolTips() ; --- Remote / Branch --- GadgetToolTip(#GID_EdRemote, T("tip.remote", "URL du remote (ex.: https://... ou git@host:org/repo.git)")) - + ; Local branches GadgetToolTip(#GID_CbLocalBranch, T("tip.branch.local.select", "Choisir la branche locale active")) GadgetToolTip(#GID_BtnNewLocalBranch,T("tip.branch.local.new", "Créer une nouvelle branche locale")) - + ; Remote branches GadgetToolTip(#GID_CbRemoteBranch, T("tip.branch.remote.select", "Choisir une branche distante (remote-tracking)")) GadgetToolTip(#GID_BtnNewRemoteBranch,T("tip.branch.remote.new", "Créer une branche sur le dépôt distant / publier")) - + ; --- Remote / Branch --- GadgetToolTip(#GID_EdRemote, T("tip.remote", "URL du remote (ex.: https://... ou git@host:org/repo.git)")) @@ -646,9 +683,9 @@ Procedure ApplyToolTips() GadgetToolTip(#GID_CbScope, T("tip.cfg.scope", "Portée de la configuration (Local/Global/System)")) GadgetToolTip(#GID_BtnSaveCfg, T("tip.cfg.save", "Enregistrer la configuration Git")) - ; --- Langue --- + ; --- Langue --- GadgetToolTip(#GID_CbAppLang, T("tip.app.lang", "Langue de l’application")) - + ; --- Proxy --- GadgetToolTip(#GID_ChkProxy, T("tip.proxy.enable", "Activer/désactiver la configuration proxy")) GadgetToolTip(#GID_EdHttpSrv, T("tip.proxy.http.server", "Serveur HTTP proxy")) @@ -660,7 +697,7 @@ Procedure ApplyToolTips() GadgetToolTip(#GID_EdHttpsUser, T("tip.proxy.https.user", "Login HTTPS proxy")) GadgetToolTip(#GID_EdHttpsPass, T("tip.proxy.https.pass", "Mot de passe HTTPS proxy")) GadgetToolTip(#GID_BtnApplyProxy,T("tip.proxy.apply", "Appliquer la configuration proxy dans Git")) - + @@ -669,9 +706,89 @@ Procedure ApplyToolTips() GadgetToolTip(#GID_HelpWeb, T("tip.help.web", "Zone d’aide (documentation / rendu HTML)")) EndProcedure +Procedure UpdateGadgetsState() + ; --- État courant --- + Protected repo.b = main\IsRepository + Protected remoteURL$ = SupTrim(GetGadgetText(#GID_EdRemote)) + Protected hasRemoteText.b = Bool(remoteURL$ <> "") + Protected hasRemoteCfg.b = Bool(repo And main\hasRemoteUrl) ; remote *réellement* configuré dans le dépôt + + Protected locBr$ = SupTrim(GetGadgetText(#GID_CbLocalBranch)) + Protected remBr$ = SupTrim(GetGadgetText(#GID_CbRemoteBranch)) + Protected hasLocBr.b = Bool(locBr$ <> "") + Protected hasRemBr.b = Bool(remBr$ <> "") + + Protected msg$ = SupTrim(GetGadgetText(#GID_EdMessage)) + Protected hasMsg.b = Bool(msg$ <> "") + + Protected checked.l = _ListCountChecked(#GID_ListStatus) ; pour Commit + Protected selected.l = _ListCountSelected(#GID_ListStatus) ; pour Restore/Rename/Delete/Ignore + + Protected histSel.b = Bool(GetGadgetState(#GID_ListHistory) >= 0) + + ; --- Règles métier --- + Protected canInit.b = Bool(Not repo) + Protected canClone.b = Bool(Not repo And hasRemoteText) ; clone quand pas de repo et URL saisie + Protected canRefresh.b = repo + + Protected canCommit.b = Bool(repo And hasMsg And (checked > 0)) + Protected canFiles.b = Bool(repo And (selected > 0)) + + Protected canPull.b = Bool(repo And hasRemoteCfg And hasLocBr And hasRemBr) + Protected canPush.b = canPull ; même prérequis de base + Protected canVerifyRemote.b = Bool(repo And hasRemoteCfg) + + ; --- Toujours utiles --- + _SetEnabled(#GID_BtnBrowseRepo, #True) + _SetEnabled(#GID_EdRepo, #True) + + ; --- Local --- + _SetEnabled(#GID_BtnInit, canInit) + _SetEnabled(#GID_BtnRefresh, canRefresh) + _SetEnabled(#GID_CbLocalBranch, repo) + _SetEnabled(#GID_BtnNewLocalBranch, repo) + + ; --- Remote --- + _SetEnabled(#GID_EdRemote, #True) ; éditable tout le temps + _SetEnabled(#GID_CbRemoteBranch, hasRemoteCfg) + _SetEnabled(#GID_BtnNewRemoteBranch, hasRemoteCfg) + _SetEnabled(#GID_BtnClone, canClone) + _SetEnabled(#GID_BtnPull, canPull) + _SetEnabled(#GID_BtnPush, canPush) + _SetEnabled(#GID_BtnVerify, canVerifyRemote) + + ; --- Fichiers & commit --- + _SetEnabled(#GID_ListStatus, repo) + _SetEnabled(#GID_BtnRestore, canFiles) + _SetEnabled(#GID_BtnRename, canFiles) + _SetEnabled(#GID_BtnDelete, canFiles) + _SetEnabled(#GID_BtnIgnore, canFiles) + + _SetEnabled(#GID_EdMessage, repo) + _SetEnabled(#GID_BtnCommit, canCommit) + + ; --- History --- + _SetEnabled(#GID_ListHistory, repo) + _SetEnabled(#GID_BtnRestoreCommit, Bool(repo And histSel)) + _SetEnabled(#GID_TxtCommitInfo, repo) + + ; --- .gitignore --- + _SetEnabled(#GID_TxtGitIgnore, repo) + _SetEnabled(#GID_BtnSaveGitIgnore, repo) + + ; --- Config & Proxy : laissons-les actifs en permanence --- +EndProcedure + + ; ----------------------------------------------------------------------------- ; BUILD GUI / CONSTRUCTION DE L’INTERFACE ; ----------------------------------------------------------------------------- +Enumeration + #Panel_Repo + #Panel_History + #Panel_GitIgnore + #Panel_Config +EndEnumeration Procedure OpenGUI() UseModule Translate Define repoDir$ = GetCurrentDirectory() @@ -685,9 +802,9 @@ Procedure OpenGUI() ; =========================================================================== ; TAB 1: REPO / DÉPÔT ; =========================================================================== - AddGadgetItem(#GID_Panel, -1, T("Tab.Repo", "Dépôt")) + AddGadgetItem(#GID_Panel, #Panel_Repo, T("Tab.Repo", "Dépôt")) -; ---- Frame: Local repository ------------------------------------------------ + ; ---- Frame: Local repository ------------------------------------------------ FrameGadget(#GID_FrmLocal, #UI_Inset, #UI_Inset, GadgetWidth(#GID_Panel) - #UI_Inset*2, #UI_FrameHeaderH + #UI_RowH*3 + #UI_Inset*3, T("Local.FrameTitle", "Dépôt local"), #PB_Frame_Container) TextGadget(#GID_LblRepo, #UI_Inset, #UI_FrameHeaderH, 70, #UI_RowH, T("Local.Label.Repo","Dépôt :")) @@ -696,7 +813,7 @@ Procedure OpenGUI() ButtonGadget(#GID_BtnInit, #UI_Inset, BottomOf(#GID_BtnBrowseRepo) + #UI_Inset, #UI_BtnW, #UI_RowH, T("Local.Button.Init","Init Dépôt")) ButtonGadget(#GID_BtnRefresh, RightOf(#GID_BtnInit) + #UI_Inset, GadgetY(#GID_BtnInit), #UI_BtnW, #UI_RowH, T("Local.Button.Refresh","Rafraîchir")) - + ; --- NEW: branche locale (sélecteur + bouton) --- Define yLocalBranch = BottomOf(#GID_BtnRefresh) + #UI_Inset TextGadget(#GID_LblLocalBranch, #UI_Inset, yLocalBranch, 120, #UI_RowH, T("Local.Label.Branch","Branche locale :")) @@ -704,25 +821,25 @@ Procedure OpenGUI() ButtonGadget(#GID_BtnNewLocalBranch, RightOf(#GID_CbLocalBranch) + #UI_Inset, yLocalBranch, 150, #UI_RowH, T("Local.Button.NewBranch","+ Nouvelle branche")) CloseGadgetList() - ; ---- Frame: Remote / Branche ------------------------------------------------ + ; ---- Frame: Remote / Branche ------------------------------------------------ Define yRemote = BottomOf(#GID_FrmLocal) + #UI_Inset FrameGadget(#GID_FrmRemote, #UI_Inset, yRemote, GadgetWidth(#GID_Panel) - #UI_Inset*2, #UI_FrameHeaderH + #UI_RowH*5 + #UI_Inset*5, T("Remote.FrameTitle","Distant (remote / branche)"), #PB_Frame_Container) ; Ligne 1: URL du remote TextGadget(#GID_LblRemote, #UI_Inset, #UI_FrameHeaderH, 70, #UI_RowH, T("Remote.Label.Remote","Remote :")) StringGadget(#GID_EdRemote, RightOf(#GID_LblRemote) + #UI_Inset, #UI_FrameHeaderH, 420, #UI_RowH, "") - + ; Ligne 2: Branche distante (sélecteur + bouton) Define yRemoteBranch = BottomOf(#GID_EdRemote) + #UI_Inset TextGadget(#GID_LblRemoteBranch, #UI_Inset, yRemoteBranch, 130, #UI_RowH, T("Remote.Label.BranchRemote","Branche distante :")) ComboBoxGadget(#GID_CbRemoteBranch, RightOf(#GID_LblRemoteBranch), yRemoteBranch, 220, #UI_RowH) ButtonGadget(#GID_BtnNewRemoteBranch, RightOf(#GID_CbRemoteBranch) + #UI_Inset, yRemoteBranch, 160, #UI_RowH, T("Remote.Button.NewRemoteBranch","+ Nouvelle branche distante")) - + ; Ligne 3: Actions réseau ButtonGadget(#GID_BtnClone, #UI_Inset, BottomOf(#GID_LblRemoteBranch) + #UI_Inset, #UI_BtnW, #UI_RowH, T("Remote.Button.Clone","Clone")) ButtonGadget(#GID_BtnPull, RightOf(#GID_BtnClone) + #UI_Inset, GadgetY(#GID_BtnClone), #UI_BtnW, #UI_RowH, T("Remote.Button.Pull","Pull")) ButtonGadget(#GID_BtnPush, RightOf(#GID_BtnPull) + #UI_Inset, GadgetY(#GID_BtnClone), #UI_BtnW, #UI_RowH, T("Remote.Button.Push","Push")) - + ; Ligne 4: Statut & dernière synchro Define yStatus = BottomOf(#GID_BtnClone) + #UI_Inset TextGadget(#GID_LblRemoteStatus, #UI_Inset, yStatus, 70, #UI_RowH, T("Remote.Status.Label","Status :")) @@ -730,53 +847,52 @@ Procedure OpenGUI() TextGadget(#GID_LblLastFetch, RightOf(#GID_TxtRemoteStatus) + 15, yStatus, 110, #UI_RowH, T("Remote.LastSync.Label","Dernière sync :")) TextGadget(#GID_TxtLastFetch, RightOf(#GID_LblLastFetch), yStatus, 120, #UI_RowH, "-", #PB_Text_Border) ButtonGadget(#GID_BtnVerify, RightOf(#GID_TxtLastFetch) + 10, yStatus - 2, 90, #UI_RowH, T("Remote.Button.Verify","Vérifier")) - + ; Ligne 5: Action en cours TextGadget(#GID_LblAction, #UI_Inset, BottomOf(#GID_LblRemoteStatus) + #UI_Inset, 60, 20, T("Remote.Action.Label","Action :")) TextGadget(#GID_TxtAction, RightOf(#GID_LblAction), GadgetY(#GID_LblAction), 300, 20, "-", #PB_Text_Border) CloseGadgetList() - + ; ---- Frame: Files & changes ------------------------------------------------- -Define yFiles = BottomOf(#GID_FrmRemote) + #UI_Inset -Define hFiles = panelH - yFiles - #UI_Inset -If hFiles < 260 : hFiles = 260 : EndIf ; hauteur mini du frame pour éviter valeurs négatives - -FrameGadget(#GID_FrmFiles, #UI_Inset, yFiles, GadgetWidth(#GID_Panel) - #UI_Inset*2, hFiles, T("Files.FrameTitle","Fichiers & modifications"), #PB_Frame_Container) - -; Hauteur de la liste avec garde-fou (même logique que dans ResizeGUI) -Define listH = hFiles - #UI_RowH*2 - #UI_Inset*4 - #UI_FrameHeaderH -If listH < 100 : listH = 100 : EndIf - -ListIconGadget(#GID_ListStatus, #UI_Inset, #UI_FrameHeaderH, GadgetWidth(#GID_FrmFiles) - #UI_Inset*2, listH, T("Files.List.Path","Path"), 300, #PB_ListIcon_CheckBoxes | #PB_ListIcon_MultiSelect | #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection) -AddGadgetColumn(#GID_ListStatus, 1, T("Files.List.Status","Status"), 80) -AddGadgetColumn(#GID_ListStatus, 2, T("Files.List.Description","Description"), 300) - -; Ligne boutons sous la liste -Define yLocalActions = #UI_FrameHeaderH + listH + #UI_Inset -ButtonGadget(#GID_BtnRestore, #UI_Inset + 10, yLocalActions, 110, #UI_RowH, T("LocalActions.Button.Restore","Restaurer")) -ButtonGadget(#GID_BtnRename, #UI_Inset + 130, yLocalActions, 110, #UI_RowH, T("LocalActions.Button.Rename","Renommer")) -ButtonGadget(#GID_BtnDelete, #UI_Inset + 250, yLocalActions, 110, #UI_RowH, T("LocalActions.Button.Delete","Supprimer")) -ButtonGadget(#GID_BtnIgnore, #UI_Inset + 370, yLocalActions, 110, #UI_RowH, T("LocalActions.Button.Ignore","Ignorer")) - -; Message de commit -Define yMsg = yLocalActions + #UI_RowH + #UI_Inset -TextGadget(#GID_LblMessage, #UI_Inset + 10, yMsg + 4, 80, 22, T("Commit.Label.Message","Message :")) -StringGadget(#GID_EdMessage, #UI_Inset + 95, yMsg, GadgetWidth(#GID_FrmFiles) - #UI_Inset*2 - 95 - 110, #UI_RowH, "") -ButtonGadget(#GID_BtnCommit, GadgetWidth(#GID_FrmFiles) - #UI_Inset - 100, yMsg - 2, 100, #UI_RowH, T("Commit.Button.Commit","Commit")) -CloseGadgetList() - + Define yFiles = BottomOf(#GID_FrmRemote) + #UI_Inset + Define hFiles = panelH - yFiles - #UI_Inset + If hFiles < 260 : hFiles = 260 : EndIf ; hauteur mini du frame pour éviter valeurs négatives + + FrameGadget(#GID_FrmFiles, #UI_Inset, yFiles, GadgetWidth(#GID_Panel) - #UI_Inset*2, hFiles, T("Files.FrameTitle","Fichiers & modifications"), #PB_Frame_Container) + + ; Hauteur de la liste avec garde-fou (même logique que dans ResizeGUI) + Define listH = hFiles - #UI_RowH*2 - #UI_Inset*4 - #UI_FrameHeaderH + If listH < 100 : listH = 100 : EndIf + + ListIconGadget(#GID_ListStatus, #UI_Inset, #UI_FrameHeaderH, GadgetWidth(#GID_FrmFiles) - #UI_Inset*2, listH, T("Files.List.Path","Path"), 300, #PB_ListIcon_CheckBoxes | #PB_ListIcon_MultiSelect | #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection) + AddGadgetColumn(#GID_ListStatus, 1, T("Files.List.Status","Status"), 80) + AddGadgetColumn(#GID_ListStatus, 2, T("Files.List.Description","Description"), 300) + + ; Ligne boutons sous la liste + Define yLocalActions = #UI_FrameHeaderH + listH + #UI_Inset + ButtonGadget(#GID_BtnRestore, #UI_Inset + 10, yLocalActions, 110, #UI_RowH, T("LocalActions.Button.Restore","Restaurer")) + ButtonGadget(#GID_BtnRename, #UI_Inset + 130, yLocalActions, 110, #UI_RowH, T("LocalActions.Button.Rename","Renommer")) + ButtonGadget(#GID_BtnDelete, #UI_Inset + 250, yLocalActions, 110, #UI_RowH, T("LocalActions.Button.Delete","Supprimer")) + ButtonGadget(#GID_BtnIgnore, #UI_Inset + 370, yLocalActions, 110, #UI_RowH, T("LocalActions.Button.Ignore","Ignorer")) + + ; Message de commit + Define yMsg = yLocalActions + #UI_RowH + #UI_Inset + TextGadget(#GID_LblMessage, #UI_Inset + 10, yMsg + 4, 80, 22, T("Commit.Label.Message","Message :")) + StringGadget(#GID_EdMessage, #UI_Inset + 95, yMsg, GadgetWidth(#GID_FrmFiles) - #UI_Inset*2 - 95 - 110, #UI_RowH, "") + ButtonGadget(#GID_BtnCommit, GadgetWidth(#GID_FrmFiles) - #UI_Inset - 100, yMsg - 2, 100, #UI_RowH, T("Commit.Button.Commit","Commit")) + CloseGadgetList() + ; =========================================================================== ; TAB 2: HISTORY ; =========================================================================== - AddGadgetItem(#GID_Panel, -1, T("Tabs.History","History")) + AddGadgetItem(#GID_Panel, #Panel_History, T("Tabs.History","History")) - ListIconGadget(#GID_ListHistory, #UI_Inset, #UI_Inset, GadgetWidth(#GID_Panel) - #UI_Inset*2, panelH - #UI_Inset*2 - #UI_RowH - 10 - 150 - 10, T("History.Headers.Header","Header"), 220, #PB_ListIcon_FullRowSelect) - AddGadgetColumn(#GID_ListHistory, 1, T("History.Headers.Date","Date"), 150) - AddGadgetColumn(#GID_ListHistory, 2, T("History.Headers.Author","Auteur"), 180) - AddGadgetColumn(#GID_ListHistory, 3, T("History.Headers.Files","Fichiers"), 120) - AddGadgetColumn(#GID_ListHistory, 4, T("History.Headers.Message","Message"), (GadgetWidth(#GID_Panel) - 2*#UI_Inset) - (220 + 150 + 180 + 120) - 20) + ListIconGadget(#GID_ListHistory, #UI_Inset, #UI_Inset, GadgetWidth(#GID_Panel) - #UI_Inset*2, panelH - #UI_Inset*2 - #UI_RowH - 10 - 150 - 10, T("History.Headers.Header","Header"), 70, #PB_ListIcon_FullRowSelect) + AddGadgetColumn(#GID_ListHistory, 1, T("History.Headers.Date","Date"), 200) + AddGadgetColumn(#GID_ListHistory, 2, T("History.Headers.Author","Auteur"), 100) + AddGadgetColumn(#GID_ListHistory, 4, T("History.Headers.Message","Message"), 300) ButtonGadget(#GID_BtnRestoreCommit, #UI_Inset, panelH - #UI_Inset - #UI_RowH - 150 - 10, 180, #UI_RowH, T("History.Button.RestoreCommit","Restore This Commit")) @@ -785,14 +901,14 @@ CloseGadgetList() ; =========================================================================== ; TAB 3: .gitignore ; =========================================================================== - AddGadgetItem(#GID_Panel, -1, T("Tabs.Gitignore",".gitignore file")) + AddGadgetItem(#GID_Panel, #Panel_GitIgnore, T("Tabs.Gitignore",".gitignore file")) EditorGadget(#GID_TxtGitIgnore, #UI_Inset, #UI_Inset, GadgetWidth(#GID_Panel) - #UI_Inset*2, panelH - #UI_Inset*4 - #UI_RowH) ButtonGadget(#GID_BtnSaveGitIgnore, #UI_Inset, GadgetY(#GID_TxtGitIgnore) + GadgetHeight(#GID_TxtGitIgnore) + #UI_Inset, 100, #UI_RowH, T("Gitignore.Button.SaveFile","Save File")) ; =========================================================================== ; TAB 4: CONFIG ; =========================================================================== - AddGadgetItem(#GID_Panel, -1, T("Tabs.Config","Config")) + AddGadgetItem(#GID_Panel, #Panel_Config, T("Tabs.Config","Config")) ; --- Frame: Paramètres de l’application (LANGUE, etc.) --- FrameGadget(#GID_FrmApp, #UI_Inset, #UI_Inset, GadgetWidth(#GID_Panel) - #UI_Inset*2, 90, T("App.FrameTitle","Paramètres de l’application"), #PB_Frame_Container) @@ -895,13 +1011,6 @@ Procedure.i GetGitVersion() ProcedureReturn #False EndProcedure -Procedure.i DoGitFetch(remote.s="origin",branch.s="main") - If Git("fetch "+remote+" "+branch) = 0 - ProcedureReturn #True - EndIf - ProcedureReturn #False -EndProcedure - Procedure.i DoCommit() Protected code.i,nb.l=0,i.l Protected args.s = "add" @@ -925,8 +1034,8 @@ Procedure.i DoCommit() If GetGadgetText(#GID_CbLocalBranch)<>"" And Git("switch "+GetGadgetText(#GID_CbLocalBranch))<>0 MessageRequester("Git switch", "Échec: " + #LF$ + main\GitCall\errors, #PB_MessageRequester_Error) EndIf - - + + If Git(args)<>0 MessageRequester("Git add", "Échec: " + #LF$ + main\GitCall\errors, #PB_MessageRequester_Error) ProcedureReturn #False @@ -945,6 +1054,58 @@ Procedure.i DoCommit() ProcedureReturn #True EndProcedure +Procedure DoRename() + Protected i.l,count.l=0 + For i = 0 To CountGadgetItems(#GID_ListStatus) - 1 + If GetGadgetItemState(#GID_ListStatus, i) & #PB_ListIcon_Selected + Protected filepath.s=StringField(GetGadgetItemText(#GID_ListStatus, i),1,Chr(10)) + Protected newfilepath.s=InputRequester("Git mv","Rename This File",filepath,0,WindowID(#WinMain)) + If newfilepath<>"" And filepath<>newfilepath + Protected sucess.b=#False + If LCase(filepath)=LCase(newfilepath) And (#PB_Compiler_OS=#PB_OS_Windows Or #PB_Compiler_OS=#PB_OS_MacOS) + ; 2 time to renome on Windows and MacOs + If git("mv "+Chr(34)+filepath+Chr(34)+" "+Chr(34)+filepath+".tmp"+Chr(34))=0 + git("mv "+Chr(34)+filepath+".tmp"+Chr(34)+" "+Chr(34)+newfilepath+Chr(34)) + count=count+1 + sucess=#True + EndIf + Else + If git("mv "+Chr(34)+filepath+Chr(34)+" "+Chr(34)+newfilepath+Chr(34))=0 + count=count+1 + sucess=#True + EndIf + EndIf + If sucess=#True + + EndIf + EndIf + + EndIf + Next i + Protected message.s + If count>0 + If count=1 + message=T("","Renommage de %1 en %2") + message=ReplaceString(message,"%1",filepath) + message=ReplaceString(message,"%2",newfilepath) + ElseIf count>1 + message=T("","Renommage de %1 fichiers") + message=ReplaceString(message,"%1",Str(count)) + EndIf + If Git("commit -m " + Chr(34)+message+Chr(34))<>0 + MessageRequester("Git commit", "Échec ou rien à valider: " + #LF$ + main\GitCall\errors + #LF$ + main\GitCall\output, #PB_MessageRequester_Warning) + EndIf + EndIf + +EndProcedure + +Procedure.i DoGitFetch(remote.s="origin",branch.s="main") + If Git("fetch "+remote+" "+branch) = 0 + ProcedureReturn #True + EndIf + ProcedureReturn #False +EndProcedure + Procedure AddRemoteRepo(Url.s,name.s="origin") Url=SupTrim(Url) name=SupTrim(name) @@ -990,7 +1151,7 @@ Procedure DoPush() MessageRequester("Git Push", "Échec: " + #LF$ + main\Gitcall\errors, #PB_MessageRequester_Error) ProcedureReturn #False EndIf - + EndProcedure Procedure.i GetRemoteStatusInfo() @@ -1021,7 +1182,7 @@ Procedure.i GetRemoteStatusInfo() If Len(counts) > 0 ; Parser les résultats (séparés par des espaces ou tabs) Protected parts.s = ReplaceString(counts, #TAB$, " ") ; Normaliser les séparateurs - parts = ReplaceString(parts, " ", " ") ; Supprimer les espaces multiples + parts = ReplaceString(parts, " ", " ") ; Supprimer les espaces multiples ahead = Val(StringField(parts, 1, " ")) behind = Val(StringField(parts, 2, " ")) @@ -1137,23 +1298,23 @@ Procedure.i GetStatusImportance(status.s) Protected x.s = Left(status, 1) Protected y.s = Mid(status, 2, 1) Protected score.i = 0 - + ; Conflits d'abord Select status Case "DD","AU","UD","UA","DU","AA","UU" ProcedureReturn 1000 EndSelect If x = "U" Or y = "U" : ProcedureReturn 1000 : EndIf - + ; Cas simples If status = "??" : ProcedureReturn 300 : EndIf ; Non suivis If status = "!!" : ProcedureReturn 50 : EndIf ; Ignorés If status = " " : ProcedureReturn 0 : EndIf ; Propres - + ; Index > Worktree If x <> " " : score + 700 : EndIf If y <> " " And y <> "?" And y <> "!" : score + 600 : EndIf - + ; Raffinement (X puis Y) Select x Case "D" : score + 80 @@ -1171,7 +1332,7 @@ Procedure.i GetStatusImportance(status.s) Case "C" : score + 20 Case "T" : score + 15 EndSelect - + ProcedureReturn score EndProcedure @@ -1189,7 +1350,7 @@ Procedure ParseStatusPorcelaine(output$) Protected i.l = 1, tok$, sp.l Protected xy$, path1$, path2$, name$, found.b ; Ne PAS vider main\Files(): on met à jour si existe déjà - + For i=1 To total tok$ = StringField(output$, i, delim$) @@ -1199,7 +1360,7 @@ Procedure ParseStatusPorcelaine(output$) Continue EndIf xy$ = Left(tok$, 2) ; ex: " M", "R ", " C", "??", "UU", etc. - path1$ = Mid(tok$, 4,Len(tok$)-(3)) ; 1er chemin + path1$ = Mid(tok$, 4,Len(tok$)-(3)) ; 1er chemin ;TODO check this ; Renomme/copie ? (si X ou Y est R/C, le prochain champ NUL = nouveau chemin) @@ -1212,10 +1373,10 @@ Procedure ParseStatusPorcelaine(output$) Else name$ = path1$ EndIf - + ; Normalisation des séparateurs name$ = ReplaceString(name$, "\", "/") - + ; MAJ si déjà présent, sinon ajout found = #False ForEach main\Files() @@ -1226,7 +1387,7 @@ Procedure ParseStatusPorcelaine(output$) Break EndIf Next - + If Not found AddElement(main\Files()) main\Files()\name = name$ @@ -1234,7 +1395,7 @@ Procedure ParseStatusPorcelaine(output$) main\Files()\statusDescription = GetStatusDescription(xy$) EndIf Next - + Debug "Récupération des status Git (-z) réussie. " + Str(ListSize(main\Files())) + " fichiers (maj/ajout)." ProcedureReturn #True EndProcedure @@ -1389,7 +1550,7 @@ EndProcedure Procedure.s RefreshLocalBranchesList(Gdt.i) ClearGadgetItems(Gdt) - + ; Parser ligne par ligne Protected n.l = CountString(main\Gitcall\output, #LF$) + 1 Protected i.l, line.s @@ -1424,7 +1585,7 @@ EndProcedure Procedure.s RefreshRemoteBranchesList(Gdt.i) ClearGadgetItems(Gdt) - + ; Parser ligne par ligne Protected n.l = CountString(main\Gitcall\output, #LF$) + 1 Protected i.l, line.s, cleanBranchName.s, defaultBranch.s @@ -1475,6 +1636,41 @@ Procedure.s RefreshRemoteBranchesList(Gdt.i) Next EndProcedure +Procedure GetCommitHistory() + Protected i.l,n.l,line.s + + ; %H: Commit hash (full) + ; %h: Commit hash (abbreviated) + ; %an: Author name + ; %ae: Author email + ; %ad: Author date + ; %cn: Committer name + ; %ce: Committer email + ; %cd: Committer date + ; %s: Subject line + ; %b: Body of the commit message + ; %n: Newline character + If git(~"log --pretty=format:\"%H|%cd|%an|%s\" --date=iso")=0 + ClearGadgetItems(#GID_ListHistory) + n.l = CountString(main\Gitcall\output, #LF$) + 1 + Debug "Nombre de ligne :"+Str(n) + For i = 1 To n + line = SupTrim(StringField(main\Gitcall\output, i, #LF$)) + line=ReplaceString(line,"|",Chr(10)) + AddGadgetItem(#GID_ListHistory,-1,line) + Next + EndIf +EndProcedure + +Procedure GetCommitInfo() + If GetGadgetState(#GID_ListHistory)>-1 + Protected hash.s=GetGadgetItemText(#GID_ListHistory, GetGadgetState(#GID_ListHistory), 0) + If git("show --pretty=fuller --stat --name-status --no-patch --show-signature "+hash)=0 + SetGadgetText(#GID_TxtCommitInfo,SupTrim(main\gitCall\output)+SupTrim(main\gitCall\errors)) + EndIf + EndIf +EndProcedure + ; --- Helper interne : scanne un dossier et alimente la liste Procedure _ScanFiles(path$, root$="") If root$="":root$=path$:EndIf @@ -1494,10 +1690,10 @@ Procedure _ScanFiles(path$, root$="") _ScanFiles(full$, root$) EndIf Else - + Protected rel$ = Mid(full$, Len(root$) + 1) rel$ = ReplaceString(rel$, "\", "/") ; chemins normalisés - + AddElement(main\Files()) main\Files()\name = rel$ main\Files()\status = " " ; 2 espaces = clean @@ -1521,7 +1717,8 @@ Procedure readDirectory() EndProcedure -Procedure RefreshFiles() + +Procedure RefreshGUI(null.i) DoGitFetch() ;TODO add Branch ClearGadgetItems(#GID_ListStatus) ClearList(main\Files()) @@ -1550,7 +1747,7 @@ Procedure RefreshFiles() main\Files()\importance = GetStatusImportance(main\Files()\status) Next - ;Sort by Importance + ;Sort by Importance SortStructuredList(main\Files(), #PB_Sort_Descending, OffsetOf(FilesStruct\importance), #PB_Integer) ;Display list @@ -1564,6 +1761,10 @@ Procedure RefreshFiles() Next EndProcedure +Procedure Refresh() + CreateThread(@RefreshGUI(),0) +EndProcedure + ; ----------------------------------------------------------------------------- ;-MAIN ; ----------------------------------------------------------------------------- @@ -1618,15 +1819,16 @@ Procedure Main() main\IsRepository=IsGitRepository() SetWindowTitle(#WinMain,#AppTitle$+" (with "+main\gitVersion$+")") SetGadgetText(#GID_EdRepo, GetCurrentDirectory()) - - RefreshFiles() - + + Refresh() + ; ----------------------------------------------------------------------------- ;-EVENT LOOP / BOUCLE D'ÉVÉNEMENTS ; ----------------------------------------------------------------------------- Protected.i ev, gid Repeat + UpdateGadgetsState() ev = WaitWindowEvent() Select ev @@ -1636,6 +1838,18 @@ Procedure Main() Case #PB_Event_Gadget gid = EventGadget() Select gid + + Case #GID_Panel + If EventType()=#PB_EventType_Change + Select GetGadgetState(#GID_Panel) + Case #Panel_Repo + Case #Panel_History + GetCommitHistory() + Case #Panel_GitIgnore + Case #Panel_Config + EndSelect + EndIf + Case #GID_BtnBrowseRepo ; FR: Sélection dossier / EN: select folder Protected path$ = PathRequester(T("Dlg.SelectRepo","Sélectionnez le dépôt local..."), GetCurrentDirectory(),WindowID(#WinMain)) @@ -1645,7 +1859,7 @@ Procedure Main() SetCurrentDirectory(path$) main\IsRepository=IsGitRepository() If main\IsRepository=#True - RefreshFiles() + Refresh() EndIf ;CreateThread(@RefreshFileList(),0) ;TODO refresh list EndIf @@ -1655,7 +1869,7 @@ Procedure Main() ; TODO: call your Git init logic Case #GID_BtnRefresh - RefreshFiles() + Refresh() Case #GID_BtnClone SetGadgetText(#GID_TxtAction, T("Action.Clone","Clone demandé")) @@ -1678,16 +1892,20 @@ Procedure Main() Case #GID_BtnRestore ; TODO: restore Case #GID_BtnRename - ; TODO: rename + DoRename() + Refresh() Case #GID_BtnDelete ; TODO: delete + + Case #GID_ListHistory + GetCommitInfo() Case #GID_BtnIgnore ; TODO: ignore Case #GID_BtnCommit If DoCommit()=#True SetGadgetText(#GID_EdMessage,"") - RefreshFiles() + Refresh() EndIf Case #GID_BtnSaveGitIgnore @@ -1706,8 +1924,9 @@ EndProcedure Main() ; IDE Options = PureBasic 6.21 (Windows - x64) -; CursorPosition = 986 -; FirstLine = 974 -; Folding = ----f-- +; CursorPosition = 771 +; FirstLine = 752 +; Folding = --------- +; EnableThread ; EnableXP ; DPIAware \ No newline at end of file