Skip to content

Commit

Permalink
Add Root URL, Add Group: Make names for Root URLs and Groups be optional
Browse files Browse the repository at this point in the history
Resolves #37
  • Loading branch information
davidfstr committed Dec 25, 2023
1 parent b5c9843 commit 8f326fe
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 27 deletions.
7 changes: 7 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ Release Notes ⋮
[high-priority issues]: https://github.com/davidfstr/Crystal-Web-Archiver/issues?q=is%3Aopen+is%3Aissue+label%3Apriority-high
[medium-priority issues]: https://github.com/davidfstr/Crystal-Web-Archiver/issues?q=is%3Aopen+is%3Aissue+label%3Apriority-medium

### main (v2.0.0?)

* First-time-run experience improvements
* Add Root URL, Add Group:
* Make it optional to provide a name for new Root URLs and Groups.
* Rearrange fields to deemphasize the Name field.

### v1.7.0b (December 18, 2023)

This release features further improvements to downloading large websites
Expand Down
4 changes: 2 additions & 2 deletions src/crystal/browser/addgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ def _create_fields(self,
name='cr-add-group-dialog__source-field')
self.source_choice_box.Append('none', None)
for rr in self._project.root_resources:
self.source_choice_box.Append(rr.name, rr)
self.source_choice_box.Append(rr.display_name, rr)
for rg in self._project.resource_groups:
self.source_choice_box.Append(rg.name, rg)
self.source_choice_box.Append(rg.display_name, rg)
self.source_choice_box.SetSelection(0)
if initial_source is not None:
for i in range(self.source_choice_box.GetCount()):
Expand Down
2 changes: 1 addition & 1 deletion src/crystal/browser/addrooturl.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def _create_fields(self, parent: wx.Window, initial_url: str) -> wx.Sizer:
self.name_field = wx.TextCtrl(
parent,
name='cr-add-url-dialog__name-field')
self.url_field.Hint = 'Home'
self.name_field.Hint = 'Home'
self.name_field.SetSelection(-1, -1) # select all upon focus
fields_sizer.Add(self.name_field, flag=wx.EXPAND)

Expand Down
31 changes: 21 additions & 10 deletions src/crystal/browser/entitytree.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,9 +709,11 @@ def _entity_tooltip(self) -> str:

def calculate_title(self):
project = self.root_resource.project
return '%s - %s' % (
project.get_display_url(self.root_resource.url),
self.root_resource.name)
display_url = project.get_display_url(self.root_resource.url)
if self.root_resource.name != '':
return '%s - %s' % (display_url, self.root_resource.name)
else:
return '%s' % (display_url,)

@property
def entity(self):
Expand Down Expand Up @@ -846,9 +848,11 @@ def icon_tooltip(self) -> Optional[str]:

def calculate_title(self):
project = self.resource_group.project
return '%s - %s' % (
project.get_display_url(self.resource_group.url_pattern),
self.resource_group.name)
display_url = project.get_display_url(self.resource_group.url_pattern)
if self.resource_group.name != '':
return '%s - %s' % (display_url, self.resource_group.name)
else:
return '%s' % (display_url,)

@property
def entity(self):
Expand Down Expand Up @@ -970,10 +974,17 @@ def icon_tooltip(self) -> Optional[str]:

def calculate_title(self):
project = self.resource_group.project
return '%s - %d of %s' % (
project.get_display_url(self.resource_group.url_pattern),
len(self.children),
self.resource_group.name)
display_url_pattern = project.get_display_url(self.resource_group.url_pattern)
if self.resource_group.name != '':
return '%s - %d of %s' % (
display_url_pattern,
len(self.children),
self.resource_group.name)
else:
return '%s - %d link%s' % (
display_url_pattern,
len(self.children),
'' if len(self.children) == 1 else 's')

