@@ -310,10 +310,10 @@ contains |
| 310 | 310 | call gtk_box_append(toolbar, copy_path_btn) |
| 311 | 311 | copy_path_btn_ptr = copy_path_btn ! Store for enabling/disabling |
| 312 | 312 | |
| 313 | | - ! Create Properties/Info button |
| 313 | + ! Create Properties/Info button (opens macOS Get Info window) |
| 314 | 314 | info_btn = gtk_button_new() |
| 315 | | - call gtk_button_set_icon_name(info_btn, "document-properties"//c_null_char) |
| 316 | | - call gtk_widget_set_tooltip_text(info_btn, "Show Properties/Info"//c_null_char) |
| 315 | + call gtk_button_set_icon_name(info_btn, "dialog-information"//c_null_char) |
| 316 | + call gtk_widget_set_tooltip_text(info_btn, "Show in Finder Info"//c_null_char) |
| 317 | 317 | call g_signal_connect(info_btn, "clicked"//c_null_char, & |
| 318 | 318 | c_funloc(on_info_clicked), c_null_ptr) |
| 319 | 319 | call gtk_box_append(toolbar, info_btn) |
@@ -590,15 +590,13 @@ contains |
| 590 | 590 | print *, "Path copied successfully!" |
| 591 | 591 | end subroutine on_copy_path_clicked |
| 592 | 592 | |
| 593 | | - ! Callback when Properties/Info button is clicked |
| 594 | | - subroutine on_info_clicked(button, user_data) bind(c) |
| 593 | + ! Helper: Build selection info string for status bar |
| 594 | + function build_selection_info() result(info_text) |
| 595 | 595 | use iso_fortran_env, only: int64 |
| 596 | 596 | use treemap_renderer, only: get_current_view_node |
| 597 | 597 | use treemap_widget, only: get_selected_index |
| 598 | 598 | use types, only: file_node |
| 599 | 599 | use file_system, only: list_directory |
| 600 | | - type(c_ptr), value :: button, user_data |
| 601 | | - character(len=:), allocatable :: info_msg |
| 602 | 600 | character(len=1024) :: info_text |
| 603 | 601 | character(len=20) :: size_str |
| 604 | 602 | type(file_node), pointer :: view_node |
@@ -606,11 +604,7 @@ contains |
| 606 | 604 | integer :: item_count, selected_idx |
| 607 | 605 | character(len=256), dimension(10000) :: entries |
| 608 | 606 | |
| 609 | | - ! Check if there's a selection |
| 610 | | - if (.not. has_selection()) then |
| 611 | | - call sniffly_show_error("No selection to show properties for") |
| 612 | | - return |
| 613 | | - end if |
| 607 | + info_text = "" |
| 614 | 608 | |
| 615 | 609 | ! Get the selected node |
| 616 | 610 | view_node => get_current_view_node() |
@@ -618,23 +612,21 @@ contains |
| 618 | 612 | return |
| 619 | 613 | end if |
| 620 | 614 | |
| 621 | | - ! Get the selected child index (1-based: 1 = first child, 2 = second child, etc.) |
| 615 | + ! Get the selected child index (1-based) |
| 622 | 616 | selected_idx = get_selected_index() |
| 623 | 617 | if (selected_idx < 1 .or. selected_idx > view_node%num_children) then |
| 624 | | - call sniffly_show_error("Invalid selection") |
| 625 | 618 | return |
| 626 | 619 | end if |
| 627 | 620 | |
| 628 | | - ! Get details from selected child (selected_idx is already 1-based) |
| 621 | + ! Get details from selected child |
| 629 | 622 | size_bytes = view_node%children(selected_idx)%size |
| 630 | 623 | |
| 631 | 624 | ! Check if this is a grouped "[N small files]" node |
| 632 | 625 | if (index(view_node%children(selected_idx)%name, '[') == 1 .and. & |
| 633 | 626 | index(view_node%children(selected_idx)%name, 'small files]') > 0) then |
| 634 | | - ! This is a grouped small files node - don't count items (name already has the count) |
| 635 | 627 | item_count = -1 ! Special marker for grouped nodes |
| 636 | 628 | else if (view_node%children(selected_idx)%is_directory) then |
| 637 | | - ! For regular directories, count entries on-demand to get accurate item count |
| 629 | + ! For regular directories, count entries on-demand |
| 638 | 630 | item_count = list_directory(view_node%children(selected_idx)%path, entries, 10000) |
| 639 | 631 | else |
| 640 | 632 | item_count = 0 ! Files don't have children |
@@ -651,7 +643,7 @@ contains |
| 651 | 643 | write(size_str, '(F0.2,A)') real(size_bytes)/(1024.0**3), ' GB' |
| 652 | 644 | end if |
| 653 | 645 | |
| 654 | | - ! Build info text for status bar |
| 646 | + ! Build info text |
| 655 | 647 | if (item_count == -1) then |
| 656 | 648 | ! Grouped small files - name already contains the count |
| 657 | 649 | write(info_text, '(A,A,A)') & |
@@ -665,10 +657,48 @@ contains |
| 665 | 657 | write(info_text, '(A,A,A,A)') & |
| 666 | 658 | trim(view_node%children(selected_idx)%name), ' | ', trim(size_str), ' | File' |
| 667 | 659 | end if |
| 660 | + end function build_selection_info |
| 661 | + |
| 662 | + ! Callback when Properties/Info button is clicked - opens macOS Get Info window |
| 663 | + subroutine on_info_clicked(button, user_data) bind(c) |
| 664 | + type(c_ptr), value :: button, user_data |
| 665 | + character(len=512) :: selected_path |
| 666 | + character(len=1024) :: applescript_cmd |
| 667 | + integer :: exit_status |
| 668 | + |
| 669 | + print *, "Info button clicked - opening macOS Get Info window" |
| 670 | + |
| 671 | + ! Check if there's a selection |
| 672 | + if (.not. has_selection()) then |
| 673 | + call sniffly_show_error("No selection to show info for") |
| 674 | + return |
| 675 | + end if |
| 668 | 676 | |
| 669 | | - ! Show properties in status bar |
| 670 | | - info_msg = trim(info_text) |
| 671 | | - call sniffly_update_status(info_msg) |
| 677 | + ! Get the selected node path |
| 678 | + selected_path = get_selected_node_path() |
| 679 | + if (len_trim(selected_path) == 0) then |
| 680 | + print *, "Invalid selection path" |
| 681 | + call sniffly_show_error("Invalid selection") |
| 682 | + return |
| 683 | + end if |
| 684 | + |
| 685 | + print *, "Opening Get Info for: ", trim(selected_path) |
| 686 | + |
| 687 | + ! Build AppleScript command to open Get Info window |
| 688 | + ! We escape single quotes in the path by replacing ' with '\'' |
| 689 | + write(applescript_cmd, '(A,A,A)') & |
| 690 | + 'osascript -e ''tell application "Finder" to open information window of (POSIX file "', & |
| 691 | + trim(selected_path), '" as alias)''' |
| 692 | + |
| 693 | + ! Execute the command |
| 694 | + call execute_command_line(trim(applescript_cmd), exitstat=exit_status) |
| 695 | + |
| 696 | + if (exit_status /= 0) then |
| 697 | + print *, "ERROR: Failed to open Get Info window (exit status:", exit_status, ")" |
| 698 | + call sniffly_show_error("Failed to open Get Info window") |
| 699 | + else |
| 700 | + print *, "Successfully opened Get Info window" |
| 701 | + end if |
| 672 | 702 | end subroutine on_info_clicked |
| 673 | 703 | |
| 674 | 704 | ! Helper: Update Back/Forward button states |
@@ -730,10 +760,11 @@ contains |
| 730 | 760 | end if |
| 731 | 761 | end subroutine update_cancel_scan_button_state |
| 732 | 762 | |
| 733 | | - ! Helper: Update selection-dependent button states |
| 763 | + ! Helper: Update selection-dependent button states and display selection info |
| 734 | 764 | subroutine update_selection_buttons() |
| 735 | 765 | use gtk, only: gtk_widget_set_sensitive |
| 736 | 766 | logical :: has_sel |
| 767 | + character(len=1024) :: sel_info |
| 737 | 768 | |
| 738 | 769 | ! Guard against accessing widgets during shutdown |
| 739 | 770 | if (app_is_shutting_down) return |
@@ -750,11 +781,20 @@ contains |
| 750 | 781 | call gtk_widget_set_sensitive(info_btn_ptr, 1_c_int) |
| 751 | 782 | call gtk_widget_set_sensitive(copy_path_btn_ptr, 1_c_int) |
| 752 | 783 | call gtk_widget_set_sensitive(delete_btn_ptr, 1_c_int) |
| 784 | + |
| 785 | + ! Auto-display selection info in status bar |
| 786 | + sel_info = build_selection_info() |
| 787 | + if (len_trim(sel_info) > 0) then |
| 788 | + call sniffly_update_status(trim(sel_info)) |
| 789 | + end if |
| 753 | 790 | else |
| 754 | 791 | print *, "DEBUG: Disabling selection-dependent buttons" |
| 755 | 792 | call gtk_widget_set_sensitive(info_btn_ptr, 0_c_int) |
| 756 | 793 | call gtk_widget_set_sensitive(copy_path_btn_ptr, 0_c_int) |
| 757 | 794 | call gtk_widget_set_sensitive(delete_btn_ptr, 0_c_int) |
| 795 | + |
| 796 | + ! Clear selection info from status bar when deselected |
| 797 | + call sniffly_update_status("") |
| 758 | 798 | end if |
| 759 | 799 | |
| 760 | 800 | ! Open in Finder button is always enabled (defaults to current directory) |