@@ -310,9 +310,15 @@ contains |
| 310 | 310 | type(tree_node), pointer, intent(inout) :: tree_root |
| 311 | 311 | type(selectable_item), allocatable :: temp_items(:) |
| 312 | 312 | integer :: i, max_items |
| 313 | + character(len=512), allocatable :: collapsed_paths(:) |
| 314 | + integer :: n_collapsed, max_collapsed |
| 313 | 315 | |
| 314 | | - ! Free old tree if it exists |
| 316 | + ! Save collapsed state from old tree if it exists |
| 317 | + n_collapsed = 0 |
| 318 | + max_collapsed = 100 |
| 319 | + allocate(collapsed_paths(max_collapsed)) |
| 315 | 320 | if (associated(tree_root)) then |
| 321 | + call collect_collapsed_paths(tree_root, '', collapsed_paths, n_collapsed, max_collapsed) |
| 316 | 322 | call free_tree(tree_root) |
| 317 | 323 | end if |
| 318 | 324 | |
@@ -334,6 +340,12 @@ contains |
| 334 | 340 | |
| 335 | 341 | call sort_tree(tree_root) |
| 336 | 342 | |
| 343 | + ! Restore collapsed state to new tree |
| 344 | + if (n_collapsed > 0) then |
| 345 | + call restore_collapsed_state(tree_root, '', collapsed_paths, n_collapsed) |
| 346 | + end if |
| 347 | + deallocate(collapsed_paths) |
| 348 | + |
| 337 | 349 | ! Collect items from tree in traversal order |
| 338 | 350 | max_items = 1000 |
| 339 | 351 | allocate(temp_items(max_items)) |
@@ -371,6 +383,89 @@ contains |
| 371 | 383 | deallocate(temp_items) |
| 372 | 384 | end subroutine rebuild_item_list_from_tree |
| 373 | 385 | |
| 386 | + recursive subroutine collect_collapsed_paths(node, parent_path, collapsed_paths, n_collapsed, max_collapsed) |
| 387 | + type(tree_node), pointer, intent(in) :: node |
| 388 | + character(len=*), intent(in) :: parent_path |
| 389 | + character(len=512), allocatable, intent(inout) :: collapsed_paths(:) |
| 390 | + integer, intent(inout) :: n_collapsed, max_collapsed |
| 391 | + type(tree_node), pointer :: child |
| 392 | + character(len=512) :: full_path |
| 393 | + |
| 394 | + ! Build full path for this node |
| 395 | + if (len_trim(parent_path) == 0) then |
| 396 | + full_path = trim(node%name) |
| 397 | + else |
| 398 | + full_path = trim(parent_path) // '/' // trim(node%name) |
| 399 | + end if |
| 400 | + |
| 401 | + ! If this is a collapsed directory, save its path |
| 402 | + if (.not. node%is_file .and. .not. node%is_expanded) then |
| 403 | + n_collapsed = n_collapsed + 1 |
| 404 | + if (n_collapsed > max_collapsed) then |
| 405 | + ! Resize array |
| 406 | + call resize_path_array(collapsed_paths, max_collapsed) |
| 407 | + end if |
| 408 | + collapsed_paths(n_collapsed) = trim(full_path) |
| 409 | + end if |
| 410 | + |
| 411 | + ! Recursively check children |
| 412 | + child => node%first_child |
| 413 | + do while (associated(child)) |
| 414 | + call collect_collapsed_paths(child, full_path, collapsed_paths, n_collapsed, max_collapsed) |
| 415 | + child => child%next_sibling |
| 416 | + end do |
| 417 | + end subroutine collect_collapsed_paths |
| 418 | + |
| 419 | + subroutine resize_path_array(paths, max_size) |
| 420 | + character(len=512), allocatable, intent(inout) :: paths(:) |
| 421 | + integer, intent(inout) :: max_size |
| 422 | + character(len=512), allocatable :: temp_paths(:) |
| 423 | + integer :: old_size |
| 424 | + |
| 425 | + old_size = max_size |
| 426 | + allocate(temp_paths(old_size)) |
| 427 | + temp_paths = paths(1:old_size) |
| 428 | + deallocate(paths) |
| 429 | + max_size = max_size * 2 |
| 430 | + allocate(paths(max_size)) |
| 431 | + paths(1:old_size) = temp_paths |
| 432 | + deallocate(temp_paths) |
| 433 | + end subroutine resize_path_array |
| 434 | + |
| 435 | + recursive subroutine restore_collapsed_state(node, parent_path, collapsed_paths, n_collapsed) |
| 436 | + type(tree_node), pointer, intent(inout) :: node |
| 437 | + character(len=*), intent(in) :: parent_path |
| 438 | + character(len=512), intent(in) :: collapsed_paths(:) |
| 439 | + integer, intent(in) :: n_collapsed |
| 440 | + type(tree_node), pointer :: child |
| 441 | + character(len=512) :: full_path |
| 442 | + integer :: i |
| 443 | + |
| 444 | + ! Build full path for this node |
| 445 | + if (len_trim(parent_path) == 0) then |
| 446 | + full_path = trim(node%name) |
| 447 | + else |
| 448 | + full_path = trim(parent_path) // '/' // trim(node%name) |
| 449 | + end if |
| 450 | + |
| 451 | + ! Check if this directory should be collapsed |
| 452 | + if (.not. node%is_file) then |
| 453 | + do i = 1, n_collapsed |
| 454 | + if (trim(collapsed_paths(i)) == trim(full_path)) then |
| 455 | + node%is_expanded = .false. |
| 456 | + exit |
| 457 | + end if |
| 458 | + end do |
| 459 | + end if |
| 460 | + |
| 461 | + ! Recursively restore for children |
| 462 | + child => node%first_child |
| 463 | + do while (associated(child)) |
| 464 | + call restore_collapsed_state(child, full_path, collapsed_paths, n_collapsed) |
| 465 | + child => child%next_sibling |
| 466 | + end do |
| 467 | + end subroutine restore_collapsed_state |
| 468 | + |
| 374 | 469 | recursive subroutine collect_items_from_tree(node, parent_path, items, n_items, max_items) |
| 375 | 470 | type(tree_node), pointer, intent(in) :: node |
| 376 | 471 | character(len=*), intent(in) :: parent_path |