@property
def entity(self):
Expand Down
43 changes: 39 additions & 4 deletions src/crystal/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1792,7 +1792,7 @@ def definitely_has_no_revisions(self) -> bool:
"""
return self._definitely_has_no_revisions

# === Download ===
# === Operations: Download ===

def download_body(self) -> 'Future[ResourceRevision]':
"""
Expand Down Expand Up @@ -2104,13 +2104,15 @@ class RootResource:
resource: Resource
_id: int # or None if deleted

# === Init ===

def __new__(cls, project: Project, name: str, resource: Resource, _id: Optional[int]=None) -> RootResource:
"""
Creates a new root resource.
Arguments:
* project -- associated `Project`.
* name -- display name.
* name -- name. Possibly ''.
* resource -- `Resource`.
Raises:
Expand Down Expand Up @@ -2148,6 +2150,8 @@ def __new__(cls, project: Project, name: str, resource: Resource, _id: Optional[

return self

# === Delete ===

def delete(self) -> None:
"""
Deletes this root resource.
Expand All @@ -2166,10 +2170,19 @@ def delete(self) -> None:

del self.project._root_resources[self.resource]

# === Properties ===

@property
def display_name(self) -> str:
"""Name of this root resource that is used in the UI."""
return self.name or self.url

@property
def url(self) -> str:
return self.resource.url

# === Operations: Download ===

# TODO: Create the underlying task with the full RootResource
# so that the correct subtitle is displayed.
def download(self, *, needs_result: bool=True) -> Future[ResourceRevision]:
Expand All @@ -2185,6 +2198,8 @@ def create_download_task(self, *, needs_result: bool=True) -> Task:
# so that the correct subtitle is displayed.
return self.resource.create_download_task(needs_result=needs_result, is_embedded=False)

# === Utility ===

def __repr__(self):
return "RootResource(%s,%s)" % (repr(self.name), repr(self.resource.url))

Expand Down Expand Up @@ -3079,19 +3094,24 @@ class ResourceGroup(ListenableMixin):
Persisted and auto-saved.
"""

# === Init ===

def __init__(self,
project: Project,
name: str,
name: str, # possibly ''
url_pattern: str,
_id: Optional[int]=None) -> None:
"""
Arguments:
* project -- associated `Project`.
* name -- name of this group.
* name -- name of this group. Possibly ''.
* url_pattern -- url pattern matched by this group.
"""
super().__init__()

if len(url_pattern) == 0:
raise ValueError('Cannot create group with empty pattern')

self.project = project
self.name = name
self.url_pattern = url_pattern
Expand All @@ -3118,6 +3138,8 @@ def __init__(self,
def _init_source(self, source: ResourceGroupSource) -> None:
self._source = source

# === Delete ===

def delete(self) -> None:
"""
Deletes this resource group.
Expand All @@ -3136,6 +3158,13 @@ def delete(self) -> None:

self.project._resource_groups.remove(self)

# === Properties ===

@property
def display_name(self) -> str:
"""Name of this group that is used in the UI."""
return self.name or self.url_pattern

def _get_source(self) -> ResourceGroupSource:
"""
The "source" of this resource group.
Expand Down Expand Up @@ -3234,6 +3263,8 @@ def members(self) -> 'Sequence[Resource]':
literal_prefix=ResourceGroup.literal_prefix_for_url_pattern(self.url_pattern))
return self._members

# === Events ===

# Called when a new Resource is created after the project has loaded
def _resource_did_instantiate(self, resource: Resource) -> None:
if self.contains_url(resource.url):
Expand All @@ -3260,6 +3291,8 @@ def _resource_will_delete(self, resource: Resource) -> None:
except ValueError: # not in list
pass

# === Operations: Download ===

def download(self, *, needs_result: bool=False) -> DownloadResourceGroupTask:
"""
Downloads this group asynchronously.
Expand Down Expand Up @@ -3303,6 +3336,8 @@ def update_membership(self) -> None:
from crystal.task import UpdateResourceGroupMembersTask
task = UpdateResourceGroupMembersTask(self)
self.project.add_task(task)

