2021-05-10 15:50:15 -03:00
/*
2022-03-05 21:30:55 -03:00
* Copyright ( c ) 2021 - 2022 , Matthew Olsson < mattco @ serenityos . org >
2021-09-13 17:48:22 -03:00
* Copyright ( c ) 2021 , Mustafa Quraish < mustafa @ serenityos . org >
2021-05-10 15:50:15 -03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "PDFViewerWidget.h"
# include <LibCore/File.h>
2021-09-02 09:22:13 -03:00
# include <LibFileSystemAccessClient/Client.h>
2021-05-10 15:50:15 -03:00
# include <LibGUI/Application.h>
# include <LibGUI/BoxLayout.h>
# include <LibGUI/FilePicker.h>
2021-05-24 02:34:44 -03:00
# include <LibGUI/Label.h>
2021-05-10 15:50:15 -03:00
# include <LibGUI/Menu.h>
# include <LibGUI/Menubar.h>
2021-05-24 18:23:08 -03:00
# include <LibGUI/MessageBox.h>
2021-05-24 01:34:06 -03:00
# include <LibGUI/Splitter.h>
2021-05-24 02:34:44 -03:00
# include <LibGUI/Toolbar.h>
# include <LibGUI/ToolbarContainer.h>
2021-05-10 15:50:15 -03:00
PDFViewerWidget : : PDFViewerWidget ( )
{
set_fill_with_background_color ( true ) ;
set_layout < GUI : : VerticalBoxLayout > ( ) ;
2022-03-29 01:19:45 -03:00
auto & toolbar_container = add < GUI : : ToolbarContainer > ( ) ;
auto & toolbar = toolbar_container . add < GUI : : Toolbar > ( ) ;
2021-05-24 02:34:44 -03:00
2021-05-24 01:34:06 -03:00
auto & splitter = add < GUI : : HorizontalSplitter > ( ) ;
2022-08-30 08:38:20 -03:00
splitter . layout ( ) - > set_spacing ( 4 ) ;
2021-05-10 15:50:15 -03:00
2021-05-24 01:34:06 -03:00
m_sidebar = splitter . add < SidebarWidget > ( ) ;
2022-08-30 08:38:20 -03:00
m_sidebar - > set_preferred_width ( 200 ) ;
m_sidebar - > set_visible ( false ) ;
2021-05-24 01:34:06 -03:00
m_viewer = splitter . add < PDFViewer > ( ) ;
2021-06-20 16:07:44 -03:00
m_viewer - > on_page_change = [ & ] ( auto new_page ) {
2022-03-31 22:01:07 -03:00
m_page_text_box - > set_current_number ( new_page + 1 , GUI : : AllowCallback : : No ) ;
2021-06-20 16:07:44 -03:00
} ;
2022-03-29 01:19:45 -03:00
initialize_toolbar ( toolbar ) ;
2021-05-10 15:50:15 -03:00
}
2021-07-21 16:21:03 -03:00
void PDFViewerWidget : : initialize_menubar ( GUI : : Window & window )
2021-05-10 15:50:15 -03:00
{
2021-07-21 16:21:03 -03:00
auto & file_menu = window . add_menu ( " &File " ) ;
2021-05-10 15:50:15 -03:00
file_menu . add_action ( GUI : : CommonActions : : make_open_action ( [ & ] ( auto & ) {
2022-01-16 22:47:11 -03:00
auto response = FileSystemAccessClient : : Client : : the ( ) . try_open_file ( & window ) ;
2022-03-29 01:19:45 -03:00
if ( ! response . is_error ( ) )
open_file ( * response . value ( ) ) ;
2021-05-10 15:50:15 -03:00
} ) ) ;
2021-05-27 14:09:37 -03:00
file_menu . add_separator ( ) ;
2021-05-10 15:50:15 -03:00
file_menu . add_action ( GUI : : CommonActions : : make_quit_action ( [ ] ( auto & ) {
GUI : : Application : : the ( ) - > quit ( ) ;
} ) ) ;
2021-05-27 14:10:34 -03:00
2021-12-27 09:41:01 -03:00
auto & view_menu = window . add_menu ( " &View " ) ;
view_menu . add_action ( * m_toggle_sidebar_action ) ;
2022-01-02 17:58:51 -03:00
view_menu . add_separator ( ) ;
2022-03-29 01:19:45 -03:00
auto & view_mode_menu = view_menu . add_submenu ( " View &Mode " ) ;
view_mode_menu . add_action ( * m_page_view_mode_single ) ;
view_mode_menu . add_action ( * m_page_view_mode_multiple ) ;
view_menu . add_separator ( ) ;
2022-01-02 17:58:51 -03:00
view_menu . add_action ( * m_zoom_in_action ) ;
view_menu . add_action ( * m_zoom_out_action ) ;
view_menu . add_action ( * m_reset_zoom_action ) ;
2021-12-27 09:41:01 -03:00
2021-07-21 16:21:03 -03:00
auto & help_menu = window . add_menu ( " &Help " ) ;
2022-07-11 14:32:29 -03:00
help_menu . add_action ( GUI : : CommonActions : : make_about_action ( " PDF Viewer " , GUI : : Icon : : default_icon ( " app-pdf-viewer " sv ) , & window ) ) ;
2021-05-24 02:34:44 -03:00
}
2021-05-24 01:34:06 -03:00
2022-03-29 01:19:45 -03:00
void PDFViewerWidget : : initialize_toolbar ( GUI : : Toolbar & toolbar )
2021-05-24 02:34:44 -03:00
{
auto open_outline_action = GUI : : Action : : create (
2022-07-11 14:32:29 -03:00
" Toggle &Sidebar " , { Mod_Ctrl , Key_S } , Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/sidebar.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) , [ & ] ( auto & ) {
2021-05-24 01:34:06 -03:00
m_sidebar_open = ! m_sidebar_open ;
2022-08-30 08:38:20 -03:00
m_sidebar - > set_visible ( m_sidebar_open ? true : false ) ;
2021-05-24 01:34:06 -03:00
} ,
nullptr ) ;
2021-05-24 02:34:44 -03:00
open_outline_action - > set_enabled ( false ) ;
m_toggle_sidebar_action = open_outline_action ;
toolbar . add_action ( * open_outline_action ) ;
toolbar . add_separator ( ) ;
2022-07-11 14:32:29 -03:00
m_go_to_prev_page_action = GUI : : Action : : create ( " Go to &Previous Page " , Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/go-up.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) , [ & ] ( auto & ) {
2021-05-27 14:47:44 -03:00
VERIFY ( m_viewer - > current_page ( ) > 0 ) ;
m_page_text_box - > set_current_number ( m_viewer - > current_page ( ) ) ;
2021-05-24 02:34:44 -03:00
} ) ;
m_go_to_prev_page_action - > set_enabled ( false ) ;
2021-05-24 01:34:06 -03:00
2022-07-11 14:32:29 -03:00
m_go_to_next_page_action = GUI : : Action : : create ( " Go to &Next Page " , Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/go-down.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) , [ & ] ( auto & ) {
2021-05-27 14:47:44 -03:00
VERIFY ( m_viewer - > current_page ( ) < m_viewer - > document ( ) - > get_page_count ( ) - 1 ) ;
m_page_text_box - > set_current_number ( m_viewer - > current_page ( ) + 2 ) ;
2021-05-24 02:34:44 -03:00
} ) ;
m_go_to_next_page_action - > set_enabled ( false ) ;
2021-05-24 01:34:06 -03:00
2021-05-24 02:34:44 -03:00
toolbar . add_action ( * m_go_to_prev_page_action ) ;
toolbar . add_action ( * m_go_to_next_page_action ) ;
m_page_text_box = toolbar . add < NumericInput > ( ) ;
m_page_text_box - > set_enabled ( false ) ;
m_page_text_box - > set_fixed_width ( 30 ) ;
m_page_text_box - > set_min_number ( 1 ) ;
m_page_text_box - > on_number_changed = [ & ] ( i32 number ) {
2021-05-27 14:47:44 -03:00
auto page_count = m_viewer - > document ( ) - > get_page_count ( ) ;
auto new_page_number = static_cast < u32 > ( number ) ;
VERIFY ( new_page_number > = 1 & & new_page_number < = page_count ) ;
m_viewer - > set_current_page ( new_page_number - 1 ) ;
m_go_to_prev_page_action - > set_enabled ( new_page_number > 1 ) ;
m_go_to_next_page_action - > set_enabled ( new_page_number < page_count ) ;
2021-05-24 02:34:44 -03:00
} ;
m_total_page_label = toolbar . add < GUI : : Label > ( ) ;
2022-03-31 22:14:54 -03:00
m_total_page_label - > set_autosize ( true , 5 ) ;
2022-01-02 17:58:51 -03:00
toolbar . add_separator ( ) ;
m_zoom_in_action = GUI : : CommonActions : : make_zoom_in_action ( [ & ] ( auto & ) {
m_viewer - > zoom_in ( ) ;
} ) ;
m_zoom_out_action = GUI : : CommonActions : : make_zoom_out_action ( [ & ] ( auto & ) {
m_viewer - > zoom_out ( ) ;
} ) ;
m_reset_zoom_action = GUI : : CommonActions : : make_reset_zoom_action ( [ & ] ( auto & ) {
m_viewer - > reset_zoom ( ) ;
} ) ;
2022-01-02 20:24:11 -03:00
m_rotate_counterclockwise_action = GUI : : CommonActions : : make_rotate_counterclockwise_action ( [ & ] ( auto & ) {
m_viewer - > rotate ( - 90 ) ;
} ) ;
m_rotate_clockwise_action = GUI : : CommonActions : : make_rotate_clockwise_action ( [ & ] ( auto & ) {
m_viewer - > rotate ( 90 ) ;
} ) ;
2022-01-02 17:58:51 -03:00
m_zoom_in_action - > set_enabled ( false ) ;
m_zoom_out_action - > set_enabled ( false ) ;
m_reset_zoom_action - > set_enabled ( false ) ;
2022-01-02 20:24:11 -03:00
m_rotate_counterclockwise_action - > set_enabled ( false ) ;
m_rotate_clockwise_action - > set_enabled ( false ) ;
2022-01-02 17:58:51 -03:00
2022-03-29 01:19:45 -03:00
m_page_view_mode_single = GUI : : Action : : create_checkable ( " Single " , [ & ] ( auto & ) {
m_viewer - > set_page_view_mode ( PDFViewer : : PageViewMode : : Single ) ;
} ) ;
m_page_view_mode_multiple = GUI : : Action : : create_checkable ( " Multiple " , [ & ] ( auto & ) {
m_viewer - > set_page_view_mode ( PDFViewer : : PageViewMode : : Multiple ) ;
} ) ;
if ( m_viewer - > page_view_mode ( ) = = PDFViewer : : PageViewMode : : Single ) {
m_page_view_mode_single - > set_checked ( true ) ;
} else {
m_page_view_mode_multiple - > set_checked ( true ) ;
}
m_page_view_action_group . add_action ( * m_page_view_mode_single ) ;
m_page_view_action_group . add_action ( * m_page_view_mode_multiple ) ;
m_page_view_action_group . set_exclusive ( true ) ;
2022-01-02 17:58:51 -03:00
toolbar . add_action ( * m_zoom_in_action ) ;
toolbar . add_action ( * m_zoom_out_action ) ;
toolbar . add_action ( * m_reset_zoom_action ) ;
2022-01-02 20:24:11 -03:00
toolbar . add_action ( * m_rotate_counterclockwise_action ) ;
toolbar . add_action ( * m_rotate_clockwise_action ) ;
2021-05-10 15:50:15 -03:00
}
2022-01-16 22:47:11 -03:00
void PDFViewerWidget : : open_file ( Core : : File & file )
2021-05-10 15:50:15 -03:00
{
2022-01-16 22:47:11 -03:00
window ( ) - > set_title ( String : : formatted ( " {} - PDF Viewer " , file . filename ( ) ) ) ;
2021-05-24 18:23:08 -03:00
2022-03-30 01:27:17 -03:00
auto handle_error = [ & ] < typename T > ( PDF : : PDFErrorOr < T > maybe_error ) {
if ( maybe_error . is_error ( ) ) {
auto error = maybe_error . release_error ( ) ;
GUI : : MessageBox : : show_error ( nullptr , String : : formatted ( " Couldn't load PDF {}: \n {} " , file . filename ( ) , error . message ( ) ) ) ;
return true ;
}
return false ;
} ;
2022-01-16 22:47:11 -03:00
m_buffer = file . read_all ( ) ;
2022-03-05 21:30:55 -03:00
auto maybe_document = PDF : : Document : : create ( m_buffer ) ;
2022-03-30 01:27:17 -03:00
if ( handle_error ( maybe_document ) )
2021-05-24 18:23:08 -03:00
return ;
2022-03-05 21:30:55 -03:00
auto document = maybe_document . release_value ( ) ;
2022-03-30 22:08:02 -03:00
if ( auto sh = document - > security_handler ( ) ; sh & & ! sh - > has_user_password ( ) ) {
2022-03-20 18:24:23 -03:00
// FIXME: Prompt the user for a password
VERIFY_NOT_REACHED ( ) ;
}
2022-03-30 01:27:17 -03:00
if ( handle_error ( document - > initialize ( ) ) )
return ;
if ( handle_error ( m_viewer - > set_document ( document ) ) )
2022-03-20 18:24:23 -03:00
return ;
2021-05-24 02:34:44 -03:00
m_total_page_label - > set_text ( String : : formatted ( " of {} " , document - > get_page_count ( ) ) ) ;
m_page_text_box - > set_enabled ( true ) ;
2022-03-31 22:01:07 -03:00
m_page_text_box - > set_current_number ( 1 , GUI : : AllowCallback : : No ) ;
2021-05-24 02:34:44 -03:00
m_page_text_box - > set_max_number ( document - > get_page_count ( ) ) ;
2021-05-27 14:47:44 -03:00
m_go_to_prev_page_action - > set_enabled ( false ) ;
m_go_to_next_page_action - > set_enabled ( document - > get_page_count ( ) > 1 ) ;
2021-05-24 02:34:44 -03:00
m_toggle_sidebar_action - > set_enabled ( true ) ;
2022-01-02 17:58:51 -03:00
m_zoom_in_action - > set_enabled ( true ) ;
m_zoom_out_action - > set_enabled ( true ) ;
m_reset_zoom_action - > set_enabled ( true ) ;
2022-01-02 20:24:11 -03:00
m_rotate_counterclockwise_action - > set_enabled ( true ) ;
m_rotate_clockwise_action - > set_enabled ( true ) ;
2021-05-24 01:34:06 -03:00
if ( document - > outline ( ) ) {
auto outline = document - > outline ( ) ;
m_sidebar - > set_outline ( outline . release_nonnull ( ) ) ;
2022-08-30 08:38:20 -03:00
m_sidebar - > set_visible ( true ) ;
2021-05-24 01:34:06 -03:00
m_sidebar_open = true ;
} else {
m_sidebar - > set_outline ( { } ) ;
2022-08-30 08:38:20 -03:00
m_sidebar - > set_visible ( false ) ;
2021-05-24 01:34:06 -03:00
m_sidebar_open = false ;
}
2021-05-10 15:50:15 -03:00
}