# HG changeset patch # User Jacob Dawid # Date 1343669234 -7200 # Node ID 48ae6a7c69c12ee316fb2fe69f8e702fa1a27c0b # Parent 6889217b9d786c5347ad55e9a76bbb6b629fd950 Integrated texinfo browser from QtOctave. * documentation-dockwidget.cc: Added new dock widget for the documentation. * documentation-dockwidget.h: Added new dock widget for the documentation. * bookmark.png: New icon file. * question.png: New icon file. * star.png: New icon file. * stop.png: New icon file. * zoom-in.png: New icon file. * zoom-out.png: New icon file. * parser.cc: Added file from QtOctave, refactored code. * parser.h: Added file from QtOctave, refactored code. * webinfo.cc: Added file from QtOctave, refactored code. * webinfo.h: Added file from QtOctave, refactored code. * main-window.cc: Added menu entries to handle documentation and integrated new documentation dock widget. * main-window.h: Including header for documentation dock widget and added member variable. * resource.qrc: Added icon entries for new icon files. * src.pro: Added file entries for new file added to the project. diff --git a/gui/src/documentation-dockwidget.cc b/gui/src/documentation-dockwidget.cc new file mode 100644 --- /dev/null +++ b/gui/src/documentation-dockwidget.cc @@ -0,0 +1,45 @@ +/* OctaveGUI - A graphical user interface for Octave + * Copyright (C) 2011 Jacob Dawid (jacob.dawid@googlemail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "documentation-dockwidget.h" + +documentation_dock_widget::documentation_dock_widget (QWidget *parent) + : QDockWidget (parent) +{ + setObjectName ("DocumentationDockWidget"); + setWindowTitle (tr ("Documentation")); + + connect (this, SIGNAL (visibilityChanged (bool)), + this, SLOT (handle_visibility_changed (bool))); + + _webinfo = new webinfo (this); + setWidget (_webinfo); +} + +void +documentation_dock_widget::handle_visibility_changed (bool visible) +{ + if (visible) + emit active_changed (true); +} + +void +documentation_dock_widget::closeEvent (QCloseEvent *event) +{ + emit active_changed (false); + QDockWidget::closeEvent (event); +} diff --git a/gui/src/documentation-dockwidget.h b/gui/src/documentation-dockwidget.h new file mode 100644 --- /dev/null +++ b/gui/src/documentation-dockwidget.h @@ -0,0 +1,45 @@ +/* OctaveGUI - A graphical user interface for Octave + * Copyright (C) 2011 Jacob Dawid (jacob.dawid@googlemail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DOCUMENTATIONDOCKWIDGET_H +#define DOCUMENTATIONDOCKWIDGET_H + +#include +#include "webinfo.h" + +class documentation_dock_widget : public QDockWidget +{ + Q_OBJECT +public: + documentation_dock_widget (QWidget *parent = 0); + +public slots: + /** Slot to steer changing visibility from outside. */ + void handle_visibility_changed (bool visible); + +signals: + /** Custom signal that tells if a user has clicked away that dock widget. */ + void active_changed (bool active); + +protected: + void closeEvent (QCloseEvent *event); + +private: + webinfo *_webinfo; +}; + +#endif // DOCUMENTATIONDOCKWIDGET_H diff --git a/gui/src/icons/bookmark.png b/gui/src/icons/bookmark.png new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5e761587198608815a4625f26923e4c2c59d5ed1 GIT binary patch literal 690 zc$@*U0!{siP)5r00004XF*Lt006JZ zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!L`g(JRCwBA zV88=DRWZzeU(PTepBjJwV#Fo!p^`y>iJ$%c@81jzzux>*l$^-$0h>C20Aj*r!2kaY z1+2RA0&IF(0)PK76yQ<^5I{H$U|?g4XLHbF;Br!C_{Yi=k4qUq0AV%YZ5cxXv#PWL zBj;lVM()Q99O?=RPntv<{{7o6fUXuGfEfREG0gw_k3r!t(64_v*&P0H^D}_h+!2-x z%pxzrivGNmV|YH}0K?zE3=H32d}Lr?=lJmP{-+B-uRQ<=AjZF)4D*8l(j07*qoM6N<$f~cq`1poj5 diff --git a/gui/src/icons/question.png b/gui/src/icons/question.png new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9cc2a8b0892852068bd18c7660c0e254d261ba4f GIT binary patch literal 1903 zc$@)m2ax!QP)+RX6@Hqw`fEck`UegG)G#_Xw ze~5=3gPW}ygQ|iE11}F70~;$d0}~S?&|QomZ!`P@8v74Ofbh5PzZpJ!`oXaG*lmX0 zM{YChJ8>K6hufX+F?m{ls8Xh6o=627W$v z24*HE24-ePAcoQ)2QV>$jRINx7li-*17au*khU1r>TQKq)YW{kCd?!%q7c3+I0*D#e@`NBW{*n|222mky zpd}0ti-0sEILH~m!OqA8v6qnnW+{^8Ao|~bIR78iAxd(>3~KVC42RD?)?nn**ZlS7 z1l$n-0R(mcyM)6DM{^bN^ax7^Awf=vg~*m7(TG$J!Lay;v*BV;$NYmhMqGp!5)v1m zssCe>c>eptmFpl!00a;dpKeVeFh$EJg;+4Kvok||@*l%z|Nj4nTLzD7Acl!SEJxOh zO0xi?Oi5Ol!OLEYftg#r0%*A?5VHXU5EC#g3w#{48Th!_!M=oB{10Ln$R}`%Q7lJd z|ASyu$H3AA!V#dv?Bl4#z{AZg&LQLN29)9f2p~|5>RB2pfD_g4-+v*Bp}zTtOv4@V z4=L6EgF6NzB#@#5Wce?k*`UPC3-qYAsssZwhqwjE0RRC6E{Y|9@dJ_sDf|k|%P5v2 zXD=l7A2>z}5wISZ{(oQ(fy6$4`2|hXObm)L!m#wm1rR_i;0ggO0l|NM|6}<6;|~KT z2Mbbp3p9uU;y^~m|Bylmo*1FQ3=4L&X!!l-AH$cgzrYC?WIjmkx9`6|8bO9I0R#{z z1U_B`7N5wD0BQd5^AA`vBCZiW{eu(&s6K~A576hof$SeZkAN`9!Ep0|)?T^&0_f0R zUqBuJ2p}d&Q)p`;XtjUCIo_Ow3GhHn<38VPaqbVm3A)W`$r@ zVBG)`hZWIGX!;<&hGHPQfBr#+e?MLw{QdFz1E2%G0t67#mm5>|{QvWHUhTx~4Bvhr z;tIndK+M97s1sONnBa8-3sfG%Vl=#d_hp7lHy(fc@$%qOpyls@_!B??fl}f>VEMfN z7q@ZHsmo79tbkdPpN|u%@?k=R05c=BZeW7@3{g^I)~f%JO3nFePch71d4l2Rt0S$y z-<~}K6n+9qe*ggltBn2ttE=rFfAZ;XJ9Jk;QAUVC8CZTZGcm!_1tf@>;AsTJ28R~N z0a$GQ4=I5dp1u6U&@yc|!^Yj0zWsQ%vkK^0P__IRh+l(>Vt@dGIpF`_Z%;o1CAa?L zRASnF{E6P#D^J<@c{zZM4-qs6z!EAGv|WJNtN_^!vUusH^9)UscQM?$egE3`$D5jd zf4F=RDD?=4Ujp$DkWzpELU%lszg@t?sdXZZb6SF*1Dp_KTsme;31}XYav|`1tt;!`0g_Aw|~jZx8?e zczNpg#~Vj~y*YIa6wgr0-vRL#^yV2r0I^_kz&~iK<=3At_df}VNa&)V?ve}8>`@%zWS=l}kE{rvU$(c4f9z60@RP%4Mg-;f(2$N(UK zSnxDh|CstsG~wi6lW_pHj_y8u%P@WEafY*(AAS4u>e}k3XXmT}s`&u*)lX=9?>E#U zWQ@0U3=ly09KayJ%b8%TE6cF!&@G15+b%PF`SkMit)tT>e*O6LDKsIyf%^6jH01t5 zX`=gk00D%vSsqugQsC$BKcK>b;rFkfudbipI`#UQwI`w3=Owft`2n?%Yyc2II75Jo zgE@$Yi;dy=vpWmcFDP9N4enP^U&9g;#Q-3H@b!#Xfmj68T!6;yD`<-TMM@A80ssNT pNTA=y4#mHr!Tp!oeM5i%0|32t1-lwDV{rfg002ovPDHLkV1n(Fe$W5_ diff --git a/gui/src/icons/star.png b/gui/src/icons/star.png new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..058efcf4ba174495d8d89d1916c3ccebf393a2af GIT binary patch literal 1468 zc$@*e1w;CYP)}N+@!!zvcc7D~w{e$0UcZJIgN| z!l7e5>pnEVk(##CP;cHzYm8u_GjHNlElS>o0JsX<8b~EMMJo(ItBt^mu^OD-f@0Ya z0AiQV(K>TtoNo=(>G9fs5+Wse&z zFjua5faH7(Rf}3(F~~PXz%qIsIC{{ke-)8C5hzNM@g;&!hGF7{NGC420Q2w>-u5 zgu&i(5l&peCqlNEN(NxdmOKw%wr|-s_zo@RvMc8@m8XnJQlF_C6M;-gAkLU>gcmKB zgW$M&3EKX^ClOXNk^%HBsW`-ca<;5`^hGG(QmmzGDPOJ6*1;_!(-P3@v0wnUw3M*K*3`xLd&d_2j+?N=_L?U4oM4|Qt=?DT1VU=ez-oQA213vZ9ymK#;$VImb?xA@ z#05LMW50{dt_rg^|I91Kxgkp`QgR zzd~?EN1%RSDO&P<{`}(Gi7j9tJob(0uFeEYff6VP6NM4?V$)DR9ANq69tyiV4DqX+ z5TVF8S;ev&3nn6=yID|0Wi_~nnnfrBVq(%1k|Yoj70+8E?r@6YTPR-UWt4>#0Wdp0 z%N5DZkk0_nr4mtEz?MkrnP+3d@_;0((WAhqP(sueamSupQL&z;R|Ft=v;)fdgwo_T z6Gk874@GpHV2xaW_Fn|BxpAfs#gnc$qZp-G-$bg&K3c#OkgO1?Fq${wY8wvO!h&qO zi=!SC=7G7D3R6}9Vu22J!(j{4BxNZuaeW>VbBTAO82T}o#wR{jz*w1BvmB>bzl%rf zxeSY$0y2r4jmZSc@knHOM`;&`ew?M%lxO!q1=k^OHfk=_77Swlo(TTHj(}gR_uq#7 zw_jTL?5Rz4!?ij@vUf_k5q2{+X?Ft18NdZcU**cUeR4igOUH-^i=LvOcg{I{2b|t8 z*hVzB`nuz7-@S6{;}0CW?(bm`DO;tgwP+Bz1IWN{;|B$hXSt{^uruI+C+}j;X2HZ1 z|Aq25%7h+NKZ)-lq;0uepgvVZcMcMTxc-GRMsSgsoD0(j7m0`V)n_93>9YFjn7*46wU0R{lz WQ-?g>7HstZ0000<>&kwejh{zL(}4fnL!i)SPZ!4!i_=FZ8|Jkb2)ND@R_JCuzo*19QV-xSBJ#LFSrszjX)&H)qwn_ex&+&k{ zV$PlaqRQ(VtS#?3f4nWmbNIj}oi(qy9A+)sEwNzLD(M2oceC|wHf_tD7_?~0A&J8# zz7oj+UW!YXysw_MjB!V+`A(*F>$0CKn_Z8xUi(!~_M^!Uozs&l=Sd#__;g~|B8AhN zWUrUX9(a0O;e0W}nynVk>rSh%+>YYNew!_tWU;EN_?+s# z-H^*iHiqQG%Eym;>-c;D+Ro12^1UbCzJ0qHgUNIfiNwRgZV^PxD26;Pr$S$TOE7-n zNid%DOM=1)6sVrp1bRfGVFrWg^gb(MMy1jGJ3G7HrstMJ4rl*mwD&DA;7Edv2!_ZI z!4&Jm@;mg77YlVqyfWV5<8q-EK3_wn($Mb(A|WB+WPLqP6P{RTJmQn5_fO=lOp+&jMvUoVGOJy}E(8&sYH4+t#o0S{-_)%1~H6e+EWvG3COFaL5be>IFigIFxq z7~)|vKy-9;5WAFPbUaVi{XO*V%Ow8fQ0h;rzDmXFvqqKnMaW$l2))w}?$2vRS(B@> z^!|mOo9)v-x!q`dao8(oy^z6%Vq#)~OwGS7B_&0eoLTa2uV?P-^M!pKQC&)Yh~#y3 z`ovl@aa!Aal_P@!N~9oGp=n5)TyMhnE>_~&l{J3sq2|wh>C<5e3}b3qS{LGF3c#N- zGBTC}qFIJR-V0xmE|0EROT zFzjc*CtnI&5}Uy{L8aht7xRJLg&c5(H&yU;YUhJf0nF9BygUf;G6mou83w>aa5P^f zcQ$!7%@jF?)q&&5BH&T*GdRytg0n^A;AEN@d=Xp&Y`k;9r^l226Yedqa*yUbu5ree ztWYQg5aMMDz-PB_-(Cqxs?s|qwej5=rzyU&6=J}1P1JRT4xgyhhn+8-FuG<+z>SwW zT*QV($G70)a4qc$orV ze);m{l_rg+_smw1uG+X7Ijsx5@^n4++xGdaqv<^l@;Dv({QUem!~?YnnY+2U1y@(!GZftu zzdfG$sL4~HBwrd`iwlP#QsB}f<^OS77xK?%Z)3c=U*A4OAK<2Q#J@E+w?LJZmCc6^ z9kQ^qvoqfe#LkPCE@ki<8VwEYGCh{n-{*37oO!PM^)0mQO``vkl?0zhi>dDQQ`Ae$ z0ZDc1kgm0@9aL0SfmxLbh{fXWs;a6AKR>^ZHwEG0;Tc|DUa6M$_Co^6Q*BxIaBFLggL1iXZe9giT3WiUUAy+lW*{uK zZL>Ur4g4XOLZ$tDzmB)o(J3@`c6A%;>KoPy;5FnP@(l8g(%kz2y)G z4jeFtKSv<^lY2`f5bM zK~#9!&6jOxTjv$WpXa{l>fM$l+mdBlwq;9BY`KwJyG??@!$~)?Eo=wS+$`Jf^m9p|#Hkx||n=&Pv>s;qJ=%+WPn3eDjU5lS1(5P&aPe80rpp zkKO-t(>y*U8{xi?8XD+UBZDDg^LkW=x31!A_UJZ`t0IY#HoI2FvCV{eAmYE;)z$g% z(W6K4lK=<^2z8?Q3tMFyY{Nr+w|J4zovC(tAGFerRagh<19AR zS(qRR$__=zGUf_)6K`k;%PQis08x@3!Sz)Az1WMq>jKcQqh~xJu&KXEBIl2Ow%F?#@B(4YQoz9ox zmQe`fxByOY|GA|DN-YiUoubXYwM#hNE}2v;2x^_c+eC&~6~KlOpkSRyrc9AH#GJ*N zvo_Vc;;B?qOVAvx=BjcY8$c9ASFwUsbGs47G$*7)MPmAs##-*sTi3^OWQGqp3P3fTF2tq0S*#Rte!1M%8cr{MDN^ zHc_#QoCdqc5V#=0aHCEcS0PN04Q47-3~4`+vok`u`WlmWwl0T(zC=P?9>bDhUBR4L1hsT7JsT}Pc?ki_}9{)dA3OQyqm#M|1BMvjd5LYsom{F-E ztq@x-DZ5IG+rcYta`~*MY{3{moSmJ0ud%Ta9~>O8le`Pq`uh5UAPW2o=Ym5Q0`AV; zSW!x3HMK+$pVg@OKsM~Dbh$Pk%lK;Jd*@&25JrN|f-RLw;gQRi!$TJ@4n-o7VaWAh zadA;QE*md$EG{nGg$a7Rv9a-5a(`cHZf!-~XU=rAG&f(W zt*w19IXU^IO9_7ooC~7q@K{wAV(0Kk5GWW7+M1i2f8Ej1@d~^V@i(qsMd5Ha+S%UP zynXxjOQWNsQ!r&;P~^XhL6jl(A!3KIe|U|dLuIpB9ai~AVB!XNsr4@}En%zGiaJA~ z+U`*3+ch;c^Sisdt6r@YlYt**p!hsMe3cMl+1OY|CdrI@dV6}?+uNT9 zz1aAd9jrPxSWoeht2`9BZqqhy!zm!r^up-+%849{mpm&l_!SZpJE= z%3lED5*X19CPccXA?Sh^JaL{!PeHL*Y#%%^4iLj$5SSCeUQl5yf6Sw&qw)*<|+#@3+U-$d{82vx!Ul0{#Wq9p+B>(^b07*qoM6N<$ Eg7rj$G5`Po diff --git a/gui/src/main-window.cc b/gui/src/main-window.cc --- a/gui/src/main-window.cc +++ b/gui/src/main-window.cc @@ -310,6 +310,19 @@ } void +main_window::focus_documentation () +{ + if (!_documentation_dock_widget->isVisible ()) + { + _documentation_dock_widget->setVisible (true); + } + + _documentation_dock_widget->setFocus (); + _documentation_dock_widget->activateWindow (); + _documentation_dock_widget->raise (); +} + +void main_window::handle_entered_debug_mode () { setWindowTitle ("Octave (Debugging)"); @@ -429,6 +442,8 @@ _history_dock_widget->setStatusTip (tr ("Browse and search the command history.")); _files_dock_widget = new files_dock_widget (this); _files_dock_widget->setStatusTip (tr ("Browse your files.")); + _documentation_dock_widget= new documentation_dock_widget (this); + _documentation_dock_widget->setStatusTip (tr ("See the documentation for help.")); _status_bar = new QStatusBar (this); _current_directory_combo_box = new QComboBox (this); @@ -639,6 +654,11 @@ show_editor_action->setCheckable (true); show_editor_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier + Qt::Key_4); + + QAction * show_documentation_action = window_menu->addAction (tr ("Show Documentation")); + show_documentation_action->setCheckable (true); + show_documentation_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier + + Qt::Key_5); window_menu->addSeparator (); QAction * command_window_action @@ -661,6 +681,10 @@ = window_menu->addAction (tr ("Editor")); editor_action->setShortcut (Qt::ControlModifier + Qt::Key_4); + QAction * documentation_action + = window_menu->addAction (tr ("Documentation")); + documentation_action->setShortcut (Qt::ControlModifier + Qt::Key_5); + window_menu->addSeparator (); QAction * reset_windows_action = window_menu->addAction (tr ("Reset Windows")); @@ -733,6 +757,10 @@ _file_editor, SLOT (setVisible (bool))); connect (_file_editor, SIGNAL (active_changed (bool)), show_editor_action, SLOT (setChecked (bool))); + connect (show_documentation_action, SIGNAL (toggled (bool)), + _documentation_dock_widget, SLOT (setVisible (bool))); + connect (_documentation_dock_widget, SIGNAL (active_changed (bool)), + show_documentation_action, SLOT (setChecked (bool))); connect (command_window_action, SIGNAL (triggered ()), this, SLOT (focus_command_window ())); @@ -744,6 +772,8 @@ this, SLOT (focus_current_directory ())); connect (editor_action, SIGNAL (triggered ()), this, SLOT (focus_editor ())); + connect (documentation_action, SIGNAL (triggered ()), + this, SLOT (focus_documentation ())); connect (reset_windows_action, SIGNAL (triggered ()), this, SLOT (reset_windows ())); @@ -796,6 +826,7 @@ addDockWidget (Qt::RightDockWidgetArea, _files_dock_widget); addDockWidget (Qt::RightDockWidgetArea, _file_editor); addDockWidget (Qt::BottomDockWidgetArea, _terminal_dock_widget); + addDockWidget (Qt::RightDockWidgetArea, _documentation_dock_widget); setStatusBar (_status_bar); read_settings (); diff --git a/gui/src/main-window.h b/gui/src/main-window.h --- a/gui/src/main-window.h +++ b/gui/src/main-window.h @@ -44,6 +44,7 @@ #include "history-dockwidget.h" #include "files-dockwidget.h" #include "terminal-dockwidget.h" +#include "documentation-dockwidget.h" #include "octave-qt-event-listener.h" #include "octave-event-observer.h" @@ -104,6 +105,7 @@ void focus_current_directory (); void focus_workspace (); void focus_editor (); + void focus_documentation (); void handle_entered_debug_mode (); void handle_quit_debug_mode (); @@ -137,6 +139,7 @@ history_dock_widget * _history_dock_widget; files_dock_widget * _files_dock_widget; terminal_dock_widget * _terminal_dock_widget; + documentation_dock_widget*_documentation_dock_widget; // Toolbars. QStatusBar * _status_bar; diff --git a/gui/src/qtinfo/parser.cc b/gui/src/qtinfo/parser.cc new file mode 100644 --- /dev/null +++ b/gui/src/qtinfo/parser.cc @@ -0,0 +1,578 @@ +/* Copyright (C) 2009 P.L. Lucas + * Copyright (C) 2012 Jacob Dawid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "parser.h" +#include +#include +#include +#include +#include +#include +#include + +parser::parser(QObject *parent) + : QObject(parent) +{ + _compressors_map.insert ("bz2", "bzip2 -dc \"%1\""); + _compressors_map.insert ("gz", "gzip -dc \"%1\""); + _compressors_map.insert ("lzma", "lzma -dc \"%1\""); + _compressors_map.insert ("xz", "xz -dc \"%1\""); + _compressors_map.insert ("Z", "gunzip -c \"%1\""); +} + +void +parser::set_info_path (QString infoPath) +{ + this->_info_path = infoPath; + + _info_files.clear (); + + QFileInfo info (infoPath); + + QString path = info.absolutePath (); + QString fileName = info.fileName (); + + QDir infoDir (path); + QStringList filter; + filter.append (fileName + "*"); + + _info_files = infoDir.entryInfoList (filter, QDir::Files); + parse_info_map (); +} + +QString +parser::get_info_path () +{ + return _info_path; +} + +QIODevice * +parser::open_file (QFileInfo & file_info) +{ + QIODevice *iodevice=NULL; + if ( _compressors_map.contains(file_info.suffix ())) + { + QProcess gzip; + gzip.start (_compressors_map.value (file_info.suffix ()).arg (file_info.absoluteFilePath ())); + + if (!gzip.waitForFinished ()) + return NULL; + + QByteArray result = gzip.readAll (); + + QBuffer *io = new QBuffer (this); + io->setData (result); + + if (!io->open (QIODevice::ReadOnly | QIODevice::Text)) + return NULL; + + iodevice = io; + } + else + { + QFile *io = new QFile (file_info.absoluteFilePath ()); + if (!io->open (QIODevice::ReadOnly | QIODevice::Text)) + return NULL; + iodevice = io; + } + + return iodevice; +} + +int +parser::is_ref (QString node) +{ + if (_ref_map.contains (node)) + { + node_position ref = _ref_map [node]; + + return ref.pos-_node_map [ref._node_name].pos; + } + return -1; +} + +QString +parser::search_node (QString node) +{ + QFileInfo file_info; + QString ref; + + if (_ref_map.contains (node)) + { + ref = node; + node = _ref_map [ref]._node_name; + } + + if (_node_map.contains (node)) + { + int pos = _node_map [node].pos; + int realPos; + + real_position (pos, file_info, realPos); + + QIODevice *io = open_file (file_info); + if (io == NULL) + { + return QString (); + } + + seek (io, realPos); + + QString text = get_next_node (io); + if (!text.isEmpty()) + { + return text; + } + + io->close (); + delete io; + } + + return QString (); +} + +QString +parser::search_node (QString node, QIODevice *io) +{ + while (!io->atEnd ()) + { + QString text = get_next_node (io); + if(node == get_node_name (text)) + { + return text; + } + } + + return QString (); +} + +QString +parser::get_next_node (QIODevice *io) +{ + QString text; + while (!io->atEnd ()) + { + QByteArray line = io->readLine (); + if (line.at(0) == 31) + { + break; + } + else + { + text.append (line); + } + } + return text; +} + +static QString +get_first_line (QString text) +{ + int n = text.indexOf ("\n"); + + if (n < 0) + { + return QString (); + } + + QString first_line = text.left (n); + return first_line; +} + +static QString +parser_node (QString text, QString node_name) +{ + QString firstLine = get_first_line (text); + QStringList nodes = firstLine.split (","); + for (int i = 0;i < nodes.size (); i++) + { + QString node = nodes.at (i).trimmed (); + + if (node.startsWith (node_name)) + { + return node.remove (0, node_name.size ()).trimmed (); + } + } + return QString (); +} + +QString +parser::get_node_name (QString text) +{ + return parser_node (text, "Node:"); +} + +QString +parser::get_node_up (QString text) +{ + return parser_node (text, "Up:"); +} + +QString +parser::get_node_next (QString text) +{ + return parser_node (text, "Next:"); +} + +QString +parser::get_node_prev (QString text) +{ + return parser_node (text, "Prev:"); +} + +static void +replace_links (QString &text) +{ + QRegExp re ("(\\*[N|n]ote|\n\\*)([ |\n]+)([^:]+):([^:\\.,]*)([:,\\.])"); + int i = 0, f; + + while ( (i = re.indexIn (text,i)) != -1) + { + QString type = re.cap (1); + QString note = re.cap (3); + QString url_link = re.cap (4); + QString link = re.cap (4); + + if (url_link.isEmpty ()) + { + url_link = note; + } + + url_link = url_link.trimmed (); + url_link.replace ("\n"," "); + url_link.replace (QRegExp (" +")," "); + url_link.replace ("",""); + url_link.replace ("",""); + url_link = QUrl::toPercentEncoding (url_link, "", "'"); + + QString href; + if (type=="\n*") + { + href="\n"; + } + else + { + href=""; + } + href += re.cap (2) + "" + note + ":" + link + re.cap (5) + ""; + f = re.matchedLength (); + text.replace (i,f,href); + i += href.size (); + } +} + +static void +replace_colons (QString &text) +{ + QRegExp re ("`([^']+)'"); + int i = 0, f; + while ( (i = re.indexIn (text, i)) != -1) + { + QString t = re.cap (1); + QString bold = "`" + t + "'"; + + f = re.matchedLength (); + text.replace (i,f,bold); + i += bold.size (); + } +} + +static void +info_to_html (QString &text) +{ + text.replace ("&", "&"); + text.replace ("<", "<"); + text.replace (">", ">"); + + text.replace ("\n* Menu:", "\nMenu:"); + text.replace ("*See also:*", "See also:"); + replace_colons (text); + replace_links (text); +} + +QString +parser::node_text_to_html (QString text, int anchorPos, QString anchor) +{ + QString nodeName = get_node_name (text); + QString nodeUp = get_node_up (text); + QString nodeNext = get_node_next (text); + QString nodePrev = get_node_prev (text); + + if (anchorPos > -1) + { + QString text1 = text.left (anchorPos); + QString text2 = text.mid (anchorPos); + + int n = text1.indexOf ("\n"); + text1.remove (0, n); + + info_to_html (text1); + info_to_html (text2); + + text = text1 + "" + text2; + } + else + { + int n = text.indexOf ("\n"); + text.remove (0, n); + info_to_html (text); + } + + QString navigationLinks = QString ( + " Section: %1
" + "Previous Section:
%3
" + "Next Section: %5
" + "Up: %7
\n" + ) + .arg (nodeName) + .arg (QString (QUrl::toPercentEncoding (nodePrev, "", "'"))) + .arg (nodePrev) + .arg (QString (QUrl::toPercentEncoding (nodeNext, "", "'"))) + .arg (nodeNext) + .arg (QString (QUrl::toPercentEncoding (nodeUp, "", "'"))) + .arg (nodeUp); + + + text.prepend ("
\n
");
+  text.append ("
\n

\n"); + text.prepend (navigationLinks); + text.append (navigationLinks); + text.prepend ("\n"); + text.append ("\n"); + return text; +} + +void +parser::parse_info_map () +{ + QRegExp re ("(Node|Ref): ([^\\0177]+)\\0177(\\d+)\n"); + QRegExp re_files ("([^:]+): (\\d+)\n"); + int foundCount = 0; + + for(int i = 0; i < _info_files.size (); i++) + { + QFileInfo fileInfo = _info_files.at (i); + + QIODevice *io = open_file (fileInfo); + if (io == NULL) + { + continue; + } + + QString nodeText; + while (! (nodeText=get_next_node (io)).isEmpty () && foundCount < 2) + { + QString first_line = get_first_line (nodeText); + if (first_line.startsWith ("Tag") ) + { + foundCount++; + int pos = 0; + QString last_node; + + while ((pos = re.indexIn (nodeText, pos)) != -1) { + QString type = re.cap (1); + QString node = re.cap (2); + int index = re.cap (3).toInt (); + + if (type == "Node") + { + node_map_item item; + item.pos = index; + _node_map [node] = item; + last_node = node; + } + else if (type == "Ref") + { + node_position item; + item._node_name = last_node; + item.pos = index; + _ref_map [node] = item; + } + pos += re.matchedLength (); + } + break; + } + else if (first_line.startsWith ("Indirect:")) + { + foundCount++; + int pos = 0; + + while ( (pos = re_files.indexIn (nodeText, pos)) != -1) { + QString fileCap = re_files.cap (1).trimmed (); + int index = re_files.cap (2).toInt (); + + info_file_item item; + for (int j = 0;j < _info_files.size (); j++) + { + QFileInfo info = _info_files.at (j); + if (info.fileName ().startsWith (fileCap)) + { + item.file_info = info; + break; + } + } + item.real_size = index; + _info_file_real_size_list.append (item); + pos += re_files.matchedLength (); + } + + } + } + io->close (); + delete io; + } +} + +void +parser::real_position (int pos, QFileInfo & file_info, int & real_pos) +{ + int header = -1, sum = 0; + for (int i = 0; i < _info_file_real_size_list.size (); i++) + { + info_file_item item = _info_file_real_size_list.at (i); + if (header == -1) + { + file_info = item.file_info; + header = item.real_size; + } + + if (pos < item.real_size) + { + break; + } + + file_info = item.file_info; + sum = item.real_size; + } + real_pos = pos - sum + header + 2; +} + +void +parser::seek (QIODevice *io, int pos) +{ + char ch; + while (!io->atEnd () && pos > 0) + { + io->getChar (&ch); + pos--; + } +} + +static void +replace (QString &text, QRegExp re, QString after) +{ + int pos = 0; + + while ( (pos = re.indexIn (text, pos)) != -1) + { + QString cap = text.mid (pos,re.matchedLength ()); + QString a (after); + a = a.arg (cap); + text.remove (pos, re.matchedLength ()); + text.insert (pos, a); + pos += a.size (); + } +} + +QString +parser::global_search (QString text, int max_founds) +{ + QString results; + QStringList words = text.split (" ",QString::SkipEmptyParts); + + QString re_program ("(" + words.at (0)); + for (int i = 1; i < words.size (); i++) + { + re_program += "|" + words.at (i); + } + re_program += ")"; + + QRegExp re (re_program, Qt::CaseInsensitive); + + results.append ("\n

Search results

\nResults for: "); + results.append (text); + results.append ("
\n"); + + for (int i = 0; i < _info_files.size (); i++) + { + QFileInfo file_info = _info_files.at (i); + QIODevice *io = open_file (file_info); + if (io == NULL) + { + continue; + } + + QString node_text; + while ( !(node_text = get_next_node (io)).isEmpty ()) + { + QString firstLine = get_first_line (node_text); + QString node = get_node_name (node_text); + if (node.isEmpty ()) + { + continue; + } + + int n = node_text.indexOf ("\n"); + node_text.remove (0, n); + + int pos = 0; + int founds = 0; + + for (; founds < words.size () && node_text.indexOf (words.at (founds)) >= 0; founds++) + { } + + if (founds\n "); + results.append (node); + results.append ("
\n"); + } + + replace (line, re, "%1"); + results.append (line); + results.append ("
\n"); + + founds++; + + pos += re.matchedLength (); + } + } + io->close (); + delete io; + } + + results.append (""); + return results; +} diff --git a/gui/src/qtinfo/parser.h b/gui/src/qtinfo/parser.h new file mode 100644 --- /dev/null +++ b/gui/src/qtinfo/parser.h @@ -0,0 +1,111 @@ +/* Copyright (C) 2009 P.L. Lucas + * Copyright (C) 2012 Jacob Dawid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include + +/** + * \class parser + * This class gets nodes and searchs inside of `info files'. + *

Each info file has nodes. Every node has the documentation. + * Info files contains a map with position of each node.

+ *

What is position? + * There is a simple answer: + * If you make a queue with info files, position will be the number of bytes + * from begining to node position.

+ *

+ * But is not so easy. There is headers, and qtinfo must not take these headers into account. + *

+ *

+ * This class also translates info files to html. + *

+ */ +class parser + : public QObject +{ + Q_OBJECT + +public: + parser (QObject *parent = 0); + void set_info_path (QString _info_path); + QString get_info_path (); + QString search_node (QString node); + QString global_search (QString text, int maxFounds); + + /** Checks if this node is reference. If node is reference, it will be returned its position + * in text, else it will be returned -1. + */ + int is_ref (QString node); + + /**Translates text of node to Html. If anchorPos is not -1, then anchor is inserted in that + * position. + */ + QString node_text_to_html (QString text, int anchorPos=-1, QString anchor=QString()); + +private: + struct node_position + { + QString _node_name; + int pos; + }; + + struct node_map_item + { + int pos; + }; + + struct info_file_item + { + QFileInfo file_info; + int real_size; + }; + + QString search_node (QString node, QIODevice * io); + QString get_next_node (QIODevice * io); + QString get_node_name (QString text); + QString get_node_up (QString text); + QString get_node_next (QString text); + QString get_node_prev (QString text); + + /** Parses info files and gets map of node positions.*/ + void parse_info_map(); + + /** Open info files and uncompress them. */ + QIODevice *open_file(QFileInfo & fileInfo); + + /** Calculates real position of nodes. + * \param pos position from info file. + * \param fileInfo returns file what contains that position. + * \param realPos returns real position inside of fileInfo. + */ + void real_position (int pos, QFileInfo & file_info, int & real_pos); + + /** Seeks to position pos. */ + void seek (QIODevice *io, int pos); + + + QString _info_path; + QFileInfoList _info_files; + QHash _node_map; + QHash _ref_map; + QList _info_file_real_size_list; + QHash _compressors_map; +}; diff --git a/gui/src/qtinfo/webinfo.cc b/gui/src/qtinfo/webinfo.cc new file mode 100644 --- /dev/null +++ b/gui/src/qtinfo/webinfo.cc @@ -0,0 +1,209 @@ +/* Copyright (C) 2009 P.L. Lucas + * Copyright (C) 2012 Jacob Dawid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "webinfo.h" +#include +#include + + +webinfo::webinfo (QWidget *parent) + :QWidget (parent) +{ + _font_web = font (); + + QVBoxLayout *layout = new QVBoxLayout (); + setLayout (layout); + + QHBoxLayout *hboxLayout = new QHBoxLayout (); + layout->addLayout (hboxLayout); + + _close_tab_button = new QPushButton (this); + _close_tab_button->setSizePolicy (QSizePolicy::Fixed,QSizePolicy::Preferred); + _close_tab_button->setIcon (QIcon (":/actions/icons/stop.png")); + hboxLayout->addWidget (_close_tab_button); + + _tab_bar = new QTabBar (this); + _tab_bar->setSizePolicy (QSizePolicy::Preferred,QSizePolicy::Preferred); + _tab_bar->setExpanding (false); + hboxLayout->addWidget (_tab_bar); + + _zoom_in_button = new QToolButton (this); + _zoom_in_button->setSizePolicy (QSizePolicy::Fixed,QSizePolicy::Preferred); + _zoom_in_button->setIcon (QIcon (":/actions/icons/zoom-in.png")); + hboxLayout->addWidget (_zoom_in_button); + + _zoom_out_button = new QToolButton (this); + _zoom_out_button->setSizePolicy (QSizePolicy::Fixed,QSizePolicy::Preferred); + _zoom_out_button->setIcon (QIcon (":/actions/icons/zoom-out.png")); + hboxLayout->addWidget (_zoom_out_button); + + _stacked_widget = new QStackedWidget (this); + layout->addWidget (_stacked_widget); + + hboxLayout = new QHBoxLayout (); + layout->addLayout (hboxLayout); + + _search_line_edit = new QLineEdit(this); + _search_line_edit->setPlaceholderText (tr ("Type here and press \'Return\' to search")); + hboxLayout->addWidget (_search_line_edit); + + _search_check_box = new QCheckBox (tr ("Global search")); + hboxLayout->addWidget (_search_check_box); + + connect (_close_tab_button, SIGNAL (clicked ()), this, SLOT (close_tab ())); + connect (_tab_bar, SIGNAL (currentChanged (int)), this, SLOT (current_tab_changed (int))); + connect (_zoom_in_button, SIGNAL (clicked ()), this, SLOT (zoom_in ())); + connect (_zoom_out_button, SIGNAL (clicked ()), this, SLOT (zoom_out ())); + connect (_search_line_edit, SIGNAL (returnPressed ()), this, SLOT (search ())); + + resize (500, 300); + + set_info_path ("../../doc/interpreter/octave.info"); +} + +void +webinfo::set_info_path (QString info_path) +{ + _parser.set_info_path (info_path); + load_node ("Top"); +} + +void +webinfo::load_node (QString node_name) +{ + //Check if node has been already opened. + for (int i = 0;i < _tab_bar->count (); i++) + { + if (node_name == _tab_bar->tabText (i)) + { + _tab_bar->setCurrentIndex (i); + return; + } + } + + QString text = _parser.search_node (node_name); + int i = _parser.is_ref (node_name); + _text_browser = addNewTab (node_name); + _text_browser->setHtml (_parser.node_text_to_html (text, i - 1, "anchor")); + + if (i != -1) + { + _text_browser->scrollToAnchor ("anchor"); + } +} + +void +webinfo::link_clicked (const QUrl & link) +{ + QString node = link.toString (); + load_node (node); +} + +void +webinfo::current_tab_changed (int index) +{ + QVariant data = _tab_bar->tabData (index); + _text_browser = (QTextBrowser*) (data.value ()); + + _stacked_widget->setCurrentIndex (_stacked_widget->indexOf (_text_browser)); + + if (_text_browser->font () != _font_web) + { + _text_browser->setFont (_font_web); + } +} + +QTextBrowser * +webinfo::addNewTab(QString name) +{ + _text_browser = new QTextBrowser (this); + _text_browser->setOpenLinks (false); + _text_browser->show (); + + connect (_text_browser, SIGNAL (anchorClicked (const QUrl &)), this, SLOT (link_clicked (const QUrl &)) ); + disconnect(_tab_bar, SIGNAL (currentChanged(int)), this, SLOT (current_tab_changed (int))); + + int ns = _stacked_widget->addWidget (_text_browser); + _stacked_widget->setCurrentIndex (ns); + + int nt = _tab_bar->addTab (name); + _tab_bar->setCurrentIndex (nt); + QVariant data; + data.setValue ( (void*)_text_browser); + _tab_bar->setTabData (nt, data); + + connect (_tab_bar, SIGNAL (currentChanged (int)), this, SLOT (current_tab_changed (int))); + + if (_text_browser->font () != _font_web) + { + _text_browser->setFont (_font_web); + } + return _text_browser; +} + +void +webinfo::close_tab () +{ + int index = _tab_bar->currentIndex (); + if (_tab_bar->tabText (index) != "Top") + closeTab (index); +} + +void +webinfo::closeTab (int index) +{ + QVariant data = _tab_bar->tabData (index); + QWidget *w = (QWidget*) (data.value ()); + _stacked_widget->removeWidget (w); + delete w; + + _tab_bar->removeTab (index); +} + +void +webinfo::search () +{ + if (_search_check_box->isChecked ()) + { + // Global search + QString results = _parser.global_search (_search_line_edit->text (), 5); + _text_browser=addNewTab ("Results for: " + _search_line_edit->text ()); + _text_browser->setHtml (results); + } + else + { + // Local search + _text_browser->find (_search_line_edit->text ()); + } +} + +void +webinfo::zoom_in () +{ + _font_web.setPointSize (_font_web.pointSize() + 1); + _text_browser->setFont (_font_web); +} + +void +webinfo::zoom_out () +{ + _font_web.setPointSize (_font_web.pointSize() - 1); + _text_browser->setFont (_font_web); +} + diff --git a/gui/src/qtinfo/webinfo.h b/gui/src/qtinfo/webinfo.h new file mode 100644 --- /dev/null +++ b/gui/src/qtinfo/webinfo.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2009 P.L. Lucas + * Copyright (C) 2012 Jacob Dawid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "parser.h" +#include +#include +#include +#include +#include +#include + +class webinfo : public QWidget +{ + Q_OBJECT +public: + webinfo (QWidget *parent = 0); + void set_info_path (QString info_path); + void load_node (QString node_name); + +public slots: + void link_clicked (const QUrl &link); + void current_tab_changed (int index); + void close_tab (); + void search (); + void zoom_in (); + void zoom_out (); + +private: + QTextBrowser *_text_browser; + QTabBar *_tab_bar; + QStackedWidget *_stacked_widget; + QPushButton *_close_tab_button; + QLineEdit *_search_line_edit; + QCheckBox *_search_check_box; + QToolButton *_zoom_in_button; + QToolButton *_zoom_out_button; + + parser _parser; + QFont _font_web; + + QTextBrowser *addNewTab (QString name); + void closeTab(int index); +}; diff --git a/gui/src/resource.qrc b/gui/src/resource.qrc --- a/gui/src/resource.qrc +++ b/gui/src/resource.qrc @@ -15,5 +15,11 @@ icons/filesaveas.png icons/redled.png icons/arrow_right.png + icons/bookmark.png + icons/question.png + icons/star.png + icons/stop.png + icons/zoom-in.png + icons/zoom-out.png diff --git a/gui/src/src.pro b/gui/src/src.pro --- a/gui/src/src.pro +++ b/gui/src/src.pro @@ -44,6 +44,7 @@ INCLUDEPATH += . \ octave-adapter \ m-editor \ + qtinfo \ ../qterminal/libqterminal \ /usr/include/qt4 \ ../.. \ @@ -83,6 +84,8 @@ m-editor/lexer-octave-gui.cc \ m-editor/file-editor.cc \ m-editor/file-editor-tab.cc \ + qtinfo/parser.cc \ + qtinfo/webinfo.cc \ main-window.cc \ workspace-view.cc \ history-dockwidget.cc \ @@ -93,7 +96,8 @@ welcome-wizard.cc \ workspace-model.cc \ terminal-dockwidget.cc \ - octave-qt-event-listener.cc + octave-qt-event-listener.cc \ + documentation-dockwidget.cc HEADERS += \ octave-adapter/octave-link.h \ @@ -105,6 +109,8 @@ m-editor/file-editor.h \ m-editor/file-editor-interface.h \ m-editor/file-editor-tab.h \ + qtinfo/parser.h \ + qtinfo/webinfo.h \ symbol-information.h \ main-window.h \ workspace-view.h \ @@ -115,7 +121,8 @@ welcome-wizard.h \ workspace-model.h \ terminal-dockwidget.h \ - octave-qt-event-listener.h + octave-qt-event-listener.h \ + documentation-dockwidget.h FORMS += \ settings-dialog.ui \