# === Utility ===

def __repr__(self):
return 'ResourceGroup(%s,%s)' % (repr(self.name), repr(self.url_pattern))
Expand Down
6 changes: 3 additions & 3 deletions src/crystal/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ def _do_GET(self) -> Generator[SwitchToThread, None, None]:
matching_rg = self._find_group_matching_archive_url(archive_url)
if matching_rg is not None and not readonly and dynamic_ok:
self._print_warning('*** Dynamically downloading new resource in group %r: %s' % (
matching_rg.name,
matching_rg.display_name,
archive_url,
))

Expand Down Expand Up @@ -453,7 +453,7 @@ def get_default_revision() -> Optional[ResourceRevision]:
matching_rr = self._find_root_resource_matching_archive_url(archive_url)
if matching_rr is not None:
self._print_warning('*** Dynamically downloading root resource %r: %s' % (
matching_rr.name,
matching_rr.display_name,
archive_url,
))

Expand All @@ -463,7 +463,7 @@ def get_default_revision() -> Optional[ResourceRevision]:
matching_rg = self._find_group_matching_archive_url(archive_url)
if matching_rg is not None:
self._print_warning('*** Dynamically downloading existing resource in group %r: %s' % (
matching_rg.name,
matching_rg.display_name,
archive_url,
))

Expand Down
19 changes: 12 additions & 7 deletions src/crystal/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,14 +586,15 @@ class TaskDisposedException(Exception):
_MAX_EMBEDDED_RESOURCE_RECURSION_DEPTH = 3


def _get_abstract_resource_title(abstract_resource):
def _get_abstract_resource_title(abstract_resource: Union[Resource, RootResource]) -> str:
"""
Arguments:
* abstract_resource -- a Resource or a RootResource.
"""
resource = abstract_resource.resource
if hasattr(abstract_resource, 'name'):
return '%s - %s' % (resource.url, abstract_resource.name)
name = getattr(abstract_resource, 'name', '') or ''
if name != '':
return '%s - %s' % (resource.url, name)
else:
return '%s' % (resource.url)

Expand Down Expand Up @@ -731,7 +732,11 @@ class DownloadResourceTask(Task):
'_download_body_with_embedded_future',
)

def __init__(self, abstract_resource, *, needs_result: bool=True, is_embedded: bool=False) -> None:
def __init__(self,
abstract_resource: Union[Resource, RootResource],
*, needs_result: bool=True,
is_embedded: bool=False,
) -> None:
"""
Arguments:
* abstract_resource -- a Resource or a RootResource.
Expand Down Expand Up @@ -1189,7 +1194,7 @@ class UpdateResourceGroupMembersTask(Task):

def __init__(self, group: ResourceGroup) -> None:
super().__init__(
title='Finding members of group: %s' % group.name)
title='Finding members of group: %s' % group.display_name)
self.group = group

if group.source is None:
Expand Down Expand Up @@ -1233,7 +1238,7 @@ class DownloadResourceGroupMembersTask(Task):

def __init__(self, group: ResourceGroup) -> None:
super().__init__(
title='Downloading members of group: %s' % group.name)
title='Downloading members of group: %s' % group.display_name)
self.group = group

if self._use_extra_listener_assertions:
Expand Down Expand Up @@ -1377,7 +1382,7 @@ class DownloadResourceGroupTask(Task):

def __init__(self, group: ResourceGroup) -> None:
super().__init__(
title='Downloading group: %s' % group.name)
title='Downloading group: %s' % group.display_name)
self._update_members_task = UpdateResourceGroupMembersTask(group)
self._download_members_task = DownloadResourceGroupMembersTask(group)
self._started_downloading_members = False
Expand Down
Loading

0 comments on commit 8f326fe

Please sign in to comment.