@@ -306,13 +306,28 @@ def create_installed_tab(self):
306306 controls_layout .addWidget (audit_button )
307307
308308 layout .addLayout (controls_layout )
309-
310- # Installed packages list
311- self .installed_list = QListWidget ()
312- layout .addWidget (self .installed_list )
309+
310+ # Installed packages split view
311+ split_layout = QHBoxLayout ()
312+
313+ apps_group = QGroupBox ("Applications (Explicit/Manual)" )
314+ apps_layout = QVBoxLayout ()
315+ self .apps_list = QListWidget ()
316+ apps_layout .addWidget (self .apps_list )
317+ apps_group .setLayout (apps_layout )
318+ split_layout .addWidget (apps_group )
319+
320+ deps_group = QGroupBox ("Dependencies (Auto-installed)" )
321+ deps_layout = QVBoxLayout ()
322+ self .deps_list = QListWidget ()
323+ deps_layout .addWidget (self .deps_list )
324+ deps_group .setLayout (deps_layout )
325+ split_layout .addWidget (deps_group )
326+
327+ layout .addLayout (split_layout )
313328
314329 # Info label
315- self .installed_info_label = QLabel ("Click 'Refresh List' to load installed packages " )
330+ self .installed_info_label = QLabel ("Click 'Refresh List' to load applications and dependencies " )
316331 layout .addWidget (self .installed_info_label )
317332
318333 self .tabs .addTab (installed_widget , "Installed Packages" )
@@ -744,39 +759,119 @@ def remove_selected_package(self):
744759
745760 def refresh_installed_packages (self ):
746761 """Refresh the list of installed packages."""
747- self .installed_list .clear ()
762+ self .apps_list .clear ()
763+ self .deps_list .clear ()
748764 self .installed_info_label .setText ("Loading installed packages..." )
749-
765+
750766 try :
751- # Get installed packages based on distro
767+ apps = set ()
768+ deps = set ()
769+
770+ # Get installed package split based on distro
752771 if self .distro_family == 'arch' :
753- result = subprocess .run (['paru' , '-Q' ], capture_output = True , text = True , timeout = 30 )
772+ apps_result = subprocess .run (['paru' , '-Qe' ], capture_output = True , text = True , timeout = 30 )
773+ deps_result = subprocess .run (['paru' , '-Qd' ], capture_output = True , text = True , timeout = 30 )
774+
775+ if apps_result .returncode == 0 :
776+ for line in apps_result .stdout .split ('\n ' ):
777+ parts = line .split ()
778+ if parts :
779+ apps .add (parts [0 ])
780+
781+ if deps_result .returncode == 0 :
782+ for line in deps_result .stdout .split ('\n ' ):
783+ parts = line .split ()
784+ if parts :
785+ deps .add (parts [0 ])
786+
754787 elif self .distro_family == 'debian' :
755- result = subprocess .run (['dpkg' , '-l' ], capture_output = True , text = True , timeout = 30 )
788+ apps_result = subprocess .run (['apt-mark' , 'showmanual' ], capture_output = True , text = True , timeout = 30 )
789+ deps_result = subprocess .run (['apt-mark' , 'showauto' ], capture_output = True , text = True , timeout = 30 )
790+
791+ if apps_result .returncode == 0 :
792+ for line in apps_result .stdout .split ('\n ' ):
793+ pkg = line .strip ()
794+ if pkg :
795+ apps .add (pkg )
796+
797+ if deps_result .returncode == 0 :
798+ for line in deps_result .stdout .split ('\n ' ):
799+ pkg = line .strip ()
800+ if pkg :
801+ deps .add (pkg )
802+
756803 elif self .distro_family == 'fedora' :
757- result = subprocess .run (['dnf' , 'list' , 'installed' ], capture_output = True , text = True , timeout = 30 )
804+ user_result = subprocess .run (
805+ ['dnf' , 'repoquery' , '--userinstalled' , '--qf' , '%{name}' ],
806+ capture_output = True ,
807+ text = True ,
808+ timeout = 30
809+ )
810+ all_result = subprocess .run (
811+ ['dnf' , 'repoquery' , '--installed' , '--qf' , '%{name}' ],
812+ capture_output = True ,
813+ text = True ,
814+ timeout = 30
815+ )
816+
817+ if user_result .returncode == 0 :
818+ for line in user_result .stdout .split ('\n ' ):
819+ pkg = line .strip ()
820+ if pkg :
821+ apps .add (pkg )
822+
823+ if all_result .returncode == 0 :
824+ all_pkgs = set ()
825+ for line in all_result .stdout .split ('\n ' ):
826+ pkg = line .strip ()
827+ if pkg :
828+ all_pkgs .add (pkg )
829+ deps = all_pkgs - apps
830+
758831 elif self .distro_family == 'suse' :
759- result = subprocess .run (['zypper' , 'se' , '--installed-only' ], capture_output = True , text = True , timeout = 30 )
832+ user_result = subprocess .run (
833+ ['zypper' , '--quiet' , 'pa' , '--userinstalled' ],
834+ capture_output = True ,
835+ text = True ,
836+ timeout = 30
837+ )
838+ all_result = subprocess .run (['rpm' , '-qa' ], capture_output = True , text = True , timeout = 30 )
839+
840+ if user_result .returncode == 0 :
841+ for line in user_result .stdout .split ('\n ' ):
842+ line = line .strip ()
843+ if line and '|' in line :
844+ parts = [part .strip () for part in line .split ('|' )]
845+ if len (parts ) >= 3 and parts [0 ] in {'i' , 'i+' }:
846+ name = parts [2 ]
847+ if name and name != 'Name' :
848+ apps .add (name )
849+
850+ if all_result .returncode == 0 :
851+ all_pkgs = set (pkg .strip () for pkg in all_result .stdout .split ('\n ' ) if pkg .strip ())
852+ deps = all_pkgs - apps
853+
760854 else :
761855 self .installed_info_label .setText ("Package listing not supported for this distribution" )
762856 return
763-
764- if result .returncode == 0 :
765- lines = result .stdout .split ('\n ' )
766- package_count = 0
767-
768- for line in lines :
769- if line .strip ():
770- parts = line .split ()
771- if parts :
772- pkg_name = parts [0 ]
773- self .installed_list .addItem (pkg_name )
774- package_count += 1
775-
776- self .installed_info_label .setText (f"Total installed packages: { package_count } " )
777- else :
778- self .installed_info_label .setText ("Failed to load installed packages" )
779-
857+
858+ # Remove overlap defensively
859+ deps = deps - apps
860+
861+ for pkg in sorted (apps ):
862+ self .apps_list .addItem (pkg )
863+
864+ for pkg in sorted (deps ):
865+ self .deps_list .addItem (pkg )
866+
867+ total_count = len (apps ) + len (deps )
868+ self .installed_info_label .setText (
869+ f"Applications: { len (apps )} | Dependencies: { len (deps )} | Total: { total_count } "
870+ )
871+
872+ if total_count == 0 :
873+ self .installed_info_label .setText ("No installed packages found or package manager query failed" )
874+
780875 except Exception as e :
781876 self .installed_info_label .setText (f"Error: { str (e )} " )
782877
0 commit comments