4848import org .eclipse .swt .graphics .Font ;
4949import org .eclipse .swt .graphics .FontData ;
5050import org .eclipse .swt .graphics .Image ;
51+ import org .eclipse .swt .graphics .Point ;
5152import org .eclipse .swt .graphics .RGB ;
5253import org .eclipse .swt .layout .FillLayout ;
5354import org .eclipse .swt .layout .GridData ;
7475import org .eclipse .ui .ide .IDE ;
7576import org .eclipse .ui .part .ViewPart ;
7677import org .osgi .service .event .EventHandler ;
77-
7878import com .checkmarx .ast .codebashing .CodeBashing ;
7979import com .checkmarx .ast .learnMore .LearnMore ;
8080import com .checkmarx .ast .learnMore .Sample ;
@@ -115,6 +115,8 @@ public class CheckmarxView extends ViewPart implements EventHandler {
115115 private static final String NO_PROJECTS_AVAILABLE = "No projects available." ;
116116 private static final String FORMATTED_SCAN_LABEL = "%s %s" ;
117117 private static final String FORMATTED_SCAN_LABEL_LATEST = "%s %s (%s)" ;
118+ private boolean isUpdatingCombo = false ;
119+ private boolean resetStoredProjects = false ;
118120
119121 private Timer debounceTimer = new Timer ("ProjectSearchDebounce" , true );
120122 private TimerTask pendingSearchTask ;
@@ -194,6 +196,7 @@ public class CheckmarxView extends ViewPart implements EventHandler {
194196 private static String currentScanIdFormmated = PluginConstants .EMPTY_STRING ;
195197 private List <String > currentBranches = new ArrayList <>();
196198 private List <Project > currentProjects = new ArrayList <>();
199+ private List <Project > storeCurrentProjects = new ArrayList <>();
197200
198201
199202 private boolean scansCleanedByProject = false ;
@@ -389,6 +392,7 @@ private void loadComboboxes() {
389392 @ Override
390393 protected IStatus run (IProgressMonitor arg0 ) {
391394 currentProjects = getProjects ();
395+ storeCurrentProjects = currentProjects ;
392396 sync .asyncExec (() -> {
393397 projectComboViewer .setInput (currentProjects );
394398 if (currentProjectId .isEmpty () || currentProjects .isEmpty ()) {
@@ -775,7 +779,8 @@ public String getText(Object element) {
775779 return super .getText (element );
776780 }
777781 });
778-
782+
783+
779784 projectComboViewer .addSelectionChangedListener (new ISelectionChangedListener () {
780785 @ Override
781786 public void selectionChanged (SelectionChangedEvent event ) {
@@ -794,6 +799,8 @@ public void selectionChanged(SelectionChangedEvent event) {
794799 // Avoid non-sense trigger changed when opening the combo
795800 if (selectedProject .getId ().equals (currentProjectId )) {
796801 CxLogger .info (PluginConstants .INFO_CHANGE_PROJECT_EVENT_NOT_TRIGGERED );
802+ preservCaretposition (storeCurrentProjects , selectedProject .getName ());
803+ currentProjects = storeCurrentProjects ;
797804 return ;
798805 }
799806
@@ -806,7 +813,6 @@ protected IStatus run(IProgressMonitor arg0) {
806813 sync .asyncExec (() -> {
807814 branchComboViewer .setInput (currentBranches );
808815 PluginUtils .setTextForComboViewer (branchComboViewer , currentBranches .isEmpty () ? NO_BRANCHES_AVAILABLE : BRANCH_COMBO_VIEWER_TEXT );
809-
810816 PluginUtils .enableComboViewer (branchComboViewer , true );
811817 PluginUtils .enableComboViewer (scanIdComboViewer , true );
812818 PluginUtils .updateFiltersEnabledAndCheckedState (toolBarActions .getFilterActions ());
@@ -818,25 +824,39 @@ protected IStatus run(IProgressMonitor arg0) {
818824 }
819825 };
820826 job .schedule ();
827+ //After project selected and branches loaded reset the project list
828+ if (resetStoredProjects ) {
829+ storeCurrentProjects .add (selectedProject );
830+ preservCaretposition (storeCurrentProjects , selectedProject .getName ());
831+ currentProjects = storeCurrentProjects ;
832+ resetStoredProjects =false ;
833+ }
821834 }
822835 }
823836 });
824837
825838 // Add ModifyListener to handle manual text input for projects
826839 projectComboViewer .getCombo ().addModifyListener (e -> {
840+ if (isUpdatingCombo ) return ;
827841 String enteredProject = projectComboViewer .getCombo ().getText ().trim ();
842+
828843 // Skip search if the text is the default instruction
829- if (enteredProject .equals (PROJECT_COMBO_VIEWER_TEXT )) {
844+ if (enteredProject .equals (PROJECT_COMBO_VIEWER_TEXT ) || enteredProject . equals ( LOADING_PROJECTS ) ) {
830845 updateStartScanButton (false ); // Disable scan button
831846 return ;
832847 }
848+ // If user starts typing again and list is empty, restore currentProjects
849+ if (projectComboViewer .getCombo ().getItemCount () == 0 && !currentProjects .isEmpty () && enteredProject .length ()>0 ) {
850+ isUpdatingCombo = true ;
851+ preservCaretposition (currentProjects ,enteredProject );
852+ isUpdatingCombo = false ;
853+ }
833854
834855 latestProjectSearchTerm = enteredProject ; // Track the latest term
835856 List <String > matchedProjects ;
836857 matchedProjects = currentProjects .stream ().map (Project ::getName )
837858 .filter (name -> name != null && name .toLowerCase ().contains (enteredProject .toLowerCase ())).limit (100 )
838859 .collect (Collectors .toList ());
839-
840860 if (matchedProjects .isEmpty ()) {
841861 CxLogger .info ("Entered project is not exist in current projects list" );
842862 // Cancel any pending search
@@ -857,13 +877,19 @@ protected IStatus run(IProgressMonitor monitor) {
857877 searchedProjects = DataProvider .getInstance ().getProjects (searchTerm );
858878 Display .getDefault ().asyncExec (() -> {
859879 if (searchTerm .equals (latestProjectSearchTerm )) {
880+ isUpdatingCombo = true ;
860881 // Update UI in UI thread
861882 if (searchedProjects != null && !searchedProjects .isEmpty ()) {
862- projectComboViewer . setInput (searchedProjects );
883+ preservCaretposition (searchedProjects , searchTerm );
863884 currentProjects = searchedProjects ;
885+ resetStoredProjects =true ;
864886 } else {
887+ preservCaretposition (Collections .emptyList (),searchTerm );
865888 updateStartScanButton (false ); // Disable scan button
889+ isUpdatingCombo = false ;
890+ return ;
866891 }
892+ isUpdatingCombo = false ;
867893 }
868894 });
869895 } catch (Exception ex ) {
@@ -876,8 +902,10 @@ protected IStatus run(IProgressMonitor monitor) {
876902 }
877903 };
878904 debounceTimer .schedule (pendingSearchTask , DEBOUNCE_DELAY_MS );
905+
879906 }
880- });
907+ });
908+
881909 }
882910 /**
883911 * Update state variables and make plugin fields loading when project changes
@@ -2570,9 +2598,10 @@ private void clearAndRefreshPlugin() {
25702598
25712599 @ Override
25722600 protected IStatus run (IProgressMonitor arg0 ) {
2573- List <Project > projectList = getProjects ();
2601+ currentProjects = getProjects ();
2602+ storeCurrentProjects = currentProjects ;
25742603 sync .asyncExec (() -> {
2575- projectComboViewer .setInput (projectList );
2604+ projectComboViewer .setInput (currentProjects );
25762605 projectComboViewer .refresh ();
25772606 PluginUtils .setTextForComboViewer (projectComboViewer , PROJECT_COMBO_VIEWER_TEXT );
25782607 PluginUtils .enableComboViewer (projectComboViewer , true );
@@ -2763,4 +2792,17 @@ private void updateStartScanButton(boolean enabled) {
27632792 toolBarActions .getStartScanAction ().setEnabled (false );
27642793 }
27652794 }
2795+
2796+ /**
2797+ * Store the user entered value and the caret position
2798+ *
2799+ * @param projectList
2800+ * @param searchText
2801+ */
2802+ private void preservCaretposition ( List <Project > projectList , String searchText ) {
2803+ int caretPos = projectComboViewer .getCombo ().getCaretPosition ();
2804+ projectComboViewer .setInput (projectList );
2805+ PluginUtils .setTextForComboViewer (projectComboViewer , searchText );
2806+ projectComboViewer .getCombo ().setSelection (new Point (caretPos , caretPos ));
2807+ }
27662808}
0 commit comments