| dotReader documentation | Contained in the dotReader distribution. |
dtRdr::GUI::Wx::BVManager - a container of sorts
This widget acts as a container for multiple book views and holding/finding various in-memory data.
Wx::Panel
Creates a frame.
$bv = dtRdr::GUI::Wx::BVManager->new($parent, @blahblahblah);
$bvm->init($frame);
$bvm->show_welcome;
$bvm->enable('_profile');
$bvm->disable('_profile');
The multi-view needs to be finished, at which point more of this will make more sense.
This API is probably stable, but the behavior will definitely change. Currently, this just loads directly in the widget unless there is a book open.
$self->load_url($url);
Opens the book object as the primary view.
$bvm->open_book($book);
$self->_annotation_created($anno);
$self->_annotation_changed($anno);
$self->_annotation_deleted($anno);
Open the note editor for a newly created note. Requires an existing note object which is not yet in the book.
$bvm->create_note($note, %args);
Edit an existing note.
$bv->edit_note($note);
$bvm->show_note($note);
This part is in flux.
my @views = $bvm->find_book_views($book);
my @views = $bvm->find_note_views($note);
Eric Wilhelm <ewilhelm at cpan dot org>
http://scratchcomputing.com/
Copyright (C) 2006 Eric L. Wilhelm and OSoft, All Rights Reserved.
Absolutely, positively NO WARRANTY, neither express or implied, is offered with this software. You use this software at your own risk. In case of loss, no person or entity owes you anything whatsoever. You have been warned.
The dotReader(TM) is OSI Certified Open Source Software licensed under the GNU General Public License (GPL) Version 2, June 1991. Non-encrypted and encrypted packages are usable in connection with the dotReader(TM). The ability to create, edit, or otherwise modify content of such encrypted packages is self-contained within the packages, and NOT provided by the dotReader(TM), and is addressed in a separate commercial license.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
| dotReader documentation | Contained in the dotReader distribution. |
package dtRdr::GUI::Wx::BVManager; $VERSION = eval{require version}?version::qv($_):$_ for(0.10.1); use warnings; use strict; use dtRdr; use dtRdr::Book; use dtRdr::HTMLWidget; use dtRdr::GUI; use dtRdr::GUI::Wx::BookView; use dtRdr::Annotation::IO; use Wx qw( wxHORIZONTAL wxVERTICAL wxEXPAND wxHW_NO_SELECTION wxDefaultSize wxDefaultPosition ); use base 'Wx::Panel'; use Class::Accessor::Classy; ro qw( main_frame book_view sidebar htmlwidget anno_io note_viewer bookbag ); ro 'in_open'; no Class::Accessor::Classy; use dtRdr::Logger; use dtRdr::BookBag;
sub new { my $class = shift; my ($parent, @args) = @_; my $self = $class->SUPER::new($parent, @args); bless($self, $class); return($self); } # end subroutine new definition ########################################################################
sub init { my $self = shift; my ($frame) = @_; $self->{main_frame} = $frame; $self->{sidebar} = $frame->sidebar; $self->{note_viewer} = $frame->note_viewer; $self->{bookbag} = dtRdr::BookBag->new; my $widget = dtRdr::HTMLWidget->new([$self, -1]); $self->{htmlwidget} = $widget; $widget->init($self, url_handler => $self); $self->show_welcome; if($widget->can('meddle')) {$widget->meddle();} if(0) { warn "\n\n"; warn "mainframe is ", $self->GetParent->GetParent, "\n"; warn "event handler: ", $widget->GetEventHandler, "\n"; warn "event handler: ", $self->GetEventHandler, "\n\n --"; } # we're a pane, so we make a sizer and set it on ourself my $sizer = $self->{sizer} = Wx::BoxSizer->new( wxHORIZONTAL #wxVERTICAL ); $sizer->Add($widget, 1, wxEXPAND, 0); $self->SetAutoLayout(1); $self->SetSizer($sizer); $sizer->SetSizeHints($self); # might need to enable this if you want to be able to flip to a # full-screen noteviewer #$self->SetMinSize(Wx::Size->new(-1, 0)); # setup the core_link callback dtRdr::Book->callback->set_core_link_sub(sub { use URI; my ($file) = @_; return( URI->new('file://' . dtRdr::GUI->find_icon($file))->as_string ); }); # setup the img_src_rewrite callback if($widget->can('img_src_rewrite_sub')) { dtRdr::Book->callback->set_img_src_rewrite_sub( $widget->img_src_rewrite_sub ); } # setup the sync callbacks # annotation_created, changed, deleted => _annotation_created ... foreach my $event (qw(created changed deleted)) { my $setter = 'set_annotation_' . $event . '_sub'; my $action = '_annotation_' . $event; dtRdr::Book->callback->$setter(sub {$self->$action(@_)}); } # get ourselves an annotation IO object my $anno_io = $self->{anno_io} = dtRdr::Annotation::IO->new(uri => dtRdr->user_dir . 'annotations/'); } # end subroutine init definition ########################################################################
sub show_welcome { my $self = shift; my $greeting = "this is " . ref($self->htmlwidget) . "<br>"; L->info("setting greeting"); if(0) { # playing with anchors $greeting .= qq(<p><a name="top">hi</a>) . qq( <a href="http://osoft.com/">osoft.com</a><br>) . qq( <a href="http://osoft.com/foo#bar">osoft.com/foo#bar</a><br>) . qq( <a href="http://osoft.com/foo.html#bar">osoft.com/foo.html#bar</a><br>) . qq( <a href="http://osoft.com/foo.html#bar">osoft.com/index.php#bar</a><br>) . qq( <a href="#foo">go to foo</a>) . qq( <a href="#bar">or bar</a>) . '<br>'x80 . "\n" . qq(<a name="foo">welcome to foo</a>) . qq( would you like to <a href="#bar">visit bar</a>) . qq( or go back to <a href="#top">the top</a>) . qq(</p>) . "\n". '<p>'.'<br>'x80 . "\n" . qq(<a name="bar">welcome to bar</a></p>) . qq( ... off to <a href="#foo">foo</a>) . qq( or go back to <a href="#top">the top</a>) . '<br>'x80 . ''; } elsif(0) { # more hackery if(defined($ENV{THOUT_HOME})) { $self->htmlwidget->LoadURL($ENV{THOUT_HOME}); } else { use dtRdr::Hack; $greeting .= dtRdr::Hack->get_widget_img(); $greeting = qq(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">). "<html><body>$greeting</body></html>"; $self->htmlwidget->SetPage($greeting); } } else { # TODO something nicer here $greeting = qq(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">). "<html><body>Welcome to DotReader!</body></html>"; $self->htmlwidget->SetPage($greeting); } } # end subroutine show_welcome definition ########################################################################
sub enable {$_[0]->{main_frame}->enable($_[1]);} sub disable {$_[0]->{main_frame}->disable($_[1]);}
sub load_url { my $self = shift; my ($url) = @_; if(my $bv = $self->book_view) { $bv->load_url($url); } else { $self->htmlwidget->load_url($url); } } # end subroutine load_url definition ######################################################################## #sub load_url { my $self = shift; $self->book_view->load_url(@_); }
sub open_book { my $self = shift; my ($book) = @_; # clear and reset a lot of stuff $self->main_frame->set_title($book->title); $self->note_viewer->no_note; # TODO clear search results? # TODO if we have a book_view, freeze it, etc $self->{book_view} and L->info("\n\nnot done\n\n"); # create and init the bookview my $bv = $self->{book_view} = dtRdr::GUI::Wx::BookView->new($book); $bv->init($self); my $sidebar = $self->sidebar; $bv->set_widgets( book_tree => $sidebar->contents, note_tree => $sidebar->notes, bookmark_tree => $sidebar->bookmarks, highlight_tree => $sidebar->highlights, htmlwidget => $self->htmlwidget ); # BOOKBAG {{{ my $bag = $self->bookbag; # TODO we need DESTROY on tab-close somewhere # for now, open one means close another $bag->delete($_) for($bag->list); # only apply if we don't have this book in the bookbag unless($bag->find($book->id)) { # disable the callbacks during the anno_io setup (or else the # callbacks would run before the populate() calls) local $self->{in_open} = 1; $self->anno_io->apply_to($book); } $bag->add($book); # BOOKBAG }}} { # populate the sidebar trees my @trees = qw( book note bookmark highlight ); foreach my $tree (@trees) { my $attrib = $tree . '_tree'; $bv->$attrib->populate($book); } } $bv->render_node_by_id($book->toc->id); $self->enable('_book'); $self->enable('_no_drm'); # XXX needs a conditional $self->disable('navigation_page_up'); $self->disable('file_add_book'); # default to disabled # sorry, we can't handle going back to a destroyed view object yet $self->disable('_history'); $self->sidebar->select_item('contents'); } # end subroutine open_book definition ########################################################################
sub _annotation_created { my $self = shift; my ($anno) = @_; $self->in_open and return; foreach my $bv ($self->find_book_views($anno->book)) { $bv->annotation_created($anno); } if($anno->ANNOTATION_TYPE eq 'note') { foreach my $nv ($self->find_note_views($anno)) { # rebuild thread $nv->show_note($anno); } } } # end subroutine _annotation_created definition ########################################################################
sub _annotation_changed { my $self = shift; my ($anno) = @_; $self->in_open and return; # SBs for title foreach my $bv ($self->find_book_views($anno->book)) { $bv->annotation_changed($anno); } if($anno->ANNOTATION_TYPE eq 'note') { # check NVs if $anno->references; foreach my $nv ($self->find_note_views($anno)) { $nv->render; } } } # end subroutine _annotation_changed definition ########################################################################
sub _annotation_deleted { my $self = shift; my ($anno) = @_; $self->in_open and return; foreach my $bv ($self->find_book_views($anno->book)) { $bv->annotation_deleted($anno); } if($anno->ANNOTATION_TYPE eq 'note') { # check NVs if $anno->references; foreach my $nv ($self->find_note_views($anno)) { # rebuild thread or maybe just go away $nv->note_deleted($anno); } } } # end subroutine _annotation_deleted definition ########################################################################
sub create_note { my $self = shift; my ($note, %args) = @_; use dtRdr::GUI::Wx::NoteEditor; my $editor = dtRdr::GUI::Wx::NoteEditor->new(); if($args{public}) { # TODO make that be an object? $editor->checkbox_public->SetValue(1); } # add the note and let the callbacks deal with the rest # -- user can then background this $note->book->add_note($note); my $saver = sub { $note->set_title($editor->text_ctrl_title->GetValue); $note->set_content($editor->text_ctrl_body->GetValue); # XXX icky if($editor->checkbox_public->IsChecked) { # TODO drop-down to pick server my ($server, @plus) = dtRdr->user->config->servers; @plus and die "ok, time to fix this bit"; $note->make_public( owner => undef, server => $server->id, ); } $note->book->change_note($note); }; $editor->set_saver($saver); # TODO # Q: what if they decide to come back and edit it again while that # editor is still open? # A: have a list of editor objects and just do $editor->Raise my $reverter = sub { $note->book->delete_note($note); }; $editor->set_reverter($reverter); $editor->set_fields( title => $note->title, body => $note->content, ); # TODO set_autosaver # defer the show until here because it messes with focus otherwise $editor->Show(1); } # end subroutine create_note definition ########################################################################
sub edit_note { my $self = shift; my ($note) = @_; if(my $pub = $note->public) { defined($pub->owner) and die "you do not own that note"; } use dtRdr::GUI::Wx::NoteEditor; if(0) { # TODO check for existing editor and raise if so WARN("edit_note() not done yet"); return; } # make a new one with a proper revert my $editor = dtRdr::GUI::Wx::NoteEditor->new(); $editor->set_fields( title => $note->title, body => $note->content, ); # XXX icky $editor->checkbox_public->SetValue(defined($note->public)); $editor->checkbox_public->Enable(0); my $book = $note->book; my $saver = sub { $note->set_title($editor->text_ctrl_title->GetValue); $note->set_content($editor->text_ctrl_body->GetValue); # TODO $note->inc_rev ? or do unchange_note below ? $note->book->change_note($note); }; $editor->set_saver($saver); # need to have a serialized note # (though this only matters if we have autosave enabled) my $snapshot = $note->clone; my $reverter = sub { WARN("revert not working yet"); # we have to write into the existing object %$note = %$snapshot; # XXX only need this when autosave is enabled # $note->book->change_note($note); }; $editor->set_reverter($reverter); # TODO autosaver # defer the show until here because it messes with focus otherwise $editor->Show(1); } # end subroutine edit_note definition ########################################################################
sub show_note { my $self = shift; my ($note) = @_; $self->note_viewer->show_note($note); } # end subroutine show_note definition ########################################################################
sub find_book_views { my $self = shift; my ($book) = @_; # TODO a bookbag, viewbag or something my @views = ($self->book_view); return(grep({$_->book == $book} @views)); } # end subroutine find_book_views definition ########################################################################
sub find_note_views { my $self = shift; my ($note) = @_; my @views = ($self->note_viewer); my $note_id = $note->id; my $root_id; if(my @refs = $note->references) { $root_id = $refs[-1]; } return( grep({ my $id = $_->thread_id; defined($id) and ( ($id eq $note_id) or (defined($root_id) and ($id eq $root_id)) ) } @views ) ); } # end subroutine find_note_views definition ########################################################################
# vi:ts=2:sw=2:et:sta 1;