jd-2.8.7-140104/0000755000076400010400000000000012261751613007574 5ustar jd-2.8.7-140104/AUTHORS0000644000076400010400000000007710626304033010641 0ustar http://jd4linux.sourceforge.jp/manual/を見てください。 jd-2.8.7-140104/autogen.sh0000755000076400010400000000373010541512201011563 0ustar #!/bin/sh if test ! -f install-sh ; then touch install-sh ; fi MAKE=`which gnumake` if test ! -x "$MAKE" ; then MAKE=`which gmake` ; fi if test ! -x "$MAKE" ; then MAKE=`which make` ; fi HAVE_GNU_MAKE=`$MAKE --version|grep -c "Free Software Foundation"` if test "$HAVE_GNU_MAKE" != "1"; then echo Only non-GNU make found: $MAKE else echo `$MAKE --version | head -1` found fi if which autoconf2.50 >/dev/null 2>&1 then AC_POSTFIX=2.50 elif which autoconf259 >/dev/null 2>&1 then AC_POSTFIX=259 elif which autoconf >/dev/null 2>&1 then AC_POSTFIX="" else echo 'you need autoconfig (2.58+ recommended) to generate the Makefile' exit 1 fi echo checking autoconf$AC_POSTFIX ... echo `autoconf$AC_POSTFIX --version | head -1` found unset AM_POSTFIX for num in 10 9 8 7 ; do if which automake-1.$num > /dev/null 2>&1 ; then AM_POSTFIX=-1.$num break fi done if test -z "$AM_POSTFIX" ; then for num in 19 18 17 ; do if which automake$num > /dev/null 2>&1 ; then AM_POSTFIX=$num break fi done fi if test -z "$AM_POSTFIX" ; then if ! which automake > /dev/null 2&1 ; then echo 'you need automake (1.8.3+ recommended) to generate the Makefile' exit 1 fi fi echo checking automake$AM_POSTFIX ... echo `automake$AM_POSTFIX --version | head -1` found if which libtoolize15 >/dev/null 2>&1 then LB_POSTFIX=15 elif which libtoolize >/dev/null 2>&1 then LB_POSTFIX="" else echo 'you need libtoolize to generate the Makefile' exit 1 fi echo checking libtoolize$LB_POSTFIX ... echo `libtoolize$LB_POSTFIX --version | head -1` found if test -d /usr/local/share/aclocal ; then ACLOCAL_INCLUDE="-I /usr/local/share/aclocal" fi echo This script runs configure and make... echo You did remember necessary arguments for configure, right? # autoreconf$AC_POSTFIX -fim _might_ do the trick, too. # chose to your taste aclocal$AM_POSTFIX $ACLOCAL_INCLUDE libtoolize$LB_POSTFIX --force --copy autoheader$AC_POSTFIX automake$AM_POSTFIX --add-missing --copy --gnu autoconf$AC_POSTFIX #./configure $* && $MAKE jd-2.8.7-140104/ChangeLog0000644000076400010400000000216312261751177011355 0ustar [ 更新履歴 ] 以前の更新履歴は"http://jd4linux.sourceforge.jp/manual/"を参照してください。 svnのコミットログを知りたい場合は svn log -r 1000:HEAD http://svn.sourceforge.jp/svnroot/jd4linux/jd/trunk などの様にしてsvnサーバから直接取得してください。 (1000のところは適当なリビジョン番号にしてください) ------------------------------------------------------------------------ 2.8.7-140104 - 2014/01/04(土) ------------------------------------------------------------------------ * したらば(JBBS)のドメイン変更に対応した * 表示中のサイドバーやスレ一覧の選択を、表示中のビューと同期するようにした * 「終了」「オンラインマニュアル」のショートカットキーを変更できるようにした * Ctrl+qでウィンドウを閉じない設定は、ショートカットキー設定に統合した * 画像ビューメニューをラジオボタンに変更 * 「AAレスと判定する正規表現」を空に設定したり、リセットできないバグを修正 jd-2.8.7-140104/configure.ac0000644000076400010400000002566212105703305012065 0ustar dnl dnl JD用 configure.ac dnl AC_PREREQ(2.50) AC_INIT(jd, 1.0) AM_INIT_AUTOMAKE AC_CONFIG_HEADERS(config.h) AC_ISC_POSIX AC_PROG_CC AC_HEADER_STDC AC_PROG_CPP AC_PROG_CXX AC_PROG_CXXCPP AC_PROG_LIBTOOL AC_LANG_CPLUSPLUS dnl dnl buildinfo.h dnl AC_DEFINE(HAVE_BUILDINFO_H, 1, Define to 1 if you have the 'buildinfo.h' header file.) AC_PATH_PROG(SVN, svn) AC_PATH_PROG(SVNVERSION, svnversion) AC_PATH_PROG(XSUM, md5sum, [cksum]) AC_SUBST(ac_configure_args) dnl dnl OSを判定してOS別の設定 dnl case "${host_os}" in freebsd*) echo "os = freebsd" AC_DEFINE(ICONV_CONST, const, "iconv_const") AC_DEFINE(USE_MKTIME, , "use mktime") ;; solaris*) echo "os = solaris" AC_DEFINE(ICONV_CONST, const, "iconv_const") AC_DEFINE(NO_TIMEGM, , "no timegm") ;; mingw*) echo "os = ${host_os}" AC_DEFINE(ICONV_CONST, , "iconv_const") AC_DEFINE(USE_MKTIME, , "use mktime") ;; darwin*) echo "os = ${host_os}" AC_DEFUN([AM_ICONV], []) AC_DEFINE(ICONV_CONST, , "iconv_const") AC_DEFINE(USE_MKTIME, , "use mktime") ;; dnl linux*|gnu*|*-gnu *) echo "os = ${host_os}" AC_DEFUN([AM_ICONV], []) AC_DEFINE(ICONV_CONST, , "iconv_const") ;; esac AM_ICONV dnl --------------------------------------------------- dnl --------------------------------------------------- dnl dnl ユーザー設定 dnl dnl 追加コンパイルオプション CXXFLAGS="$CXXFLAGS -ggdb -Wall" dnl --------------------------------------------------- dnl --------------------------------------------------- LIBSM_CFLAGS="" LIBSM_LIBS="" GNOMEUI_CFLAGS="" GNOMEUI_LIBS="" dnl dnl パッケージのチェック dnl PKG_CHECK_MODULES(GTKMM,[gtkmm-2.4 >= 2.4.0], [], []) PKG_CHECK_MODULES(GTHREAD, [gthread-2.0 >= 2.0] ) AC_SUBST(GTKMM_CFLAGS) AC_SUBST(GTKMM_LIBS) AC_SUBST(GTHREAD_CFLAGS) AC_SUBST(GTHREAD_LIBS) dnl dnl crypt dnl echo "use crypt" AC_CHECK_HEADERS([crypt.h]) AC_CHECK_LIB(crypt,crypt) dnl dnl zlib dnl echo "use zlib" AC_CHECK_HEADERS([zlib.h]) AC_CHECK_LIB(z,inflate) dnl dnl packages dependent on platform dnl use_windres="" case "${host_os}" in mingw*) dnl dnl winsock2 using model of socket dnl not available uname on windows dnl echo "use winsock2" AC_CHECK_HEADERS([winsock2.h]) AC_CHECK_LIB(ws2_32,_head_libws2_32_a) echo "use regex2" AC_CHECK_HEADERS([regex.h]) AC_CHECK_LIB(regex,regexec) echo "use iconv" AC_CHECK_HEADERS([iconv.h]) AC_CHECK_LIB(iconv,_head_libiconv_a) echo "use windows resources" AC_CHECK_TOOL([WINDRES], [windres], [windres]) AC_SUBST(WINDRES) AC_DEFINE(USE_WINDRES, , "use windres") use_windres="yes" ;; *) dnl dnl any other POSIX systems dnl echo "use uname" AC_CHECK_HEADERS([sys/utsname.h]) echo "use socket" AC_CHECK_HEADERS([socket.h]) AC_CHECK_LIB(socket,socket) ;; esac AM_CONDITIONAL(MAKE_WINDRES, test -n "$use_windres") dnl dnl X関連ライブラリ dnl X11_CFLAGS="" X11_LIBS="" case "${host_os}" in mingw*) ;; *) PKG_CHECK_MODULES(X11, x11) AC_SUBST(X11_CFLAGS) AC_SUBST(X11_LIBS) ;; esac dnl dnl セッション管理 dnl dnl use_xsmp=no use_gnomeui=no AC_ARG_WITH(sessionlib, [ --with-sessionlib[[=xsmp/gnomeui/no]] use session control library [[default=xsmp]] ], [case "${withval}" in xsmp) use_xsmp=yes ;; gnomeui) use_gnomeui=yes ;; no) use_xsmp=no use_gnomeui=no ;; *) use_xsmp=yes ;; esac],use_xsmp=yes) dnl dnl XSMPを使ってセッション管理をする。libSMとlibICEが必要。無ければXSMPは無効になる dnl dnl dirsの並びは Tk の configure に書いてあったもの + Fedora 向けにディレクトリを追加 dnl if test x"$use_xsmp" = "xyes" ; then AC_MSG_CHECKING(for SMlib.h and ICElib.h) LIBSM_CFLAGS="" dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include /usr/include" for i in $dirs ; do if test -r $i/X11/ICE/ICElib.h -a -r $i/X11/SM/SMlib.h ; then AC_MSG_RESULT($i) LIBSM_CFLAGS="-I$i" break fi done if test -z "$LIBSM_CFLAGS" ; then AC_MSG_RESULT(could not find SMlib.h and ICElib.h) fi AC_MSG_CHECKING(for libSM and libICE) LIBSM_LIBS="" dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib /usr/lib /usr/X11R6/lib64 /usr/lib64" for i in $dirs ; do if test -r $i/libICE.so -a -r $i/libSM.so ; then AC_MSG_RESULT($i) LIBSM_LIBS="-L$i -lICE -lSM" break fi done if test -z "$LIBSM_LIBS" ; then AC_MSG_RESULT(could not find libSM and libICE.) fi if test -n "$LIBSM_CFLAGS" -a -n "$LIBSM_LIBS" ; then echo "use XSMP" AC_SUBST(LIBSM_CFLAGS) AC_SUBST(LIBSM_LIBS) CXXFLAGS="$CXXFLAGS -DUSE_XSMP" fi fi dnl dnl GNOMEUIを使ってセッション管理をする。libgnomeui-develが必要。 dnl if test x"$use_gnomeui" = "xyes" ; then PKG_CHECK_MODULES(GNOMEUI, [libgnomeui-2.0 >= 2.0] ) echo "use GNOMEUI" AC_SUBST(GNOMEUI_CFLAGS) AC_SUBST(GNOMEUI_LIBS) CXXFLAGS="$CXXFLAGS -DUSE_GNOMEUI" fi dnl dnl SSL dnl use_gnutls=yes AC_ARG_WITH(openssl,[ --with-openssl (use openssl)], [ if test "$withval" != "no" ;then use_gnutls=no fi ]) case "${use_gnutls}" in yes) echo "use gnutls" PKG_CHECK_MODULES(GNUTLS, [gnutls >= 1.2], [echo "gnutls >= 1.2"]) AC_DEFINE(USE_GNUTLS, , "use gnutls") AC_CHECK_HEADERS([gcrypt.h]) AC_CHECK_LIB(gcrypt, gcry_md_hash_buffer, [], [AC_MSG_ERROR([gcrypt not found])]) AC_SUBST(GNUTLS_CFLAGS) AC_SUBST(GNUTLS_LIBS) ;; *) echo "use openssl" PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9] ) AC_DEFINE(USE_OPENSSL, , "use openssl") AC_SUBST(OPENSSL_CFLAGS) AC_SUBST(OPENSSL_LIBS) ;; esac dnl dnl enable gprof dnl use_gprof=no AC_ARG_ENABLE(gprof,[ --enable-gprof (enable gprof)], [ if test "$enable_gprof" = "yes"; then echo "use gprof" CXXFLAGS="$CXXFLAGS -pg" use_gprof=yes fi ]) dnl dnl checking migemo dnl AC_ARG_WITH(migemo,[ --with-migemo (enable migemo search)], [ if test "$withval" != "no" ;then echo "use migemo" AC_CHECK_HEADERS([migemo.h]) AC_CHECK_LIB(migemo,migemo_open) fi ]) AC_ARG_WITH(migemodict,[ --with-migemodict (specifiy the path of migemo dictionary)], [ if test "$withval" ;then echo "migemodict = $withval" AC_DEFINE_UNQUOTED(MIGEMODICT, "$withval" , "migemodict") fi ]) dnl dnl checking xdg-open dnl AC_ARG_WITH(xdgopen,[ --with-xdgopen (use xdg-open as default browser)], [ if test "$withval" ;then echo "use xdg-open" AC_DEFINE(XDGOPEN, , "use xdg-open") fi ]) dnl dnl checking alsa dnl case "${host_os}" in linux*|*linux) AC_ARG_WITH(alsa,[ --with-alsa (enable alsa)], [ if test "$withval" != "no" ;then echo "use alsa" PKG_CHECK_MODULES(ALSA, [alsa >= 1.0] ) AC_DEFINE(USE_ALSA, , "use alsa") AC_SUBST(ALSA_CFLAGS) AC_SUBST(ALSA_LIBS) fi ]) ;; esac dnl dnl checking oniguruma dnl AC_ARG_WITH(oniguruma,[ --with-oniguruma (enable oniguruma)], [ if test "$withval" != "no" ;then echo "use oniguruma" AC_CHECK_PROG(ONIG_CONFIG, onig-config, onig-config) if test "x${ONIG_CONFIG}" = "x" ; then AC_MSG_ERROR([onig-config not found]) fi ONIG_CFLAGS=`onig-config --cflags` CPPFLAGS="${CPPFLAGS} ${ONIG_CFLAGS}" ONIG_LIBS=`onig-config --libs` LDFLAGS_ORIGINAL="${LDFLAGS}" LDFLAGS="${LDFLAGS} ${ONIG_LIBS}" AC_CHECK_HEADER([onigposix.h], ,[AC_MSG_ERROR([onigposix.h not found])]) AC_CHECK_LIB([onig],[regexec], ,[AC_MSG_ERROR([libonig.a not found])]) AC_DEFINE(USE_ONIG, , "use oniguruma") AC_SUBST(ONIG_LIBS) LDFLAGS="${LDFLAGS_ORIGINAL}" fi ]) dnl dnl checking PCRE dnl AC_ARG_WITH(pcre,[ --with-pcre (enable PCRE)], [ if test "$withval" != "no" ;then echo "use PCRE" PKG_CHECK_MODULES(PCRE, [libpcre >= 6.5] ) AC_DEFINE(USE_PCRE, , "use PCRE") AC_SUBST(PCRE_CFLAGS) AC_SUBST(PCRE_LIBS) AC_CHECK_HEADERS([pcreposix.h]) AC_CHECK_LIB(pcreposix,regexec) fi ]) dnl dnl checking gthread dnl AC_ARG_WITH(gthread,[ --with-gthread (use gthread instead of pthread)], [ if test "$withval" ;then echo "use gthread" AC_DEFINE(USE_GTHREAD, , "use gthread") fi ]) dnl dnl CPU別の最適化オプション dnl if test "$use_gprof" = "no"; then dnl dnl checking native (gcc >= 4.2 x86 & x86_64) dnl AC_ARG_WITH(native,[ --with-native (use native)], [ if test "$withval" != "no"; then echo "use native" CXXFLAGS="$CXXFLAGS -march=native" fi ]) dnl dnl checking core2duo dnl AC_ARG_WITH(core2duo,[ --with-core2duo (use core2duo)], [ if test "$withval" != "no"; then echo "use core2duo" CXXFLAGS="$CXXFLAGS -march=pentium-m -msse3" fi ]) dnl dnl checking athlon64 dnl AC_ARG_WITH(athlon64,[ --with-athlon64 (use athlon64)], [ if test "$withval" != "no"; then echo "use athlon64" CXXFLAGS="$CXXFLAGS -march=athlon64" fi ]) dnl dnl checking atom dnl AC_ARG_WITH(atom,[ --with-atom (use atom)], [ if test "$withval" != "no"; then echo "use atom" CXXFLAGS="$CXXFLAGS -march=prescott" fi ]) dnl dnl checking ppc7400 dnl AC_ARG_WITH(ppc7400,[ --with-ppc7400 (use PowerPC7400)], [ if test "$withval" != "no"; then echo "use ppc7400" CXXFLAGS="$CXXFLAGS -mcpu=7400 -maltivec -mabi=altivec" fi ]) dnl dnl checking ppc7450 dnl AC_ARG_WITH(ppc7450,[ --with-ppc7450 (use PowerPC7450)], [ if test "$withval" != "no"; then echo "use ppc7450" CXXFLAGS="$CXXFLAGS -mcpu=7450 -maltivec -mabi=altivec" fi ]) fi dnl dnl checking pangolayout dnl AC_ARG_WITH(pangolayout,[ --with-pangolayout (use pangolayout)], [ if test "$withval" != "no" ;then echo "use pango_layout for drawing" CXXFLAGS="$CXXFLAGS -DUSE_PANGOLAYOUT" fi ]) AC_OUTPUT(Makefile src/Makefile src/skeleton/Makefile src/jdlib/Makefile src/dbtree/Makefile src/dbimg/Makefile src/bbslist/Makefile src/board/Makefile src/article/Makefile src/image/Makefile src/message/Makefile src/history/Makefile src/config/Makefile src/icons/Makefile src/sound/Makefile src/xml/Makefile src/control/Makefile ) jd-2.8.7-140104/COPYING0000644000076400010400000004311010437333047010626 0ustar GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. jd-2.8.7-140104/INSTALL0000644000076400010400000000770712011441650010626 0ustar [ make、実行方法について ] * 動作環境 必須環境 ・gtkmm-2.4.8 以上 ・zlib-1.2 以上 ・gnutls-1.2 以上 推奨環境 ・Linux Kernel 2.6以上 ・gtkmm-2.8以上 ( 2.6より低いとレイアウトが一部崩れる、2.8より低いとスレ一覧表示が遅い ) ・UTF-8環境 ( EUC環境では LANG="ja_JP.UTF-8" を指定する必要がある ) * makeに必要なツール、ライブラリ 必須 ・autoconf ・automake ・g++ ・gnutls ・gtkmm ・libtool ・make ・zlib オプション ・alsa-lib (--with-alsa) ・libgnomeui (--with-sessionlib=gnomeui) ・openssl (--with-openssl) ・oniguruma (--with-oniguruma) ・libpcre (--with-pcre) OSやディストリビューション別の解説は"OS/ディストリビューション別インストール方法 [http://sourceforge.jp/projects/jd4linux/wiki/OS%2f%E3%83%87%E3%82%A3%E3%82%B9%E3%83%88%E3%83%AA%E3%83%93%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E5%88%A5%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%96%B9%E6%B3%95]"(wiki) を参照。 * make 方法( rpmbuild の場合 ) 1. rpmbuild -tb 〜.tgz でrpmファイルが出来るのであとは rpm -Uvh 〜.rpm 2. ライブラリが足りないといわれたら yum install 〜-devel 3. 起動はメニューから起動するか、端末で jd と打ち込んでエンターを押す。 * make 方法( configure + make の場合 ) 1. autoreconf -i ( 又は ./autogen.sh ) 2. ./configure 3. make 4. (お好みで) strip src/jd * configureオプション --with-sessionlib=[xsmp|gnomeui|no] GNOMEUIを使ってセッション管理をするには「gnomeui」を、セッション管理を無効にするには「no」を選択。デフォルトでは XSMPを使用する。 --with-pangolayout 描画にPangoLayoutを使う。デフォルトでは PangoGlyphString を使用する。 --with-migemo migemoによる検索が有効になる。migemoがUTF-8の辞書でインストールされている必要がある。 --with-[native|core2duo|athlon64|atom|ppc7400|ppc7450] CPUに合わせた最適化 --with-openssl GNU TLSではなく OpenSSLを使用する。ライセンス上バイナリ配布が出来なくなることに注意すること。 --with-alsa ALSAによる効果音再生機能を有効にする。詳しくは"http://jd4linux.sourceforge.jp/manual/"の項を参照すること。 --with-xdgopen デフォルトブラウザとしてxdg-openを使用する。 --enable-gprof gprofによるプロファイリングを行う。コンパイルオプションに -pg が付き、JDを実行すると gmon.out が出来るのでgprof./jdgmon.out で解析できる。CPUの最適化は効かなくなるので注意する。 --with-oniguruma 正規表現ライブラリとしてPOSIX regex の代わりに鬼車を使用する。鬼車はBSDライセンスなのでJDをバイナリ配布する場合には注意すること(ライセンスはGPLになる)。 --with-pcre 正規表現ライブラリとしてPOSIX regex の代わりにPCREを使用する。PCREはBSDライセンスなのでJDをバイナリ配布する場合には注意すること(ライセンスはGPLになる)。UTF-8が有効な ( --enable-utf オプションを用いて make する ) PCRE 6.5 以降が必要となる。Perl互換の正規表現なので、従来の POSIX 拡張の正規表現から設定変更が必要になる場合がある。 --with-gthread pthreadの代わりにgthreadを使用する。 * メモ 最近のディストリビューションの場合は autogen.sh よりも autoreconf -i の方を推奨。 実行するには直接 src/jd を起動するか手動で /usr/bin あたりに src/jd を cp する。 以上の操作でmakeが通らなかったり動作が変な時は configure のオプションを変更する。jd-2.8.7-140104/jd.desktop0000644000076400010400000000034610770732407011572 0ustar [Desktop Entry] Exec=jd Icon=jd Terminal=false Type=Application Name=JD 2ch browser Name[ja]=2ch ブラウザ JD Comment=JD is a 2ch browser based on gtkmm2. Comment[ja]=gtkmm2 を利用した 2ch ブラウザ Categories=Network; jd-2.8.7-140104/jd.png0000644000076400010400000001124310437333376010705 0ustar PNG  IHDR``w8sBIT|dZIDATx{E~?=ϝ}^`ΊtYĀ,8P."S0A"Q;)JEo}@r`6< `ֲf=3;Q3=J_UWկ~Ko2: Xx9DH@ƀ_S;$ .T`xk`Mly9oۀ> A" JJ!OC>wQkiidÆMA728N29adGaxS.4BB~,W.ei?`C%jn.ӵ uA:EUժOEkL&%>e!>SzXzaۊg_XkR:2Tp(|\&fpp//L=)cMִ +y꩟au.mþ'8v D…sG9lp0 |A*a4PEYg-/JouҵPגNg8} gX9۷?W˺t_<Nj7ez=LBBUU5ޓ!jY8x.eb͖y2y.|1x\q +fǎwE[1uqcZk DdU 4zoJ2ܹ/d!zz}x>|>>Ϗ' y9Raٲ%AΜ9G(m%V,>>_+fD1V\ƍYn[nEQ|7rmmD" mN㎎zzdRzzres5* BbCZD2"zu=Պ6)rW*Zu28p~6o̖-[XjU)$ ^` h4~X1---lt3ܲtr-eK!Lq%JVJ/҃u6fy`4<< 05UF6%4"D">zgOzcߨ /\}ٲek-P{Bi/Dpiv}ǓO>G}T1L]zuzf3ZhmmUrwI-}lvAv ߈\.CCC~nVn|sCC>,_B@WW9V\EOዕH-)A6^c۶m>Oٿuj\`Ag[FƇј7"Hw^}Q^z%Kn^O"p\jD P(5U+N 5/Z;A*bpp۷388hhmB~Fywd<(V@_5bgLi8qTzcѣŢsahӳBYJY0fn"199E*/s>;B:6B>Z$4QT) {UR,ccakx.L&I3OLZ[ToZW`7aOp Witt:cxGV(Bܨ܆v,}Us~5LU͛<VVt-,:a%_y8t9߿}vLO'N஻b5i[-ڙkZՐɤ˺[ס3Nws7XpXˣж/qF6mTu~ի[عi&&m)ɐϫ|Q=OC2)jѱUVsUZ܌dPU{ݻwHT,Wfٲؼif2ScWp(-cmVdn={]vqbE? [gŊs%+@r5-VpFLMM{n;VN{ɀ9FGsOm74ƴl6˾}8x` Bm( e3ȅ (5A9v팡!^}բhOxN>{>22ž={HEZcX٬ª/ҳ?׺ M*JtnINI w^rIMu2/JO)B97ӱH$'Ӎ8κ +ndhꎊlPf PkE bX6Ir#2/@*nzn2865 NH1F3MAMN)Sd2GڐS&kX7g٣eϫ;6$ ;qMQccc|h8PWr;Zn9\%FFFvB(N]V4,tZh7X4oA`#lX*%0`4 _x^C7bQS3ro? Q S[o oآd)L{2fǎ풨 ]T _:'DQ9lx<,݃q+[x<^ɴA2\g~d2SVVskv ȅuԸ&p<#5-,Y Pf=zur E^uQUͫEP!H^/`]u…]DKK!]]=e$ ɷTYobŕ]ڵغ΢rC'Y ^+]7o% 륻{1PH "O!#5tx}b₫ChWk hmm VX`!mm%8Yk׮c׮=LMH$y-WWE}B0B sAuYP=Ea >_~^y忸xjŖ PYK 7ldrr?\ZU# VTL] 믿rn 1N=O>_z41ffM56v={v* xW \\.M,6YX47yX Av;k8/gMr?m1' V)* ـ{ݣQy}/ z=~H! (;~nڂbEVB9iNOOE&D.'Lp5-<5 hfRPh&E,>7>clM f͚m,P6茛An:Ưbb1mrK۲˸LHY!@.x+ L&`PM$PuZbHg5w!ۀ=L.V+|([8_oiO"wȋ'8W֪p$t"_7y`1aCYت)O+np%r)_<r/-t!T*/N[^k{ ^B9rH8st!Dr1Sb>ߑ~:IENDB`jd-2.8.7-140104/jd.spec0000644000076400010400000000663512261751177011064 0ustar ########################################## # For using svn: do # export SVNROOT="http://svn.sourceforge.jp/svnroot/jd4linux/jd" # svn checkout $SVNROOT/trunk # mv trunk jd-%%{main_ver}-%%{strtag} # tar czf jd-%%{main_ver}-%%{strtag}.tgz jd-%%{main_ver}-%%{strtag} ########################################## ########################################## # Defined by upsteam # %define main_ver 2.8.7 %define strtag 140104 %define repoid ????? # Define this if this is pre-version %define pre_release 0 ########################################## ########################################## # Defined by vendor # %define vendor_rel 1 # Tag name changed from vendor to vendorname so as not to # overwrite Vendor entry in Summary %define vendorname fedora %define gtkmmdevel gtkmm24-devel %define fontpackage fonts-japanese %define icondir %{_datadir}/icons/hicolor/96x96/apps/ ########################################## ########################################## %if %{pre_release} %define rel 0.%{vendor_rel}.%{strtag}%{?dist} %else %define rel %{vendor_rel}%{?dist} %endif # By default, Migemo support is disabled. %if 0%{?fedora} >= 5 %define _with_migemo 1 %endif %define migemo_dict %{_datadir}/cmigemo/utf-8/migemo-dict ########################################## Name: jd Version: %{main_ver} Release: %{rel} Summary: A 2ch browser Group: Applications/Internet License: GPLv2 URL: http://jd4linux.sourceforge.jp/ Source0: http://downloads.sourceforge.jp/jd4linux/%{repoid}/%{name}-%{main_ver}-%{strtag}.tgz #Source0: %{name}-%{main_ver}-%{strtag}.tgz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: %{gtkmmdevel} BuildRequires: libtool automake BuildRequires: gnutls-devel BuildRequires: desktop-file-utils BuildRequires: libSM-devel %if 0%{?_with_migemo} >= 1 BuildRequires: cmigemo-devel %endif Requires: %{fontpackage} %description JD is a 2ch browser based on gtkmm2. %prep %setup -q -n %{name}-%{main_ver}-%{strtag} #find . -name .svn | sort -r | xargs %{__rm} -rf %build sh autogen.sh # set TZ for __TIME__ export TZ='Asia/Tokyo' %configure \ %if 0%{?_with_migemo} >= 1 --with-migemo \ --with-migemodict=%{migemo_dict} %endif %{__make} %{?_smp_mflags} %install %{__rm} -rf $RPM_BUILD_ROOT %{__make} install DESTDIR=$RPM_BUILD_ROOT %{__mkdir_p} $RPM_BUILD_ROOT%{icondir} %{__install} -p -m 644 %{name}.png $RPM_BUILD_ROOT%{icondir} desktop-file-install \ --vendor %{vendorname} \ --dir $RPM_BUILD_ROOT%{_datadir}/applications \ --delete-original \ $RPM_BUILD_ROOT%{_datadir}/applications/%{name}.desktop %clean %{__rm} -rf $RPM_BUILD_ROOT %post touch --no-create %{_datadir}/icons/hicolor || : %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || : %postun touch --no-create %{_datadir}/icons/hicolor || : %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || : %files %defattr(-,root,root,-) %doc COPYING ChangeLog README %{_bindir}/%{name} %{_datadir}/applications/%{vendorname}-%{name}.desktop %{_datadir}/pixmaps/%{name}.png %{icondir}/%{name}.png %changelog * Sun Mar 9 2006 Houritsuchu - Version up. - add icon * Sat Feb 25 2006 Houritsuchu - first jd-2.8.7-140104/Makefile.am0000644000076400010400000000460112101405306011615 0ustar SUBDIRS = src desktopdir= $(datadir)/applications desktop_DATA = jd.desktop icondir = $(datadir)/pixmaps icon_DATA = jd.png EXTRA_DIST = AUTHORS TODO README configure jd_BUILDINFO_HEADER = buildinfo.h jd_CONFIGURE_ARGS = @ac_configure_args@ all: $(jd_BUILDINFO_HEADER) .PHONY: $(jd_BUILDINFO_HEADER) $(jd_BUILDINFO_HEADER): @-rm -f $@.new @echo '/* This file is generated from Makefile by make. */' >> $@.new @echo '#ifndef _BUILDINFO_H' >> $@.new @echo '#define _BUILDINFO_H' >> $@.new @echo '' >> $@.new @echo '// Build information.' >> $@.new @if test -n "$(CC)"; \ then \ CC_INFO=$(CC); \ CC_VERSION=`LANG=C $(CC) -dumpversion 2>/dev/null`; \ test -n "$${CC_VERSION}" && CC_INFO="$(CC)($${CC_VERSION})"; \ echo "#define CC_INFO \"$${CC_INFO}\"" >> $@.new; \ fi @if test -n "$(CXX)"; \ then \ CXX_INFO=$(CXX); \ CXX_VERSION=`LANG=C $(CXX) -dumpversion 2>/dev/null`; \ test -n "$${CXX_VERSION}" && CXX_INFO="$(CXX)($${CXX_VERSION})"; \ echo "#define CXX_INFO \"$${CXX_INFO}\"" >> $@.new; \ fi @if test -n "$(jd_CONFIGURE_ARGS)"; \ then \ echo "#define CONFIGURE_ARGS \"$(jd_CONFIGURE_ARGS)\"" >> $@.new; \ fi @echo '' >> $@.new @echo '// Version information of SVN.' >> $@.new @if test -n "$(SVN)" -a -n "$(AWK)"; \ then \ SVN_REPOSITORY=`LANG=C "$(SVN)" info 2>/dev/null | $(AWK) '/^URL/ {print $$2}' 2>/dev/null`; \ if test -n "$${SVN_REPOSITORY}"; \ then \ echo "SVN: Repository = \"$${SVN_REPOSITORY}\""; \ echo "#define SVN_REPOSITORY \"$${SVN_REPOSITORY}\"" >> $@.new; \ fi \ fi @if test -n "$(SVNVERSION)"; \ then \ SVN_REVISION=`LANG=C "$(SVNVERSION)" -n 2>/dev/null`; \ if test -n "$${SVN_REVISION}" -a "$${SVN_REVISION}" != "exported"; \ then \ echo "SVN: Revision = \"$${SVN_REVISION}\""; \ echo "#define SVN_REVISION \"$${SVN_REVISION}\"" >> $@.new; \ fi \ fi @echo '' >> $@.new @echo '#endif' >> $@.new @if test ! -e $@; \ then \ echo '$@: Created.'; \ mv -f $@.new $@; \ elif test -z "$(XSUM)"; \ then \ echo '$@: Refreshed.'; \ mv -f $@.new $@; \ else \ HASH1=`cat $@ | $(XSUM)`; \ HASH2=`cat $@.new | $(XSUM)`; \ if test "$${HASH1}" = "$${HASH2}"; \ then \ echo '$@: Not modified.'; \ rm -f $@.new; \ else \ echo '$@: Modified.'; \ mv -f $@.new $@; \ fi \ fi jd-2.8.7-140104/NEWS0000644000076400010400000000007710626304033010270 0ustar http://jd4linux.sourceforge.jp/manual/を見てください。 jd-2.8.7-140104/README0000644000076400010400000001035312261751177010463 0ustar [ JDについて ] ここに書かれていない詳細については"http://jd4linux.sourceforge.jp/"や "http://sourceforge.jp/projects/jd4linux/wiki/FrontPage"を参照してください。 * 概要 JDはGTK+2(gtkmm)を使用した"2ちゃんねる [http://www.2ch.net/]"型マルチスレッドBBSを閲覧するためのブラウザです。 * 著作権 ©2006-2014 "JD Project [http://sourceforge.jp/projects/jd4linux/]" パッチやファイルを取り込んだ場合、それらのコピーライトは「JD Project」に統一します。 * ライセンス "GNU General Public License, version 2 [http://sourceforge.jp/projects/opensource/wiki/licenses%2FGNU_General_Public_License]" 将来的にライセンスをGPL3に変更するかもしれません。GPL3以降へのライセンス変更に関してはプロジェクトリーダーに一任させて頂きます。 * 連絡先 バグ報告その他は"Linux板@2ちゃんねる [http://www.2ch.net/linux/]"のJDスレ、またはJDのヘルプメニューから行くことが出来るサポート掲示板にて行ってください。 * 動作プラットフォーム LinuxなどのUnixライクなOS(FreeBSD,OpenBSD,Nexenta,MacOSXでも動作報告例があります)。 WindowsではMinGWを使ってビルド可能ですが、動作はまだ安定していないようです。 * 通常の起動 使い方は以下のとおり。 $ jd [OPTION] [URL,FILE] 引数にURLを付けて起動する事も出来るので、他のアプリケーションから外部コマンドとしてURLを開く事などが出来る。(JDが扱う事の出来るURLでない場合は設定されているWebブラウザに渡される) $ jd http://pc99.2ch.net/test/read.cgi/linux/1234567890/ ローカルにあるdatファイルを指定して、一時的にスレビュー表示させることも出来る。 $ jd ./12345.dat 環境変数 JD_CACHE でキャッシュディレクトリの位置を変更・指定することが可能。指定しなければ ~/.jd がキャッシュディレクトリになる。 $ JD_CACHE=~/.mycache jd 環境変数 JD_LOCK でロックファイルの位置を変更・指定することが可能。指定しなければ ~/.jd/JDLOCK がロックファイルになる。 $ JD_LOCK=~/mylock jd オプション -h, --help ヘルプを表示 -m, --multi 多重起動時のサブプロセスであっても終了しない -n, --norestore 前回異常終了した時にバックアップファイルを復元しない -s, --skip-setup 初回起動時の設定ダイアログを表示しない -l, --logfile エラーなどのメッセージをファイル(キャッシュディレクトリのlog/msglog)に出力する -g, --geometry WxH-X+Y 幅(W)高さ(H)横位置(X)縦位置(Y)の指定。WxHは省略化(例: -g 100x40-10+30, -g -20+100 ) -V, --version バージョン及びconfigureオプションを全て表示 * 多重起動について JDはメインプロセス/サブプロセスという関係で動作する。 メインプロセス: 指令を受け取る事が出来るプロセス サブプロセス : 指令を出す事が出来るプロセス 通常は最初に起動した物がメインプロセスとなり、メインプロセスは1つだけ存在する事が出来る。メインプロセスが存在する状態で起動したプロセスはサブプロセスとして扱われ、複数存在させる事も可能。なお、指令を受け取るのはメインプロセスのみなので、指令を出す側のサブプロセスでURLは開かれない。 以下のコマンドを使い分ける事でサブプロセスの起動のしかたをコントロール出来る。 a. 起動するかどうか確認してサブプロセスを起動 $ jd b. 確認せずにサブプロセスを起動 $ jd -m c. メインプロセスにを渡してサブプロセスを起動 $ jd -m http://pc99.2ch.net/test/read.cgi/linux/1234567890/ 注: サブプロセスを残したままメインプロセスを終了していた場合は次に起動したプロセスがメインプロセスとなる。jd-2.8.7-140104/src/0000755000076400010400000000000012261751613010363 5ustar jd-2.8.7-140104/src/aamanager.cpp0000644000076400010400000001775511437471144013024 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "aamanager.h" #include "jdlib/miscutil.h" #include "xml/document.h" #include "xml/tools.h" #include "config/globalconf.h" #include "cache.h" #include "type.h" CORE::AAManager* instance_aamanager = NULL; CORE::AAManager* CORE::get_aamanager() { if( ! instance_aamanager ) instance_aamanager = new CORE::AAManager(); return instance_aamanager; } void CORE::delete_aamanager() { if( instance_aamanager ) delete instance_aamanager; instance_aamanager = NULL; } //////////////////////////////////// // ルート要素名 #define ROOT_NODE_NAME "history" enum { AA_LIMIT = 4096 }; using namespace CORE; AAManager::AAManager() { #ifdef _DEBUG std::cout << "AAManager::AAManager\n"; #endif load_label(); load_history(); } AAManager::~AAManager() { #ifdef _DEBUG std::cout << "AAManager::~AAManager\n"; #endif } // // ラベル、AA読み込み // void AAManager::load_label() { std::string aa_lines; if( CACHE::load_rawdata( CACHE::path_aalist(), aa_lines ) ){ std::list< std::string > list_label = MISC::get_lines( aa_lines ); list_label = MISC::remove_nullline_from_list( list_label ); std::list< std::string >::iterator it = list_label.begin(); for( int id = 0 ; it != list_label.end() ; ++it, ++id ) { std::string asciiart = *it; m_vec_label.push_back( asciiart ); #ifdef _DEBUG std::cout << "id = " << id << " label = " << asciiart << std::endl; #endif // 先頭に"**"がある場合は、"*"を一つ取り除いて一行AAとして扱う if( asciiart.find( "**", 0 ) == 0 ) { // **example -> *example asciiart.erase( 0, 1 ); } // "*"が一つだけある場合は、"*"を取り除いてファイル名とみなす else if( asciiart.find( "*", 0 ) == 0 ) { // *example -> example asciiart.erase( 0, 1 ); // example -> .jd/aa/example std::string aafile_path = CACHE::path_aadir().append( asciiart ); #ifdef _DEBUG std::cout << "load : " << aafile_path << std::endl; #endif // ファイルが存在しなければ".txt"を追加( .jd/aa/example -> .jd/aa/example.txt ) if( CACHE::file_exists( aafile_path ) != CACHE::EXIST_FILE ) aafile_path.append( ".txt" ); // ファイル読み込み if( CACHE::file_exists( aafile_path ) != CACHE::EXIST_FILE ) asciiart = aafile_path + " が存在しません"; else if( CACHE::get_filesize( aafile_path ) > AA_LIMIT ) asciiart = "ファイルサイズが大きすぎます"; else CACHE::load_rawdata( aafile_path, asciiart ); } #ifdef _DEBUG std::cout << "AA : " << asciiart << std::endl; #endif m_vec_aa.push_back( asciiart ); // ショートカット char shortcut = 0; const int base_a = 10; const int base_A = base_a + 'z' - 'a' -4 + 1; if( id <= 9 ) shortcut = '0' + id; else if( id <= base_a + 'z' - 'a' -4 ){ shortcut = 'a' + id - base_a; if( shortcut >= 'h' ) ++shortcut; // hを除く if( shortcut >= 'j' ) shortcut += 3; // j,k,lを除く } else if( id <= base_A + 'Z' - 'A' ){ shortcut = 'A' + id - base_A; } if( shortcut ) m_map_shortcut.insert( std::make_pair( id, shortcut ) ); } } } // // 履歴読み込み // void AAManager::load_history() { #ifdef _DEBUG std::cout << "AAManager::load_history\n"; #endif std::string xml; if( ! CACHE::load_rawdata( CACHE::path_aahistory(), xml ) ) return; #ifdef _DEBUG std::cout << xml << std::endl; #endif XML::Document document( xml ); XML::Dom* root = document.get_root_element( std::string( ROOT_NODE_NAME ) ); if( ! root ) return; std::list< std::string > tmp_history; XML::DomList domlist = root->childNodes(); std::list< XML::Dom* >::iterator it = domlist.begin(); for( ; it != domlist.end() && (int) tmp_history.size() < CONFIG::get_aahistory_size(); ++it ){ if( ( *it )->nodeType() == XML::NODE_TYPE_ELEMENT ){ const int type = XML::get_type( (*it)->nodeName() ); const std::string name = (*it)->getAttribute( "name" ); if( type == TYPE_AA && ! name.empty() ) tmp_history.push_back( name ); } } std::vector< bool > tmp_vec; tmp_vec.resize( get_size() ); std::list< std::string >::iterator it_hist = tmp_history.begin(); for( ; it_hist != tmp_history.end(); ++it_hist ){ for( int i = 0; i < get_size() ; ++i ){ if( ! tmp_vec[ i ] && m_vec_label[ i ] == *it_hist ){ m_history.push_back( i ); tmp_vec[ i ] = true; break; } } } #ifdef _DEBUG std::list< int >::iterator it_history = m_history.begin(); for( ; it_history != m_history.end(); ++it_history ) std::cout << *it_history << std::endl; #endif } // // 履歴保存 // void AAManager::save_history() { #ifdef _DEBUG std::cout << "AAManager::save_history\n"; #endif XML::Document document; XML::Dom* root = document.appendChild( XML::NODE_TYPE_ELEMENT, std::string( ROOT_NODE_NAME ) ); std::list< int >::iterator it = m_history.begin(); for( ; it != m_history.end(); ++it ){ const Glib::ustring name = m_vec_label[ *it ]; if( ! name.empty() ){ XML::Dom* node = root->appendChild( XML::NODE_TYPE_ELEMENT, XML::get_name( TYPE_AA ) ); node->setAttribute( "name", name ); } } std::string xml; if( root->hasChildNodes() ) xml = document.get_xml(); #ifdef _DEBUG std::cout << xml << std::endl; #endif if( ! xml.empty() ) CACHE::save_rawdata( CACHE::path_aahistory(), xml ); } // ラベル、AA取得 const std::string AAManager::get_label( const int id ) { if( id >= (int) m_vec_label.size() ) return std::string(); return m_vec_label[ id ]; } const std::string AAManager::get_aa( const int id ) { if( id >= (int) m_vec_aa.size() ) return std::string(); return m_vec_aa[ id ]; } // // ショートカットキー取得 // const std::string AAManager::id2shortcut( const int id ) { if( id >= (int) m_map_shortcut.size() ) return std::string(); #ifdef _DEBUG std::cout << "AAManager::id2shortcut id = " << id << std::endl; #endif int key = m_map_shortcut[ id ]; if( !key ) return std::string(); char tmpchar[2]; tmpchar[0] = key; tmpchar[1] = '\0'; return std::string( tmpchar ); } // ショートカットからid取得 const int AAManager::shortcut2id( const char key ) { if( key == '\0' ) return -1; std::map< int, char >::iterator it = m_map_shortcut.begin(); for( ; it != m_map_shortcut.end(); ++it ){ if( (*it).second == key ) return (*it).first; } return -1; } // id 番を履歴に追加 void AAManager::append_history( const int id ) { if( id >= 0 && id < get_size() ){ // 既に履歴に含まれている場合 std::list< int >::iterator it = m_history.begin(); for( ; it != m_history.end(); ++it ){ if( *it == id ){ m_history.remove( id ); m_history.push_front( id ); return; } } // 含まれていない場合 while( (int) m_history.size() >= CONFIG::get_aahistory_size() ) m_history.pop_back(); m_history.push_front( id ); } } // num 番目の履歴をIDに変換 const int AAManager::history2id( const int num ) { if( num < 0 || num >= get_historysize() ) return -1; std::list< int >::iterator it = m_history.begin(); for( int i = 0; i < num; ++i, ++it ); #ifdef _DEBUG std::cout << "AAManager::conv_history2id " << num << " -> " << *it << std::endl; #endif return *it; } jd-2.8.7-140104/src/aamanager.h0000644000076400010400000000252511437471144012456 0ustar // ライセンス: GPL2 // // AA 管理クラス // #ifndef _AAMANAGER_H #define _AAMANAGER_H #include #include #include #include namespace CORE { class AAManager { std::list< int > m_history; // 履歴 std::vector< std::string > m_vec_label; // メニューに表示するラベル std::vector< std::string > m_vec_aa; // AA (1行AAの場合はラベルと同じ) std::map< int, char > m_map_shortcut; // ショートカットキー public: AAManager(); virtual ~AAManager(); const int get_size(){ return m_vec_label.size(); } const int get_historysize(){ return m_history.size(); } const std::string get_label( const int id ); const std::string get_aa( const int id ); // ショートカットキー取得 const std::string id2shortcut( const int id ); // ショートカットからid取得 const int shortcut2id( const char key ); // id 番を履歴に追加 void append_history( const int id ); // num 番目の履歴をIDに変換 const int history2id( const int num ); void save_history(); private: void load_label(); void load_history(); }; CORE::AAManager* get_aamanager(); void delete_aamanager(); } #endif jd-2.8.7-140104/src/article/0000755000076400010400000000000012261751607012011 5ustar jd-2.8.7-140104/src/article/articleadmin.cpp0000644000076400010400000005612011617532134015151 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articleadmin.h" #include "articleviewbase.h" #include "font.h" #include "toolbar.h" #include "toolbarsimple.h" #include "toolbarsearch.h" #include "dbtree/interface.h" #include "jdlib/miscutil.h" #include "jdlib/jdregex.h" #include "jdlib/miscmsg.h" #include "jdlib/timeout.h" #include "skeleton/view.h" #include "skeleton/dragnote.h" #include "icons/iconmanager.h" #include "history/historymanager.h" #include "global.h" #include "type.h" #include "viewfactory.h" #include "sharedbuffer.h" #include "session.h" #include "command.h" #include "config/globalconf.h" #include "dndmanager.h" ARTICLE::ArticleAdmin *instance_articleadmin = NULL; ARTICLE::ArticleAdmin* ARTICLE::get_admin() { if( ! instance_articleadmin ) instance_articleadmin = new ARTICLE::ArticleAdmin( URL_ARTICLEADMIN ); assert( instance_articleadmin ); return instance_articleadmin; } void ARTICLE::delete_admin() { if( instance_articleadmin ) delete instance_articleadmin; instance_articleadmin = NULL; } using namespace ARTICLE; ArticleAdmin::ArticleAdmin( const std::string& url ) : SKELETON::Admin( url ), m_toolbar( NULL ), m_toolbarsimple( NULL ), m_search_toolbar( NULL ) { set_use_viewhistory( true ); set_use_switchhistory( true ); ARTICLE::init_font(); get_notebook()->set_dragable( true ); get_notebook()->set_fixtab( false ); if( ! SESSION::get_show_article_tab() ) get_notebook()->set_show_tabs( false ); setup_menu(); // スムーススクロール用タイマセット // オートスクロール時など、スムースにスクロールをするため描画用タイマーを // メインタイマと別にする。DrawAreaBase::clock_in_smooth_scroll() も参照すること sigc::slot< bool > slot_timeout = sigc::bind( sigc::mem_fun(*this, &ArticleAdmin::clock_in_smooth_scroll ), 0 ); JDLIB::Timeout::connect( slot_timeout, TIMER_TIMEOUT_SMOOTH_SCROLL ); } ArticleAdmin::~ArticleAdmin() { #ifdef _DEBUG std::cout << "ArticleAdmin::~ArticleAdmin\n"; #endif if( m_toolbar ) delete m_toolbar; if( m_toolbarsimple ) delete m_toolbarsimple; if( m_search_toolbar ) delete m_search_toolbar; ARTICLE::init_font(); } void ArticleAdmin::save_session() { Admin::save_session(); SESSION::set_article_URLs( get_URLs() ); SESSION::set_article_locked( get_locked() ); SESSION::set_article_switchhistory( get_switchhistory() ); SESSION::set_article_page( get_current_page() ); } bool ArticleAdmin::clock_in_smooth_scroll( int timer_number ) { // アクティブなビューにクロックを送る ArticleViewBase* view = dynamic_cast< ArticleViewBase* >( get_current_view() ); if( view ) view->clock_in_smooth_scroll(); return true; } // 前回開いていたURLを復元 void ArticleAdmin::restore( const bool only_locked ) { #ifdef _DEBUG std::cout << "ArticleAdmin::restore\n"; #endif int set_page_num = 0; const bool online = SESSION::is_online(); SESSION::set_online( false ); const std::list< std::string >& list_url = SESSION::get_article_URLs(); std::list< std::string >::const_iterator it_url = list_url.begin(); std::list< std::string > list_switchhistory = SESSION::get_article_switchhistory(); const std::list< bool >& list_locked = SESSION::get_article_locked(); std::list< bool >::const_iterator it_locked = list_locked.begin(); for( int page = 0; it_url != list_url.end(); ++it_url, ++page ){ // タブのロック状態 bool lock = false; if( it_locked != list_locked.end() ){ if( (*it_locked ) ) lock = true; ++it_locked; } // ロックされているものだけ表示 if( only_locked && ! lock ){ list_switchhistory.remove( *it_url ); continue; } if( page == SESSION::article_page() ) set_page_num = get_tab_nums(); COMMAND_ARGS command_arg = url_to_openarg( *it_url, true, lock ); // 板がDBに登録されていない場合は表示しない if( command_arg.url != URL_SEARCH_ALLBOARD && command_arg.arg4 != "SEARCHTITLE" && command_arg.arg4 != "POSTLOG" && DBTREE::url_boardbase( *it_url ).empty() ){ MISC::ERRMSG( *it_url + " is not registered" ); list_switchhistory.remove( *it_url ); continue; } if( command_arg.arg4 == "MAIN" && DBTREE::url_dat( *it_url ).empty() ){ list_switchhistory.remove( *it_url ); continue; } // Admin::open_view() 中の create_viewhistory()やappend_viewhistory()を実行しない // Admin::Open_view()も参照すること const bool use_history = get_use_viewhistory(); set_use_viewhistory( false ); open_view( command_arg ); set_use_viewhistory( use_history ); } set_switchhistory( list_switchhistory ); SESSION::set_online( online ); if( get_tab_nums() ) set_command( "set_page", std::string(), MISC::itostr( set_page_num ) ); } COMMAND_ARGS ArticleAdmin::url_to_openarg( const std::string& url, const bool tab, const bool lock ) { JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; COMMAND_ARGS command_arg; command_arg.command = "open_view"; command_arg.url = std::string(); #ifdef _DEBUG std::cout << "ArticleAdmin::url_to_openarg url = " << url << std::endl; #endif // レス抽出 if( regex.exec( std::string( "(.*)" ) + ARTICLE_SIGN + RES_SIGN + "(.*)" + CENTER_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "RES"; command_arg.arg5 = regex.str( 2 ); if( regex.str( 3 ) != "0" ) command_arg.arg6 = regex.str( 3 ); } // 名前抽出 else if( regex.exec( std::string( "(.*)" ) + ARTICLE_SIGN + NAME_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "NAME"; command_arg.arg5 = regex.str( 2 ); } // ID抽出 else if( regex.exec( std::string( "(.*)" ) + ARTICLE_SIGN + ID_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "ID"; command_arg.arg5 = regex.str( 2 ); } // ブックマーク抽出 else if( regex.exec( std::string( "(.*)" ) + ARTICLE_SIGN + BOOKMK_SIGN, url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "BM"; } // 書き込み抽出 else if( regex.exec( std::string( "(.*)" ) + ARTICLE_SIGN + POST_SIGN, url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "POST"; } // URL抽出 else if( regex.exec( std::string( "(.*)" ) + ARTICLE_SIGN + URL_SIGN, url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "URL"; } // 参照 else if( regex.exec( std::string( "(.*)" ) + ARTICLE_SIGN + REFER_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "REF"; command_arg.arg5 = regex.str( 2 ); } // キーワード else if( regex.exec( std::string( "(.*)" ) + ARTICLE_SIGN + KEYWORD_SIGN + "(.*)" + ORMODE_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; if( regex.str( 3 ) == "1" ) command_arg.arg4 = "KEYWORD_OR"; else command_arg.arg4 = "KEYWORD"; command_arg.arg5 = regex.str( 2 ); } // 書き込みログ表示 else if( regex.exec( std::string( "(.*)" ) + POSTLOG_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar ) ){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "POSTLOG"; command_arg.arg5 = regex.str( 2 ); // ログ番号 } // キャッシュのログ検索 else if( regex.exec( std::string( "(.*)" ) + BOARD_SIGN + KEYWORD_SIGN + "(.*)" + ORMODE_SIGN + "(.*)" + BOOKMK_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; if( command_arg.url == URL_SEARCH_ALLBOARD ) command_arg.arg4 = "SEARCHALLLOG"; else command_arg.arg4 = "SEARCHLOG"; command_arg.arg5 = regex.str( 2 ); // query command_arg.arg6 = "noexec"; // Viewを開いた直後に検索を実行しない if( regex.str( 3 ) == "1" ) command_arg.arg7 = "OR"; if( regex.str( 4 ) == "1" ) command_arg.arg8 = "BM"; } // スレタイ検索 else if( regex.exec( std::string( "(.*)" ) + TITLE_SIGN + KEYWORD_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // command.url を開いてるかチェックする if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "SEARCHTITLE"; command_arg.arg5 = regex.str( 2 ); // query command_arg.arg6 = "noexec"; // Viewを開いた直後に検索を実行しない } // 通常のスレ else if( !url.empty() ){ command_arg.url = url; if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // 既に開いているかチェック if( lock ) command_arg.arg3 = "lock"; command_arg.arg4 = "MAIN"; } #ifdef _DEBUG std::cout << command_arg.url << std::endl << command_arg.arg1 << std::endl << command_arg.arg2 << std::endl << command_arg.arg3 << std::endl << command_arg.arg4 << std::endl << command_arg.arg5 << std::endl << command_arg.arg6 << std::endl << command_arg.arg7 << std::endl << command_arg.arg8 << std::endl << std::endl; #endif return command_arg; } const std::string ArticleAdmin::command_to_url( const COMMAND_ARGS& command ) { std::string url; if( command.arg4 == "RES" ){ url = command.url + ARTICLE_SIGN + RES_SIGN + command.arg5 + CENTER_SIGN; if( ! command.arg6.empty() ) url += command.arg6; else url += "0"; return url; } if( command.arg4 == "NAME" ) return command.url + ARTICLE_SIGN + NAME_SIGN + command.arg5; if( command.arg4 == "ID" ) return command.url + ARTICLE_SIGN + ID_SIGN + command.arg5; if( command.arg4 == "BM" ) return command.url + ARTICLE_SIGN + BOOKMK_SIGN; if( command.arg4 == "POST" ) return command.url + ARTICLE_SIGN + POST_SIGN; if( command.arg4 == "URL" ) return command.url + ARTICLE_SIGN + URL_SIGN; if( command.arg4 == "REF" ) return command.url + ARTICLE_SIGN + REFER_SIGN + command.arg5; if( command.arg4 == "KEYWORD" ) return command.url + ARTICLE_SIGN + KEYWORD_SIGN + command.arg5 + ORMODE_SIGN + "0"; if( command.arg4 == "KEYWORD_OR" ) return command.url + ARTICLE_SIGN + KEYWORD_SIGN + command.arg5 + ORMODE_SIGN + "1"; if( command.arg4 == "POSTLOG" ) return command.url + POSTLOG_SIGN + command.arg5; if( command.arg4 == "SEARCHALLLOG" || command.arg4 == "SEARCHLOG" ){ url = command.url + BOARD_SIGN + KEYWORD_SIGN + command.arg5; url += ORMODE_SIGN; if( command.arg7 == "OR" ) url += "1"; else url += "0"; url += BOOKMK_SIGN; if( command.arg8 == "BM" ) url += "1"; else url += "0"; return url; } if( command.arg4 == "SEARCHTITLE" ) return command.url + TITLE_SIGN + KEYWORD_SIGN + command.arg5; return command.url; } void ArticleAdmin::switch_admin() { if( ! has_focus() ) CORE::core_set_command( "switch_article" ); } void ArticleAdmin::restore_lasttab() { HISTORY::restore_history( URL_HISTCLOSEVIEW ); } // // リストで与えられたページをタブで連続して開くとき(Admin::open_list())の引数セット // COMMAND_ARGS ArticleAdmin::get_open_list_args( const std::string& url, const COMMAND_ARGS& command_list ) { COMMAND_ARGS command_arg; command_arg.arg4 = "MAIN"; return command_arg; } // // カレントビューでポップアップ表示していたら消す // void ArticleAdmin::delete_popup() { SKELETON::View* view = get_current_view(); if( view ) view->set_command( "delete_popup" ); } // // 全ポップアップを消す // void ArticleAdmin::delete_all_popups() { std::list< SKELETON::View* > list_view = get_list_view(); std::list< SKELETON::View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); if( view ) view->set_command( "delete_popup" ); } } // // view の作成 // SKELETON::View* ArticleAdmin::create_view( const COMMAND_ARGS& command ) { #ifdef _DEBUG std::cout << "ArticleAdmin::create_view : " << command.arg4 << std::endl; #endif delete_popup(); int type = CORE::VIEW_NONE; CORE::VIEWFACTORY_ARGS view_args; // メインビュー if( command.arg4 == "MAIN" ){ type = CORE::VIEW_ARTICLEVIEW; } // レス抽出ビュー else if( command.arg4 == "RES" ){ type = CORE::VIEW_ARTICLERES; } // 名前抽出ビュー else if( command.arg4 == "NAME" ){ type = CORE::VIEW_ARTICLENAME; } // ID 抽出ビュー else if( command.arg4 == "ID" ){ type = CORE::VIEW_ARTICLEID; } // ブックマーク抽出ビュー else if( command.arg4 == "BM" ){ type = CORE::VIEW_ARTICLEBM; } // 書き込み抽出ビュー else if( command.arg4 == "POST" ){ type = CORE::VIEW_ARTICLEPOST; } // URL抽出ビュー else if( command.arg4 == "URL" ){ type = CORE::VIEW_ARTICLEURL; } // 参照抽出ビュー else if( command.arg4 == "REF" ){ type = CORE::VIEW_ARTICLEREFER; } // キーワード抽出ビュー else if( command.arg4 == "KEYWORD" || command.arg4 == "KEYWORD_OR" ){ type = CORE::VIEW_ARTICLEDRAWOUT; } // 書き込みログ表示 else if( command.arg4 == "POSTLOG" ){ type = CORE::VIEW_ARTICLEPOSTLOG; } // ログ検索 else if( command.arg4 == "SEARCHLOG" ){ type = CORE::VIEW_ARTICLESEARCHLOG; view_args.arg1 = command.arg6; // exec } // 全キャッシュログ検索 else if( command.arg4 == "SEARCHALLLOG" ){ type = CORE::VIEW_ARTICLESEARCHALLLOG; view_args.arg1 = command.arg6; // exec } // スレタイ検索 else if( command.arg4 == "SEARCHTITLE" ){ type = CORE::VIEW_ARTICLESEARCHTITLE; view_args.arg1 = command.arg6; // exec } else return NULL; SKELETON::View* view = CORE::ViewFactory( type, command_to_url( command ), view_args ); assert( view != NULL ); return view; } // // ツールバー表示 // void ArticleAdmin::show_toolbar() { // まだ作成されていない場合は作成する if( ! m_toolbar ){ // 通常のツールバー( TOOLBAR_ARTICLE ) m_toolbar = new ArticleToolBar(); get_notebook()->append_toolbar( *m_toolbar ); // 簡易版ツールバー( TOOLBAR_SIMPLE ) m_toolbarsimple = new ArticleToolBarSimple(); get_notebook()->append_toolbar( *m_toolbarsimple ); // ログ検索などのツールバー( TOOLBAR_SEARCH ) m_search_toolbar = new SearchToolBar(); get_notebook()->append_toolbar( *m_search_toolbar ); if( SESSION::get_show_article_toolbar() ){ m_toolbar->open_buttonbar(); m_toolbarsimple->open_buttonbar(); m_search_toolbar->open_buttonbar(); } } get_notebook()->show_toolbar(); } // // ツールバー表示/非表示切り替え // void ArticleAdmin::toggle_toolbar() { if( ! m_toolbar ) return; if( SESSION::get_show_article_toolbar() ){ m_toolbar->open_buttonbar(); m_toolbarsimple->open_buttonbar(); m_search_toolbar->open_buttonbar(); switch( get_notebook()->get_current_toolbar() ){ case TOOLBAR_ARTICLE: m_toolbar->show_toolbar(); break; case TOOLBAR_SIMPLE: m_toolbarsimple->show_toolbar(); break; case TOOLBAR_SEARCH: m_search_toolbar->show_toolbar(); break; } } else{ m_toolbar->close_buttonbar(); m_toolbarsimple->close_buttonbar(); m_search_toolbar->close_buttonbar(); } } // // 検索バー表示 // void ArticleAdmin::open_searchbar() { if( ! m_toolbar ) return; SKELETON::View* view = get_current_view(); if( ! view ) return; m_toolbar->open_searchbar(); m_toolbarsimple->open_searchbar(); m_search_toolbar->open_searchbar(); switch( get_notebook()->get_current_toolbar() ){ case TOOLBAR_ARTICLE: m_toolbar->show_toolbar(); m_toolbar->focus_entry_search(); break; case TOOLBAR_SIMPLE: m_toolbarsimple->show_toolbar(); m_toolbarsimple->focus_entry_search(); break; case TOOLBAR_SEARCH: m_search_toolbar->show_toolbar(); m_search_toolbar->focus_entry_search(); break; } } // // 検索バー非表示 // void ArticleAdmin::close_searchbar() { if( ! m_toolbar ) return; m_toolbar->close_searchbar(); m_toolbarsimple->close_searchbar(); m_search_toolbar->close_searchbar(); } // // ローカルなコマンド // void ArticleAdmin::command_local( const COMMAND_ARGS& command ) { if( command.command == "goto_num" ){ SKELETON::View* view = get_view( command.url ); if( view ) view->set_command( "goto_num", command.arg1, command.arg2 ); } // ポップアップを消去 else if( command.command == "delete_popup" ) delete_popup(); // 全ポップアップを消去 else if( command.command == "delete_all_popups" ) delete_all_popups(); // ポップアップメニューの再作成 else if( command.command == "reset_popupmenu" ){ std::list< SKELETON::View* > list_view = get_list_view(); std::list< SKELETON::View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); if( view ) view->set_command( "reset_popupmenu" ); } } // command.url を含むビューを全て再レイアウト else if( command.command == "relayout_views" ){ std::list< SKELETON::View* > list_view = get_list_view( command.url ); std::list< SKELETON::View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); if( view ) view->relayout(); } } // フォント初期化 else if( command.command == "init_font" ) ARTICLE::init_font(); // ハイライト解除 else if( command.command == "clear_highlight" ){ SKELETON::View* view = get_view( command.url ); if( view ) view->set_command( "clear_highlight" ); } // 実況開始/停止 else if( command.command == "live_start_stop" ){ SKELETON::View* view = get_view( command.url ); if( view ){ view->set_command( "live_start_stop" ); // ツールバー表示更新 get_notebook()->set_current_toolbar( view->get_id_toolbar(), view ); } } // 実況停止 else if( command.command == "live_stop" ){ SKELETON::View* view = get_view( command.url ); if( view ){ view->set_command( "live_stop" ); // ツールバー表示更新 get_notebook()->set_current_toolbar( view->get_id_toolbar(), view ); } } // 検索ビューなどで、URL とツールバーの状態を一致させる else if( command.command == "set_toolbar_from_url" ){ SKELETON::View* view = get_view( command.url ); if( view ) view->set_command( "set_toolbar_from_url" ); } } // // タブをお気に入りにドロップした時にお気に入りがデータ送信を要求してきた // void ArticleAdmin::slot_drag_data_get( Gtk::SelectionData& selection_data, const int page ) { #ifdef _DEBUG std::cout << "ArticleAdmin::slot_drag_data_get page = " << page << std::endl; #endif SKELETON::View* view = ( SKELETON::View* )get_notebook()->get_nth_page( page ); if( ! view ) return; const std::string url = view->get_url(); CORE::DATA_INFO info; info.type = TYPE_THREAD; info.url = DBTREE::url_readcgi( url, 0, 0 ); info.name = DBTREE::article_subject( info.url ); info.path = Gtk::TreePath( "0" ).to_string(); if( info.url.empty() ) return; #ifdef _DEBUG std::cout << "name = " << info.name << std::endl; #endif CORE::DATA_INFO_LIST list_info; list_info.push_back( info ); CORE::SBUF_set_list( list_info ); selection_data.set( DNDTARGET_FAVORITE, get_url() ); } jd-2.8.7-140104/src/article/articleadmin.h0000644000076400010400000000361511542415626014622 0ustar // ライセンス: GPL2 // // 記事の管理クラス // #ifndef _ARTICLEADMIN_H #define _ARTICLEADMIN_H #include "skeleton/admin.h" #include "sign.h" #include #include #include namespace ARTICLE { class ArticleToolBar; class ArticleToolBarSimple; class SearchToolBar; enum { TOOLBAR_ARTICLE = 0, TOOLBAR_SIMPLE, TOOLBAR_SEARCH }; class ArticleAdmin : public SKELETON::Admin { ArticleToolBar* m_toolbar; ArticleToolBarSimple* m_toolbarsimple; SearchToolBar* m_search_toolbar; public: ArticleAdmin( const std::string& url ); ~ArticleAdmin(); virtual void save_session(); protected: virtual COMMAND_ARGS get_open_list_args( const std::string& url, const COMMAND_ARGS& command_list ); virtual SKELETON::View* create_view( const COMMAND_ARGS& command ); // ツールバー virtual void show_toolbar(); virtual void toggle_toolbar(); virtual void open_searchbar(); virtual void close_searchbar(); virtual void command_local( const COMMAND_ARGS& command ); virtual void restore( const bool only_locked ); virtual COMMAND_ARGS url_to_openarg( const std::string& url, const bool tab, const bool lock ); virtual const std::string command_to_url( const COMMAND_ARGS& command ); virtual void switch_admin(); virtual void restore_lasttab(); private: bool clock_in_smooth_scroll( int timer_number ); void delete_popup(); void delete_all_popups(); // タブをお気に入りにドロップした時にお気に入りがデータ送信を要求してきた virtual void slot_drag_data_get( Gtk::SelectionData& selection_data, const int page ); }; ARTICLE::ArticleAdmin* get_admin(); void delete_admin(); } #endif jd-2.8.7-140104/src/article/articleview.cpp0000644000076400010400000005315412061154775015044 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articleadmin.h" #include "articleview.h" #include "drawareamain.h" #include "skeleton/msgdiag.h" #include "message/messageadmin.h" #include "dbtree/interface.h" #include "dbtree/articlebase.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "config/globalconf.h" #include "sound/soundmanager.h" #include "control/controlid.h" #include "history/historymanager.h" #include "command.h" #include "global.h" #include "httpcode.h" #include "session.h" #include using namespace ARTICLE; enum { CANCEL_RELOAD = 500, // msec 連続リロード防止用カウンタ LIVE_SEC_PLUS = 5, // 実況で更新失敗/成功ごとに増減する更新間隔(秒) LIVE_MAX_RELOAD = 5 // 実況でこの回数連続でリロードに失敗したら実況停止 }; // メインビュー ArticleViewMain::ArticleViewMain( const std::string& url ) : ArticleViewBase( url, url ), m_gotonum_reserve_to( 0 ), m_gotonum_reserve_from( 0 ), m_gotonum_seen( 0 ), m_playsound( false ), m_reload_reserve( false ), m_cancel_reload_counter( 0 ) { #ifdef _DEBUG std::cout << "ArticleViewMain::ArticleViewMain " << get_url() << " url_article = " << url_article() << std::endl; #endif // オートリロード可 set_enable_autoreload( true ); // 実況可能 set_enable_live( true ); // 実況したままスレを閉じたらJD終了後にスレを削除する // キャンセルするにはもう一度スレを開いて実況しないで閉じる // ArticleViewBase::set_command()も参照 SESSION::remove_delete_list( url_article() ); setup_view(); } ArticleViewMain::~ArticleViewMain() { #ifdef _DEBUG std::cout << "ArticleViewMain::~ArticleViewMain : " << get_url() << " url_article = " << url_article() << std::endl; #endif save_session(); // 閉じたタブ履歴更新 HISTORY::append_history( URL_HISTCLOSEVIEW, DBTREE::url_dat( get_url() ), DBTREE::article_subject( get_url() ), TYPE_THREAD ); CORE::core_set_command( "close_message" ,url_article() ); if( get_live() ) live_stop(); } void ArticleViewMain::save_session() { const int seen = drawarea()->get_seen_current(); #ifdef _DEBUG std::cout << "set seen to " << seen << std::endl; #endif if( seen >= 1 ) get_article()->set_number_seen( seen ); } // virtual void ArticleViewMain::clock_in() { ArticleViewBase::clock_in(); // 実況モードでリロード if( get_live() && ! is_loading() && inc_autoreload_counter() ) exec_reload(); // 更新チェック中にshow_view()が呼び出された場合は // チェックが終わってから改めてロードする if( m_reload_reserve ){ if( ! get_article()->is_checking_update() ){ m_reload_reserve = false; show_view(); } } if( m_cancel_reload_counter ) --m_cancel_reload_counter; } // // num 番にジャンプ // // ローディング中ならジャンプ予約をしてロード後に update_finish() の中で改めて goto_num() を呼び出す // void ArticleViewMain::goto_num( const int num_to, const int num_from ) { #ifdef _DEBUG std::cout << "ArticleViewMain::goto_num num = " << num_to << " num_from " << num_from << " gotonum_seen = " << m_gotonum_seen << " gotonum_reserve = " << m_gotonum_reserve_to << std::endl; #endif m_gotonum_seen = 0; // m_gotonum_reserve_to を優先させる m_gotonum_reserve_to = num_to; m_gotonum_reserve_from = num_from; if( get_article()->get_number_load() < num_to && is_loading() ){ #ifdef _DEBUG std::cout << "reserve\n"; #endif return; } #ifdef _DEBUG std::cout << "jump\n"; #endif ArticleViewBase::goto_num( num_to, num_from ); } // ロード中 const bool ArticleViewMain::is_loading() { return get_article()->is_loading(); } // 更新した const bool ArticleViewMain::is_updated() { #ifdef _DEBUG std::cout << "ArticleViewMain::is_updated " << url_article() << " " << ( get_article()->get_status() & STATUS_UPDATED ) << std::endl; #endif return ( get_article()->get_status() & STATUS_UPDATED ); } // 更新チェックして更新可能か const bool ArticleViewMain::is_check_update() { #ifdef _DEBUG std::cout << "ArticleViewMain::is_check_update " << url_article() << " " << ( get_article()->get_status() & STATUS_UPDATE ) << std::endl; #endif return ( get_article()->get_status() & STATUS_UPDATE ); } // 古いデータか const bool ArticleViewMain::is_old() { return ( get_article()->get_status() & STATUS_OLD ); } // 壊れているか const bool ArticleViewMain::is_broken() { return ( get_article()->get_status() & STATUS_BROKEN ); } // // 再読み込み実行 // // virtual void ArticleViewMain::exec_reload() { #ifdef _DEBUG std::cout << "ArticleViewMain::exec_reload\n"; #endif // オフライン if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); if( get_live() ) ARTICLE::get_admin()->set_command( "live_stop", get_url() ); return; } show_view(); } // // キャッシュ表示 & 差分ロード開始 // void ArticleViewMain::show_view() { // 更新チェック中の場合はチェックが終わってからclock_in()でロードする if( get_article()->is_checking_update() ){ m_reload_reserve = true; return; } if( is_loading() ) return; if( m_cancel_reload_counter ){ #ifdef _DEBUG std::cout << "cancel reload\n"; #endif return; } // キャッシュを削除してからスレを再読み込み if( SESSION::is_online() && get_reget() ){ int jump_to = drawarea()->get_seen_current(); if( ! jump_to ) jump_to = get_article()->get_number_seen(); #ifdef _DEBUG std::cout << "ArticleViewMain::show_view reget url_article = " << url_article() << " jump_to = " << jump_to << std::endl; #endif set_reget( false ); CORE::core_set_command( "delete_article", url_article(), "reget", MISC::itostr( jump_to ) ); return; } m_gotonum_reserve_to = 0; m_gotonum_reserve_from = 0; m_gotonum_seen = 0; m_set_history = false; m_show_instdialog = false; m_playsound = false; m_show_closedialog = false; // オートリロードのカウンタを0にする reset_autoreload_counter(); #ifdef _DEBUG std::cout << "ArticleViewMain::show_view " << url_article() << std::endl; #endif if( get_url().empty() ){ set_status( "invalid URL" ); ARTICLE::get_admin()->set_command( "set_status", get_url(), get_status() ); return; } // 負荷を減らすため update_view() や update_finish() が呼び出されるまで描画不可にしておく drawarea()->set_enable_draw( false ); // articleクラスがまだキャッシュにあるdatを解析していないときに // drawarea()->append_res()を呼ぶと、 nodetree が作られて update_finish() が // コールバックされるので、 キャッシュをまだ読み込んでない時は show_view() の中で // update_finish()を呼ばないようにする。動作をまとめると次のようになる。 // // オフライン かつ // キャッシュを読み込んでいない場合 -> articleでnodetreeが作られた時に update_finish がコールバックされる // キャッシュを読み込んでいる場合 -> show_viewから直接 update_finish を呼ぶ // // オンライン かつ // キャッシュを読み込んでいない場合 -> articleでnodetreeが作られた時に update_finish がコールバックされる //                     ロード終了時にもupdate_finish がコールバックされる // キャッシュを読み込んでいる場合 -> show_viewから直接 update_finish を呼ぶ //                     ロード終了時にもupdate_finish がコールバックされる const bool call_update_finish = get_article()->is_cache_read(); // キャッシュに含まれているレスを表示 const int from_num = drawarea()->max_number() + 1; const int to_num = get_article()->get_number_load(); if( from_num <= to_num ){ drawarea()->append_res( from_num, to_num ); // update_finish()を呼び出したときに以前見ていたところにジャンプ m_gotonum_seen = get_article()->get_number_seen(); } // セパレータを最後に移動 drawarea()->set_separator_new( to_num + 1 ); // update_finish() を呼んでキャッシュの分を描画 if( call_update_finish ){ #ifdef _DEBUG std::cout << "call_update_finish\n"; #endif // update_finish()後に一番最後や新着にジャンプしないように設定を一時的に解除する const bool jump_bottom = CONFIG::get_jump_after_reload(); const bool jump_new = CONFIG::get_jump_new_after_reload(); CONFIG::set_jump_after_reload( false ); CONFIG::set_jump_new_after_reload( false ); // 一時的に実況モード解除 const bool live = get_live(); set_live( false ); if( ! SESSION::is_online() ) m_set_history = true; update_finish(); CONFIG::set_jump_after_reload( jump_bottom ); CONFIG::set_jump_new_after_reload( jump_new ); set_live( live ); } else{ // キャッシュにログが無く、かつオフラインで開くとラベルが表示されないので // ラベルとタブのアイコン状態を更新しておく if( ! SESSION::is_online() ) update_finish(); } m_set_history = true; // オフラインならダウンロードを開始しない if( ! SESSION::is_online() ) return; // 板一覧との切り替え方法説明ダイアログ表示 if( CONFIG::get_instruct_tglart() && SESSION::get_mode_pane() == SESSION::MODE_2PANE ){ m_show_instdialog = true; } m_show_closedialog = true; clear_highlight(); if( ! get_live() && SESSION::is_online() ) m_playsound = true; // 差分 download 開始 const bool check_update = false; get_article()->download_dat( check_update ); if( is_loading() ){ #ifdef _DEBUG std::cout << "loading start\n"; #endif set_status( "loading..." ); ARTICLE::get_admin()->set_command( "set_status", get_url(), get_status(), ( get_live() ? "force" : "" ) ); // タブのアイコン状態を更新 ARTICLE::get_admin()->set_command( "toggle_icon", get_url() ); // スレ一覧などを素早くクリックした時などに2回リロードされるのを防ぐ m_cancel_reload_counter = CANCEL_RELOAD / TIMER_TIMEOUT; } } // // ロード中にノード構造が変わったら呼ばれる // void ArticleViewMain::update_view() { const int code = DBTREE::article_code( url_article() ); const int num_from = drawarea()->max_number() + 1; const int num_to = get_article()->get_number_load(); #ifdef _DEBUG std::cout << "ArticleViewMain::update_view : from " << num_from << " to " << num_to << " play = " << m_playsound << " code = " << code << std::endl; #endif // 音を鳴らす if( m_playsound ){ if( num_to >= num_from ){ // 新着 if( num_from == 1 ) SOUND::play( SOUND::SOUND_NEW ); // 更新 else SOUND::play( SOUND::SOUND_RES ); m_playsound = false; } else{ // 更新無し if( code == HTTP_NOT_MODIFIED ){ SOUND::play( SOUND::SOUND_NO ); m_playsound = false; } // エラー else if( code != HTTP_INIT ){ SOUND::play( SOUND::SOUND_ERR ); m_playsound = false; } } } if( num_from > num_to ) return; #ifdef _DEBUG std::cout << "append " << num_from << " to " << num_to << std::endl; #endif drawarea()->append_res( num_from, num_to ); drawarea()->set_enable_draw( true ); drawarea()->redraw_view(); } // // ロードが終わったときに呼ばれる // void ArticleViewMain::update_finish() { // スレラベルセット std::string str_tablabel; if( is_broken() ) str_tablabel = "[ 壊れています ] "; else if( is_old() ) str_tablabel = "[ DAT落ち ] "; if( get_label().empty() || ! str_tablabel.empty() ) set_label( str_tablabel + DBTREE::article_subject( url_article() ) ); ARTICLE::get_admin()->set_command( "redraw_toolbar" ); // タブのラベルセット std::string str_label = DBTREE::article_subject( url_article() ); if( str_label.empty() ) str_label = "???"; ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), str_label ); // タブのアイコン状態を更新 ARTICLE::get_admin()->set_command( "toggle_icon", get_url() ); #ifdef _DEBUG const int code = DBTREE::article_code( url_article() ); std::cout << "ArticleViewMain::update_finish " << str_label << " code = " << code << std::endl;; #endif // 新着セパレータを消す const int number_load = DBTREE::article_number_load( url_article() ); const int number_new = DBTREE::article_number_new( url_article() ); if( ! number_new ) drawarea()->hide_separator_new(); // ステータス更新 (実況中はフォーカスされてなくても表示) std::string force; if( get_live() ) force = "force"; create_status_message(); ARTICLE::get_admin()->set_command( "set_status", get_url(), get_status(), force ); ARTICLE::get_admin()->set_command( "set_status_color", get_url(), get_color(), force ); // タイトルセット set_title( DBTREE::article_subject( url_article() ) ); ARTICLE::get_admin()->set_command( "set_title", get_url(), get_title() ); drawarea()->set_enable_draw( true ); // ロード中に goto_num() が明示的に呼び出された場合はgoto_num()を呼びつづける if( m_gotonum_reserve_to ){ #ifdef _DEBUG std::cout << "reserve\n"; #endif goto_num( m_gotonum_reserve_to, m_gotonum_reserve_from ); } // 前回見ていた所にジャンプ else if( m_gotonum_seen && number_load >= m_gotonum_seen ){ #ifdef _DEBUG std::cout << "goto_seen\n"; #endif ArticleViewBase::goto_num( m_gotonum_seen, 0 ); m_gotonum_seen = 0; } // ロード後に末尾ジャンプ else if( ! get_live() && CONFIG::get_jump_after_reload() && number_new ){ #ifdef _DEBUG std::cout << "jump_after_reload\n"; #endif goto_bottom(); } // ロード後に新着へジャンプ else if( ! get_live() && CONFIG::get_jump_new_after_reload() && number_new ){ #ifdef _DEBUG std::cout << "jump_new_after_reload\n"; #endif goto_new(); } // 全体再描画 else{ #ifdef _DEBUG std::cout << "redraw\n"; #endif drawarea()->redraw_view(); } // 実況モードで新着がない場合はリロード間隔を空ける if( get_live() ){ const int live_sec = DBTREE::board_get_live_sec( get_url() ); // 新着無し if( ! number_new ){ set_autoreload_sec( get_autoreload_sec() + LIVE_SEC_PLUS ); // 何回かリロードに失敗したら実況モード停止 if( get_autoreload_sec() >= live_sec + LIVE_MAX_RELOAD * LIVE_SEC_PLUS ){ ARTICLE::get_admin()->set_command( "live_stop", get_url() ); } // DAT 落ちしていたら停止 if( is_old() ) ARTICLE::get_admin()->set_command( "live_stop", get_url() ); } // 新着あり else{ set_autoreload_sec( MAX( live_sec, get_autoreload_sec() - LIVE_SEC_PLUS ) ); // messageビューが出ているときはフォーカスを移す if( ! MESSAGE::get_admin()->empty() ){ // 実況モードかつポップアップが表示されている状態で、 "switch_message" コマンドを発行すると、 // 埋め込みメッセージモードだと、 MessageAdmin に対して "focus_current_view" されるので、 // ArticleView に focus_out イベントが発生して、ポップアップが消えてしまう // ポップアップが表示されているときは、フォーカスを移さない if( ! is_popup_shown() ){ CORE::core_set_command( "switch_message" ); } } } drawarea()->update_live_speed( get_autoreload_sec() ); } // 履歴に登録 if( m_set_history ) HISTORY::append_history( URL_HISTTHREADVIEW, DBTREE::url_dat( get_url() ), DBTREE::article_subject( get_url() ), TYPE_THREAD ); if( m_show_instdialog ) show_instruct_diag(); if( m_show_closedialog && !number_load && is_old() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "DAT落ちしたためスレッドを取得できませんでした。\n\nタブを閉じますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_YES ); if( mdiag.run() == Gtk::RESPONSE_YES ) close_view(); } } // // ステータスに表示する文字列作成 // void ArticleViewMain::create_status_message() { #ifdef _DEBUG std::cout << "ArticleViewMain::create_status_message\n"; #endif const int number_load = DBTREE::article_number_load( url_article() ); const int number_new = DBTREE::article_number_new( url_article() ); std::ostringstream ss_tmp; ss_tmp << DBTREE::article_str_code( url_article() ) << " [ 全 " << number_load << " / 新着 " << number_new; const time_t wtime = DBTREE::article_write_time( url_article() ); if( wtime ) ss_tmp << " / 最終書込 " << ( MISC::timettostr( wtime, MISC::TIME_WEEK ) + " ( " + MISC::timettostr( wtime, MISC::TIME_PASSED ) + " )" ); std::string str_stat; if( is_old() ) str_stat = "[ DAT落ち 又は 移転しました ] "; if( is_check_update() ) str_stat += "[ 更新可能です ] "; if( is_broken() ) str_stat += "[ 壊れています ] "; if( ! DBTREE::article_ext_err( url_article() ).empty() ) str_stat += "[ " + DBTREE::article_ext_err( url_article() ) + " ] "; ss_tmp << " / 速度 " << DBTREE::article_get_speed( url_article() ) << " / " << DBTREE::article_lng_dat( url_article() )/1024 << " K ] " << str_stat; set_status( ss_tmp.str() ); } // // 板一覧との切り替え方法説明ダイアログ表示 // void ArticleViewMain::show_instruct_diag() { m_show_instdialog = false; SKELETON::MsgCheckDiag mdiag( get_parent_win(), "スレビューからスレ一覧表示に戻る方法として\n\n(1) マウスジェスチャを使う\n(マウス右ボタンを押しながら左または下にドラッグして右ボタンを離す)\n\n(2) マウスの5ボタンを押す\n\n(3) Alt+x か h か ← を押す\n\n(4) ツールバーのスレ一覧アイコンを押す\n\n(5) 表示メニューからスレ一覧を選ぶ\n\nなどがあります。詳しくはオンラインマニュアルを参照してください。" , "今後表示しない(_D)" ); mdiag.set_title( "ヒント" ); mdiag.run(); if( mdiag.get_chkbutton().get_active() ) CONFIG::set_instruct_tglart( false ); } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewMain::relayout() { #ifdef _DEBUG std::cout << "ArticleViewMain::relayout " << DBTREE::article_subject( url_article() ) << std::endl;; #endif hide_popup( true ); int seen = drawarea()->get_seen_current(); int num_reserve = drawarea()->get_goto_num_reserve(); int separator_new = drawarea()->get_separator_new(); drawarea()->clear_screen(); drawarea()->set_separator_new( separator_new ); drawarea()->append_res( 1, get_article()->get_number_load() ); if( num_reserve ) drawarea()->goto_num( num_reserve ); else if( seen ) drawarea()->goto_num( seen ); drawarea()->redraw_view(); // ステータス更新 create_status_message(); ARTICLE::get_admin()->set_command( "set_status", get_url(), get_status() ); } // // 実況開始 // // virtual void ArticleViewMain::live_start() { if( get_live() ) return; // オフライン if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); return; } #ifdef _DEBUG std::cout << "ArticleViewMain::live_start\n"; #endif const int live_sec = DBTREE::board_get_live_sec( get_url() ); set_live( true ); ARTICLE::get_admin()->set_command_immediately( "start_autoreload", get_url(), "on", MISC::itostr( live_sec ) ); set_autoreload_counter( live_sec * 1000/TIMER_TIMEOUT ); drawarea()->live_start(); drawarea()->update_live_speed( live_sec ); goto_bottom(); } // // 実況停止 // // virtual void ArticleViewMain::live_stop() { if( ! get_live() ) return; #ifdef _DEBUG std::cout << "ArticleViewMain::live_stop\n"; #endif set_live( false ); ARTICLE::get_admin()->set_command_immediately( "stop_autoreload", get_url() ); drawarea()->live_stop(); set_status( "実況停止" ); ARTICLE::get_admin()->set_command( "set_status", get_url(), get_status(), "force" ); } jd-2.8.7-140104/src/article/articleview.h0000644000076400010400000000316511532474236014505 0ustar // ライセンス: GPL2 // // メインビュー // #ifndef _ARTICLEVIEW_H #define _ARTICLEVIEW_H #include "articleviewbase.h" namespace ARTICLE { class ArticleViewMain : public ArticleViewBase { // ジャンプ予約, goto_num() のコメント参照 int m_gotonum_reserve_to; int m_gotonum_reserve_from; int m_gotonum_seen; // 前回見ていた場所へのジャンプ用 bool m_set_history; // update_finish() で履歴を登録する bool m_show_instdialog; bool m_playsound; bool m_show_closedialog; bool m_reload_reserve; // 連続リロード防止用 int m_cancel_reload_counter; public: ArticleViewMain( const std::string& url ); ~ArticleViewMain(); virtual void clock_in(); virtual void goto_num( const int num_to, const int num_from ); // SKELETON::View の関数のオーバロード virtual void save_session(); virtual const bool is_loading(); virtual const bool is_updated(); virtual const bool is_check_update(); virtual const bool is_old(); virtual const bool is_broken(); virtual void show_view(); virtual void update_view(); virtual void update_finish(); virtual void relayout(); protected: // 実況 virtual void live_start(); virtual void live_stop(); private: virtual void exec_reload(); // ステータスに表示する文字列作成 void create_status_message(); void show_instruct_diag(); }; } #endif jd-2.8.7-140104/src/article/articleviewbase.cpp0000644000076400010400000037126412105670136015675 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "gtkmmversion.h" #include "articleadmin.h" #include "articleviewbase.h" #include "drawareamain.h" #include "skeleton/msgdiag.h" #include "jdlib/miscutil.h" #include "jdlib/miscgtk.h" #include "jdlib/miscx.h" #include "jdlib/misccharcode.h" #include "dbtree/articlebase.h" #include "dbtree/interface.h" #include "dbimg/imginterface.h" #include "skeleton/popupwin.h" #include "config/globalconf.h" #include "history/historymanager.h" #include "message/logmanager.h" #include "image/imageviewpopup.h" #include "xml/document.h" #include "xml/tools.h" #include "control/controlutil.h" #include "control/controlid.h" #include "global.h" #include "type.h" #include "httpcode.h" #include "command.h" #include "session.h" #include "viewfactory.h" #include "sharedbuffer.h" #include "prefdiagfactory.h" #include "usrcmdmanager.h" #include "linkfiltermanager.h" #include "compmanager.h" #include "icons/iconmanager.h" #include #include #ifndef MAX #define MAX( a, b ) ( a > b ? a : b ) #endif #ifndef MIN #define MIN( a, b ) ( a < b ? a : b ) #endif using namespace ARTICLE; #define PROTO_URL4REPORT "url4report://" ArticleViewBase::ArticleViewBase( const std::string& url, const std::string& url_article ) : SKELETON::View( url ), m_url_article( url_article ), m_popup_win( NULL ), m_popup_shown( false ), m_hidepopup_counter( 0 ), m_enable_menuslot( true ), m_current_bm( 0 ), m_current_post( 0 ), m_show_url4report( false ), m_url_show_status( false ), m_enable_live( false ), m_live( false ) { #ifdef _DEBUG std::cout << "ArticleViewBase::ArticleViewBase : " << get_url() << " : " << m_url_article << std::endl; #endif set_id_toolbar( TOOLBAR_ARTICLE ); // マウスジェスチャ可能 set_enable_mg( true ); // コントロールモード設定 get_control().add_mode( CONTROL::MODE_ARTICLE ); // 板名セット update_boardname(); } ArticleViewBase::~ArticleViewBase() { #ifdef _DEBUG std::cout << "ArticleViewBase::~ArticleViewBase : " << get_url() << std::endl; #endif hide_popup( true ); delete_popup(); } SKELETON::Admin* ArticleViewBase::get_admin() { return ARTICLE::get_admin(); } // // コピー用URL( readcgi型 ) // // メインウィンドウのURLバーなどの表示用にも使う // const std::string ArticleViewBase::url_for_copy() { return DBTREE::url_readcgi( m_url_article, 0, 0 ); } JDLIB::RefPtr_Lock< DBTREE::ArticleBase >& ArticleViewBase::get_article() { assert( m_article ); return m_article; } DrawAreaBase* ArticleViewBase::drawarea() { assert( m_drawarea ); return m_drawarea; } DrawAreaBase* ArticleViewBase::create_drawarea() { return Gtk::manage( new ARTICLE::DrawAreaMain( m_url_article ) ); } // // セットアップ // // 各派生ビューで初期設定が済んだ後に呼ばれる // void ArticleViewBase::setup_view() { #ifdef _DEBUG std::cout << "ArticleViewBase::setup_view " << get_url() << " url_article = " << m_url_article << std::endl; #endif m_article = DBTREE::get_article( m_url_article ); m_drawarea = create_drawarea(); assert( m_article ); assert( m_drawarea ); m_drawarea->sig_button_press().connect( sigc::mem_fun( *this, &ArticleViewBase::slot_button_press )); m_drawarea->sig_button_release().connect( sigc::mem_fun( *this, &ArticleViewBase::slot_button_release )); m_drawarea->sig_motion_notify().connect( sigc::mem_fun( *this, &ArticleViewBase::slot_motion_notify ) ); m_drawarea->sig_key_press().connect( sigc::mem_fun(*this, &ArticleViewBase::slot_key_press ) ); m_drawarea->sig_key_release().connect( sigc::mem_fun(*this, &ArticleViewBase::slot_key_release ) ); m_drawarea->sig_scroll_event().connect( sigc::mem_fun( *this, &ArticleViewBase::slot_scroll_event )); m_drawarea->sig_leave_notify().connect( sigc::mem_fun( *this, &ArticleViewBase::slot_leave_notify ) ); m_drawarea->sig_on_url().connect( sigc::mem_fun(*this, &ArticleViewBase::slot_on_url ) ); m_drawarea->sig_leave_url().connect( sigc::mem_fun(*this, &ArticleViewBase::slot_leave_url ) ); pack_start( *m_drawarea, Gtk::PACK_EXPAND_WIDGET ); setup_action(); show_all_children(); } // // アクション初期化 // void ArticleViewBase::setup_action() { #ifdef _DEBUG std::cout << "ArticleViewBase::setup_action\n"; #endif // アクショングループを作ってUIマネージャに登録 action_group().clear(); action_group() = Gtk::ActionGroup::create(); action_group()->add( Gtk::Action::create( "BookMark", "しおりを設定/解除(_B)"), sigc::mem_fun( *this, &ArticleViewBase::slot_bookmark ) ); action_group()->add( Gtk::Action::create( "PostedMark", "書き込みマークを設定/解除(_P)"), sigc::mem_fun( *this, &ArticleViewBase::slot_postedmark ) ); action_group()->add( Gtk::Action::create( "OpenBrowser", ITEM_NAME_OPEN_BROWSER "(_W)" ), sigc::mem_fun( *this, &ArticleViewBase::slot_open_browser ) ); action_group()->add( Gtk::Action::create( "OpenBrowserRes", ITEM_NAME_OPEN_BROWSER "(_S)" ), // レスをクリックした時のメニュー用 sigc::mem_fun( *this, &ArticleViewBase::slot_open_browser ) ); action_group()->add( Gtk::Action::create( "OpenCacheBrowser", ITEM_NAME_OPEN_CACHE_BROWSER "(_X)" ), sigc::mem_fun( *this, &ArticleViewBase::slot_open_cache_browser ) ); action_group()->add( Gtk::Action::create( "CopyURL", ITEM_NAME_COPY_URL "(_U)" ), sigc::mem_fun( *this, &ArticleViewBase::slot_copy_current_url ) ); action_group()->add( Gtk::Action::create( "CopyTitleURL", ITEM_NAME_COPY_TITLE_URL_THREAD "(_L)" ), sigc::mem_fun( *this, &ArticleViewBase::slot_copy_title_url ) ); action_group()->add( Gtk::Action::create( "CopyNAME", "名前コピー(_N)"), sigc::mem_fun( *this, &ArticleViewBase::slot_copy_name ) ); action_group()->add( Gtk::Action::create( "CopyID", "IDコピー(_D)"), sigc::mem_fun( *this, &ArticleViewBase::slot_copy_id ) ); action_group()->add( Gtk::Action::create( "Copy", "Copy"), sigc::mem_fun( *this, &ArticleViewBase::slot_copy_selection_str ) ); action_group()->add( Gtk::Action::create( "WriteRes", "レスする(_W)" ),sigc::mem_fun( *this, &ArticleViewBase::slot_write_res ) ); action_group()->add( Gtk::Action::create( "QuoteRes", "引用してレスする(_Q)"),sigc::mem_fun( *this, &ArticleViewBase::slot_quote_res ) ); action_group()->add( Gtk::Action::create( "QuoteSelectionRes", ITEM_NAME_QUOTE_SELECTION "(_Q)" ), sigc::mem_fun( *this, &ArticleViewBase::slot_quote_selection_res ) ); action_group()->add( Gtk::Action::create( "CopyRes", "レスをコピー(_R)"), sigc::bind< bool >( sigc::mem_fun( *this, &ArticleViewBase::slot_copy_res ), false ) ); action_group()->add( Gtk::Action::create( "CopyResRef", "引用コピー(_F)"), sigc::bind< bool >( sigc::mem_fun( *this, &ArticleViewBase::slot_copy_res ), true ) ); action_group()->add( Gtk::Action::create( "Delete_Menu", "削除(_D)" ) ); action_group()->add( Gtk::Action::create( "Delete", "Delete"), sigc::mem_fun( *this, &ArticleViewBase::exec_delete ) ); action_group()->add( Gtk::Action::create( "DeleteOpen", "スレ情報を消さずにスレ再取得(_R)"), sigc::mem_fun( *this, &ArticleViewBase::delete_open_view ) ); action_group()->add( Gtk::Action::create( "AppendFavorite", "AppendFavorite"), sigc::mem_fun( *this, &ArticleViewBase::set_favorite ) ); action_group()->add( Gtk::Action::create( "Reload", "Reload"), sigc::mem_fun( *this, &ArticleViewBase::exec_reload ) ); action_group()->add( Gtk::Action::create( "PreferenceArticle", "PreferenceArticle" ), sigc::mem_fun( *this, &ArticleViewBase::show_preference ) ); action_group()->add( Gtk::Action::create( "PreferenceImage", ITEM_NAME_PREF_IMAGE "(_M)..." ), sigc::mem_fun( *this, &ArticleViewBase::slot_preferences_image ) ); // 検索 action_group()->add( Gtk::Action::create( "Search_Menu", ITEM_NAME_SEARCH "(_H)" ) ); action_group()->add( Gtk::Action::create( "SearchNextArticle", "SearchNextArticle"), sigc::mem_fun( *this, &ArticleViewBase::slot_search_next ) ); action_group()->add( Gtk::Action::create( "SearchWeb", "SearchWeb" ), sigc::mem_fun( *this, &ArticleViewBase::slot_search_web ) ); action_group()->add( Gtk::Action::create( "SearchCacheLocal", "SearchCacheLocal" ), sigc::mem_fun( *this, &ArticleViewBase::slot_search_cachelocal ) ); action_group()->add( Gtk::Action::create( "SearchCacheAll", "SearchCacheAll") ); action_group()->add( Gtk::Action::create( "ExecSearchCacheAll", "検索する(_E)"), sigc::mem_fun( *this, &ArticleViewBase::slot_search_cacheall ) ); action_group()->add( Gtk::Action::create( "SearchTitle", "SearchTitle" ), sigc::mem_fun( *this, &ArticleViewBase::slot_search_title ) ); // 抽出系 action_group()->add( Gtk::Action::create( "Drawout_Menu", ITEM_NAME_DRAWOUT "(_E)" ) ); action_group()->add( Gtk::Action::create( "DrawoutWord", "キーワード抽出(_K)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_selection_str ) ); action_group()->add( Gtk::Action::create( "DrawoutRes", "レス抽出(_R)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_res ) ); action_group()->add( Gtk::Action::create( "DrawoutNAME", "名前抽出(_E)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_name ) ); action_group()->add( Gtk::Action::create( "DrawoutID", "ID抽出(_I)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_id ) ); action_group()->add( Gtk::Action::create( "DrawoutBM", "しおり抽出(_B)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_bm ) ); action_group()->add( Gtk::Action::create( "DrawoutPost", "書き込み抽出(_W)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_post ) ); action_group()->add( Gtk::Action::create( "DrawoutURL", "URL抽出(_U)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_url ) ); action_group()->add( Gtk::Action::create( "DrawoutRefer", "参照抽出(_E)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_refer ) ); action_group()->add( Gtk::Action::create( "DrawoutAround", "周辺抽出(_A)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_around ) ); action_group()->add( Gtk::Action::create( "DrawoutTmp", "テンプレート抽出(_T)"), sigc::mem_fun( *this, &ArticleViewBase::slot_drawout_tmp ) ); // あぼーん系 action_group()->add( Gtk::Action::create( "AboneWord_Menu", ITEM_NAME_NGWORD "(_N)" ) ); action_group()->add( Gtk::Action::create( "AboneRes", "レスをあぼ〜んする(_A)"), sigc::mem_fun( *this, &ArticleViewBase::slot_abone_res ) ); action_group()->add( Gtk::Action::create( "AboneSelectionRes", "AboneSelectionRes" ), sigc::mem_fun( *this, &ArticleViewBase::slot_abone_selection_res ) ); action_group()->add( Gtk::Action::create( "AboneID", "NG IDに追加(_G)"), sigc::mem_fun( *this, &ArticleViewBase::slot_abone_id ) ); action_group()->add( Gtk::Action::create( "AboneName", "NG 名前に追加 (対象: ローカル)(_L)"), sigc::mem_fun( *this, &ArticleViewBase::slot_abone_name ) ); action_group()->add( Gtk::Action::create( "AboneWord", "NG ワードに追加 (対象: ローカル)(_L)"), sigc::mem_fun( *this, &ArticleViewBase::slot_abone_word ) ); action_group()->add( Gtk::Action::create( "AboneNameBoard", "NG 名前に追加 (対象: 板)(_B)" ) ); action_group()->add( Gtk::Action::create( "SetAboneNameBoard", "追加する(_A)"), sigc::mem_fun( *this, &ArticleViewBase::slot_abone_name_board ) ); action_group()->add( Gtk::Action::create( "AboneWordBoard", "NG ワードに追加 (対象: 板)(_B)" ) ); action_group()->add( Gtk::Action::create( "SetAboneWordBoard", "追加する(_A)"), sigc::mem_fun( *this, &ArticleViewBase::slot_abone_word_board ) ); action_group()->add( Gtk::Action::create( "GlobalAboneName", "NG 名前に追加 (対象: 全体)(_A)" ) ); action_group()->add( Gtk::Action::create( "SetGlobalAboneName", "追加する(_A)"), sigc::mem_fun( *this, &ArticleViewBase::slot_global_abone_name ) ); action_group()->add( Gtk::Action::create( "GlobalAboneWord", "NG ワードに追加 (対象: 全体)(_A)" ) ); action_group()->add( Gtk::Action::create( "SetGlobalAboneWord", "追加する(_A)"), sigc::mem_fun( *this, &ArticleViewBase::slot_global_abone_word ) ); action_group()->add( Gtk::ToggleAction::create( "TranspAbone", "透明あぼ〜ん(_T)", std::string(), false ), sigc::mem_fun( *this, &ArticleViewBase::slot_toggle_abone_transp ) ); action_group()->add( Gtk::ToggleAction::create( "TranspChainAbone", "透明/連鎖あぼ〜ん(_C)", std::string(), false ), sigc::mem_fun( *this, &ArticleViewBase::slot_toggle_abone_transp_chain ) ); action_group()->add( Gtk::Action::create( "SetupAbone", "あぼ〜ん設定(対象: ローカル)(_L)..."), sigc::mem_fun( *this, &ArticleViewBase::slot_setup_abone ) ); action_group()->add( Gtk::Action::create( "SetupAboneBoard", "あぼ〜ん設定(対象: 板)(_B)..." ), sigc::mem_fun( *this, &ArticleViewBase::slot_setup_abone_board ) ); action_group()->add( Gtk::Action::create( "SetupAboneAll", "あぼ〜ん設定(対象: 全体)(_A)..." ), sigc::mem_fun( *this, &ArticleViewBase::slot_setup_abone_all ) ); // 移動系 action_group()->add( Gtk::Action::create( "Move_Menu", ITEM_NAME_GO "(_M)" ) ); action_group()->add( Gtk::Action::create( "Home", "Home"), sigc::mem_fun( *this, &ArticleViewBase::goto_top ) ); action_group()->add( Gtk::Action::create( "GotoNew", "GotoNew"), sigc::mem_fun( *this, &ArticleViewBase::goto_new ) ); action_group()->add( Gtk::Action::create( "End", "End"), sigc::mem_fun( *this, &ArticleViewBase::goto_bottom ) ); action_group()->add( Gtk::Action::create( "PreBookMark", "PreBookMark"), sigc::mem_fun( *this, &ArticleViewBase::slot_pre_bm ) ); action_group()->add( Gtk::Action::create( "NextBookMark", "NextBookMark"), sigc::mem_fun( *this, &ArticleViewBase::slot_next_bm ) ); action_group()->add( Gtk::Action::create( "PrePost", "PrePost"), sigc::mem_fun( *this, &ArticleViewBase::slot_pre_post ) ); action_group()->add( Gtk::Action::create( "NextPost", "NextPost"), sigc::mem_fun( *this, &ArticleViewBase::slot_next_post ) ); action_group()->add( Gtk::Action::create( "Jump", "ジャンプ(_J)"), sigc::mem_fun( *this, &ArticleViewBase::slot_jump ) ); action_group()->add( Gtk::Action::create( "PrevView", "PrevView"), sigc::bind< int >( sigc::mem_fun( *this, &ArticleViewBase::back_viewhistory ), 1 ) ); action_group()->add( Gtk::Action::create( "NextView", "NextView"), sigc::bind< int >( sigc::mem_fun( *this, &ArticleViewBase::forward_viewhistory ), 1 ) ); // 画像系 action_group()->add( Gtk::Action::create( "Cancel_Mosaic", "モザイク解除(_C)"), sigc::mem_fun( *this, &ArticleViewBase::slot_cancel_mosaic ) ); action_group()->add( Gtk::Action::create( "Show_Mosaic", "モザイクで開く(_M)"), sigc::mem_fun( *this, &ArticleViewBase::slot_show_image_with_mosaic ) ); action_group()->add( Gtk::Action::create( "ShowSelectImage", "ShowSelectImage" ) , sigc::mem_fun( *this, &ArticleViewBase::slot_show_selection_images ) ); action_group()->add( Gtk::Action::create( "DeleteSelectImage_Menu", ITEM_NAME_SELECTDELIMG "(_T)" ) ); action_group()->add( Gtk::Action::create( "DeleteSelectImage", "DeleteSelectImage"), sigc::mem_fun( *this, &ArticleViewBase::slot_delete_selection_images ) ); action_group()->add( Gtk::Action::create( "AboneSelectImage_Menu", ITEM_NAME_SELECTABONEIMG "(_B)" ) ); action_group()->add( Gtk::Action::create( "AboneSelectImage", "AboneSelectImage"), sigc::mem_fun( *this, &ArticleViewBase::slot_abone_selection_images ) ); action_group()->add( Gtk::Action::create( "ShowLargeImg", "サイズが大きい画像を表示(_L)"), sigc::mem_fun( *this, &ArticleViewBase::slot_show_large_img ) ); action_group()->add( Gtk::ToggleAction::create( "ProtectImage", "キャッシュを保護する(_P)", std::string(), false ), sigc::mem_fun( *this, &ArticleViewBase::slot_toggle_protectimage ) ); action_group()->add( Gtk::Action::create( "DeleteImage_Menu", "削除(_D)" ) ); action_group()->add( Gtk::Action::create( "DeleteImage", "削除する(_D)"), sigc::mem_fun( *this, &ArticleViewBase::slot_deleteimage ) ); action_group()->add( Gtk::Action::create( "SaveImage", "名前を付けて保存(_S)..."), sigc::mem_fun( *this, &ArticleViewBase::slot_saveimage ) ); action_group()->add( Gtk::ToggleAction::create( "AboneImage", "画像をあぼ〜んする(_A)", std::string(), false ), sigc::mem_fun( *this, &ArticleViewBase::slot_abone_img ) ); // その他 action_group()->add( Gtk::Action::create( "Etc_Menu", ITEM_NAME_ETC "(_O)" ) ); action_group()->add( Gtk::Action::create( "SaveDat", "SaveDat" ), sigc::mem_fun( *this, &ArticleViewBase::slot_save_dat ) ); action_group()->add( Gtk::Action::create( "CopyInfo", ITEM_NAME_COPY_THREAD_INFO "(_I)..." ), sigc::mem_fun( *this, &ArticleViewBase::slot_copy_article_info ) ); m_usrcmd = CORE::get_usrcmd_manager()->create_usrcmd_menu( action_group() ); const int usrcmd_size = CORE::get_usrcmd_manager()->get_size(); for( int i = 0; i < usrcmd_size; ++i ){ Glib::RefPtr< Gtk::Action > act = CORE::get_usrcmd_manager()->get_action( action_group(), i ); if( act ) act->signal_activate().connect( sigc::bind< int >( sigc::mem_fun( *this, &ArticleViewBase::slot_usrcmd ), i ) ); } ui_manager().clear(); ui_manager() = Gtk::UIManager::create(); ui_manager()->insert_action_group( action_group() ); // 削除ボタン押したときのポップアップ const std::string menu_delete = "" "" "" "" ""; // 壊れていますをクリックしたときのポップアップ const std::string menu_broken = "" "" ""; // レス番号をクリックしたときのメニュー const std::string menu_res = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; // レスアンカーをクリックしたときのメニュー const std::string menu_anc = "" "" "" "" ""; // IDをクリックしたときのメニュー const std::string menu_id = "" "" "" "" "" ""; // 名前をクリックしたときのメニュー const std::string menu_name = "" "" "" "" "" "" "" "" "" "" "" ""; // あぼーんをクリックしたときのメニュー const std::string menu_abone = "" "" "" "" "" "" "" ""; // 画像メニュー const std::string menu_img = "" "" "" "" "" "" "" + m_usrcmd + std::string( "" "" "" "" "" "" "" "" "" "" "" "" "" "" ); ui_manager()->add_ui_from_string( "" + menu_delete + menu_broken + menu_res + menu_anc + menu_id + menu_name + menu_abone + menu_img + create_context_menu() + "" ); // ポップアップメニューにショートカットキーやマウスジェスチャを表示 Gtk::Menu* popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu" ) ); CONTROL::set_menu_motion( popupmenu ); popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_delete" ) ); CONTROL::set_menu_motion( popupmenu ); } // // 通常の右クリックメニューの作成 // const std::string ArticleViewBase::create_context_menu() { std::list< int > list_menu; list_menu.push_back( ITEM_DRAWOUT ); list_menu.push_back( ITEM_GO ); list_menu.push_back( ITEM_SEARCH ); list_menu.push_back( ITEM_NGWORD ); list_menu.push_back( ITEM_QUOTE_SELECTION ); list_menu.push_back( ITEM_OPEN_BROWSER ); list_menu.push_back( ITEM_USER_COMMAND ); list_menu.push_back( ITEM_COPY_URL ); list_menu.push_back( ITEM_COPY ); list_menu.push_back( ITEM_RELOAD ); list_menu.push_back( ITEM_DELETE ); list_menu.push_back( ITEM_COPY_TITLE_URL_THREAD ); list_menu.push_back( ITEM_SAVE_DAT ); list_menu.push_back( ITEM_COPY_THREAD_INFO ); list_menu.push_back( ITEM_APPENDFAVORITE ); list_menu.push_back( ITEM_ABONE_SELECTION ); list_menu.push_back( ITEM_SELECTIMG ); list_menu.push_back( ITEM_SELECTDELIMG ); list_menu.push_back( ITEM_SELECTABONEIMG ); list_menu.push_back( ITEM_PREF_THREAD ); // メニューに含まれていない項目を抜き出して「その他」に含める int num = 0; for(;;){ const int item = SESSION::get_item_article_menu( num ); if( item == ITEM_END ) break; list_menu.remove( item ); ++num; } std::string menu; num = 0; for(;;){ const int item = SESSION::get_item_article_menu( num ); if( item == ITEM_END ) break; else if( item == ITEM_ETC && list_menu.size() ){ menu += std::string( "" ); std::list< int >::iterator it = list_menu.begin(); for( ; it != list_menu.end(); ++it ) menu += get_menu_item( *it ); menu += std::string( "" ); } else menu += get_menu_item( item ); ++num; } #ifdef _DEBUG std::cout << "menu = " << menu << std::endl; #endif return "" + menu + ""; } const char* ArticleViewBase::get_menu_item( const int item ) { switch( item ){ // 抽出 case ITEM_DRAWOUT: return "" "" "" "" "" "" "" ; // 移動 case ITEM_GO: return "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ; // 検索 case ITEM_SEARCH: return "" "" "" "" "" "" "" "" "" "" "" "" ; // NGワード case ITEM_NGWORD: return "" "" "" "" "" "" "" "" "" ; // 選択範囲のレスをあぼーん case ITEM_ABONE_SELECTION: return "" ; // 引用してレス case ITEM_QUOTE_SELECTION: return ""; // リンクをブラウザで開く case ITEM_OPEN_BROWSER: return ""; // ユーザコマンド case ITEM_USER_COMMAND: return m_usrcmd.c_str(); // リンクのURLをコピー case ITEM_COPY_URL: return ""; // スレのタイトルとURLをコピー case ITEM_COPY_TITLE_URL_THREAD: return ""; // コピー case ITEM_COPY: return ""; // 再読み込み case ITEM_RELOAD: return ""; // dat 保存 case ITEM_SAVE_DAT: return ""; // 情報コピー case ITEM_COPY_THREAD_INFO: return ""; // お気に入り case ITEM_APPENDFAVORITE: return ""; // プロパティ case ITEM_PREF_THREAD: return ""; // 選択範囲の画像を開く case ITEM_SELECTIMG: return ""; // 選択範囲の画像を削除 case ITEM_SELECTDELIMG: return "" "" ""; // 選択範囲の画像をあぼーん case ITEM_SELECTABONEIMG: return "" "" ""; // 区切り case ITEM_SEPARATOR: return ""; // 削除 case ITEM_DELETE: return "" "" "" ""; } return ""; } // // クライアント領域幅 // const int ArticleViewBase::width_client() { #ifdef _DEBUG if( m_drawarea ) std::cout << "ArticleViewBase::width_client : " << m_drawarea->width_client() << std::endl; #endif if( m_drawarea ) return m_drawarea->width_client(); return SKELETON::View::width_client(); } // // クライアント領高さ // const int ArticleViewBase::height_client() { #ifdef _DEBUG if( m_drawarea ) std::cout << "ArticleViewBase::height_client : " << m_drawarea->height_client() << std::endl; #endif if( m_drawarea ) return m_drawarea->height_client(); return SKELETON::View::height_client(); } // アイコンのID取得 const int ArticleViewBase::get_icon( const std::string& iconname ) { int id = ICON::NONE; if( iconname == "default" ) id = ICON::THREAD; if( iconname == "loading" ) id = ICON::LOADING; if( iconname == "loading_stop" ) id = ICON::LOADING_STOP; if( iconname == "update" ) id = ICON::THREAD_UPDATE; // 更新チェックしで更新があった場合 if( iconname == "updated" ) id = ICON::THREAD_UPDATED; if( iconname == "old" ) id = ICON::THREAD_OLD; #ifdef _DEBUG std::cout << "ArticleViewBase::get_icon : " << iconname << " url = " << get_url() << std::endl; #endif return id; } // // コマンド // const bool ArticleViewBase::set_command( const std::string& command, const std::string& arg1, const std::string& arg2 ) { #ifdef _DEBUG std::cout << "ArticleViewBase::set_command " << get_url() << std::endl << "command = " << command << std::endl; #endif if( command == "append_dat" ) append_dat( arg1, -1 ); else if( command == "append_html" ) append_html( arg1 ); else if( command == "clear_screen" ) { if( m_drawarea ) m_drawarea->clear_screen(); } else if( command == "goto_num" ) goto_num( atoi( arg1.c_str() ), atoi( arg2.c_str() ) ); else if( command == "hide_popup" ) hide_popup( true ); else if( command == "delete_popup" ) delete_popup(); else if( command == "clear_highlight" ) clear_highlight(); else if( command == "reset_popupmenu" ) setup_action(); // 実況手動切り替え else if( command == "live_start_stop" ){ if( ! get_enable_live() ){ if( m_enable_live && ! DBTREE::board_get_live_sec( m_url_article ) ){ SKELETON::MsgDiag mdiag( get_parent_win(), "実況を行うには板のプロパティで更新間隔を設定して下さい。" ); mdiag.run(); } return true; } if( get_live() ){ live_stop(); // 実況したスレは終了時に削除する SESSION::remove_delete_list( m_url_article ); } else{ live_start(); // 手動で停止した場合は終了時の削除をキャンセルする SESSION::append_delete_list( m_url_article ); } } // dat落ちや更新が無い場合は実況停止 // 終了時にスレを削除する else if( command == "live_stop" && get_enable_live() ) live_stop(); return true; } // // クロック入力 // // クロックタイマーの本体はコアが持っていて、定期的にadminがアクティブなviewにクロック入力を渡す // // virtual void ArticleViewBase::clock_in() { assert( m_drawarea ); View::clock_in(); // ポップアップを時間差で消す if( m_hidepopup_counter ){ --m_hidepopup_counter; if( ! m_hidepopup_counter ){ // ポインタがポップアップ上に戻っていたらキャンセル if( ! is_mouse_on_popup() ) slot_hide_popup(); } } // ポップアップが出てたらそっちにクロックを回す if( is_popup_shown() && m_popup_win->view() ){ m_popup_win->view()->clock_in(); return; } m_drawarea->clock_in(); } // // スムーススクロール用クロック入力 // // タイマー本体はArticleAdminが持っている // void ArticleViewBase::clock_in_smooth_scroll() { assert( m_drawarea ); // ポップアップが出てたらそっちにクロックを回す if( is_popup_shown() && m_popup_win->view() ){ ArticleViewBase* view = dynamic_cast< ArticleViewBase* >( m_popup_win->view() ); if( view ) view->clock_in_smooth_scroll(); return; } m_drawarea->clock_in_smooth_scroll(); } // // 再読み込みボタンを押した // void ArticleViewBase::reload() { if( m_article->empty() ) return; if( CONFIG::get_reload_allthreads() ) ARTICLE::get_admin()->set_command( "reload_all_tabs" ); else exec_reload(); } // // 再読み込み実行 // // virtual void ArticleViewBase::exec_reload() { reload_article(); } // // 元のスレを開く (shift+s) // void ArticleViewBase::reload_article() { if( m_article->empty() ) return; CORE::core_set_command( "open_article", m_url_article , "newtab", "" ); } // // ロード停止 // void ArticleViewBase::stop() { assert( m_article ); m_article->stop_load(); } // // 再描画 // void ArticleViewBase::redraw_view() { // 起動中とシャットダウン中は処理しない if( SESSION::is_booting() ) return; if( SESSION::is_quitting() ) return; #ifdef _DEBUG std::cout << "ArticleViewBase::redraw_view " << get_url() << std::endl; #endif assert( m_drawarea ); m_drawarea->redraw_view_force(); // ポップアップが表示されていたらポップアップも再描画 if( is_popup_shown() ) m_popup_win->view()->redraw_view(); } // // フォーカスイン // void ArticleViewBase::focus_view() { assert( m_drawarea ); #ifdef _DEBUG std::cout << "ArticleViewBase::focus_view " << get_url() << std::endl; #endif m_drawarea->focus_view(); m_drawarea->redraw_view(); } // // フォーカスアウト // void ArticleViewBase::focus_out() { SKELETON::View::focus_out(); #ifdef _DEBUG std::cout << "ArticleViewBase::focus_out " << get_url() << std::endl; #endif m_drawarea->focus_out(); if( is_popup_shown() ){ // フォーカスアウトした瞬間に、子ポップアップが表示されていて、かつ // ポインタがその上だったらポップアップは消さない if( is_mouse_on_popup() ) return; if( CONFIG::get_hide_popup_msec() ) m_hidepopup_counter = CONFIG::get_hide_popup_msec() / TIMER_TIMEOUT; else hide_popup(); } } // // 閉じる // void ArticleViewBase::close_view() { if( m_article->is_loading() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "読み込み中です" ); mdiag.run(); return; } ARTICLE::get_admin()->set_command( "close_view", get_url() ); } // // 削除ボタンを押した // void ArticleViewBase::delete_view() { show_popupmenu( "popup_menu_delete", false ); } // // 削除実行 // void ArticleViewBase::exec_delete() { CORE::core_set_command( "delete_article", m_url_article ); ARTICLE::get_admin()->set_command( "switch_admin" ); } // // スレ再取得 // void ArticleViewBase::delete_open_view() { if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); return; } if( DBTREE::article_status( m_url_article ) & STATUS_OLD ){ SKELETON::MsgDiag mdiag( get_parent_win(), "DAT落ちしています。\n\nログが消える恐れがあります。実行しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; } const std::string str_tab = "false"; const std::string mode = "reget"; CORE::core_set_command( "open_article", m_url_article, str_tab, mode ); } // 実況可能か const bool ArticleViewBase::get_enable_live() { return ( m_enable_live && DBTREE::board_get_live_sec( m_url_article ) ); } // // マウスポインタをポップアップの上に移動する // void ArticleViewBase::warp_pointer_to_popup() { if( is_popup_shown() ){ const int mrg = 32; int x, y; get_pointer( x, y ); m_popup_win->get_pointer( x, y ); if( x < mrg ) x = mrg; else if( x > m_popup_win->get_width() - mrg ) x = m_popup_win->get_width() - mrg; if( y < 0 ) y = mrg; else y = m_popup_win->get_height() - mrg; MISC::WarpPointer( get_window(), m_popup_win->get_window(), x, y ); } } // // viewの操作 // const bool ArticleViewBase::operate_view( const int control ) { assert( m_drawarea ); // スレタイ検索 // CONTROL::operate_common()の中で処理しないようにCONTROL::operate_common()の前で処理 if( control == CONTROL::SearchTitle ){ slot_search_title(); return true; } if( CONTROL::operate_common( control, get_url(), ARTICLE::get_admin() ) ) return true; if( control == CONTROL::None ) return false;; // スクロール系操作 if( m_drawarea->set_scroll( control ) ) return true; #ifdef _DEBUG std::cout << "ArticleViewBase::operate_view control = " << control << std::endl; #endif // その他の処理 switch( control ){ // リロード case CONTROL::Reload: exec_reload(); break; // 元のスレを開く case CONTROL::ReloadArticle: reload_article(); break; // コピー case CONTROL::Copy: slot_copy_selection_str(); break; // 全て選択 case CONTROL::SelectAll: slot_select_all(); break; // お気に入りに追加 case CONTROL::AppendFavorite: set_favorite(); break; // 検索 case CONTROL::Search: open_searchbar( false ); break; case CONTROL::SearchInvert: open_searchbar( true ); break; case CONTROL::SearchNext: down_search(); break; case CONTROL::SearchPrev: up_search(); break; // datを保存 case CONTROL::Save: slot_save_dat(); break; // 閉じる case CONTROL::Quit: close_view(); break; // 書き込み case CONTROL::WriteMessage: write(); break; // 削除 case CONTROL::Delete: { if( m_article->empty() ) break; if( ! CONFIG::get_show_delartdiag() ){ exec_delete(); break; } SKELETON::MsgCheckDiag mdiag( get_parent_win(), "ログを削除しますか?\n\n「スレ再取得」を押すと\nあぼ〜んなどのスレ情報を削除せずにスレを再取得します。", "今後表示しない(常に削除)(_D)", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE ); mdiag.add_button( Gtk::Stock::NO, Gtk::RESPONSE_NO ); mdiag.add_default_button( Gtk::Stock::YES, Gtk::RESPONSE_YES ); #if GTKMM_CHECK_VERSION(2,6,0) Gtk::Button *button = mdiag.add_button( "スレ再取得(_R)", Gtk::RESPONSE_YES + 100 ); Gtk::Image image( Gtk::Stock::REFRESH, Gtk::ICON_SIZE_BUTTON ); button->set_image( image ); #else mdiag.add_button( "スレ再取得(_R)", Gtk::RESPONSE_YES + 100 ); #endif mdiag.set_default_response( Gtk::RESPONSE_YES ); int ret = mdiag.run(); if( ret == Gtk::RESPONSE_YES ) exec_delete(); else if( ret == Gtk::RESPONSE_YES + 100 ) delete_open_view(); if( mdiag.get_chkbutton().get_active() ) CONFIG::set_show_delartdiag( false ); break; } // Board に切り替え case CONTROL::Left: CORE::core_set_command( "switch_leftview" ); break; case CONTROL::ToggleArticle: CORE::core_set_command( "toggle_article" ); break; // image に切り替え case CONTROL::Right: CORE::core_set_command( "switch_rightview" ); break; // 戻る、進む case CONTROL::PrevView: back_viewhistory( 1 ); break; case CONTROL::NextView: forward_viewhistory( 1 ); break; // ポップアップメニュー表示 case CONTROL::ShowPopupMenu: show_popupmenu( "", true ); break; // ブックマーク移動 case CONTROL::PreBookMark: slot_pre_bm(); break; case CONTROL::NextBookMark: slot_next_bm(); break; // 書き込み移動 case CONTROL::PrePost: slot_pre_post(); break; case CONTROL::NextPost: slot_next_post(); break; // 親にhideを依頼する and ローディング停止 case CONTROL::StopLoading: stop(); sig_hide_popup().emit(); break; // 実況モード切り替え case CONTROL::LiveStartStop: if( ! m_article->empty() ) ARTICLE::get_admin()->set_command( "live_start_stop", get_url() ); break; // 次スレ検索 case CONTROL::SearchNextArticle: slot_search_next(); break; // Web検索 case CONTROL::SearchWeb: slot_search_web(); break; // ログ検索(板内) case CONTROL::SearchCacheLocal: slot_search_cachelocal(); break; // ログ検索(全て) case CONTROL::SearchCacheAll: slot_search_cacheall(); break; // 選択範囲の画像を開く case CONTROL::ShowSelectImage: slot_show_selection_images(); break; // 選択範囲の画像を削除 case CONTROL::DeleteSelectImage: slot_delete_selection_images(); break; // 選択範囲の画像をあぼ〜ん case CONTROL::AboneSelectImage: slot_abone_selection_images(); break; // 選択範囲のレスをあぼ〜ん case CONTROL::AboneSelectionRes: slot_abone_selection_res(); break; // スレのプロパティ case CONTROL::PreferenceView: show_preference(); break; default: return false; } return true; } // // 一番上へ // void ArticleViewBase::goto_top() { assert( m_drawarea ); m_drawarea->goto_top(); } // // 一番下へ // void ArticleViewBase::goto_bottom() { assert( m_drawarea ); m_drawarea->goto_bottom(); } // // num_from から num_to番へジャンプ // // num_from が 0 の時は m_drawarea->get_seen_current() からジャンプすると見なす // void ArticleViewBase::goto_num( const int num_to, const int num_from ) { assert( m_drawarea ); const int from = ( ( num_from > 0 && num_to != num_from ) ? num_from : m_drawarea->get_seen_current() ); #ifdef _DEBUG std::cout << "ArticleViewBase::goto_num to = " << num_to << " from = " << from << std::endl; #endif m_drawarea->set_jump_history( from ); m_drawarea->goto_num( num_to ); } // // 新着に移動 // void ArticleViewBase::goto_new() { assert( m_drawarea ); m_drawarea->goto_new(); } // // 検索バーを開く // void ArticleViewBase::open_searchbar( bool invert ) { ARTICLE::get_admin()->set_command( "open_searchbar", get_url() ); m_search_invert = invert; } // // 前を検索 // void ArticleViewBase::up_search() { m_search_invert = true; exec_search(); redraw_view(); } // // 次を検索 // void ArticleViewBase::down_search() { m_search_invert = false; exec_search(); redraw_view(); } // // ハイライト解除 // void ArticleViewBase::clear_highlight() { assert( m_drawarea ); if( get_pre_query().empty() ) return; set_pre_query( std::string() ); m_drawarea->clear_highlight(); } // // メッセージ書き込みボタン // void ArticleViewBase::write() { if( ! is_writeable() ) return; CORE::core_set_command( "open_message" ,m_url_article, std::string() ); } // // プロパティ表示 // void ArticleViewBase::show_preference() { #ifdef _DEBUG std::cout << "ArticleViewBase::show_preference\n"; #endif SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_ARTICLE, m_url_article ); pref->run(); delete pref; } // // 画像プロパティ表示 // void ArticleViewBase::slot_preferences_image() { if( m_url_tmp.empty() ) return; std::string url = m_url_tmp; SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_IMAGE, url ); pref->run(); delete pref; } // // 戻る // void ArticleViewBase::back_viewhistory( const int count ) { ARTICLE::get_admin()->set_command( "back_viewhistory", get_url(), MISC::itostr( count ) ); } // // 進む // void ArticleViewBase::forward_viewhistory( const int count ) { ARTICLE::get_admin()->set_command( "forward_viewhistory", get_url(), MISC::itostr( count ) ); } // // 前のブックマークに移動 // void ArticleViewBase::slot_pre_bm() { assert( m_article ); if( m_current_bm == 0 ) m_current_bm = m_drawarea->get_seen_current(); for( int i = m_current_bm -1 ; i >= 1 ; --i ){ if( m_article->is_bookmarked( i ) ){ goto_num( i, 0 ); m_current_bm = i; return; } } for( int i = m_article->get_number_load() ; i > m_current_bm ; --i ){ if( m_article->is_bookmarked( i ) ){ goto_num( i, 0 ); m_current_bm = i; return; } } } // // 後ろのブックマークに移動 // void ArticleViewBase::slot_next_bm() { assert( m_article ); if( m_current_bm == 0 ) m_current_bm = m_drawarea->get_seen_current(); for( int i = m_current_bm + 1; i <= m_article->get_number_load() ; ++i ){ if( m_article->is_bookmarked( i ) ){ goto_num( i, 0 ); m_current_bm = i; return; } } for( int i = 1; i <= m_current_bm ; ++i ){ if( m_article->is_bookmarked( i ) ){ goto_num( i, 0 ); m_current_bm = i; return; } } } // // 前の書き込みに移動 // void ArticleViewBase::slot_pre_post() { assert( m_article ); if( m_current_post == 0 ) m_current_post = m_drawarea->get_seen_current(); for( int i = m_current_post -1 ; i >= 1 ; --i ){ if( m_article->is_posted( i ) ){ goto_num( i, 0 ); m_current_post = i; return; } } for( int i = m_article->get_number_load() ; i > m_current_post ; --i ){ if( m_article->is_posted( i ) ){ goto_num( i, 0 ); m_current_post = i; return; } } } // // 後ろの書き込みに移動 // void ArticleViewBase::slot_next_post() { assert( m_article ); if( m_current_post == 0 ) m_current_post = m_drawarea->get_seen_current(); for( int i = m_current_post + 1; i <= m_article->get_number_load() ; ++i ){ if( m_article->is_posted( i ) ){ goto_num( i, 0 ); m_current_post = i; return; } } for( int i = 1; i <= m_current_post ; ++i ){ if( m_article->is_posted( i ) ){ goto_num( i, 0 ); m_current_post = i; return; } } } // // ジャンプ // // 呼び出す前に m_jump_to に対象のレス番号を入れておくこと // void ArticleViewBase::slot_jump() { const std::string str_tab = "true"; const std::string str_mode = "auto"; CORE::core_set_command( "open_article", m_url_article , str_tab, str_mode, m_jump_to, m_jump_from ); } // // dat 保存 // void ArticleViewBase::slot_save_dat() { m_article->save_dat( std::string() ); } // // スレ情報コピー // void ArticleViewBase::slot_copy_article_info() { if( m_url_tmp.empty() ) return; if( ! DBTREE::article_is_cached( m_url_tmp ) ) return; m_article->copy_article_info( m_url_tmp ); CORE::core_set_command( "replace_favorite_thread", "", m_url_tmp, m_url_article ); // 再レイアウト ARTICLE::get_admin()->set_command( "relayout_views", m_url_article ); } // // あぼーん設定 // void ArticleViewBase::slot_setup_abone() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_ARTICLE, m_url_article, "show_abone" ); pref->run(); delete pref; } void ArticleViewBase::slot_setup_abone_board() { SKELETON::PrefDiag* pref = CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_BOARD, DBTREE::url_subject( m_url_article ), "show_abone_article" ); pref->run(); delete pref; } void ArticleViewBase::slot_setup_abone_all() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_GLOBALABONE, "" ); pref->run(); delete pref; } // // 荒らし報告用のURLリストをHTML形式で取得 // const std::string ArticleViewBase::get_html_url4report( const std::list< int >& list_resnum ) { std::string html; std::list < int >::const_iterator it = list_resnum.begin(); for( ; it != list_resnum.end(); ++it ){ const int num = (*it); const std::string time_str = m_article->get_time_str( num ); const std::string id_str = m_article->get_id_name( num ); html += url_for_copy() + MISC::itostr( num ); if( ! time_str.empty() ) html += " " + MISC::remove_str_regex( time_str, "\\([^\\)]+\\)" ); // 曜日を取り除く if( ! id_str.empty() ) html += " " + id_str.substr( strlen( PROTO_ID ) ); html += "
"; } return html; } // // レスを抽出して表示 // // num は "from-to" の形式。"a+b"の時はaとbを連結する(bのヘッダ行を取り除く) // // (例) 3から10を表示したいなら "3-10" // 3と4を連結して表示したい時は "3+4" // // show_title == trueの時は 板名、スレ名を表示 // void ArticleViewBase::show_res( const std::string& num, const bool show_title ) { assert( m_article ); #ifdef _DEBUG std::cout << "ArticleViewBase::show_res num = " << num << " show_title = " << show_title << std::endl; #endif // 板名、スレ名 if( show_title ){ std::string html; std::string tmpstr = DBTREE::board_name( m_url_article ); if( ! tmpstr.empty() ) html += "[ " + tmpstr + " ] "; tmpstr = DBTREE::article_subject( m_url_article ); if( ! tmpstr.empty() ) html += tmpstr; if( ! html.empty() ) append_html( html ); } std::list< bool > list_joint; std::list< int > list_resnum = m_article->get_res_str_num( num, list_joint ); if( !list_resnum.empty() ) append_res( list_resnum, list_joint ); else if( !show_title ) append_html( "未取得レス" ); } // // 名前 で抽出して表示 // // show_option = true の時は URL 表示などのオプションが表示される // void ArticleViewBase::show_name( const std::string& name, bool show_option ) { assert( m_article ); #ifdef _DEBUG std::cout << "ArticleViewBase::show_name " << name << std::endl; #endif std::list< int > list_resnum = m_article->get_res_name( name ); std::ostringstream comment; comment << "名前:" << name << " " << list_resnum.size() << " 件
"; comment << "総参照数:" << m_article->get_res_reference( list_resnum ).size() << " 件"; if( show_option && ! list_resnum.empty() ){ if( !m_show_url4report ) comment << "

抽出したレスのURLをリスト表示"; else comment << "

" + get_html_url4report( list_resnum ); comment << "

" << url_for_copy(); if( url_for_copy()[ url_for_copy().size() - 1 ] != '/' ) comment << "/"; comment << MISC::intlisttostr( list_resnum ) << "

"; } append_html( comment.str() ); if( ! list_resnum.empty() ) append_res( list_resnum ); } // // ID で抽出して表示 // // show_option = true の時は URL 表示などのオプションが表示される // void ArticleViewBase::show_id( const std::string& id_name, const bool show_option ) { assert( m_article ); #ifdef _DEBUG std::cout << "ArticleViewBase::show_id " << id_name << std::endl; #endif const std::list< int > list_resnum = m_article->get_res_id_name( id_name ); const std::string raw_id = id_name.substr( strlen( PROTO_ID ) ); std::ostringstream comment; comment << raw_id << " " << list_resnum.size() << " 件
"; comment << "総参照数:" << m_article->get_res_reference( list_resnum ).size() << " 件"; // 末尾判定 if( raw_id.length() == 9 ){ char c = raw_id.c_str()[ 8 ]; switch( c ){ case 'O': comment << "
末尾:" << c << " 携帯"; break; case 'o': comment << "
末尾:" << c << " 携帯(WILLCOM)"; break; case 'Q': comment << "
末尾:" << c << " ibisBrowserDX"; break; case 'I': case 'i': comment << "
末尾:" << c << " iPhone"; break; case 'P': comment << "
末尾:" << c << " p2"; break; case '0': comment << "
末尾:" << c << " PC"; break; } } if( show_option && ! list_resnum.empty() ){ if( !m_show_url4report ) comment << "

抽出したレスのURLをリスト表示"; else comment << "

" + get_html_url4report( list_resnum ); comment << "

" << url_for_copy(); if( url_for_copy()[ url_for_copy().size() - 1 ] != '/' ) comment << "/"; comment << MISC::intlisttostr( list_resnum ) << "

"; } append_html( comment.str() ); if( ! list_resnum.empty() ) append_res( list_resnum ); } // // ブックマークを抽出して表示 // void ArticleViewBase::show_bm() { assert( m_article ); #ifdef _DEBUG std::cout << "ArticleViewBase::show_bm " << std::endl; #endif std::list< int > list_resnum = m_article->get_res_bm(); if( ! list_resnum.empty() ) append_res( list_resnum ); else append_html( "しおりはセットされていません" ); } // // 書き込みを抽出して表示 // void ArticleViewBase::show_post() { assert( m_article ); #ifdef _DEBUG std::cout << "ArticleViewBase::show_post " << std::endl; #endif std::list< int > list_resnum = m_article->get_res_posted(); if( ! list_resnum.empty() ){ std::ostringstream comment; comment << "書き込み数:" << list_resnum.size() << " 件
"; comment << "総参照数:" << m_article->get_res_reference( list_resnum ).size() << " 件"; append_html( comment.str() ); append_res( list_resnum ); } else append_html( "このスレでは書き込みしていません" ); } // // 書き込みログを表示 // void ArticleViewBase::show_postlog( const int num ) { const int maxno = MESSAGE::get_log_manager()->get_max_num_of_log() + 1; std::string html_header; for( int i = 1; i <= maxno; ++i ){ int no; if( i == 1 ) no = 0; else no = maxno - ( i -1 ); if( no == num ) html_header += MISC::itostr( i ) + " "; else html_header += std::string( "" + MISC::itostr( i ) + " "; } #ifdef _DEBUG std::cout << "ArticleViewBase::show_postlog " << num << " / " << maxno << std::endl << html_header << std::endl; #endif std::string html = MESSAGE::get_log_manager()->get_post_log( num ); if( html.empty() ) html = "書き込みログがありません"; else html = html_header + "
" + html + "

" + html_header; append_html( html ); } // // URLを含むレスを抽出して表示 // void ArticleViewBase::show_res_with_url() { assert( m_article ); #ifdef _DEBUG std::cout << "ArticleViewBase::show_res_with_url\n"; #endif std::list< int > list_resnum = m_article->get_res_with_url(); if( ! list_resnum.empty() ) append_res( list_resnum ); else append_html( "リンクを含むレスはありません" ); } // // num 番のレスを参照してるレスを抽出して表示 // void ArticleViewBase::show_refer( int num ) { assert( m_article ); #ifdef _DEBUG std::cout << "ArticleViewBase::show_refer " << num << std::endl; #endif std::list< int > list_resnum = m_article->get_res_reference( num ); std::ostringstream comment; comment << "参照数:" << list_resnum.size() << " 件"; append_html( comment.str() ); // num 番は先頭に必ず表示 list_resnum.push_front( num ); append_res( list_resnum ); } // // キーワードで抽出して表示 // // mode_or = true の時は or 検索 // show_option = true の時は URL 表示などのオプションが表示される // void ArticleViewBase::drawout_keywords( const std::string& query, bool mode_or, bool show_option ) { assert( m_article ); #ifdef _DEBUG std::cout << "ArticleViewBase::drawout_keywords " << query << std::endl; #endif std::list< int > list_resnum = m_article->get_res_query( query, mode_or ); std::ostringstream comment; comment << query << " " << list_resnum.size() << " 件"; if( show_option && ! list_resnum.empty() ){ if( !m_show_url4report ) comment << " 抽出したレスのURLをリスト表示"; else comment << "

" + get_html_url4report( list_resnum ); comment << "

" << url_for_copy(); if( url_for_copy()[ url_for_copy().size() - 1 ] != '/' ) comment << "/"; comment << MISC::intlisttostr( list_resnum ) << "

"; } append_html( comment.str() ); if( ! list_resnum.empty() ){ append_res( list_resnum ); // ハイライト表示 std::list< std::string > list_query = MISC::split_line( query ); m_drawarea->search( list_query, false ); } } // // html をappend // void ArticleViewBase::append_html( const std::string& html ) { #ifdef _DEBUG std::cout << "ArticleViewBase::append_html html = " << html << std::endl; #endif assert( m_drawarea ); m_drawarea->append_html( html ); redraw_view(); } // // dat をレス番号 num 番として append // // num < 0 の時は現在の最大スレ番号の後に追加 // void ArticleViewBase::append_dat( const std::string& dat, int num ) { assert( m_drawarea ); if( num < 0 ) num = get_article()->get_number_load() +1; m_drawarea->append_dat( dat, num ); redraw_view(); } // // リストで指定したレスの表示 // void ArticleViewBase::append_res( const std::list< int >& list_resnum ) { assert( m_drawarea ); m_drawarea->append_res( list_resnum ); redraw_view(); } // // リストで指定したレスを表示(連結情報付き) // // list_joint で連結指定したレスはヘッダを取り除いて前のレスに連結する // void ArticleViewBase::append_res( const std::list< int >& list_resnum, const std::list< bool >& list_joint ) { assert( m_drawarea ); m_drawarea->append_res( list_resnum, list_joint ); redraw_view(); } // // drawareaから出た // bool ArticleViewBase::slot_leave_notify( GdkEventCrossing* event ) { // クリックしたときやホイールを回すと event->mode に GDK_CROSSING_GRAB // か GDK_CROSSING_UNGRAB がセットされてイベントが発生する場合がある if( event->mode == GDK_CROSSING_GRAB ) return false; if( event->mode == GDK_CROSSING_UNGRAB ) return false; // クリックしたりホイールを回すとイベントが発生する時があるのでキャンセルする if( event->state & ( GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK ) ) return false; #ifdef _DEBUG std::cout << "ArticleViewBase::slot_leave_drawarea :"; std::cout << " type = " << event->type; std::cout << " mode = " << event->mode; std::cout << " detail = " << event->detail; std::cout << " state = " << event->state << std::endl; #endif focus_out(); // ステータスバーの表示を戻す if( m_url_show_status ) { CORE::core_set_command( "restore_status", m_url_article ); m_url_show_status = false; } return false; } // // drawarea のクリックイベント // bool ArticleViewBase::slot_button_press( std::string url, int res_number, GdkEventButton* event ) { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_button_press url = " << get_url() << std::endl; #endif // マウスジェスチャ get_control().MG_start( event ); // ホイールマウスジェスチャ get_control().MG_wheel_start( event ); ARTICLE::get_admin()->set_command( "switch_admin" ); return true; } // // drawarea でのマウスボタンのリリースイベント // bool ArticleViewBase::slot_button_release( std::string url, int res_number, GdkEventButton* event ) { /// マウスジェスチャ const int mg = get_control().MG_end( event ); // ホイールマウスジェスチャ // 実行された場合は何もしない if( get_control().MG_wheel_end( event ) ) return true; #ifdef _DEBUG std::cout << "ArticleViewBase::slot_button_release mg = " << mg << " url = " << get_url() << " url = " << url << " res = " << res_number << std::endl; #endif if( event->type == GDK_BUTTON_RELEASE ){ if( ! is_mouse_on_popup() ){ // マウスジェスチャ if( mg != CONTROL::None && enable_mg() ){ hide_popup(); operate_view( mg ); } // リンクをクリック else if( click_url( url, res_number, event ) ); // コンテキストメニュー表示 else if( get_control().button_alloted( event, CONTROL::PopupmenuButton ) ) show_popupmenu( url, false ); // 実況中の場合は停止 else if( get_control().button_alloted( event, CONTROL::ClickButton ) && get_live() ) ARTICLE::get_admin()->set_command( "live_start_stop", get_url() ); // その他 else operate_view( get_control().button_press( event ) ); } } return true; } // // drawarea でマウスが動いた // bool ArticleViewBase::slot_motion_notify( GdkEventMotion* event ) { /// マウスジェスチャ get_control().MG_motion( event ); return true; } // // drawareaのキープレスイベント // const bool ArticleViewBase::slot_key_press( GdkEventKey* event ) { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_key_press\n"; #endif // ポップアップはキーフォーカスを取れないので親からキー入力を送ってやる if( is_popup_shown() ){ ArticleViewBase* popup_article = dynamic_cast< ArticleViewBase* >( m_popup_win->view() ); if( popup_article ){ if( DBTREE::article_is_cached( popup_article->url_article() ) ) return popup_article->slot_key_press( event ); } else{ IMAGE::ImageViewPopup* popup_image = dynamic_cast< IMAGE::ImageViewPopup* >( m_popup_win->view() ); if( popup_image ) return popup_image->slot_key_press( event ); } } int key = get_control().key_press( event ); if( key != CONTROL::None ){ if( operate_view( key ) ) return true; } else if( release_keyjump_key( event->keyval ) ) return true; return false; } // // drawareaのキーリリースイベント // bool ArticleViewBase::slot_key_release( GdkEventKey* event ) { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_key_release\n"; #endif // ポップアップはキーフォーカスを取れないのでキー入力を送ってやる ArticleViewBase* popup_article = NULL; if( is_popup_shown() ) popup_article = dynamic_cast< ArticleViewBase* >( m_popup_win->view() ); if( popup_article ) return popup_article->slot_key_release( event ); return true; } // // drawareaのマウスホイールイベント // bool ArticleViewBase::slot_scroll_event( GdkEventScroll* event ) { // ポップアップしているときはそちらにイベントを送ってやる ArticleViewBase* popup_article = NULL; if( is_popup_shown() ) popup_article = dynamic_cast< ArticleViewBase* >( m_popup_win->view() ); if( popup_article ) return popup_article->slot_scroll_event( event ); // ホイールマウスジェスチャ int control = get_control().MG_wheel_scroll( event ); if( enable_mg() && control != CONTROL::None ){ operate_view( control ); return true; } m_drawarea->wheelscroll( event ); return true; } // // リンクの上にポインタが来た // // drawareaのsig_on_url()シグナルとつなぐ // void ArticleViewBase::slot_on_url( std::string url, std::string imgurl, int res_number ) { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_on_url = " << url << " imgurl = " << imgurl << std::endl; #endif // ポップアップが消えるまでに同じリンク上にポインタを乗せたら // カウンタをリセットする if( m_hidepopup_counter && m_popup_url == url ){ m_hidepopup_counter = 0; return; } CORE::VIEWFACTORY_ARGS args; SKELETON::View* view_popup = NULL; int margin_popup_x = 0; int margin_popup_y = CONFIG::get_margin_popup(); m_popup_url = url; // 画像ポップアップ if( DBIMG::get_type_ext( imgurl ) != DBIMG::T_UNKNOWN ){ // あぼーん if( DBIMG::get_abone( imgurl ) ){ args.arg1 = "あぼ〜んされています"; view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPHTML, m_url_article, args ); } else if( ( ! DBIMG::is_cached( imgurl ) || CONFIG::get_use_image_popup() ) && ( DBIMG::is_loading( imgurl ) || DBIMG::is_wait( imgurl ) || DBIMG::get_code( imgurl ) != HTTP_INIT ) ){ #ifdef _DEBUG std::cout << "image " << DBIMG::get_code( imgurl) << " " << DBIMG::is_loading( imgurl ) << "\n"; #endif view_popup = CORE::ViewFactory( CORE::VIEW_IMAGEPOPUP, imgurl ); margin_popup_x = CONFIG::get_margin_imgpopup_x(); margin_popup_y = CONFIG::get_margin_imgpopup(); } } // レスポップアップ else if( url.find( PROTO_ANCHORE ) == 0 ){ args.arg1 = url.substr( strlen( PROTO_ANCHORE) ); args.arg2 = "false"; // 板名、スレ名非表示 args.arg3 = "false"; // あぼーんしたレスの内容は非表示(あぼーんと表示) #ifdef _DEBUG std::cout << "anchore = " << args.arg1 << std::endl; #endif view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPRES, m_url_article, args ); } // レス番号 else if( url.find( PROTO_RES ) == 0 ){ args.arg1 = url.substr( strlen( PROTO_RES ) ); int tmp_num = atoi( args.arg1.c_str() ); #ifdef _DEBUG std::cout << "res = " << args.arg1 << std::endl; #endif // あぼーんされたレスの内容をポップアップ表示 if( m_article->get_abone( tmp_num ) ){ args.arg2 = "false"; // 板名、スレ名非表示 args.arg3 = "true"; // あぼーんレスの内容を表示 view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPRES, m_url_article, args ); } // 参照ポップアップ else if( CONFIG::get_refpopup_by_mo() && m_article->get_res_reference( tmp_num ).size() ){ view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPREFER, m_url_article, args ); } } // 抽出(or) else if( url.find( PROTO_OR ) == 0 ){ std::string url_tmp = url.substr( strlen( PROTO_OR ) ); int i = url_tmp.find( KEYWORD_SIGN ); std::string url_dat = DBTREE::url_dat( url_tmp.substr( 0, i ) ); args.arg1 = url_tmp.substr( i + strlen( KEYWORD_SIGN ) ); args.arg2 = "OR"; if( ! url_dat.empty() ){ view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPDRAWOUT, url_dat, args ); } } // しおり else if( url.find( PROTO_BM ) == 0 ){ const std::string url_tmp = url.substr( strlen( PROTO_BM ) ); const std::string url_dat = DBTREE::url_dat( url_tmp ); if( ! url_dat.empty() ){ view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPBM, url_dat ); } } // 名前ポップアップ else if( CONFIG::get_namepopup_by_mo() && url.find( PROTO_NAME ) == 0 ){ int num_name = m_article->get_num_name( res_number ); args.arg1 = m_article->get_name( res_number ); if( num_name >= 1 ){ view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPNAME, m_url_article, args ); } } // IDポップアップ else if( CONFIG::get_idpopup_by_mo() && url.find( PROTO_ID ) == 0 ){ args.arg1 = m_article->get_id_name( res_number ); int num_id = m_article->get_num_id_name( res_number ); if( num_id >= 1 ){ view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPID, m_url_article, args ); } } // ID:〜の範囲選択の上にポインタがあるときIDポップアップ else if( url.find( "ID:" ) == 0 ){ args.arg1 = PROTO_ID + url; int num_id = m_article->get_num_id_name( args.arg1 ); #ifdef _DEBUG std::cout << "num_id = " << num_id << std::endl; #endif if( num_id >= 1 ){ view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPID, m_url_article, args ); } } // その他のリンク else{ // dat 又は板の場合 int num_from, num_to; std::string num_str; const std::string url_dat = DBTREE::url_dat( url, num_from, num_to, num_str ); const std::string url_subject = DBTREE::url_subject( url ); #ifdef _DEBUG std::cout << "ArticleViewBase::slot_on_url " << url << std::endl; std::cout << "url_dat = " << url_dat << std::endl; std::cout << "url_subject = " << url_subject << std::endl; std::cout << "num_from = " << num_from << std::endl; std::cout << "num_to = " << num_to << std::endl; std::cout << "num = " << num_str << std::endl; #endif // 他スレ if( ! url_dat.empty() ){ if( num_from == 0 ) args.arg1 = "1"; // 最低でも1レス目は表示 else if( num_str.empty() ) args.arg1 = "1"; else args.arg1 = num_str; args.arg2 = "true"; // 板名、スレ名表示 args.arg3 = "false"; // あぼーんしたレスの内容は非表示(あぼーんと表示) view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPRES, url_dat, args ); } // 板 else if( ! url_subject.empty() ){ std::string tmpstr = DBTREE::board_name( url ); args.arg1 = "[ " + tmpstr + " ] "; view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPHTML, m_url_article, args ); } } if( view_popup ) show_popup( view_popup, margin_popup_x, margin_popup_y ); // リンクとして扱うURLをステータスバーに表示する if( MISC::is_url_scheme( url.c_str() ) != MISC::SCHEME_NONE ) { std::string status_url; // デコードが必要な物 if( url.find( "%" ) != std::string::npos ) { std::string tmp = MISC::url_decode( url ); const int char_code = MISC::judge_char_code( tmp ); switch( char_code ) { case MISC::CHARCODE_EUC_JP: status_url = MISC::Iconv( tmp, "EUC-JP", "UTF-8" ); break; case MISC::CHARCODE_JIS: status_url = MISC::Iconv( tmp, "ISO-2022-JP", "UTF-8" ); break; case MISC::CHARCODE_SJIS: status_url = MISC::Iconv( tmp, "MS932", "UTF-8" ); break; case MISC::CHARCODE_ASCII: case MISC::CHARCODE_UTF: status_url = tmp; break; default: status_url = url; } // 改行はスペースに変えておく status_url = MISC::replace_newlines_to_str( status_url, " " ); } // デコードの必要がない物 else { status_url = url; } // 一時的にステータスバーにURLを表示( 長くても全部表示しちゃう? ) CORE::core_set_command( "set_status_temporary", m_url_article, status_url ); m_url_show_status = true; } } // // リンクからマウスが出た // void ArticleViewBase::slot_leave_url() { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_leave_url\n"; #endif if( m_url_show_status ) { // ステータスバーの表示を戻す CORE::core_set_command( "restore_status", m_url_article ); m_url_show_status = false; } if( is_popup_shown() ){ if( CONFIG::get_hide_popup_msec() ) m_hidepopup_counter = CONFIG::get_hide_popup_msec() / TIMER_TIMEOUT; else hide_popup(); } } // // リンクをクリック // bool ArticleViewBase::click_url( std::string url, int res_number, GdkEventButton* event ) { assert( m_article ); if( url.empty() ) return false; CONTROL::Control& control = get_control(); #ifdef _DEBUG std::cout << "ArticleViewBase::click_url " << url << std::endl; #endif // プレビュー画面など、レスが存在しないときはいくつかの機能を無効にする const bool res_exist = ( ! m_article->empty() && m_article->res_header( res_number ) ); // ssspの場合は PROTO_SSSP が前に付いているので取り除く const bool sssp = ( url.find( PROTO_SSSP ) == 0 ); if( sssp ) url = url.substr( strlen( PROTO_SSSP ) ); ///////////////////////////////////////////////////////////////// // ID クリック if( url.find( PROTO_ID ) == 0 ){ if( ! res_exist ) return true; if( is_popup_shown() && control.button_alloted( event, CONTROL::PopupWarpButton ) ) warp_pointer_to_popup(); else{ hide_popup(); const int num_id = m_article->get_num_id_name( res_number ); m_id_name = m_article->get_id_name( res_number ); // ID ポップアップ if( num_id >= 1 && control.button_alloted( event, CONTROL::PopupIDButton ) ){ CORE::VIEWFACTORY_ARGS args; args.arg1 = m_id_name; SKELETON::View* view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPID, m_url_article, args ); const int margin_popup_x = 0; const int margin_popup_y = CONFIG::get_margin_popup(); show_popup( view_popup, margin_popup_x, margin_popup_y ); } else if( control.button_alloted( event, CONTROL::DrawoutIDButton ) ) slot_drawout_id(); else if( control.button_alloted( event, CONTROL::PopupmenuIDButton ) ){ show_popupmenu( url, false ); } } } ///////////////////////////////////////////////////////////////// // 名前クリック else if( url.find( PROTO_NAME ) == 0 ){ if( ! res_exist ) return true; if( is_popup_shown() && control.button_alloted( event, CONTROL::PopupWarpButton ) ) warp_pointer_to_popup(); else{ hide_popup(); int num_name = m_article->get_num_name( res_number ); m_name = m_article->get_name( res_number ); // 名前ポップアップ if( num_name >= 1 && control.button_alloted( event, CONTROL::PopupIDButton ) ){ CORE::VIEWFACTORY_ARGS args; args.arg1 = m_name; SKELETON::View* view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPNAME, m_url_article, args ); const int margin_popup_x = 0; const int margin_popup_y = CONFIG::get_margin_popup(); show_popup( view_popup, margin_popup_x, margin_popup_y ); } else if( control.button_alloted( event, CONTROL::DrawoutIDButton ) ) slot_drawout_name(); else if( control.button_alloted( event, CONTROL::PopupmenuIDButton ) ){ show_popupmenu( url, false ); } } } ///////////////////////////////////////////////////////////////// // あぼーんクリック else if( url.find( PROTO_ABONE ) == 0 ){ hide_popup(); if( control.button_alloted( event, CONTROL::PopupmenuAncButton ) ){ show_popupmenu( url, false ); } } ///////////////////////////////////////////////////////////////// // 壊れていますクリック else if( url.find( PROTO_BROKEN ) == 0 ){ hide_popup(); if( control.button_alloted( event, CONTROL::PopupmenuAncButton ) ){ show_popupmenu( url, false ); } } ///////////////////////////////////////////////////////////////// // 荒らし報告用URL表示クリック else if( url.find( PROTO_URL4REPORT ) == 0 ){ hide_popup(); m_show_url4report = true; relayout(); } ///////////////////////////////////////////////////////////////// // 書き込みログ表示クリック else if( url.find( PROTO_POSTLOG ) == 0 ){ hide_popup(); CORE::core_set_command( "open_article_postlog" ,"", url.substr( strlen( PROTO_POSTLOG ) ) ); } ///////////////////////////////////////////////////////////////// // BE クリック else if( url.find( PROTO_BE ) == 0 ){ if( ! res_exist ) return true; hide_popup(); std::stringstream ssurl; ssurl << "http://be.2ch.net/test/p.php?i=" << url.substr( strlen( PROTO_BE ) ) << "&u=d:" << DBTREE::url_readcgi( m_url_article, res_number, 0 ); #ifdef _DEBUG std::cout << "open " << ssurl.str() << std::endl; #endif if( control.button_alloted( event, CONTROL::OpenBeButton ) ) CORE::core_set_command( "open_url_browser", ssurl.str() ); else if( control.button_alloted( event, CONTROL::PopupmenuBeButton ) ){ show_popupmenu( ssurl.str(), false ); } } ///////////////////////////////////////////////////////////////// // アンカーをクリック else if( url.find( PROTO_ANCHORE ) == 0 ){ if( is_popup_shown() && control.button_alloted( event, CONTROL::PopupWarpButton ) ) warp_pointer_to_popup(); else{ // ジャンプ先セット m_jump_to = url.substr( strlen( PROTO_ANCHORE ) ); m_jump_from = MISC::itostr( res_number ); m_str_num = m_jump_to; #ifdef _DEBUG std::cout << "anchor num = " << m_str_num << std::endl; #endif hide_popup(); if( control.button_alloted( event, CONTROL::JumpAncButton ) ) slot_jump(); else if( control.button_alloted( event, CONTROL::PopupmenuAncButton ) ) show_popupmenu( url, false ); else if( control.button_alloted( event, CONTROL::DrawoutAncButton ) ) slot_drawout_around(); } } ///////////////////////////////////////////////////////////////// // レス番号クリック else if( url.find( PROTO_RES ) == 0 ){ if( ! res_exist ) return true; if( is_popup_shown() && control.button_alloted( event, CONTROL::PopupWarpButton ) ) warp_pointer_to_popup(); else{ hide_popup(); m_str_num = MISC::itostr( res_number ); m_url_tmp = DBTREE::url_readcgi( m_url_article, res_number, 0 ); // ジャンプ先セット m_jump_to = m_str_num; m_jump_from = m_str_num; if( control.button_alloted( event, CONTROL::PopupmenuResButton ) ) show_popupmenu( url, false ); // ブックマークセット else if( control.button_alloted( event, CONTROL::BmResButton ) ) slot_bookmark(); // 参照ポップアップ表示 else if( control.button_alloted( event, CONTROL::ReferResButton ) ){ CORE::VIEWFACTORY_ARGS args; args.arg1 = m_str_num; SKELETON::View* view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPREFER, m_url_article, args ); const int margin_popup_x = 0; const int margin_popup_y = CONFIG::get_margin_popup(); show_popup( view_popup, margin_popup_x, margin_popup_y ); } } } ///////////////////////////////////////////////////////////////// // OR抽出 else if( url.find( PROTO_OR ) == 0 ){ const std::string url_tmp = url.substr( strlen( PROTO_OR ) ); int i = url_tmp.find( KEYWORD_SIGN ); const std::string url_dat = DBTREE::url_dat( url_tmp.substr( 0, i ) ); if( ! url_dat.empty() ){ const std::string query = url_tmp.substr( i + strlen( KEYWORD_SIGN ) ); CORE::core_set_command( "open_article_keyword" ,url_dat, query, "true" ); } } ///////////////////////////////////////////////////////////////// // しおり抽出 else if( url.find( PROTO_BM ) == 0 ){ const std::string url_tmp = url.substr( strlen( PROTO_BM ) ); const std::string url_dat = DBTREE::url_dat( url_tmp ); if( ! url_dat.empty() ){ CORE::core_set_command( "open_article_bm" , url_dat ); } } ///////////////////////////////////////////////////////////////// // リンクフィルタ else if( control.button_alloted( event, CONTROL::ClickButton ) && CORE::get_linkfilter_manager()->exec( m_url_article, url, m_drawarea->str_pre_selection() ) ){} ///////////////////////////////////////////////////////////////// // 画像クリック else if( DBIMG::get_type_ext( url ) != DBIMG::T_UNKNOWN && ( CONFIG::get_use_image_view() || CONFIG::get_use_inline_image() || ( sssp && CONFIG::get_show_ssspicon() ) ) ){ hide_popup(); if( control.button_alloted( event, CONTROL::PopupmenuImageButton ) ){ m_str_num = MISC::itostr( res_number ); show_popupmenu( url, false ); } else if( ! DBIMG::is_cached( url ) && ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); } else if( DBIMG::get_abone( url )){ SKELETON::MsgDiag mdiag( get_parent_win(), "あぼ〜んされています" ); mdiag.run(); } else if( DBIMG::get_type_real( url ) == DBIMG::T_LARGE ){ SKELETON::MsgDiag mdiag( get_parent_win(), "画像サイズが大きすぎます。\n\n表示するにはリンクの上でコンテキストメニューを開いて\n「サイズが大きい画像を表示」をクリックしてください。" ); mdiag.run(); } else{ const bool open_imageview = ( ! sssp // sssp の時は画像ビューを開かない && CONFIG::get_use_image_view() && ( control.button_alloted( event, CONTROL::ClickButton ) || control.button_alloted( event, CONTROL::OpenBackImageButton ) ) ); const bool open_browser = ( ! open_imageview && control.button_alloted( event, CONTROL::ClickButton ) ); const bool mosaic = ( CONFIG::get_use_mosaic() && ! sssp // sssp の時はモザイクをかけない ); // 画像ビューに切り替える const bool switch_image = ( open_imageview && ! control.button_alloted( event, CONTROL::OpenBackImageButton ) ); open_image( url, res_number, open_imageview, open_browser, mosaic, switch_image ); } } ///////////////////////////////////////////////////////////////// // ブラウザで開く else if( control.button_alloted( event, CONTROL::ClickButton ) ){ std::string tmp_url = url; // 相対パス if( url.find( "./" ) == 0 ) tmp_url = DBTREE::url_boardbase( m_url_article ) + url.substr( 1 ); // 絶対パス else if( url.find( "/" ) == 0 ) tmp_url = DBTREE::url_root( m_url_article ) + url.substr( 1 ); hide_popup(); // tmp_urlが他スレのアドレスなら、datロード終了時に次スレ移行チェックを行う DBTREE::article_set_url_pre_article( tmp_url, m_url_article ); CORE::core_set_command( "open_url", tmp_url ); } ///////////////////////////////////////////////////////////////// // 失敗 else return false; return true; } // // 画像表示 // void ArticleViewBase::open_image( const std::string& url, const int res_number, const bool open_imageview, const bool open_browser, const bool mosaic, const bool switch_image ) { #ifdef _DEBUG std::cout << "ArticleViewBase::open_image url = " << url << " num = " << res_number << " open_view = " << open_imageview << " open_browser = " << open_browser << " mosaic = " << mosaic << " switch_image = " << switch_image << std::endl; #endif bool load = false; // キャッシュに無かったらロード if( ! DBIMG::is_cached( url ) ){ DBIMG::download_img( url, DBTREE::url_readcgi( m_url_article, res_number, 0 ), mosaic ); // ポップアップ表示してダウンロードサイズを表示 hide_popup(); SKELETON::View* view_popup = CORE::ViewFactory( CORE::VIEW_IMAGEPOPUP, url ); const int margin_popup_x = CONFIG::get_margin_imgpopup_x(); const int margin_popup_y = CONFIG::get_margin_imgpopup(); show_popup( view_popup, margin_popup_x, margin_popup_y ); load = true; } // 画像ビューを開く if( open_imageview ){ CORE::core_set_command( "open_image", url ); if( ! load && switch_image ) CORE::core_set_command( "switch_image" ); } // ブラウザで画像を開く else if( ! load && open_browser ) CORE::core_set_command( "open_url", url ); redraw_view(); } // // ポップアップが表示されているか // const bool ArticleViewBase::is_popup_shown() const { return ( m_popup_win && m_popup_shown ); } // // ポップアップが表示されていてかつマウスがその上にあるか // const bool ArticleViewBase::is_mouse_on_popup() { if( ! is_popup_shown() ) return false; return m_popup_win->view()->is_mouse_on_view(); } // // ポップアップ表示 // // view にあらかじめ内容をセットしてから呼ぶこと // viewは SKELETON::PopupWin のデストラクタで削除される // void ArticleViewBase::show_popup( SKELETON::View* view, const int mrg_x, const int mrg_y ) { hide_popup(); if( !view ) return; delete_popup(); m_popup_win = new SKELETON::PopupWin( this, view, mrg_x, mrg_y ); m_popup_win->signal_leave_notify_event().connect( sigc::mem_fun( *this, &ArticleViewBase::slot_popup_leave_notify_event ) ); m_popup_win->sig_hide_popup().connect( sigc::mem_fun( *this, &ArticleViewBase::slot_hide_popup ) ); m_popup_shown = true; } // // 子 popup windowの外にポインタが出た // bool ArticleViewBase::slot_popup_leave_notify_event( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_popup_leave_notify_event\n"; #endif // クリックしたときやホイールを回すと event->mode に GDK_CROSSING_GRAB // か GDK_CROSSING_UNGRAB がセットされてイベントが発生する場合がある if( event->mode == GDK_CROSSING_GRAB ) return false; if( event->mode == GDK_CROSSING_UNGRAB ) return false; // ポインタがポップアップ上だったらポップアップは消さない // 時々ポインタがポップアップの上にあってもイベントが発生する場合がある if( is_mouse_on_popup() ) return false; if( CONFIG::get_hide_popup_msec() ) m_hidepopup_counter = CONFIG::get_hide_popup_msec() / TIMER_TIMEOUT; else slot_hide_popup(); return true; } // // 子 popup windowからhide依頼が来た // void ArticleViewBase::slot_hide_popup() { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_hide_popup\n"; #endif hide_popup(); // ポインタがwidgetの外にあったら親に知らせて自分も閉じてもらう if( ! is_mouse_on_view() ) sig_hide_popup().emit(); } // // popup のhide // // force = true ならチェック無しで強制 hide // void ArticleViewBase::hide_popup( const bool force ) { if( ! is_popup_shown() ) return; m_hidepopup_counter = 0; #ifdef _DEBUG std::cout << "ArticleViewBase::hide_popup force = " << force << " " << get_url() << std::endl; #endif // ArticleView をポップアップ表示している場合 ArticleViewBase* popup_article = NULL; popup_article = dynamic_cast< ArticleViewBase* >( m_popup_win->view() ); if( popup_article ){ if( ! force ){ // 孫のpopupが表示されてたらhideしない if( popup_article->is_popup_shown() ) return; // ポップアップメニューが表示されてたらhideしない // ( ポップアップメニューがhideしたときにhideする ) if( SESSION::is_popupmenu_shown() ) return; #ifdef _DEBUG std::cout << "target = " << popup_article->get_url() << std::endl; #endif } popup_article->hide_popup( force ); } m_popup_win->hide(); if( m_popup_win->view() ) m_popup_win->view()->stop(); m_popup_shown = false; m_drawarea->redraw_view(); } // // ポップアップの削除 // void ArticleViewBase::delete_popup() { #ifdef _DEBUG std::cout << "ArticleViewBase::delete_popup " << get_url() << std::endl; #endif if( m_popup_win ) delete m_popup_win; m_popup_win = NULL; m_popup_shown = false; } // // ポップアップメニューを表示する前にメニューのアクティブ状態を切り替える // // SKELETON::View::show_popupmenu() を参照すること // void ArticleViewBase::activate_act_before_popupmenu( const std::string& url ) { #ifdef _DEBUG std::cout << "ArticleViewBase::activate_act_before_popupmenu url = " << url << std::endl; #endif // toggle アクションを activeにするとスロット関数が呼ばれるので処理しないようにする m_enable_menuslot = false; // 子ポップアップが表示されていて、かつポインタがその上だったら表示しない ArticleViewBase* popup_article = NULL; if( is_popup_shown() ) popup_article = dynamic_cast< ArticleViewBase* >( m_popup_win->view() ); if( popup_article && popup_article->is_mouse_on_view() ) return; hide_popup(); Glib::RefPtr< Gtk::Action > act, act2; act = action_group()->get_action( "CopyURL" ); act2 = action_group()->get_action( "OpenBrowser" ); // url がセットされてない if( url.empty() ) { if( act ) act->set_sensitive( false ); if( act2 ) act2->set_sensitive( false ); m_url_tmp = std::string(); } // url がセットされている else { if( act ) act->set_sensitive( true ); if( act2 ) act2->set_sensitive( true ); // レス番号クリックの場合 if( url.find( PROTO_RES ) == 0 ){ m_url_tmp = DBTREE::url_readcgi( m_url_article, atoi( url.substr( strlen( PROTO_RES ) ).c_str() ), 0 ); } // アンカークリックの場合 else if( url.find( PROTO_ANCHORE ) == 0 ){ m_url_tmp = DBTREE::url_readcgi( m_url_article, atoi( url.substr( strlen( PROTO_ANCHORE ) ).c_str() ), 0 ); } else m_url_tmp = url; } // 検索ビューや書き込みログ表示などの場合 const bool nourl = DBTREE::url_readcgi( m_url_article, 0, 0 ).empty(); act = action_group()->get_action( "Drawout_Menu" ); if( act ){ if( nourl ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "SearchCacheLocal" ); if( act ){ if( nourl ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "SearchCacheAll" ); if( act ){ if( nourl ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "SearchNextArticle" ); if( act ){ if( nourl ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "QuoteRes" ); if( act ){ if( nourl ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "SaveDat" ); if( act ){ if( nourl ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "PreferenceArticle" ); if( act ){ if( nourl ) act->set_sensitive( false ); else act->set_sensitive( true ); } // 範囲選択されてない const unsigned int max_selection_str = 1024; const unsigned int max_selection_str_quote = 8192; std::string str_select = m_drawarea->str_selection(); act = action_group()->get_action( "QuoteSelectionRes" ); if( act ){ if( nourl || str_select.empty() || str_select.length() > max_selection_str_quote ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "Copy" ); if( act ){ if( str_select.empty() ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "DrawoutWord" ); if( act ){ if( str_select.empty() || str_select.length() > max_selection_str ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "AboneWord_Menu" ); if( act ){ if( nourl || str_select.empty() || str_select.length() > max_selection_str ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "AboneSelectionRes" ); if( act ){ if( nourl || str_select.empty() ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "ShowSelectImage" ); if( act ){ if( str_select.empty() || ! m_drawarea->get_selection_imgurls().size() ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "DeleteSelectImage_Menu" ); if( act ){ if( str_select.empty() || ! m_drawarea->get_selection_imgurls().size() ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "AboneSelectImage_Menu" ); if( act ){ if( str_select.empty() || ! m_drawarea->get_selection_imgurls().size() ) act->set_sensitive( false ); else act->set_sensitive( true ); } // 検索関係 act = action_group()->get_action( "SearchWeb" ); if( act ){ if( str_select.empty() || str_select.length() > max_selection_str ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "SearchCacheLocal" ); if( act ){ if( str_select.empty() || str_select.length() > max_selection_str ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "SearchCacheAll" ); if( act ){ if( str_select.empty() || str_select.length() > max_selection_str ) act->set_sensitive( false ); else act->set_sensitive( true ); } act = action_group()->get_action( "SearchTitle" ); if( act ){ if( str_select.empty() || str_select.length() > max_selection_str ) act->set_sensitive( false ); else act->set_sensitive( true ); } // ユーザコマンド // 選択不可かどうか判断して visible か sensitive にする CORE::get_usrcmd_manager()->toggle_sensitive( action_group(), m_url_article, url, str_select ); // ブックマークがセットされていない act = action_group()->get_action( "DrawoutBM" ); if( act ){ if( m_article->get_num_bookmark() ) act->set_sensitive( true ); else act->set_sensitive( false ); } act = action_group()->get_action( "PreBookMark" ); if( act ){ if( m_article->get_num_bookmark() ) act->set_sensitive( true ); else act->set_sensitive( false ); } act = action_group()->get_action( "NextBookMark" ); if( act ){ if( m_article->get_num_bookmark() ) act->set_sensitive( true ); else act->set_sensitive( false ); } // 書き込みしていない act = action_group()->get_action( "DrawoutPost" ); if( act ){ if( m_article->get_num_posted() ) act->set_sensitive( true ); else act->set_sensitive( false ); } act = action_group()->get_action( "PrePost" ); if( act ){ if( m_article->get_num_posted() ) act->set_sensitive( true ); else act->set_sensitive( false ); } act = action_group()->get_action( "NextPost" ); if( act ){ if( m_article->get_num_posted() ) act->set_sensitive( true ); else act->set_sensitive( false ); } // 新着移動 act = action_group()->get_action( "GotoNew" ); if( act ){ if( m_article->get_number_new() ) act->set_sensitive( true ); else act->set_sensitive( false ); } // 進む、戻る act = action_group()->get_action( "PrevView" ); if( act ){ if( HISTORY::get_history_manager()->can_back_viewhistory( get_url(), 1 ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } act = action_group()->get_action( "NextView" ); if( act ){ if( HISTORY::get_history_manager()->can_forward_viewhistory( get_url(), 1 ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } // 透明あぼーん act = action_group()->get_action( "TranspAbone" ); if( act ){ Glib::RefPtr< Gtk::ToggleAction > tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( m_article->get_abone_transparent() ) tact->set_active( true ); else tact->set_active( false ); } // 透明/連鎖あぼーん act = action_group()->get_action( "TranspChainAbone" ); if( act ){ Glib::RefPtr< Gtk::ToggleAction > tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( m_article->get_abone_transparent() && m_article->get_abone_chain() ) tact->set_active( true ); else tact->set_active( false ); } // 画像 if( ! url.empty() && DBIMG::get_type_ext( url ) != DBIMG::T_UNKNOWN ){ // モザイク解除 act = action_group()->get_action( "Cancel_Mosaic" ); if( act ){ if( DBIMG::is_cached( url ) && DBIMG::get_mosaic( url ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } // モザイクで開く act = action_group()->get_action( "Show_Mosaic" ); if( act ){ if( ! DBIMG::is_cached( url ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } // サイズの大きい画像を表示 act = action_group()->get_action( "ShowLargeImg" ); if( act ){ if( DBIMG::get_type_real( url ) == DBIMG::T_LARGE ) act->set_sensitive( true ); else act->set_sensitive( false ); } // 保護のトグル切替え act = action_group()->get_action( "ProtectImage" ); if( act ){ if( DBIMG::is_cached( url ) ){ act->set_sensitive( true ); Glib::RefPtr< Gtk::ToggleAction > tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( DBIMG::is_protected( url ) ) tact->set_active( true ); else tact->set_active( false ); } else act->set_sensitive( false ); } // 削除 act = action_group()->get_action( "DeleteImage_Menu" ); if( act ){ if( DBIMG::get_code( url ) != HTTP_INIT && ! DBIMG::is_protected( url ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } // 保存 act = action_group()->get_action( "SaveImage" ); if( act ){ if( DBIMG::is_cached( url ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } // プロパティ act = action_group()->get_action( "PreferenceImage" ); if( act ){ if( DBIMG::is_cached( url ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } // あぼーん act = action_group()->get_action( "AboneImage" ); if( act ){ if( DBIMG::is_protected( url ) ) act->set_sensitive( false ); else{ act->set_sensitive( true ); Glib::RefPtr< Gtk::ToggleAction > tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( DBIMG::get_abone( url ) ) tact->set_active( true ); else tact->set_active( false ); } } // キャッシュをブラウザで開く act = action_group()->get_action( "OpenCacheBrowser" ); if( act ){ if( DBIMG::is_cached( url ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } } // スレ情報コピー act = action_group()->get_action( "CopyInfo" ); if( act ){ if( ! url.empty() && ! DBTREE::url_dat( url ).empty() ) act->set_sensitive( true ); else act->set_sensitive( false ); } m_enable_menuslot = true; } // // ポップアップメニュー取得 // // SKELETON::View::show_popupmenu() を参照すること // Gtk::Menu* ArticleViewBase::get_popupmenu( const std::string& url ) { // 表示 Gtk::Menu* popupmenu = NULL; // 削除サブメニュー if( url == "popup_menu_delete" ){ popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_delete" ) ); } // レス番号ポップアップメニュー else if( url.find( PROTO_RES ) == 0 ){ popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_res" ) ); } // アンカーポップアップメニュー else if( url.find( PROTO_ANCHORE ) == 0 ){ popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_anc" ) ); } // IDポップアップメニュー else if( url.find( PROTO_ID ) == 0 ){ popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_id" ) ); } // 名前ポップアップメニュー else if( url.find( PROTO_NAME ) == 0 ){ popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_name" ) ); } // あぼーんポップアップメニュー else if( url.find( PROTO_ABONE ) == 0 ){ popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_abone" ) ); } // 壊れていますポップアップメニュー else if( url.find( PROTO_BROKEN ) == 0 ){ popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_broken" ) ); } // 画像ポップアップメニュー else if( DBIMG::get_type_ext( url ) != DBIMG::T_UNKNOWN ){ popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_img" ) ); } // 通常メニュー else popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu" ) ); return popupmenu; } // // クリップボードに選択文字コピーのメニュー // void ArticleViewBase::slot_copy_selection_str() { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_copy_selection_str " << get_url() << std::endl; #endif if( m_drawarea->str_selection().empty() ) return; MISC::CopyClipboard( m_drawarea->str_selection() ); } // // 全選択 // void ArticleViewBase::slot_select_all() { if( m_drawarea ) m_drawarea->select_all(); } // // 選択して抽出 // void ArticleViewBase::slot_drawout_selection_str() { std::string query = m_drawarea->str_selection(); query = MISC::remove_spaces( query ); query = MISC::replace_str( query, "\n", "" ); if( query.find( " " ) != std::string::npos ) query = "\"" + query + "\""; if( query.empty() ) return; const bool escape = false; // \ を エスケープ文字として考慮しない CORE::core_set_command( "open_article_keyword" ,m_url_article, MISC::regex_escape( query, escape ), "false" ); } // // 全ログ検索実行 // void ArticleViewBase::slot_search_cacheall() { std::string query = m_drawarea->str_selection(); query = MISC::replace_str( query, "\n", "" ); if( query.empty() ) return; #ifdef _DEBUG std::cout << "ArticleViewBase::slot_search_cacheall "<< query << std::endl; #endif CORE::core_set_command( "open_article_searchlog", URL_SEARCH_ALLBOARD , query, "exec" ); } // // ログ検索実行 // void ArticleViewBase::slot_search_cachelocal() { std::string query = m_drawarea->str_selection(); query = MISC::replace_str( query, "\n", "" ); if( query.empty() ) return; const std::string url = DBTREE::url_subject( m_url_article ); #ifdef _DEBUG std::cout << "ArticleViewBase::slot_search_cachelocal " << url << std::endl << query << std::endl; #endif CORE::core_set_command( "open_article_searchlog", url , query, "exec" ); } // // 次スレ検索 // void ArticleViewBase::slot_search_next() { if( m_article->empty() ) return; CORE::core_set_command( "open_board_next", DBTREE::url_subject( m_url_article ) , m_url_article ); } // // web検索実行 // void ArticleViewBase::slot_search_web() { std::string query = m_drawarea->str_selection(); query = MISC::replace_str( query, "\n", "" ); if( query.empty() ) return; std::string url = CORE::get_usrcmd_manager()->replace_cmd( CONFIG::get_url_search_web(), "", "", query, 0 ); #ifdef _DEBUG std::cout << "ArticleViewBase::slot_search_web query = " << query << std::endl; std::cout << "url = " << url << std::endl; #endif CORE::core_set_command( "open_url_browser", url ); } // // スレタイ検索実行 // void ArticleViewBase::slot_search_title() { std::string query = m_drawarea->str_selection(); query = MISC::replace_str( query, "\n", "" ); #ifdef _DEBUG std::cout << "ArticleViewBase::slot_search_title query = " << query << std::endl; #endif if( query.empty() ) CORE::core_set_command( "open_article_searchtitle", "", "", "noexec" ); else CORE::core_set_command( "open_article_searchtitle", "" , query, "exec" ); } // // ユーザコマンド実行 // void ArticleViewBase::slot_usrcmd( int num ) { int res_num = 0; if( m_drawarea ) res_num = m_drawarea->get_current_res_num(); CORE::core_set_command( "exec_usr_cmd" ,m_url_article, MISC::itostr( num ), m_url_tmp, m_drawarea->str_selection(), MISC::itostr( res_num ) ); } // // ブックマーク設定、解除 // // 呼び出す前に m_str_num に対象のレス番号を入れておくこと // void ArticleViewBase::slot_bookmark() { if( m_str_num.empty() ) return; int number = atoi( m_str_num.c_str() ); bool bookmark = ! DBTREE::is_bookmarked( m_url_article, number ); DBTREE::set_bookmark( m_url_article, number, bookmark ); if( bookmark ) m_current_bm = number; redraw_view(); ARTICLE::get_admin()->set_command( "redraw_views", m_url_article ); } // // 書き込みマーク設定、解除 // // 呼び出す前に m_str_num に対象のレス番号を入れておくこと // void ArticleViewBase::slot_postedmark() { if( m_str_num.empty() ) return; int number = atoi( m_str_num.c_str() ); bool postedmark = ! m_article->is_posted( number ); m_article->set_posted( number, postedmark ); redraw_view(); ARTICLE::get_admin()->set_command( "redraw_views", m_url_article ); } // // ポップアップメニューでブラウザで開くを選択 // void ArticleViewBase::slot_open_browser() { if( m_url_tmp.empty() ) return; CORE::core_set_command( "open_url_browser", m_url_tmp ); } // // ポップアップメニューで画像のキャッシュをブラウザで開くを選択 // void ArticleViewBase::slot_open_cache_browser() { if( m_url_tmp.empty() ) return; if( ! DBIMG::is_cached( m_url_tmp ) ) return; const std::string url = "file://" + DBIMG::get_cache_path( m_url_tmp ); CORE::core_set_command( "open_url_browser", url ); } // // レスをする // // 呼び出す前に m_str_num に対象のレス番号を入れておくこと // void ArticleViewBase::slot_write_res() { if( m_article->empty() ) return; if( m_str_num.empty() ) return; #ifdef _DEBUG std::cout << "ArticleViewBase::slot_write_res number = " << m_str_num << std::endl; #endif CORE::core_set_command( "open_message" ,m_url_article, ">>" + m_str_num + "\n" ); } // // 参照レスをする // // 呼び出す前に m_str_num に対象のレス番号を入れておくこと // void ArticleViewBase::slot_quote_res() { assert( m_article ); if( m_str_num.empty() ) return; #ifdef _DEBUG std::cout << "ArticleViewBase::slot_quote_res number = " << m_str_num << std::endl; #endif CORE::core_set_command( "open_message" ,m_url_article, ">>" + m_str_num + "\n" + m_article->get_res_str( atoi( m_str_num.c_str() ), true ) ); } // // 選択部分を引用してレスする // void ArticleViewBase::slot_quote_selection_res() { assert( m_article ); const int num_from = m_drawarea->get_selection_resnum_from(); if( ! num_from ) return; const int num_to = m_drawarea->get_selection_resnum_to(); std::string str_num = MISC::itostr( num_from ); if( num_from < num_to ) str_num += "-" + MISC::itostr( num_to ); std::string str_res; str_res = CONFIG::get_ref_prefix(); std::string query = m_drawarea->str_selection(); if( query.empty() ) return; query = MISC::replace_str( query, "\n", "\n" + str_res ); #ifdef _DEBUG std::cout << "ArticleViewBase::slot_quote_selection_res number = " << str_num << std::endl; #endif CORE::core_set_command( "open_message", m_url_article, ">>" + str_num + "\n" + str_res + query + "\n" ); } // // リンクのURLをコピーのメニュー // void ArticleViewBase::slot_copy_current_url() { if( m_url_tmp.empty() ) return; #ifdef _DEBUG std::cout << "ArticleViewBase::slot_copy_current_url url = " << m_url_tmp << std::endl; #endif MISC::CopyClipboard( m_url_tmp ); } // // 名前をコピー // // 呼び出す前に m_name に名前をセットしておくこと // void ArticleViewBase::slot_copy_name() { std::string name = m_name; MISC::CopyClipboard( name ); } // // IDをコピー // // 呼び出す前に m_id_name にIDをセットしておくこと // void ArticleViewBase::slot_copy_id() { std::string id = m_id_name.substr( strlen( PROTO_ID ) ); MISC::CopyClipboard( id ); } // // レス番号クリック時のレスのコピーのメニュー // // 呼び出す前に m_str_num に対象のレス番号を入れておくこと // void ArticleViewBase::slot_copy_res( bool ref ) { assert( m_article ); if( m_str_num.empty() ) return; #ifdef _DEBUG std::cout << "ArticleViewBase::copy_res number = " << m_str_num << std::endl; #endif std::string tmpstr = m_url_tmp + "\n"; if( ref ) tmpstr += CONFIG::get_ref_prefix(); std::string board_name = DBTREE::board_name( m_url_article ); if( ! board_name.empty() ) tmpstr += "[ " + board_name + " ] "; tmpstr += DBTREE::article_subject( m_url_article ) + "\n\n"; tmpstr += m_article->get_res_str( atoi( m_str_num.c_str() ), ref ); MISC::CopyClipboard( tmpstr ); } // // スレのタイトルとURLをコピー // void ArticleViewBase::slot_copy_title_url() { MISC::CopyClipboard( DBTREE::article_subject( m_url_article ) + '\n' + url_for_copy() ); } // // お気に入り登録 // void ArticleViewBase::set_favorite() { if( m_article->empty() ) return; CORE::DATA_INFO info; info.type = TYPE_THREAD; info.parent = ARTICLE::get_admin()->get_win(); info.url = m_url_article;; info.name = DBTREE::article_subject( m_url_article ); info.path = Gtk::TreePath( "0" ).to_string(); CORE::DATA_INFO_LIST list_info; list_info.push_back( info ); CORE::SBUF_set_list( list_info ); CORE::core_set_command( "append_favorite", URL_FAVORITEVIEW ); } // // 別のタブを開いてレス抽出 // // 呼び出す前に m_str_num に抽出するレスをセットしておくこと // void ArticleViewBase::slot_drawout_res() { CORE::core_set_command( "open_article_res" ,m_url_article, m_str_num ); } // // 別のタブを開いて周辺のレスを抽出 // // 呼び出す前に m_str_num に対象のレス番号を入れておくこと // void ArticleViewBase::slot_drawout_around() { const int range = 10; int center = atoi( m_str_num.c_str() ); int from = MAX( 0, center - range ); int to = center + range; std::stringstream ss; ss << from << "-" << to; CORE::core_set_command( "open_article_res" ,m_url_article, ss.str(), m_str_num ); } // // 別のタブを開いてテンプレート表示 // void ArticleViewBase::slot_drawout_tmp() { const int to = 20; std::stringstream ss; ss << "1-" << to; CORE::core_set_command( "open_article_res" ,m_url_article, ss.str() ); } // // 別のタブを開いて名前抽出 // // 呼び出す前に m_name にIDをセットしておくこと // void ArticleViewBase::slot_drawout_name() { CORE::core_set_command( "open_article_name" ,m_url_article, m_name ); } // // 別のタブを開いてID抽出 // // 呼び出す前に m_id_name にIDをセットしておくこと // void ArticleViewBase::slot_drawout_id() { CORE::core_set_command( "open_article_id" ,m_url_article, m_id_name ); } // // 別のタブを開いてブックマーク抽出 // void ArticleViewBase::slot_drawout_bm() { CORE::core_set_command( "open_article_bm" ,m_url_article ); } // // 別のタブを開いて自分の書き込みを抽出 // void ArticleViewBase::slot_drawout_post() { CORE::core_set_command( "open_article_post" ,m_url_article ); } // // 別のタブを開いて参照抽出 // // 呼び出す前に m_str_num に対象のレス番号を入れておくこと // void ArticleViewBase::slot_drawout_refer() { CORE::core_set_command( "open_article_refer" ,m_url_article, m_str_num ); } // // 別のタブを開いてURL抽出 // void ArticleViewBase::slot_drawout_url() { CORE::core_set_command( "open_article_url" ,m_url_article ); } // // レス番号であぼ〜ん // // 呼び出す前に m_str_num に対象のレス番号を入れておくこと // void ArticleViewBase::slot_abone_res() { const int number = atoi( m_str_num.c_str() ); DBTREE::set_abone_res( m_url_article, number, number, true ); // 再レイアウト ARTICLE::get_admin()->set_command( "relayout_views", m_url_article ); } // // 選択範囲内のレス番号であぼ〜ん // void ArticleViewBase::slot_abone_selection_res() { const int num_from = m_drawarea->get_selection_resnum_from(); if( ! num_from ) return; const int num_to = m_drawarea->get_selection_resnum_to(); DBTREE::set_abone_res( m_url_article, num_from, num_to, true ); // 再レイアウト ARTICLE::get_admin()->set_command( "relayout_views", m_url_article ); } // // IDであぼ〜ん(ローカル、板(一時的) ) // // 呼び出す前に m_id_name にIDをセットしておくこと // void ArticleViewBase::slot_abone_id() { DBTREE::add_abone_id( m_url_article, m_id_name ); DBTREE::add_abone_id_board( m_url_article, m_id_name ); } // // 名前であぼ〜ん // // 呼び出す前に m_name に名前をセットしておくこと // void ArticleViewBase::slot_abone_name() { DBTREE::add_abone_name( m_url_article, m_name ); // 再レイアウト ARTICLE::get_admin()->set_command( "relayout_views", m_url_article ); } // // 範囲選択した文字列であぼ〜ん // void ArticleViewBase::slot_abone_word() { DBTREE::add_abone_word( m_url_article, m_drawarea->str_selection() ); // 再レイアウト ARTICLE::get_admin()->set_command( "relayout_views", m_url_article ); } // // 名前であぼ〜ん(板レベル) // // 呼び出す前に m_name に名前をセットしておくこと // void ArticleViewBase::slot_abone_name_board() { DBTREE::add_abone_name_board( m_url_article, m_name ); DBTREE::board_save_info( m_url_article ); } // // 範囲選択した文字列であぼ〜ん(板レベル) // void ArticleViewBase::slot_abone_word_board() { DBTREE::add_abone_word_board( m_url_article, m_drawarea->str_selection() ); DBTREE::board_save_info( m_url_article ); } // // 名前であぼ〜ん(全体) // // 呼び出す前に m_name に名前をセットしておくこと // void ArticleViewBase::slot_global_abone_name() { CORE::core_set_command( "set_global_abone_name", "", m_name ); } // // 範囲選択した文字列であぼ〜ん(全体) // void ArticleViewBase::slot_global_abone_word() { CORE::core_set_command( "set_global_abone_word", "", m_drawarea->str_selection() ); } // // 透明あぼーん // void ArticleViewBase::slot_toggle_abone_transp() { if( ! m_enable_menuslot ) return; assert( m_article ); bool setval = true; if( m_article->get_abone_transparent() ) setval = false; m_article->set_abone_transparent( setval ); // 再レイアウト ARTICLE::get_admin()->set_command( "relayout_views", m_url_article ); } // // 透明/連鎖あぼーん // void ArticleViewBase::slot_toggle_abone_transp_chain() { if( ! m_enable_menuslot ) return; assert( m_article ); bool setval = true; if( m_article->get_abone_transparent() && m_article->get_abone_chain() ) setval = false; m_article->set_abone_transparent( setval ); m_article->set_abone_chain( setval ); // 再レイアウト ARTICLE::get_admin()->set_command( "relayout_views", m_url_article ); } // // 画像のモザイク解除 // void ArticleViewBase::slot_cancel_mosaic() { if( ! DBIMG::is_cached( m_url_tmp ) ) return; if( DBIMG::is_fake( m_url_tmp ) ){ SKELETON::MsgDiag mdiag( get_parent_win(), "拡張子が偽装されています。モザイクを解除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; } DBIMG::set_mosaic( m_url_tmp, false ); CORE::core_set_command( "redraw", m_url_tmp ); } // // 画像をモザイク付きでダウンロード及び表示 // void ArticleViewBase::slot_show_image_with_mosaic() { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_show_image_with_mosaic url = " << m_url_tmp << " num = " << m_str_num << std::endl; #endif if( DBIMG::is_cached( m_url_tmp ) ) return; const int res_number = atoi( m_str_num.c_str() ); if( ! res_number ) return; const bool open_imageview = CONFIG::get_use_image_view(); const bool open_browser = ! open_imageview; const bool mosaic = true; const bool switch_image = open_imageview; open_image( m_url_tmp, res_number, open_imageview, open_browser, mosaic, switch_image ); } // // 選択範囲の画像を開く // void ArticleViewBase::slot_show_selection_images() { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_show_selection_images\n"; #endif if( m_drawarea->get_selection_imgurls().size() ){ bool first = true; std::vector< URLINFO >::const_iterator it = m_drawarea->get_selection_imgurls().begin(); for( ; it != m_drawarea->get_selection_imgurls().end(); ++it ){ const std::string& url = (*it).url; const int res_number = (*it).res_number; if( DBIMG::get_abone( url ) ) continue; // オフラインでキャッシュが無い場合はスキップ if( ! SESSION::is_online() && ! DBIMG::is_cached( url ) ) continue; const std::string refurl = DBTREE::url_readcgi( m_url_article, res_number, 0 ); const bool open_imageview = CONFIG::get_use_image_view(); const bool mosaic = CONFIG::get_use_mosaic(); #ifdef _DEBUG std::cout << url << " - " << res_number << " : " << refurl << std::endl; #endif if( ! DBIMG::is_cached( url ) ){ DBIMG::download_img_wait( url, refurl, mosaic, first ); first = false; } if( open_imageview ) CORE::core_set_command( "open_image", url ); } redraw_view(); } } // // 選択範囲の画像を削除 // void ArticleViewBase::slot_delete_selection_images() { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_delete_selection_images\n"; #endif if( m_drawarea->get_selection_imgurls().size() ){ std::vector< URLINFO >::const_iterator it = m_drawarea->get_selection_imgurls().begin(); for( ; it != m_drawarea->get_selection_imgurls().end(); ++it ){ const std::string& url = (*it).url; if( ! DBIMG::is_protected( url ) ){ CORE::core_set_command( "delete_image", url ); } } redraw_view(); } } // // 選択範囲の画像をあぼーん // void ArticleViewBase::slot_abone_selection_images() { #ifdef _DEBUG std::cout << "ArticleViewBase::slot_abone_selection_images\n"; #endif if( m_drawarea->get_selection_imgurls().size() ){ std::vector< URLINFO >::const_iterator it = m_drawarea->get_selection_imgurls().begin(); for( ; it != m_drawarea->get_selection_imgurls().end(); ++it ){ const std::string& url = (*it).url; if( ! DBIMG::is_protected( url ) ){ DBIMG::set_abone( url, true ); CORE::core_set_command( "delete_image", url ); } } redraw_view(); } } // // 大きい画像を表示 // void ArticleViewBase::slot_show_large_img() { DBIMG::show_large_img( m_url_tmp ); } // // 画像削除 // void ArticleViewBase::slot_deleteimage() { if( ! m_url_tmp.empty() ) CORE::core_set_command( "delete_image", m_url_tmp ); } // // 画像保存 // void ArticleViewBase::slot_saveimage() { DBIMG::save( m_url_tmp, NULL, std::string() ); } // // 画像保護 // void ArticleViewBase::slot_toggle_protectimage() { if( ! m_enable_menuslot ) return; DBIMG::set_protect( m_url_tmp , ! DBIMG::is_protected( m_url_tmp ) ); } // // 画像あぼ〜ん // void ArticleViewBase::slot_abone_img() { if( ! m_enable_menuslot ) return; if( m_url_tmp.empty() ) return; DBIMG::set_abone( m_url_tmp , ! DBIMG::get_abone( m_url_tmp ) ); if( DBIMG::get_abone( m_url_tmp ) ) CORE::core_set_command( "delete_image", m_url_tmp ); redraw_view(); } // // 検索entryでenterを押した // void ArticleViewBase::exec_search() { std::string query = get_search_query(); if( query.empty() ){ clear_highlight(); focus_view(); CORE::core_set_command( "set_info", "", "" ); return; } std::list< std::string > list_query; list_query = MISC::split_line( query ); if( get_pre_query() != query ){ set_pre_query( query ); CORE::get_completion_manager()->set_query( CORE::COMP_SEARCH_ARTICLE, query ); m_drawarea->set_jump_history( m_drawarea->get_seen_current() ); m_drawarea->search( list_query, m_search_invert ); } int hit = m_drawarea->search_move( m_search_invert ); if( ! hit ){ clear_highlight(); CORE::core_set_command( "set_info", "", "検索結果: ヒット無し" ); } else{ focus_view(); CORE::core_set_command( "set_info", "", "検索結果: " + MISC::itostr( hit ) + "件" ); } } // // 検索entryの操作 // void ArticleViewBase::operate_search( const std::string& controlid ) { const int id = atoi( controlid.c_str() ); if( id == CONTROL::Cancel ){ focus_view(); ARTICLE::get_admin()->set_command( "close_searchbar" ); } // AND 抽出 else if( id == CONTROL::DrawOutAnd ){ std::string query = get_search_query(); if( query.empty() ) return; CORE::core_set_command( "open_article_keyword" ,m_url_article, query, "false" ); } } // // 実況モードのセット // void ArticleViewBase::set_live( const bool live ) { if( ! m_enable_live ) return; m_live = live; if( m_live ) SESSION::append_live( m_url_article ); else SESSION::remove_live( m_url_article ); } jd-2.8.7-140104/src/article/articleviewbase.h0000644000076400010400000002771012061154775015343 0ustar // ライセンス: GPL2 // スレビュークラスの基本クラス #ifndef _ARTICLEVIEWBASE_H #define _ARTICLEVIEWBASE_H #include "skeleton/view.h" #include "jdlib/refptr_lock.h" #include #include namespace SKELETON { class Admin; class PopupWin; } namespace DBTREE { class ArticleBase; } namespace XML { class Dom; } namespace ARTICLE { class DrawAreaBase; class ArticleViewBase : public SKELETON::View { // viewに表示するdatファイルのURL ( SKELETON::View::m_url はview自身のURLなのに注意すること ) std::string m_url_article; // ツールバーの板ボタンに表示する文字列 std::string m_label_board; // 高速化のため直接アクセス JDLIB::RefPtr_Lock< DBTREE::ArticleBase > m_article; // widget DrawAreaBase* m_drawarea; // slot呼び出し時にURLのやりとりに使う一時変数 std::string m_url_tmp; // url std::string m_str_num; // レス番号 std::string m_jump_to; // ジャンプ先番号 std::string m_jump_from; // ジャンプ元番号 std::string m_id_name; // ID std::string m_name; // 名前 // ポップアップ SKELETON::PopupWin* m_popup_win; bool m_popup_shown; // 表示されているならtrue, falseでもdeleteしない限りは m_popup_win != NULLに注意 int m_hidepopup_counter; // ポップアップを消すまでのカウンタ std::string m_popup_url; // 表示中のポップアップのアドレス // 検索用 bool m_search_invert; // 逆方向検索モード std::string m_pre_query; // 前回の検索で使ったクエリー // ポップアップメニュー表示のときにactivate_act_before_popupmenu()で使う変数 bool m_enable_menuslot; // ブックマーク移動時の現在の位置(レス番号) int m_current_bm; // 書き込みマーク移動時の現在の位置(レス番号) int m_current_post; // 抽出ビューで荒らし報告用のURLを表示する bool m_show_url4report; // URLをステータスバーに表示しているかどうか bool m_url_show_status; // 実況モードが可能か bool m_enable_live; // ライブモードか bool m_live; // メニューのユーザコマンド、 create_usrcmd_menu() で作成 std::string m_usrcmd; public: ArticleViewBase( const std::string& url, const std::string& url_article ); virtual ~ArticleViewBase(); const std::string& url_article() const { return m_url_article; } const std::string& get_label_board(){ return m_label_board; } // SKELETON::View の関数のオーバロード virtual void save_session(){} virtual const std::string url_for_copy(); // コピーやURLバー表示用のURL virtual const int width_client(); virtual const int height_client(); virtual const int get_icon( const std::string& iconname ); virtual const bool set_command( const std::string& command, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() ); virtual void clock_in(); void clock_in_smooth_scroll(); // キーを押した virtual const bool slot_key_press( GdkEventKey* event ); virtual void write(); virtual void reload(); virtual void stop(); virtual void redraw_view(); virtual void focus_view(); virtual void focus_out(); virtual void close_view(); virtual void delete_view(); virtual void set_favorite(); virtual const bool operate_view( const int control ); virtual void goto_top(); virtual void goto_bottom(); virtual void goto_num( const int num_to, const int num_from ); virtual void show_preference(); // 進む、戻る virtual void back_viewhistory( const int count ); virtual void forward_viewhistory( const int count ); // 検索 virtual void exec_search(); virtual void up_search(); virtual void down_search(); virtual void operate_search( const std::string& controlid ); void clear_highlight(); // ハイライト解除 // 記事削除 & 再オープン void delete_open_view(); // 実況モードが可能か const bool get_enable_live(); // 実況モードか const bool get_live() const { return m_live; } DrawAreaBase* drawarea(); protected: // Viewが所属するAdminクラス virtual SKELETON::Admin* get_admin(); JDLIB::RefPtr_Lock< DBTREE::ArticleBase >& get_article(); // ポップアップメニューを表示する前にメニューのアクティブ状態を切り替える virtual void activate_act_before_popupmenu( const std::string& url ); // ポップアップメニュー取得 virtual Gtk::Menu* get_popupmenu( const std::string& url ); // レスポップアップを隠す void hide_popup( const bool force = false ); // ポップアップが表示されているか const bool is_popup_shown() const; // 初期設定 void setup_view(); // 新着に移動 void goto_new(); // レスを抽出して表示 // num は "from-to" の形式 (例) 3から10を抽出したいなら "3-10" // show_title == trueの時は 板名、スレ名を表示 void show_res( const std::string& num, const bool show_title ); // 名前 で抽出して表示 // show_option = true の時は URL 表示などのオプションが表示される void show_name( const std::string& name, bool show_option ); // ID で抽出して表示 // show_option = true の時は URL 表示などのオプションが表示される void show_id( const std::string& id_name, const bool show_option ); // ブックマークを抽出して表示 void show_bm(); // 書き込みを抽出して表示 void show_post(); // 書き込みログを表示 void show_postlog( const int num ); // URLを含むレスを抽出して表示 void show_res_with_url(); // num 番のレスを参照してるレスを抽出して表示 void show_refer( int num ); // 前回の検索で使ったクエリー void set_pre_query( const std::string& query ){ m_pre_query = query; } const std::string& get_pre_query() const{ return m_pre_query; } // キーワードで抽出して表示 // mode_or = true の時は or 検索 // show_option = true の時は URL 表示などのオプションが表示される void drawout_keywords( const std::string& query, bool mode_or, bool show_option ); // HTML追加 void append_html( const std::string& html ); // dat追加 virtual void append_dat( const std::string& dat, int num ); // リストで指定したレスを表示 void append_res( const std::list< int >& list_resnum ); // リストで指定したレスを表示(連結情報付き) void append_res( const std::list< int >& list_resnum, const std::list< bool >& list_joint ); // 画像プロパティ表示 void slot_preferences_image(); void slot_copy_selection_str(); void slot_select_all(); // 実況用 void set_enable_live( const bool enable ){ m_enable_live = enable; } void set_live( const bool live ); virtual void live_start(){} virtual void live_stop(){} private: virtual DrawAreaBase* create_drawarea(); void setup_action(); // 通常の右クリックメニューの作成 const std::string create_context_menu(); const char* get_menu_item( const int item ); virtual void exec_reload(); void reload_article(); void exec_delete(); // 荒らし報告用のURLリストをHTML形式で取得 const std::string get_html_url4report( const std::list< int >& list_resnum ); // drawarea の signal を受け取る slots virtual bool slot_button_press( std::string url, int res_number, GdkEventButton* event ); bool slot_button_release( std::string url, int res_number, GdkEventButton* event ); bool slot_motion_notify( GdkEventMotion* event ); bool slot_key_release( GdkEventKey* event ); bool slot_scroll_event( GdkEventScroll* event ); bool slot_leave_notify( GdkEventCrossing* ev ); // レスポップアップ関係 // ポップアップが表示されていてかつマウスがその上にあるか const bool is_mouse_on_popup(); void show_popup( SKELETON::View* view, const int mrg_x, const int mrg_y ); bool slot_popup_leave_notify_event( GdkEventCrossing* event ); void slot_hide_popup(); void delete_popup(); // ポップアップ強制削除 void warp_pointer_to_popup(); // マウスポインタをポップアップの上に移動する void slot_bookmark(); void slot_postedmark(); void slot_open_browser(); void slot_open_cache_browser(); void slot_write_res(); void slot_quote_res(); void slot_quote_selection_res(); void slot_copy_current_url(); void slot_copy_name(); void slot_copy_id(); void slot_drawout_selection_str(); void slot_search_cacheall(); void slot_search_cachelocal(); void slot_search_next(); void slot_search_web(); void slot_search_title(); void slot_usrcmd( int num ); void slot_copy_res( bool ref ); void slot_copy_title_url(); void slot_drawout_res(); void slot_drawout_around(); void slot_drawout_tmp(); void slot_drawout_name(); void slot_drawout_id(); void slot_drawout_bm(); void slot_drawout_post(); void slot_drawout_refer(); void slot_drawout_url(); void slot_abone_res(); void slot_abone_selection_res(); void slot_abone_id(); void slot_abone_name(); void slot_abone_word(); void slot_abone_name_board(); void slot_abone_word_board(); void slot_global_abone_name(); void slot_global_abone_word(); void slot_toggle_abone_transp(); void slot_toggle_abone_transp_chain(); void slot_pre_bm(); void slot_next_bm(); void slot_pre_post(); void slot_next_post(); void slot_jump(); void slot_save_dat(); void slot_copy_article_info(); // あぼーん設定 void slot_setup_abone(); void slot_setup_abone_board(); void slot_setup_abone_all(); // リンクの処理 virtual void slot_on_url( std::string url, std::string imgurl, int res_number ); void slot_leave_url(); bool click_url( std::string url, int res_number, GdkEventButton* event ); void open_image( const std::string& url, const int res_number, const bool open_imageview, const bool open_browser, const bool mosaic, const bool switch_image ); // 画像ポップアップメニュー用 void slot_cancel_mosaic(); void slot_show_image_with_mosaic(); void slot_show_selection_images(); void slot_delete_selection_images(); void slot_abone_selection_images(); void slot_show_large_img(); void slot_deleteimage(); void slot_toggle_protectimage(); void slot_saveimage(); void slot_abone_img(); // 検索バーを開く void open_searchbar( bool invert ); }; } #endif jd-2.8.7-140104/src/article/articleviewetc.cpp0000644000076400010400000003245311451123122015517 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articleadmin.h" #include "articleviewetc.h" #include "drawareamain.h" #include "dbtree/interface.h" #include "dbtree/articlebase.h" #include "control/controlid.h" #include "global.h" #include using namespace ARTICLE; // レス抽出ビュー ArticleViewRes::ArticleViewRes( const std::string& url ) : ArticleViewBase( url, url.substr( 0, url.find( ARTICLE_SIGN ) ) ) { const int pos0 = url.find( RES_SIGN ) + strlen( RES_SIGN ); const int pos1 = url.find( CENTER_SIGN ); m_str_num = url.substr( pos0, pos1 - pos0 ); m_str_center = url.substr( pos1 + strlen( CENTER_SIGN ) ); #ifdef _DEBUG std::cout << "ArticleViewRes::ArticleViewRes " << get_url() << " num = " << m_str_num << " center = " << m_str_center << std::endl; #endif setup_view(); // ラベル更新 set_label( " [ RES:" + m_str_num + " ] - " + DBTREE::article_subject( url_article() ) ); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } ArticleViewRes::~ArticleViewRes() { #ifdef _DEBUG std::cout << "ArticleViewRes::~ArticleViewRes : " << get_url() << std::endl; #endif } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewRes::relayout() { #ifdef _DEBUG std::cout << "ArticleViewRes::relayout\n"; #endif drawarea()->clear_screen(); show_res( m_str_num, false ); drawarea()->redraw_view(); ARTICLE::get_admin()->set_command( "goto_num", get_url(), m_str_center ); } // // 抽出表示 // void ArticleViewRes::show_view() { relayout(); } // // 再読み込みボタンを押した // void ArticleViewRes::reload() { exec_reload(); } // // 再読み込み実行 // // virtual void ArticleViewRes::exec_reload() { relayout(); } //////////////////////////////////////////////////////////////////////////////////////////////////// // 名前抽出ビュー ArticleViewName::ArticleViewName( const std::string& url ) : ArticleViewBase( url, url.substr( 0, url.find( ARTICLE_SIGN ) ) ) { m_str_name = url.substr( url.find( NAME_SIGN ) + strlen( NAME_SIGN ) ); #ifdef _DEBUG std::cout << "ArticleViewName::ArticleViewName " << get_url() << " name = " << m_str_name << std::endl; #endif setup_view(); // ラベル更新 set_label( " [ 名前:" + m_str_name + " ] - " + DBTREE::article_subject( url_article() )); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } ArticleViewName::~ArticleViewName() { #ifdef _DEBUG std::cout << "ArticleViewName::~ArticleViewName : " << get_url() << std::endl; #endif } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewName::relayout() { #ifdef _DEBUG std::cout << "ArticleViewName::relayout\n"; #endif drawarea()->clear_screen(); show_name( m_str_name, true ); drawarea()->redraw_view(); } // // 抽出表示 // void ArticleViewName::show_view() { relayout(); } // // 再読み込みボタンを押した // void ArticleViewName::reload() { exec_reload(); } // // 再読み込み実行 // // virtual void ArticleViewName::exec_reload() { relayout(); } //////////////////////////////////////////////////////////////////////////////////////////////////// // ID抽出ビュー ArticleViewID::ArticleViewID( const std::string& url ) : ArticleViewBase( url, url.substr( 0, url.find( ARTICLE_SIGN ) ) ) { m_str_id = url.substr( url.find( ID_SIGN ) + strlen( ID_SIGN ) ); #ifdef _DEBUG std::cout << "ArticleViewID::ArticleViewID " << get_url() << " ID = " << m_str_id << std::endl; #endif setup_view(); // ラベル更新 set_label( " [ " + m_str_id.substr( strlen( PROTO_ID ) ) + " ] - " + DBTREE::article_subject( url_article() )); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } ArticleViewID::~ArticleViewID() { #ifdef _DEBUG std::cout << "ArticleViewID::~ArticleViewID : " << get_url() << std::endl; #endif } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewID::relayout() { #ifdef _DEBUG std::cout << "ArticleViewID::relayout\n"; #endif drawarea()->clear_screen(); show_id( m_str_id, true ); drawarea()->redraw_view(); } // // 抽出表示 // void ArticleViewID::show_view() { relayout(); } // // 再読み込みボタンを押した // void ArticleViewID::reload() { exec_reload(); } // // 再読み込み実行 // // virtual void ArticleViewID::exec_reload() { relayout(); } //////////////////////////////////////////////////////////////////////////////////////////////////// // ブックマーク抽出ビュー ArticleViewBM::ArticleViewBM( const std::string& url ) : ArticleViewBase( url, url.substr( 0, url.find( ARTICLE_SIGN ) ) ) { #ifdef _DEBUG std::cout << "ArticleViewBM::ArticleViewBM " << get_url() << std::endl; #endif setup_view(); // ラベル更新 set_label( " [ しおり ] - " + DBTREE::article_subject( url_article() )); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } ArticleViewBM::~ArticleViewBM() { #ifdef _DEBUG std::cout << "ArticleViewBM::~ArticleViewBM : " << get_url() << std::endl; #endif } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewBM::relayout() { #ifdef _DEBUG std::cout << "ArticleViewBM::relayout\n"; #endif drawarea()->clear_screen(); show_bm(); drawarea()->redraw_view(); } // // 抽出表示 // void ArticleViewBM::show_view() { relayout(); } // // 再読み込みボタンを押した // void ArticleViewBM::reload() { exec_reload(); } // // 再読み込み実行 // // virtual void ArticleViewBM::exec_reload() { relayout(); } //////////////////////////////////////////////////////////////////////////////////////////////////// // 書き込み抽出ビュー ArticleViewPost::ArticleViewPost( const std::string& url ) : ArticleViewBase( url, url.substr( 0, url.find( ARTICLE_SIGN ) ) ) { #ifdef _DEBUG std::cout << "ArticleViewPost::ArticleViewPost " << get_url() << std::endl; #endif setup_view(); // ラベル更新 set_label( " [ 書き込み ] - " + DBTREE::article_subject( url_article() )); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } ArticleViewPost::~ArticleViewPost() { #ifdef _DEBUG std::cout << "ArticleViewPost::~ArticleViewPost : " << get_url() << std::endl; #endif } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewPost::relayout() { #ifdef _DEBUG std::cout << "ArticleViewPost::relayout\n"; #endif drawarea()->clear_screen(); show_post(); drawarea()->redraw_view(); } // // 抽出表示 // void ArticleViewPost::show_view() { relayout(); } // // 再読み込みボタンを押した // void ArticleViewPost::reload() { exec_reload(); } // // 再読み込み実行 // // virtual void ArticleViewPost::exec_reload() { relayout(); } //////////////////////////////////////////////////////////////////////////////////////////////////// // URL抽出ビュー ArticleViewURL::ArticleViewURL( const std::string& url ) : ArticleViewBase( url, url.substr( 0, url.find( ARTICLE_SIGN ) ) ) { #ifdef _DEBUG std::cout << "ArticleViewURL::ArticleViewURL " << get_url() << std::endl; #endif setup_view(); // ラベル更新 set_label( " [ URL ] - " + DBTREE::article_subject( url_article() )); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } ArticleViewURL::~ArticleViewURL() { #ifdef _DEBUG std::cout << "ArticleViewURL::~ArticleViewURL : " << get_url() << std::endl; #endif } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewURL::relayout() { #ifdef _DEBUG std::cout << "ArticleViewURL::relayout\n"; #endif drawarea()->clear_screen(); show_res_with_url(); drawarea()->redraw_view(); } // // 抽出表示 // void ArticleViewURL::show_view() { relayout(); } // // 再読み込みボタンを押した // void ArticleViewURL::reload() { exec_reload(); } // // 再読み込み実行 // // virtual void ArticleViewURL::exec_reload() { relayout(); } //////////////////////////////////////////////////////////////////////////////////////////////////// // 参照抽出ビュー ArticleViewRefer::ArticleViewRefer( const std::string& url ) : ArticleViewBase( url, url.substr( 0, url.find( ARTICLE_SIGN ) ) ) { m_str_num = url.substr( url.find( REFER_SIGN ) + strlen( REFER_SIGN ) ); #ifdef _DEBUG std::cout << "ArticleViewRefer::ArticleViewRefer " << get_url() << " num = " << m_str_num << std::endl; #endif setup_view(); // ラベル更新 set_label( " [ Re:" + m_str_num + " ] - " + DBTREE::article_subject( url_article() )); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } ArticleViewRefer::~ArticleViewRefer() { #ifdef _DEBUG std::cout << "ArticleViewRefer::~ArticleViewRefer : " << get_url() << std::endl; #endif } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewRefer::relayout() { #ifdef _DEBUG std::cout << "ArticleViewRefer::relayout\n"; #endif drawarea()->clear_screen(); show_refer( atol( m_str_num.c_str() ) ); drawarea()->redraw_view(); } // // 抽出表示 // void ArticleViewRefer::show_view() { relayout(); } // // 再読み込みボタンを押した // void ArticleViewRefer::reload() { exec_reload(); } // // 再読み込み実行 // // virtual void ArticleViewRefer::exec_reload() { relayout(); } //////////////////////////////////////////////////////////////////////////////////////////////////// // キーワード抽出ビュー ArticleViewDrawout::ArticleViewDrawout( const std::string& url ) : ArticleViewBase( url, url.substr( 0, url.find( ARTICLE_SIGN ) ) ) { const int pos0 = url.find( KEYWORD_SIGN ) + strlen( KEYWORD_SIGN ); const int pos1 = url.find( ORMODE_SIGN ); m_query = url.substr( pos0, pos1 - pos0 ); m_mode_or = ( url.substr( pos1 + strlen( ORMODE_SIGN ) ) == "1" ); set_search_query( m_query ); set_pre_query( m_query ); #ifdef _DEBUG std::cout << "ArticleViewDrawout::ArticleViewDrawout " << get_url() << std::endl; #endif setup_view(); // ラベル更新 std::string str_label; if( m_mode_or ) str_label = "[ OR 抽出 ] - "; else str_label = "[ AND 抽出 ] - "; set_label( str_label + DBTREE::article_subject( url_article() ) ); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } ArticleViewDrawout::~ArticleViewDrawout() { #ifdef _DEBUG std::cout << "ArticleViewDrawout::~ArticleViewDrawout : " << get_url() << std::endl; #endif } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewDrawout::relayout() { #ifdef _DEBUG std::cout << "ArticleViewDrawout::relayout\n"; #endif drawarea()->clear_screen(); drawarea()->clear_highlight(); drawout_keywords( m_query, m_mode_or, true ); drawarea()->redraw_view(); } // // 抽出表示 // void ArticleViewDrawout::show_view() { relayout(); } // // 再読み込みボタンを押した // void ArticleViewDrawout::reload() { exec_reload(); } // // 再読み込み実行 // // virtual void ArticleViewDrawout::exec_reload() { relayout(); } //////////////////////////////////////////////////////////////////////////////////////////////////// // 書き込みログ表示ビュー ArticleViewPostlog::ArticleViewPostlog( const std::string& url ) : ArticleViewBase( url, url.substr( 0, url.find( POSTLOG_SIGN ) ) ) { m_num = atoi( url.substr( url.find( POSTLOG_SIGN ) + strlen( POSTLOG_SIGN ) ).c_str() ); #ifdef _DEBUG std::cout << "ArticleViewPostlog::ArticleViewPostlog " << get_url() << " num = " << m_num << std::endl; #endif set_id_toolbar( TOOLBAR_SIMPLE ); set_writeable( false ); setup_view(); // ラベル更新 set_label( " [ 書き込みログ ] " ); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } ArticleViewPostlog::~ArticleViewPostlog() { #ifdef _DEBUG std::cout << "ArticleViewPostlog::~ArticleViewPostlog : " << get_url() << std::endl; #endif } // // 検索entryの操作 // void ArticleViewPostlog::operate_search( const std::string& controlid ) { const int id = atoi( controlid.c_str() ); if( id == CONTROL::Cancel ){ focus_view(); ARTICLE::get_admin()->set_command( "close_searchbar" ); } } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewPostlog::relayout() { #ifdef _DEBUG std::cout << "ArticleViewPostlog::relayout\n"; #endif drawarea()->clear_screen(); show_postlog( m_num ); drawarea()->redraw_view(); goto_bottom(); } // // 抽出表示 // void ArticleViewPostlog::show_view() { relayout(); } // // 再読み込みボタンを押した // void ArticleViewPostlog::reload() { exec_reload(); } // // 再読み込み実行 // void ArticleViewPostlog::exec_reload() { relayout(); } jd-2.8.7-140104/src/article/articleviewetc.h0000644000076400010400000001140611443161740015170 0ustar // ライセンス: GPL2 // // その他のarticle系view // #ifndef _ARTICLEVIEWETC_H #define _ARTICLEVIEWETC_H #include "articleviewbase.h" namespace ARTICLE { // レス抽出ビュー class ArticleViewRes : public ArticleViewBase { std::string m_str_num; std::string m_str_center; public: ArticleViewRes( const std::string& url ); ~ArticleViewRes(); // SKELETON::View の関数のオーバロード virtual void relayout(); virtual void show_view(); virtual void reload(); private: virtual void exec_reload(); }; ///////////////////////////////////////////////////////////////////////// // 名前抽出ビュー class ArticleViewName : public ArticleViewBase { std::string m_str_name; public: ArticleViewName( const std::string& url ); ~ArticleViewName(); // SKELETON::View の関数のオーバロード virtual void relayout(); virtual void show_view(); virtual void reload(); private: virtual void exec_reload(); }; ///////////////////////////////////////////////////////////////////////// // ID 抽出ビュー class ArticleViewID : public ArticleViewBase { std::string m_str_id; public: ArticleViewID( const std::string& url ); ~ArticleViewID(); // SKELETON::View の関数のオーバロード virtual void relayout(); virtual void show_view(); virtual void reload(); private: virtual void exec_reload(); }; ///////////////////////////////////////////////////////////////////////// // ブックマーク抽出ビュー class ArticleViewBM : public ArticleViewBase { std::string m_str_id; public: ArticleViewBM( const std::string& url ); ~ArticleViewBM(); // SKELETON::View の関数のオーバロード virtual void relayout(); virtual void show_view(); virtual void reload(); private: virtual void exec_reload(); }; ///////////////////////////////////////////////////////////////////////// // 書き込み抽出ビュー class ArticleViewPost : public ArticleViewBase { std::string m_str_id; public: ArticleViewPost( const std::string& url ); ~ArticleViewPost(); // SKELETON::View の関数のオーバロード virtual void relayout(); virtual void show_view(); virtual void reload(); private: virtual void exec_reload(); }; ///////////////////////////////////////////////////////////////////////// // URL抽出ビュー class ArticleViewURL : public ArticleViewBase { public: ArticleViewURL( const std::string& url ); ~ArticleViewURL(); // SKELETON::View の関数のオーバロード virtual void relayout(); virtual void show_view(); virtual void reload(); private: virtual void exec_reload(); }; ///////////////////////////////////////////////////////////////////////// // 参照抽出ビュー class ArticleViewRefer : public ArticleViewBase { std::string m_str_num; public: ArticleViewRefer( const std::string& url ); ~ArticleViewRefer(); // SKELETON::View の関数のオーバロード virtual void relayout(); virtual void show_view(); virtual void reload(); private: virtual void exec_reload(); }; ///////////////////////////////////////////////////////////////////////// // キーワード抽出ビュー class ArticleViewDrawout : public ArticleViewBase { std::string m_query; bool m_mode_or; public: ArticleViewDrawout( const std::string& url ); ~ArticleViewDrawout(); // SKELETON::View の関数のオーバロード virtual void relayout(); virtual void show_view(); virtual void reload(); private: virtual void exec_reload(); }; ///////////////////////////////////////////////////////////////////////// // 書き込みログ表示ビュー class ArticleViewPostlog : public ArticleViewBase { int m_num; public: ArticleViewPostlog( const std::string& url ); ~ArticleViewPostlog(); // SKELETON::View の関数のオーバロード virtual void relayout(); virtual void stop(){} // キャンセル // 検索 virtual void operate_search( const std::string& controlid ); virtual void show_view(); virtual void reload(); private: virtual void exec_reload(); }; } #endif jd-2.8.7-140104/src/article/articleviewinfo.cpp0000644000076400010400000000127111443161740015702 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articleadmin.h" #include "articleviewinfo.h" #include "drawareainfo.h" using namespace ARTICLE; ArticleViewInfo::ArticleViewInfo( const std::string& url ) : ArticleViewBase( url, url ) { #ifdef _DEBUG std::cout << "ArticleViewInfo::ArticleViewInfo " << get_url() << std::endl; #endif set_writeable( false ); setup_view(); } ArticleViewInfo::~ArticleViewInfo() { #ifdef _DEBUG std::cout << "ArticleViewInfo::~ArticleViewInfo : " << get_url() << std::endl; #endif } DrawAreaBase* ArticleViewInfo::create_drawarea() { return Gtk::manage( new ARTICLE::DrawAreaInfo( url_article() ) ); } jd-2.8.7-140104/src/article/articleviewinfo.h0000644000076400010400000000167211065722577015367 0ustar // ライセンス: GPL2 // // 情報表示用 // #ifndef _ARTICLEVIEWINFO_H #define _ARTICLEVIEWINFO_H #include "articleviewbase.h" namespace ARTICLE { class ArticleViewInfo : public ArticleViewBase { public: ArticleViewInfo( const std::string& url ); ~ArticleViewInfo(); // viewの操作をキャンセル virtual const bool operate_view( const int control ){ return false; } protected: // ポップアップメニューは表示しない virtual Gtk::Menu* get_popupmenu( const std::string& url ){ return NULL; } private: // ボタンプレスキャンセル virtual bool slot_button_press( std::string url, int res_number, GdkEventButton* event ){ return true; } // ポップアップ表示キャンセル virtual void slot_on_url( std::string url, int res_number ){} virtual DrawAreaBase* create_drawarea(); }; } #endif jd-2.8.7-140104/src/article/articleviewpopup.cpp0000644000076400010400000000251611443161740016115 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articleviewpopup.h" #include "drawareapopup.h" #include "global.h" #include "config/globalconf.h" using namespace ARTICLE; // show_abone == true ならあぼーんされたスレも表示 ArticleViewPopup::ArticleViewPopup( const std::string& url, bool show_abone ) : ArticleViewBase( url, url ), m_show_abone( show_abone ) { #ifdef _DEBUG std::cout << "ArticleViewPopup::ArticleViewPupup " << get_url() << " show_abone " << m_show_abone << std::endl; #endif setup_view(); } ArticleViewPopup::~ArticleViewPopup() { #ifdef _DEBUG std::cout << "ArticleViewPopup::~ArticleViewPopup : " << get_url() << std::endl; #endif } // // 多重ポップアップのヒント表示 // void ArticleViewPopup::show_instruct_popup() { if( CONFIG::get_instruct_popup() ) append_html( "ヒント:マウスの右ボタンを押しながらポインタを移動すると多重ポップアップが可能
または設定メニューの「シングルクリックで多重ポップアップモードに移行する」
をチェックしてからアンカーをクリックする" ); } // // drawareaの作成 // DrawAreaBase* ArticleViewPopup::create_drawarea() { return Gtk::manage( new ARTICLE::DrawAreaPopup( url_article(), m_show_abone ) ); } jd-2.8.7-140104/src/article/articleviewpopup.h0000644000076400010400000001050411376762460015571 0ustar // ライセンス: GPL2 // // ポップアップ系ビュー // #ifndef _ARTICLEVIEWPOPUP_H #define _ARTICLEVIEWPOPUP_H #include "articleviewbase.h" namespace ARTICLE { // ポップアップビューのベース class ArticleViewPopup : public ArticleViewBase { bool m_show_abone; public: ArticleViewPopup( const std::string& url, bool show_abone ); virtual ~ArticleViewPopup(); virtual void stop(){} protected: void show_instruct_popup(); const bool show_abone() const { return m_show_abone; } private: virtual DrawAreaBase* create_drawarea(); }; ///////////////////////////////////////////////////////////////////////// // HTMLコメントポップアップ class ArticleViewPopupHTML : public ArticleViewPopup { std::string m_html; public: ArticleViewPopupHTML( const std::string& url, const std::string& html ): ArticleViewPopup( url, false ), m_html( html ){} virtual ~ArticleViewPopupHTML(){} virtual void show_view(){ append_html( m_html ); } }; ///////////////////////////////////////////////////////////////////////// // レス抽出ポップアップ class ArticleViewPopupRes : public ArticleViewPopup { std::string m_str_num; bool m_show_title; public: ArticleViewPopupRes( const std::string& url, const std::string& num, bool show_title, bool show_abone ) : ArticleViewPopup( url, show_abone ), m_str_num( num ), m_show_title( show_title ){} virtual ~ArticleViewPopupRes(){} virtual void show_view(){ show_instruct_popup(); show_res( m_str_num, m_show_title ); } }; ///////////////////////////////////////////////////////////////////////// // 名前抽出ポップアップ class ArticleViewPopupName : public ArticleViewPopup { std::string m_str_name; public: ArticleViewPopupName( const std::string& url, const std::string& name ): ArticleViewPopup( url, false ), m_str_name( name ){} virtual ~ArticleViewPopupName(){} virtual void show_view(){ show_instruct_popup(); show_name( m_str_name, false ); } }; ///////////////////////////////////////////////////////////////////////// // ID 抽出ポップアップ class ArticleViewPopupID : public ArticleViewPopup { std::string m_str_id; public: ArticleViewPopupID( const std::string& url, const std::string& id ): ArticleViewPopup( url, false ), m_str_id( id ) {} virtual ~ArticleViewPopupID(){} virtual void show_view(){ show_instruct_popup(); show_id( m_str_id, false ); } }; ///////////////////////////////////////////////////////////////////////// // 参照抽出ポップアップ class ArticleViewPopupRefer : public ArticleViewPopup { std::string m_str_num; public: ArticleViewPopupRefer( const std::string& url, const std::string& num ): ArticleViewPopup( url, false ), m_str_num( num ){} virtual ~ArticleViewPopupRefer(){} virtual void show_view(){ show_instruct_popup(); show_refer( atol( m_str_num.c_str() ) ); } }; ///////////////////////////////////////////////////////////////////////// // キーワード抽出ビュー class ArticleViewPopupDrawout : public ArticleViewPopup { std::string m_query; bool m_mode_or; public: ArticleViewPopupDrawout( const std::string& url, const std::string& query, bool mode_or ) : ArticleViewPopup( url, false ), m_query( query ), m_mode_or( mode_or ){} virtual ~ArticleViewPopupDrawout(){} virtual void show_view(){ show_instruct_popup(); drawout_keywords( m_query, m_mode_or, false ); } }; ///////////////////////////////////////////////////////////////////////// // しおり抽出ポップアップ class ArticleViewPopupBM : public ArticleViewPopup { public: ArticleViewPopupBM( const std::string& url ) : ArticleViewPopup( url, false ){} virtual ~ArticleViewPopupBM(){} virtual void show_view(){ show_instruct_popup(); show_bm(); } }; } #endif jd-2.8.7-140104/src/article/articleviewpreview.cpp0000644000076400010400000000521411443161740016431 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articleadmin.h" #include "articleviewpreview.h" #include "drawareamain.h" #include "message/messageadmin.h" #include "dbtree/articlebase.h" #include "control/controlid.h" #include "command.h" using namespace ARTICLE; ArticleViewPreview::ArticleViewPreview( const std::string& url ) : ArticleViewBase( url, url ) { m_url_messageview = url; #ifdef _DEBUG std::cout << "ArticleViewPreview::ArticleViewPreview " << get_url() << std::endl; #endif set_writeable( false ); setup_view(); // コントロールモード設定 get_control().clear_mode(); get_control().add_mode( CONTROL::MODE_MESSAGE ); get_control().add_mode( CONTROL::MODE_ARTICLE ); } ArticleViewPreview::~ArticleViewPreview() { #ifdef _DEBUG std::cout << "ArticleViewPreview::~ArticleViewPreview : " << get_url() << std::endl; #endif } // // viewの操作 // const bool ArticleViewPreview::operate_view( const int control ) { if( control == CONTROL::None ) return false; // スクロール系操作 if( drawarea()->set_scroll( control ) ) return true; switch( control ){ // コピー case CONTROL::Copy: slot_copy_selection_str(); break; // 全て選択 case CONTROL::SelectAll: slot_select_all(); break; // 閉じる case CONTROL::Quit: case CONTROL::CancelWrite: MESSAGE::get_admin()->set_command( "close_currentview" ); break; // 書き込み実行 case CONTROL::ExecWrite: MESSAGE::get_admin()->set_command( "toolbar_write", m_url_messageview ); break; case CONTROL::TabLeft: case CONTROL::TabLeftUpdated: MESSAGE::get_admin()->set_command( "tab_left" ); break; case CONTROL::TabRight: case CONTROL::TabRightUpdated: MESSAGE::get_admin()->set_command( "tab_right" ); break; case CONTROL::FocusWrite: MESSAGE::get_admin()->set_command( "focus_button_write" ); break; default: return false; } return true; } // // drawarea のクリックイベント // // ArticleViewBase::slot_button_press()をオーパロードしてマウスジェスチャを無効にする // bool ArticleViewPreview::slot_button_press( std::string url, int res_number, GdkEventButton* event ) { #ifdef _DEBUG std::cout << "ArticleViewPreview::slot_button_press url = " << get_url() << std::endl; #endif MESSAGE::get_admin()->set_command( "switch_admin" ); return true; } jd-2.8.7-140104/src/article/articleviewpreview.h0000644000076400010400000000121311325334242016067 0ustar // ライセンス: GPL2 // // 書き込みなどのプレビュー // #ifndef _ARTICLEVIEWPREVIEW_H #define _ARTICLEVIEWPREVIEW_H #include "articleviewbase.h" namespace ARTICLE { class ArticleViewPreview : public ArticleViewBase { std::string m_url_messageview; public: ArticleViewPreview( const std::string& url ); ~ArticleViewPreview(); virtual const bool operate_view( const int control ); private: virtual bool slot_button_press( std::string url, int res_number, GdkEventButton* event ); virtual void goto_num( const int num_to, const int num_from ){} }; } #endif jd-2.8.7-140104/src/article/articleviewsearch.cpp0000644000076400010400000002753711566222167016240 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articleadmin.h" #include "articleviewsearch.h" #include "drawareamain.h" #include "skeleton/msgdiag.h" #include "dbtree/interface.h" #include "jdlib/miscutil.h" #include "jdlib/jdregex.h" #include "config/globalconf.h" #include "control/controlid.h" #include "global.h" #include "session.h" #include "usrcmdmanager.h" #include using namespace ARTICLE; // ログやスレタイ検索抽出ビュー ArticleViewSearch::ArticleViewSearch( const std::string& url, const bool exec_search ) : ArticleViewBase( url, "dummy" ), m_mode_or( false ), m_enable_bm( false ), m_bm( false ), m_loading( false ), m_search_executed( false ), m_escaped( false ) { set_id_toolbar( TOOLBAR_SEARCH ); set_writeable( false ); #ifdef _DEBUG std::cout << "ArticleViewSearch::ArticleViewSearch " << get_url() << std::endl; #endif setup_view(); CORE::get_search_manager()->sig_search_fin().connect( sigc::mem_fun( *this, &ArticleViewSearch::slot_search_fin ) ); m_cancel_reload = ! exec_search; } ArticleViewSearch::~ArticleViewSearch() { #ifdef _DEBUG std::cout << "ArticleViewSearch::~ArticleViewSearch : " << get_url() << std::endl; #endif stop(); } // // url から query などを取得してツールバーの状態をセット // void ArticleViewSearch::set_toolbar_from_url() { #ifdef _DEBUG std::cout << "ArticleViewSearch::set_toolbar_from_url url = " << get_url() << std::endl; #endif JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( std::string( "(.*)" ) + BOARD_SIGN + KEYWORD_SIGN + "(.*)" + ORMODE_SIGN + "(.*)" + BOOKMK_SIGN + "(.*)", get_url(), offset, icase, newline, usemigemo, wchar )){ m_url_board = regex.str( 1 ); if( m_url_board == URL_SEARCH_ALLBOARD ) m_searchmode = CORE::SEARCHMODE_ALLLOG; else m_searchmode = CORE::SEARCHMODE_LOG; set_search_query( regex.str( 2 ) ); if( regex.str( 3 ) == "1" ) m_mode_or = true; else m_mode_or = false; if( regex.str( 4 ) == "1" ) m_bm = true; else m_bm = false; m_enable_bm = true; } else if( regex.exec( std::string( "(.*)" ) + TITLE_SIGN + KEYWORD_SIGN + "(.*)", get_url(), offset, icase, newline, usemigemo, wchar )){ m_url_board = regex.str( 1 ); m_searchmode = CORE::SEARCHMODE_TITLE; set_search_query( regex.str( 2 ) ); m_mode_or = false; m_bm = false; m_enable_bm = false; } update_label(); } // // queryなどを変更した時の新しいURL // // queryが変化したときにurlを更新しないと再起動したときのrestoreで // 古いqueryのままになる // const std::string ArticleViewSearch::get_new_url() { std::string url_tmp = m_url_board; if( m_searchmode == CORE::SEARCHMODE_TITLE ) url_tmp += TITLE_SIGN; else url_tmp += BOARD_SIGN; url_tmp += KEYWORD_SIGN + get_search_query(); if( m_searchmode != CORE::SEARCHMODE_TITLE ){ url_tmp += ORMODE_SIGN; if( m_mode_or ) url_tmp += "1"; else url_tmp += "0"; url_tmp += BOOKMK_SIGN; if( get_bm() ) url_tmp += "1"; else url_tmp += "0"; } #ifdef _DEBUG std::cout << "ArticleViewSearch::get_new_url " << url_tmp << std::endl; #endif return url_tmp; } // // ラベルやタブを更新 // void ArticleViewSearch::update_label() { std::string label; if( m_searchmode == CORE::SEARCHMODE_TITLE ) label = "スレタイ検索"; else if( m_searchmode == CORE::SEARCHMODE_ALLLOG ) label = "全ログ検索"; else label = "ログ検索"; if( ! get_search_query().empty() ) label += " : " + get_search_query(); set_label( label ); ARTICLE::get_admin()->set_command( "redraw_toolbar" ); // タブ更新 ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() ); } // // 正規表現メタ文字をエスケープ // void ArticleViewSearch::regex_escape() { m_escaped = false; if( m_searchmode == CORE::SEARCHMODE_LOG || m_searchmode == CORE::SEARCHMODE_ALLLOG ){ const bool escape = false; // \ を エスケープ文字として考慮しない if( MISC::has_regex_metachar( get_search_query(), escape ) ){ m_escaped = true; set_search_query( MISC::regex_escape( get_search_query(), escape ) ); } } } // // コピー用URL( readcgi型 ) // // メインウィンドウのURLバーなどの表示用にも使う // const std::string ArticleViewSearch::url_for_copy() { if( m_searchmode == CORE::SEARCHMODE_TITLE ) return m_url_title; return std::string(); } // // コマンド // const bool ArticleViewSearch::set_command( const std::string& command, const std::string& arg1, const std::string& arg2 ) { // URL とツールバーの状態を一致させる if( command == "set_toolbar_from_url" ){ set_toolbar_from_url(); return true; } return ArticleViewBase::set_command( command, arg1, arg2 ); } // // フォーカスイン // void ArticleViewSearch::focus_view() { if( ! m_loading && m_list_searchdata.empty() ){ ARTICLE::get_admin()->set_command( "open_searchbar", get_url() ); } else ArticleViewBase::focus_view(); } // // 表示 // void ArticleViewSearch::show_view() { #ifdef _DEBUG std::cout << "ArticleViewSearch::show_view()\n"; #endif set_toolbar_from_url(); // コンストラクタのパラメータの exec_search が false の時にロードをキャンセル if( ! m_cancel_reload ) reload(); m_cancel_reload = false; relayout(); } // // 画面を消してレイアウトやりなおし & 再描画 // void ArticleViewSearch::relayout() { #ifdef _DEBUG std::cout << "ArticleViewSearch::relayout\n"; #endif drawarea()->clear_screen(); drawarea()->clear_highlight(); std::ostringstream comment; const bool has_query = ! get_search_query().empty(); if( m_searchmode == CORE::SEARCHMODE_ALLLOG ) comment << "検索対象:キャッシュ内の全ログ
"; else if( m_searchmode == CORE::SEARCHMODE_TITLE ) comment << "検索サイト : " + MISC::get_hostname( CONFIG::get_url_search_title() ) + "
"; else comment << "検索対象:" << DBTREE::board_name( m_url_board ) << "
"; if( get_bm() ) comment << "検索条件:しおり
"; if( m_loading ){ comment << "

検索中・・・"; ARTICLE::get_admin()->set_command( "toggle_icon", get_url() ); } else{ if( m_search_executed ){ if( has_query ) comment << get_search_query() << " "; comment << m_list_searchdata.size() << " 件
"; if( m_escaped ) comment << "ログ検索では正規表現は使用出来ません。メタ文字はエスケープされました。
"; } else{ comment << "

検索条件を入れて再検索ボタンを押してください。"; } comment << "
"; if( ! m_list_searchdata.empty() ){ std::list< CORE::SEARCHDATA >::iterator it = m_list_searchdata.begin(); for(; it != m_list_searchdata.end(); ++it ){ // 板名表示 if( m_searchmode == CORE::SEARCHMODE_ALLLOG || m_searchmode == CORE::SEARCHMODE_TITLE ) comment << "[ " << (*it).boardname << " ] "; comment << "" << MISC::html_escape( (*it).subject ) << ""; if( (*it).num ) comment << " ( " << (*it).num << " )"; // queryの抽出表示 if( m_searchmode != CORE::SEARCHMODE_TITLE && has_query ) comment << "
" << "抽出表示する" << ""; if( (*it).bookmarked ) comment << "
スレにしおりが付けられています"; if( (*it).num_bookmarked ){ comment << "
レスに付けられたしおり " << (*it).num_bookmarked << "件 " << "抽出表示する" << ""; } comment << "

"; } } } append_html( comment.str() ); drawarea()->redraw_view(); } // // 検索終了 // void ArticleViewSearch::slot_search_fin( const std::string& id ) { if( id != get_url() ) return; #ifdef _DEBUG std::cout << "ArticleViewSearch::slot_search_fin " << get_url() << std::endl; #endif m_loading = false; m_list_searchdata = CORE::get_search_manager()->get_list_data(); relayout(); ARTICLE::get_admin()->set_command( "toggle_icon", get_url() ); } // // 再読み込みボタンを押した // void ArticleViewSearch::reload() { exec_reload(); } // // 再読み込み実行 // void ArticleViewSearch::exec_reload() { if( CORE::get_search_manager()->is_searching() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "他の検索スレッドが実行中です" ); mdiag.run(); return; } #ifdef _DEBUG std::cout << "ArticleViewSearch::exec_reload\n"; #endif // 検索が終わると ArticleViewSearch::slot_search_fin() が呼ばれる if( ! get_search_query().empty() || get_bm() ){ // url 変更 const std::string new_url = get_new_url(); if( new_url != get_url() ){ // 他のタブで既に開いていたら切り替える if( ARTICLE::get_admin()->exist_tab( new_url ) ){ #ifdef _DEBUG std::cout << "switch -> " << new_url << std::endl; #endif // 切り替える前に URL とツールバーの状態を合わせておかないと無限ループになる時がある ARTICLE::get_admin()->set_command_immediately( "set_toolbar_from_url", new_url ); ARTICLE::get_admin()->set_command( "switch_view", new_url ); ARTICLE::get_admin()->set_command( "reload_view", new_url ); return; } set_url( new_url ); update_label(); } regex_escape(); const std::string id = get_url(); #ifdef _DEBUG std::cout << "id = " << id << std::endl; #endif if( m_searchmode == CORE::SEARCHMODE_TITLE ){ if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); return; } CORE::get_search_manager()->search_title( id, get_search_query() ); m_url_title = CORE::get_usrcmd_manager()->replace_cmd( CONFIG::get_url_search_title(), "", "", get_search_query(), 0 ); } else{ const bool calc_data = true; CORE::get_search_manager()->search( id, m_searchmode, m_url_board, MISC::regex_unescape( get_search_query() ), m_mode_or, get_bm(), calc_data ); } m_search_executed = true; m_loading = true; relayout(); focus_view(); } } // // 検索停止 // void ArticleViewSearch::stop() { CORE::get_search_manager()->stop( get_url() ); } // // 検索entryでenterを押した // void ArticleViewSearch::exec_search() { reload(); } // // 検索entryの操作 // void ArticleViewSearch::operate_search( const std::string& controlid ) { const int id = atoi( controlid.c_str() ); if( id == CONTROL::Cancel ){ focus_view(); ARTICLE::get_admin()->set_command( "close_searchbar" ); } else if( id == CONTROL::DrawOutAnd ) reload(); } jd-2.8.7-140104/src/article/articleviewsearch.h0000644000076400010400000000446011443161740015664 0ustar // ライセンス: GPL2 // // ログやスレタイ検索抽出ビュー // #ifndef _ARTICLEVIEWSEARCH_H #define _ARTICLEVIEWSEARCH_H #include "articleviewbase.h" #include "searchmanager.h" namespace ARTICLE { class ArticleViewSearch : public ArticleViewBase { std::string m_url_title; std::string m_url_board; int m_searchmode; // searchmanager.hで定義した検索モード bool m_mode_or; bool m_enable_bm; bool m_bm; std::list< CORE::SEARCHDATA > m_list_searchdata; bool m_loading; bool m_search_executed; bool m_escaped; bool m_cancel_reload; public: // exec_search == true ならviewを開いてすぐに検索開始 ArticleViewSearch( const std::string& url, const bool exec_search ); ~ArticleViewSearch(); // SKELETON::View の関数のオーバロード virtual const std::string url_for_copy(); // コピーやURLバー表示用のURL virtual const bool set_command( const std::string& command, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() ); virtual const bool is_loading(){ return m_loading; } virtual void focus_view(); virtual void show_view(); virtual void relayout(); virtual void reload(); virtual void stop(); // 検索 virtual void exec_search(); virtual void operate_search( const std::string& controlid ); const bool get_enable_bm() const{ return m_enable_bm; } const bool get_bm() const { return m_bm; } void set_bm( const bool set ){ m_bm = set; } protected: virtual void slot_push_write(){} // 書き込みキャンセル private: // url から query などを取得してツールバーの状態をセット void set_toolbar_from_url(); // queryなどを変更した時の新しいURL const std::string get_new_url(); // ラベルやタブを更新 void update_label(); // 正規表現メタ文字をエスケープ void regex_escape(); void slot_search_fin( const std::string& id ); virtual void exec_reload(); }; } #endif jd-2.8.7-140104/src/article/caret.h0000644000076400010400000000522110540252733013252 0ustar // ライセンス: GPL2 // キャレットの座標とかを計算するクラス #ifndef _CARET_H #define _CARET_H #include "layouttree.h" namespace ARTICLE { class CARET_POSITION { public: long x; long y; LAYOUT* layout; // キャレットの属するレイアウトノードへのポインタ long byte; // 何バイト目の文字の「前」か CARET_POSITION() : x( 0 ), y( 0 ), layout( 0 ), byte( 0 ){} ~CARET_POSITION(){} // キャレット座標計算関数 void set( LAYOUT* _layout, long _byte, // マウスポインタのx座標 long _x = 0, // 文字の座標、幅、バイト数 long char_x = 0, long char_y = 0, long char_width = 0, long byte_char = 0 ){ layout = _layout; byte = _byte; y = char_y; // 文字の真ん中から左にマウスポインタがある if( _x <= char_x + char_width / 2 ){ x = char_x; } // 文字の真ん中から右にマウスポインタあるなら次の文字の前にキャレットセット else{ x = char_x + char_width; byte += byte_char; } } // 後は演算子 bool operator != ( const CARET_POSITION& caret_pos ){ if( ! layout && ! caret_pos.layout ) return false; if( ! layout || ! caret_pos.layout ) return true; if( layout->id_header != caret_pos.layout->id_header || layout->id != caret_pos.layout->id || byte != caret_pos.byte ) return true; return false; } bool operator == ( const CARET_POSITION& caret_pos ) { return ! ( *this != caret_pos ); } bool operator > ( const CARET_POSITION& caret_pos ){ if( ! layout && ! caret_pos.layout ) return true; if( ! layout ) return false; if( ! caret_pos.layout ) return true; if( layout->id_header > caret_pos.layout->id_header ) return true; if( layout->id_header < caret_pos.layout->id_header ) return false; // ブロック同じ if( layout->id > caret_pos.layout->id ) return true; if( layout->id < caret_pos.layout->id ) return false; // ノード同じ if( byte > caret_pos.byte ) return true; return false; } bool operator < ( const CARET_POSITION& caret_pos ){ return ! ( *this > caret_pos ); } }; } #endif jd-2.8.7-140104/src/article/drawareabase.cpp0000644000076400010400000046663612260126053015151 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _DEBUG_CARETMOVE //#define _DRAW_CARET #include "jddebug.h" #include "gtkmmversion.h" #include "drawareabase.h" #include "layouttree.h" #include "font.h" #include "embeddedimage.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/jdregex.h" #include "dbtree/articlebase.h" #include "dbtree/node.h" #include "dbtree/interface.h" #include "dbimg/imginterface.h" #include "dbimg/img.h" #include "config/globalconf.h" #include "icons/iconmanager.h" #include "control/controlid.h" #include "global.h" #include "httpcode.h" #include "colorid.h" #include "fontid.h" #include "cache.h" #include "cssmanager.h" #include "session.h" #include #include #include using namespace ARTICLE; enum { AUTOSCR_CIRCLE = 24, // オートスクロールの時のサークルの大きさ BIG_HEIGHT = 100000000, LAYOUT_MIN_HEIGHT = 2, // viewの高さがこの値よりも小さい時はリサイズしていないと考える EIMG_ICONSIZE = 32, // 埋め込み画像のアイコンサイズ EIMG_MRG = 8, // 埋め込み画像のアイコンの間隔 WIDTH_FRAME = 1, // フレーム幅 SPACE_TAB = 4, // 水平タブをどれだけ空けるか ( フォントの高さ * SPACE_TAB ) COUNTER_NOMOTION = 16, // ホイールスクロール直後にモーションイベントをキャンセルする時の遊び量 SEARCH_BUFFER_SIZE = 64 * 1024 // 検索のバッファサイズ }; #define SCROLLSPEED_FAST ( m_vscrbar ? \ m_vscrbar->get_adjustment()->get_page_size() \ - m_vscrbar->get_adjustment()->get_step_increment()*CONFIG::get_key_fastscroll_size() \ : 0 ) #define SCROLLSPEED_MID ( m_vscrbar ? m_vscrbar->get_adjustment()->get_page_size()/2 : 0 ) #define SCROLLSPEED_SLOW ( m_vscrbar ? m_vscrbar->get_adjustment()->get_step_increment()*CONFIG::get_key_scroll_size() : 0 ) #define IS_ALPHABET( chr ) ( ( chr >= 'a' && chr <= 'z' ) || ( chr >= 'A' && chr <= 'Z' ) ) #define HAS_TEXT(layout) ( ( layout->type == DBTREE::NODE_TEXT || layout->type == DBTREE::NODE_IDNUM || layout->type == DBTREE::NODE_LINK ) && layout->text ) // 検索で使用 struct LAYOUT_TABLE { LAYOUT* layout; size_t offset; }; ////////////////////////////////////////////////////////// DrawAreaBase::DrawAreaBase( const std::string& url ) : m_url( url ) , m_vscrbar( 0 ) , m_layout_tree( 0 ) , m_seen_current( 0 ) , m_window( 0 ) , m_gc( 0 ) , m_backscreen( NULL ) , m_pango_layout( 0 ) , m_draw_frame( false ) , m_back_frame( NULL ) , m_ready_back_frame( false ) , m_aafont_initialized( false ) , m_strict_of_char( false ) , m_configure_reserve( false ) , m_configure_width( 0 ) , m_configure_height( 0 ) , m_back_marker( NULL ) , m_ready_back_marker( false ) , m_wait_scroll( 0 ) , m_cursor_type( Gdk::ARROW ) { #ifdef _DEBUG std::cout << "DrawAreaBase::DrawAreaBase " << m_url << std::endl;; #endif // フォント設定 set_fontid( FONT_MAIN ); // 文字色 set_colorid_text( COLOR_CHAR ); // 背景色 set_colorid_back( COLOR_BACK ); // bodyのcssプロパティ int classid = CORE::get_css_manager()->get_classid( "body" ); m_css_body = CORE::get_css_manager()->get_property( classid ); } DrawAreaBase::~DrawAreaBase() { #ifdef _DEBUG std::cout << "DrawAreaBase::~DrawAreaBase " << m_url << std::endl;; #endif if( m_layout_tree ) delete m_layout_tree; m_layout_tree = NULL; clear(); } // // セットアップ // // show_abone : あぼーんされたスレも表示 // show_scrbar : スクロールバーを最初から表示 // show_multispace : 連続空白も表示 // void DrawAreaBase::setup( const bool show_abone, const bool show_scrbar, const bool show_multispace ) { if( m_layout_tree ) delete m_layout_tree; m_layout_tree = NULL; clear(); m_article = DBTREE::get_article( m_url ); m_layout_tree = new LayoutTree( m_url, show_abone, show_multispace ); m_view.set_double_buffered( false ); // デフォルトではoffになってるイベントを追加 m_view.add_events( Gdk::BUTTON_PRESS_MASK ); m_view.add_events( Gdk::BUTTON_RELEASE_MASK ); m_view.add_events( Gdk::SCROLL_MASK ); m_view.add_events( Gdk::POINTER_MOTION_MASK ); m_view.add_events( Gdk::LEAVE_NOTIFY_MASK ); m_view.add_events( Gdk::VISIBILITY_NOTIFY_MASK ); // focus 可にセット m_view.set_flags( m_view.get_flags() | Gtk::CAN_FOCUS ); m_view.add_events( Gdk::KEY_PRESS_MASK ); m_view.add_events( Gdk::KEY_RELEASE_MASK ); // イベント接続 m_view.signal_leave_notify_event().connect( sigc::mem_fun( *this, &DrawAreaBase::slot_leave_notify_event ) ); m_view.signal_realize().connect( sigc::mem_fun( *this, &DrawAreaBase::slot_realize )); m_view.signal_configure_event().connect( sigc::mem_fun( *this, &DrawAreaBase::slot_configure_event )); m_view.signal_expose_event().connect( sigc::mem_fun( *this, &DrawAreaBase::slot_expose_event )); m_view.signal_scroll_event().connect( sigc::mem_fun( *this, &DrawAreaBase::slot_scroll_event )); m_view.signal_button_press_event().connect( sigc::mem_fun( *this, &DrawAreaBase::slot_button_press_event )); m_view.signal_button_release_event().connect( sigc::mem_fun( *this, &DrawAreaBase::slot_button_release_event )); m_view.signal_motion_notify_event().connect( sigc::mem_fun( *this, &DrawAreaBase::slot_motion_notify_event )); m_view.signal_key_press_event().connect( sigc::mem_fun(*this, &DrawAreaBase::slot_key_press_event )); m_view.signal_key_release_event().connect( sigc::mem_fun(*this, &DrawAreaBase::slot_key_release_event )); m_view.signal_visibility_notify_event().connect( sigc::mem_fun(*this, &DrawAreaBase::slot_visibility_notify_event ) ); pack_start( m_view ); // pango layout 作成 m_pango_layout = m_view.create_pango_layout( "" ); m_pango_layout->set_width( -1 ); // no wrap // フォント初期化 // 色の初期化は realize したとき init_font(); // スクロールバー作成 if( show_scrbar ) create_scrbar(); show_all_children(); } // // 背景色のID( colorid.h にある ID を指定) // const int DrawAreaBase::get_colorid_back() { if( m_css_body.bg_color >= 0 ) return m_css_body.bg_color; return m_colorid_back; } // // 変数初期化 // void DrawAreaBase::clear() { m_scrollinfo.reset(); m_selection.select = false; m_multi_selection.clear(); m_layout_current = NULL; m_width_client = 0; m_height_client = 0; m_clicked = false; m_drugging = false; m_r_drugging = false; m_pre_pos_y = -1; m_cancel_change_adjust = false; m_key_press = false; m_key_locked = false; m_keyval = 0; m_goto_num_reserve = 0; m_goto_bottom_reserve = false; m_wheel_scroll_time = 0; m_caret_pos = CARET_POSITION(); m_caret_pos_pre = CARET_POSITION(); m_caret_pos_dragstart = CARET_POSITION(); m_drawinfo.draw = false; m_rect_backscreen.y = 0; m_rect_backscreen.height = 0; m_scroll_window = true; m_enable_draw = true; m_jump_history.clear(); // 埋め込み画像削除 std::list< EmbeddedImage* >::iterator it = m_eimgs.begin(); for( ; it != m_eimgs.end(); ++it ) if( *it ) delete *it; m_eimgs.clear(); } // // スクロールバー作成とパック // void DrawAreaBase::create_scrbar() { if( m_vscrbar ) return; #ifdef _DEBUG std::cout << "DrawAreaBase::create_scrbar\n"; #endif // そのままHBoxにスクロールバーをパックすると、スクロールしたときに何故かHBox全体が // 再描画されて負荷が高くなるのでEventBoxを間に挟む m_vscrbar = Gtk::manage( new Gtk::VScrollbar() ); m_event = Gtk::manage( new Gtk::EventBox() ); assert( m_vscrbar ); assert( m_event ); if( CONFIG::get_left_scrbar() ) remove( m_view ); m_event->add( *m_vscrbar ); pack_start( *m_event, Gtk::PACK_SHRINK ); if( CONFIG::get_left_scrbar() ) pack_start( m_view ); m_vscrbar->get_adjustment()->signal_value_changed().connect( sigc::mem_fun( *this, &DrawAreaBase::slot_change_adjust ) ); show_all_children(); } // // 色初期化 ( colorid.h 参照 ) // void DrawAreaBase::init_color() { const std::vector< std::string >& colors = CORE::get_css_manager()->get_colors(); const int usrcolor = colors.size(); m_color.resize( END_COLOR_FOR_THREAD + usrcolor ); Glib::RefPtr< Gdk::Colormap > colormap = get_default_colormap(); int i = COLOR_FOR_THREAD +1; for( ; i < END_COLOR_FOR_THREAD; ++i ){ m_color[ i ] = Gdk::Color( CONFIG::get_color( i ) ); colormap->alloc_color( m_color[ i ] ); } // スレビューの選択色でgtkrcの設定を使用 if( CONFIG::get_use_select_gtkrc() ){ m_color[ COLOR_CHAR_SELECTION ] = get_style()->get_text( Gtk::STATE_SELECTED ); colormap->alloc_color( m_color[ COLOR_CHAR_SELECTION ] ); m_color[ COLOR_BACK_SELECTION ] = get_style()->get_base( Gtk::STATE_SELECTED ); colormap->alloc_color( m_color[ COLOR_BACK_SELECTION ] ); } std::vector< std::string >::const_iterator it = colors.begin(); for( ; it != colors.end(); ++it, ++i ){ m_color[ i ] = Gdk::Color( ( *it ) ); colormap->alloc_color( m_color[ i ] ); } } // // フォント初期化 // void DrawAreaBase::init_font() { // スレビューで文字幅の近似を厳密にするか m_strict_of_char = CONFIG::get_strict_char_width(); m_context = get_pango_context(); assert( m_context ); std::string fontname = CONFIG::get_fontname( m_defaultfontid ); if( fontname.empty() ) return; init_fontinfo( m_defaultfont, fontname ); if( CONFIG::get_aafont_enabled() ){ m_aafont_initialized = true; std::string aafontname = CONFIG::get_fontname( FONT_AA ); init_fontinfo( m_aafont, aafontname ); #ifdef _DEBUG std::cout << "DrawAreaBase::aa_fontname = " << aafontname << std::endl; #endif } // layoutにフォントをセット m_font = &m_defaultfont; m_pango_layout->set_font_description( m_font->pfd ); modify_font( m_font->pfd ); } // // フォント情報初期化 // void DrawAreaBase::init_fontinfo( FONTINFO& fi, std::string& fontname ) { fi.fontname = fontname; // layoutにフォントをセット fi.pfd = Pango::FontDescription( fontname ); fi.pfd.set_weight( Pango::WEIGHT_NORMAL ); m_pango_layout->set_font_description( fi.pfd ); // フォント情報取得 Pango::FontMetrics metrics = m_context->get_metrics( fi.pfd ); fi.ascent = PANGO_PIXELS( metrics.get_ascent() ); fi.descent = PANGO_PIXELS( metrics.get_descent() ); fi.height = fi.ascent + fi.descent; // 改行高さ ( トップからの距離 ) fi.br_size = ( int )( fi.height * CONFIG::get_adjust_line_space() ); const char* wstr = "あいうえお"; m_pango_layout->set_text( wstr ); // リンクの下線の位置 ( トップからの距離 ) #if GTKMM_CHECK_VERSION(2,5,0) fi.underline_pos = PANGO_PIXELS( ( metrics.get_ascent() - metrics.get_underline_position() ) * CONFIG::get_adjust_underline_pos() ); #else fi.underline_pos = int( ( m_pango_layout->get_pixel_logical_extents().get_height() ) * CONFIG::get_adjust_underline_pos() ); #endif // 左右padding取得 // マージン幅は真面目にやると大変そうなので文字列 wstr の平均を取る int width = m_pango_layout->get_pixel_ink_extents().get_width() / 5; fi.mrg_right = width /2 * 3; } // // クロック入力 // void DrawAreaBase::clock_in() { if( m_scrollinfo.mode != SCROLL_NOT && ! ( m_scrollinfo.mode == SCROLL_AUTO || m_scrollinfo.live ) ){ // スクロール中にダイアログを開いた場合はスクロールされたままになるのでスクロールを止める if( SESSION::is_dialog_shown() ) focus_out(); else exec_scroll(); } } // // スムーススクロール用クロック入力 // void DrawAreaBase::clock_in_smooth_scroll() { if( m_scrollinfo.mode == SCROLL_AUTO || m_scrollinfo.live ){ // スクロール中にダイアログを開いた場合はスクロールされたままになるのでスクロールを止める if( ! m_scrollinfo.live && SESSION::is_dialog_shown() ){ m_scrollinfo.mode = SCROLL_NOT; focus_out(); } else exec_scroll(); } } // // フォーカス // void DrawAreaBase::focus_view() { m_view.grab_focus(); } // // フォーカス解除 // void DrawAreaBase::focus_out() { // realize していない if( !m_gc ) return; #ifdef _DEBUG std::cout << "DrawAreaBase::focus_out\n"; #endif change_cursor( Gdk::ARROW ); m_key_press = false; m_key_locked = false; m_keyval = 0; if( m_scrollinfo.mode != SCROLL_AUTO ) m_scrollinfo.reset(); } // 新着セパレータのあるレス番号の取得とセット const int DrawAreaBase::get_separator_new() { return m_layout_tree->get_separator_new(); } void DrawAreaBase::set_separator_new( int num ) { m_layout_tree->set_separator_new( num ); } // 新着セパレータを隠す void DrawAreaBase::hide_separator_new() { if( ! get_separator_new() ) return; m_layout_tree->set_separator_new( 0 ); exec_layout(); } // セパレータが画面に表示されているか const bool DrawAreaBase::is_separator_on_screen() { if( ! m_layout_tree ) return false; const int separator_new = m_layout_tree->get_separator_new(); if( ! separator_new ) return false; const RECTANGLE* rect = m_layout_tree->get_separator()->rect; if( ! rect ) return false; const int height_view = m_view.get_height(); const int pos_y = get_vscr_val(); if( rect->y + rect->height <= pos_y || rect->y > pos_y + height_view ) return false; return true; } // 現在のポインタの下にあるレス番号取得 const int DrawAreaBase::get_current_res_num() { const int y = m_y_pointer + get_vscr_val(); // 先頭のヘッダブロックから順に調べる LAYOUT* header = m_layout_tree->top_header(); while( header ){ // y が含まれているブロックを探す if( header->rect->y >= y ) return header->res_number -1; // 次のブロックへ header = header->next_header; } return max_number(); } // 範囲選択中の文字列 const std::string DrawAreaBase::str_selection() { if( ! m_selection.select ) return std::string(); return m_selection.str; } // 範囲選択を開始したレス番号 const int DrawAreaBase::get_selection_resnum_from() { if( ! m_selection.select ) return 0; if( ! m_selection.caret_from.layout ) return 0; return m_selection.caret_from.layout->res_number; } // 範囲選択を終了したレス番号 const int DrawAreaBase::get_selection_resnum_to() { if( ! m_selection.select ) return 0; if( ! m_selection.caret_to.layout ) return 0; return m_selection.caret_to.layout->res_number; } // // 表示されている最後のレスの番号 // int DrawAreaBase::max_number() { assert( m_layout_tree ); return m_layout_tree->max_res_number(); } // // from_num から to_num までレスをappendして再レイアウト // void DrawAreaBase::append_res( const int from_num, const int to_num ) { assert( m_article ); assert( m_layout_tree ); #ifdef _DEBUG std::cout << "DrawAreaBase::append_res from " << from_num << " to " << to_num << std::endl; #endif // スクロールバーが一番下にある(つまり新着スレがappendされた)場合は少しだけスクロールする bool scroll = false; const int pos = get_vscr_val(); if( ! m_layout_tree->get_separator_new() && pos && pos == get_vscr_maxval() && ! m_scrollinfo.live ){ #ifdef _DEBUG std::cout << "on bottom pos = " << pos << std::endl; #endif scroll = true; } for( int num = from_num; num <= to_num; ++num ) m_layout_tree->append_node( m_article->res_header( num ), false ); // クライアント領域のサイズをリセットして再レイアウト m_width_client = 0; m_height_client = 0; exec_layout(); if( scroll ){ CORE::CSS_PROPERTY* css = m_layout_tree->get_separator()->css; RECTANGLE* rect = m_layout_tree->get_separator()->rect; m_scrollinfo.reset(); m_scrollinfo.dy = 0; if( css ) m_scrollinfo.dy += css->mrg_top + css->mrg_bottom; if( rect ) m_scrollinfo.dy += rect->height; if( m_scrollinfo.dy ){ #ifdef _DEBUG std::cout << "exec scroll dy = " << m_scrollinfo.dy << std::endl; #endif m_scrollinfo.mode = SCROLL_NORMAL; exec_scroll(); } } } // // リストで指定したレスをappendして再レイアウト // void DrawAreaBase::append_res( const std::list< int >& list_resnum ) { std::list< bool > list_joint; append_res( list_resnum, list_joint ); } // // リストで指定したレスをappendして再レイアウト( 連結情報付き ) // // list_joint で連結指定したレスはヘッダを取り除いて前のレスに連結する // void DrawAreaBase::append_res( const std::list< int >& list_resnum, const std::list< bool >& list_joint ) { assert( m_article ); assert( m_layout_tree ); if( list_resnum.size() == 0 ) return; #ifdef _DEBUG std::cout << "DrawAreaBase::append_res" << std::endl; #endif const bool use_joint = ( list_joint.size() == list_resnum.size() ); std::list< int >::const_iterator it = list_resnum.begin(); std::list< bool >::const_iterator it_joint = list_joint.begin(); for( ; it != list_resnum.end(); ++it ){ bool joint = false; if( use_joint ){ joint = ( *it_joint ); ++it_joint; } #ifdef _DEBUG std::cout << "append no. " << ( *it ) << " joint = " << joint << std::endl; #endif m_layout_tree->append_node( m_article->res_header( ( *it ) ), joint ); } // クライアント領域のサイズをリセットして再レイアウト m_width_client = 0; m_height_client = 0; exec_layout(); } // // html をappendして再レイアウト // void DrawAreaBase::append_html( const std::string& html ) { assert( m_layout_tree ); if( html.empty() ) return; #ifdef _DEBUG std::cout << "DrawAreaBase::append_html " << html << std::endl; #endif m_layout_tree->append_html( html ); // クライアント領域のサイズをリセットして再レイアウト m_width_client = 0; m_height_client = 0; exec_layout(); } // // datをappendして再レイアウト // void DrawAreaBase::append_dat( const std::string& dat, int num ) { assert( m_layout_tree ); if( dat.empty() ) return; #ifdef _DEBUG std::cout << "DrawAreaBase::append_dat " << dat << std::endl; #endif m_layout_tree->append_dat( dat, num ); // クライアント領域のサイズをリセットして再レイアウト m_width_client = 0; m_height_client = 0; exec_layout(); } // // 画面初期化 // // 色、フォントを初期化して画面を消す // void DrawAreaBase::clear_screen() { if( ! m_layout_tree ) return; m_layout_tree->clear(); clear(); init_color(); init_font(); if( exec_layout() ) redraw_view_force(); } // // 再描画 // 再レイアウトはしないが configureの予約がある場合は再レイアウトしてから再描画する // void DrawAreaBase::redraw_view() { // 起動中とシャットダウン中は処理しない if( SESSION::is_booting() ) return; if( SESSION::is_quitting() ) return; // タブ操作中は処理しない if( SESSION::is_tab_operating( URL_ARTICLEADMIN ) ) return; #ifdef _DEBUG std::cout << "DrawAreaBase::redraw_view " << m_url << std::endl; #endif configure_impl(); m_view.queue_draw(); if( m_window ) m_window->process_updates( false ); } // 強制再描画 void DrawAreaBase::redraw_view_force() { #ifdef _DEBUG std::cout << "DrawAreaBase::redraw_view_force()\n"; #endif m_drawinfo.draw = false; m_rect_backscreen.y = 0; m_rect_backscreen.height = 0; redraw_view(); } // // レイアウト(ノードの座標演算)実行 // bool DrawAreaBase::exec_layout() { return exec_layout_impl( false, 0 ); } // // 先頭ノードから順に全ノードの座標を計算する(描画はしない) // // is_popup = true ならポップアップウィンドウの幅を親ビューの幅とする // offset_y は y 座標の上オフセット行数 // const bool DrawAreaBase::exec_layout_impl( const bool is_popup, const int offset_y ) { // 起動中とシャットダウン中は処理しない if( SESSION::is_booting() ) return false; if( SESSION::is_quitting() ) return false; // タブ操作中は処理しない if( SESSION::is_tab_operating( URL_ARTICLEADMIN ) ) return true; // レイアウトがセットされていない if( ! m_layout_tree ) return false; if( ! m_layout_tree->top_header() ) return false; // drawareaのウィンドウサイズ int width_view = m_view.get_width(); const int height_view = m_view.get_height(); int width_base_vscrbar = 0; if( is_popup && SESSION::get_base_drawarea() && SESSION::get_base_drawarea()->get_vscrbar() ){ width_base_vscrbar = SESSION::get_base_drawarea()->get_vscrbar()->get_width(); } #ifdef _DEBUG std::cout << "DrawAreaBase::exec_layout_impl : is_popup = " << is_popup << " url = " << m_url << std::endl; #endif //表示はされてるがまだリサイズしてない状況 if( height_view < LAYOUT_MIN_HEIGHT ){ // ポップアップで無い場合は処理しない if( ! is_popup ){ #ifdef _DEBUG std::cout << "drawarea is not resized yet.\n"; #endif return false; } // ポップアップの場合、横幅が確定出来ないのでメインウィンドウのスレビューの // drawarea の幅を最大幅とする if( SESSION::get_base_drawarea() && SESSION::get_base_drawarea()->get_view() ){ width_view = SESSION::get_base_drawarea()->get_view()->get_width(); } // スレビューを表示していない場合はメインウィンドウサイズを使用 else width_view = SESSION::get_width_win_main(); } #ifdef _DEBUG std::cout << "width_view = " << width_view << " height_view = " << height_view << std::endl; #endif // 新着セパレータの挿入 // 実況時は新着セパレータを表示しない(スクロールがガタガタするから) if( ! m_scrollinfo.live ) m_layout_tree->move_separator(); m_width_client = 0; m_height_client = 0; int x, y = 0; LAYOUT* header = m_layout_tree->top_header(); // フォント設定 set_node_font( header ); CORE::get_css_manager()->set_size( &m_css_body, m_font->height ); y += offset_y * m_font->br_size; y += m_css_body.padding_top; while( header ){ LAYOUT* layout = header->next_layout; if( ! layout ) break; // フォント設定 set_node_font( header ); // (注) header は div ノードであり、クラス名は "res" // 詳しくは LayoutTree::create_layout_header() を参照せよ CORE::get_css_manager()->set_size( header->css, m_font->height ); // div の位置と幅を計算 // 高さは子ノードのレイアウトが全て済んでから計算 if( ! m_pixbuf_bkmk ) m_pixbuf_bkmk = ICON::get_icon( ICON::BKMARK_THREAD ); // 最低でもブックマークのアイコン分だけ左のスペース開ける x = MAX( 1 + m_pixbuf_bkmk->get_width() + 1, m_css_body.padding_left + header->css->mrg_left ); y += header->css->mrg_top; if( ! header->rect ) header->rect = m_layout_tree->create_rect(); header->rect->x = x; header->rect->y = y; header->rect->width = width_view - x - ( header->css->mrg_right + m_css_body.padding_right ); // 内部ノードの開始座標 x += header->css->padding_left; y += header->css->padding_top; LAYOUT* current_div = NULL; int br_size = m_font->br_size; // 現在行の改行サイズ // 先頭の子ノードから順にレイアウトしていく while ( layout ){ // フォント設定 set_node_font( layout ); switch( layout->type ){ // div (注) div の中に div は作れない仕様になっている( header は除く ) case DBTREE::NODE_DIV: // 違うdivに切り替わったら以前のdivの高さを更新 if( current_div ){ y += br_size; y += current_div->css->padding_bottom; current_div->rect->height = y - current_div->rect->y; y += current_div->css->mrg_bottom; // align 調整 if( current_div->css->align != CORE::ALIGN_LEFT ) set_align( current_div, layout->id, current_div->css->align ); } current_div = layout; // div の位置と幅を計算 // 高さは違う div に切り替わった時に計算 CORE::get_css_manager()->set_size( current_div->css, m_font->height ); x = header->rect->x + header->css->padding_left; x += current_div->css->mrg_left; y += current_div->css->mrg_top; if( ! current_div->rect ) current_div->rect = m_layout_tree->create_rect(); current_div->rect->x = x; current_div->rect->y = y; current_div->rect->width = header->rect->width - ( header->css->padding_left + current_div->css->mrg_left ) - ( header->css->padding_right + current_div->css->mrg_right ); // divの内部にあるノードの開始座標 x += current_div->css->padding_left; y += current_div->css->padding_top; break; ////////////////////////////////////////// case DBTREE::NODE_IDNUM: // 発言数ノード if( ! set_num_id( layout ) ) break; case DBTREE::NODE_TEXT: // テキスト case DBTREE::NODE_LINK: // リンク // ノードをレイアウトして次のノードの左上座標を計算 // x,y,br_size が参照なので更新された値が戻る layout_one_text_node( layout, x, y, br_size, width_view ); break; ////////////////////////////////////////// case DBTREE::NODE_IMG: // img // レイアウトして次のノードの左上座標を計算 // x,y, br_size が参照なので更新された値が戻る layout_one_img_node( layout, x, y, br_size, m_width_client, is_popup, EIMG_MRG ); break; ////////////////////////////////////////// case DBTREE::NODE_SSSP: // sssp アイコン y += EIMG_MRG; layout_one_img_node( layout, x, y, br_size, m_width_client, is_popup, 0 ); if( layout->rect->height > m_font->br_size ){ br_size = m_font->br_size; y += layout->rect->height - br_size; } break; ////////////////////////////////////////// case DBTREE::NODE_HR: // 水平線 if( ! layout->rect ) layout->rect = m_layout_tree->create_rect(); layout->rect->x = layout->div ? layout->div->rect->x + layout->div->css->padding_left : 0; layout->rect->y = y + br_size; layout->rect->width = layout->div ? layout->div->rect->width - layout->div->css->padding_left : width_view; layout->rect->height = 1; y += 1; // フォールスルー ////////////////////////////////////////// case DBTREE::NODE_BR: // 改行 x = 0; if( layout->div ) x = layout->div->rect->x + layout->div->css->padding_left; y += br_size; break; ////////////////////////////////////////// case DBTREE::NODE_ZWSP: // 幅0スペース break; ////////////////////////////////////////// case DBTREE::NODE_HTAB: // 水平タブ x += m_font->height * SPACE_TAB; break; } // クライアント領域の幅を更新 if( layout->type != DBTREE::NODE_DIV && layout->rect ){ int width_tmp = layout->rect->x + layout->rect->width; width_tmp += ( header->css->padding_right + header->css->mrg_right ); // divの中なら右スペースの分も足す if( layout->div ) width_tmp += ( layout->div->css->padding_right + layout->div->css->mrg_right ); width_tmp += m_font->mrg_right + m_css_body.padding_right; if( width_tmp > width_view ) width_tmp = width_view; width_tmp += width_base_vscrbar; if( width_tmp > m_width_client ) m_width_client = width_tmp; } layout = layout->next_layout; } y += br_size; // 属している div の高さ確定 if( current_div ){ y += current_div->css->padding_bottom; current_div->rect->height = y - current_div->rect->y; y += current_div->css->mrg_bottom; // align 調整 if( current_div->css->align != CORE::ALIGN_LEFT ) set_align( current_div, 0, current_div->css->align ); } // ヘッダブロック高さ確定 y += header->css->padding_bottom; header->rect->height = y - header->rect->y; if( header->next_header ) y += header->css->mrg_bottom; // align 調整 if( header->css->align != CORE::ALIGN_LEFT ) set_align( header, 0, header->css->align ); header = header->next_header; } y += m_css_body.padding_bottom; // クライアント領域の高さ確定 m_height_client = y; #ifdef _DEBUG std::cout << "virtual size of drawarea : m_width_client = " << m_width_client << " m_height_client = " << m_height_client << std::endl; #endif // 実際に画面に表示されてない if( ! is_drawarea_realized() ){ #ifdef _DEBG std::cout << "windows is not shown yet\n"; #endif return false; } // 表示はされてるがまだリサイズしてない状況 if( height_view < LAYOUT_MIN_HEIGHT ){ #ifdef _DEBG std::cout << "windows is not resized yet\n"; #endif return false; } // ポップアップなどでスクロールバーが表示されていないならここで作成 // (注) メインウィンドウのスレビューなどは DrawAreaBase::setup() の show_scrbar // が true 指定されているので、はじめからスクロールバーが表示されている if( ! m_vscrbar && m_height_client > height_view ) create_scrbar(); // adjustment 範囲変更 Gtk::Adjustment* adjust = m_vscrbar ? m_vscrbar->get_adjustment(): NULL; if( adjust ){ const double current = adjust->get_value(); const double newpos = MAX( 0, MIN( m_height_client - height_view , current ) ); m_pre_pos_y = -1; adjust->set_lower( 0 ); adjust->set_upper( m_height_client ); adjust->set_page_size( height_view ); adjust->set_step_increment( m_font->br_size ); adjust->set_page_increment( height_view / 2 ); m_cancel_change_adjust = true; adjust->set_value( newpos ); m_cancel_change_adjust = false; } // 裏描画画面作成と初期描画 #ifdef _DEBUG std::cout << "create backscreen : width = " << m_view.get_width() << " height = " << m_view.get_height() << std::endl; #endif m_backscreen.clear(); m_backscreen = Gdk::Pixmap::create( m_window, m_view.get_width(), m_view.get_height() ); m_rect_backscreen.y = 0; m_rect_backscreen.height = 0; m_back_frame.clear(); m_back_frame = Gdk::Pixmap::create( m_window, m_view.get_width(), WIDTH_FRAME * 2 ); m_ready_back_frame = false; // 予約されているならジャンプ予約を実行 if( m_goto_num_reserve ) goto_num( m_goto_num_reserve ); if( m_goto_bottom_reserve ) goto_bottom(); return true; } // // ブロック要素のalign設定 // // id_end == 0 の時は最後のノードまでおこなう // void DrawAreaBase::set_align( LAYOUT* div, int id_end, int align ) { #ifdef _DEBUG // std::cout << "DrawAreaBase::set_align width = " << div->rect->width << std::endl; #endif LAYOUT* layout_from = NULL; LAYOUT* layout_to = NULL; RECTANGLE* rect_from = NULL; RECTANGLE* rect_to = NULL; LAYOUT* layout = div->next_layout; int width_line = 0; while( layout && ( ! id_end || layout->id != id_end ) ){ RECTANGLE* rect = layout->rect; while( rect ){ if( ! layout_from ){ layout_from = layout; rect_from = rect; width_line = 0; } layout_to = layout; rect_to = rect; width_line += rect->width; #ifdef _DEBUG // std::cout << "id = " << layout->id << " w = " << width_line << std::endl; #endif if( rect->end ) break; // wrap set_align_line( div, layout_from, layout_to, rect_from, rect_to, width_line, align ); layout_from = NULL; rect = rect->next_rect; } // 改行 if( layout_from && ( ! layout->next_layout || layout->type == DBTREE::NODE_BR || layout->id == id_end -1 ) ){ set_align_line( div, layout_from, layout_to, rect_from, rect_to, width_line, align ); layout_from = NULL; } layout = layout->next_layout; } } void DrawAreaBase::set_align_line( LAYOUT* div, LAYOUT* layout_from, LAYOUT* layout_to, RECTANGLE* rect_from, RECTANGLE* rect_to, int width_line, int align ) { int padding = div->rect->width - div->css->padding_left - div->css->padding_right - width_line; if( align == CORE::ALIGN_CENTER ) padding /= 2; #ifdef _DEBUG // std::cout << "from = " << layout_from->id << " padding = " << padding << std::endl; #endif for(;;){ bool break_for = ( layout_from == layout_to && rect_from == rect_to ); if( rect_from ){ rect_from->x += padding; rect_from = rect_from->next_rect; } if( ! rect_from ){ layout_from = layout_from->next_layout; if( layout_from ) rect_from = layout_from->rect; } if( break_for ) break; } } // // テキストノードの座標を計算する関数 // // x,y (参照) : ノードの初期座標(左上)を渡して、次のノードの左上座標が入って返る // br_size : 改行量 // width_view : 描画領域の幅 // void DrawAreaBase::layout_one_text_node( LAYOUT* layout, int& x, int& y, int& br_size, const int width_view ) { if( ! layout->lng_text ) layout->lng_text = strlen( layout->text ); int byte_to = layout->lng_text; LAYOUT* div = layout->div; // wrap 処理用の閾値計算 // x が border よりも右に来たら wrap する int border = 0; if( div ) border = div->rect->x + div->rect->width - div->css->padding_right; else border = width_view; border -= m_font->mrg_right; // 先頭の RECTANGLE型のメモリ確保 // wrapが起きたらまたRECTANGLE型のメモリを確保してリストの後ろに繋ぐ bool head_rect = true; RECTANGLE* rect = layout->rect; int pos_start = 0; for(;;){ // 横に何文字並べるか計算 char pre_char = 0; bool draw_head = true; // 先頭は最低1文字描画 int pos_to = pos_start; int width_line = 0; int n_byte = 0; int n_ustr = 0; // utfで数えたときの文字数 // この文字列の全角/半角モードの初期値を決定 bool wide_mode = set_init_wide_mode( layout->text, pos_start, byte_to ); // 右端がはみ出るまで文字を足していく while( pos_to < byte_to && ( ! is_wrapped( x + PANGO_PIXELS( width_line ), border, layout->text + pos_to ) || draw_head ) ) { int byte_char; width_line += get_width_of_one_char( layout->text + pos_to, byte_char, pre_char, wide_mode, get_fontid() ); pos_to += byte_char; n_byte += byte_char; ++n_ustr; draw_head = false; } // 幅確定 width_line = PANGO_PIXELS( width_line ); if( ! width_line ) break; if( layout->bold ) ++width_line; // RECTANGLEのメモリ確保 if( head_rect ){ // 先頭 if( ! rect ) rect = layout->rect = m_layout_tree->create_rect(); head_rect = false; } else{ // wrap したので次のRECTANGLEを確保してリストで繋ぐ rect->end = false; if( ! rect->next_rect ) rect->next_rect = m_layout_tree->create_rect(); rect = rect->next_rect; } // 座標情報更新 br_size = m_font->br_size; rect->end = true; rect->x = x; rect->y = y; rect->width = width_line; rect->height = br_size; rect->pos_start = pos_start; rect->n_byte = n_byte; rect->n_ustr = n_ustr; #ifdef _DEBUG // std::cout << do_draw << " " << layout->id_header << " " << layout->id // << " x = " << layout->rect->x << " y = " << layout->rect->y // << " w = " << layout->rect->width << " h = " << layout->rect->height << std::endl; #endif x += rect->width; if( pos_to >= byte_to ) break; // wrap 処理 x = 0; if( div ) x = div->rect->x + div->css->padding_left; y += br_size; pos_start = pos_to; } } // // 画像ノードの座標を計算する関数 // // x,y (参照) : ノードの初期座標(左上)を渡して、次のノードの左上座標が入って返る // br_size : 現在行での改行量 // width_view : 描画領域の幅 // init_popupwin : ポップアップウィンドウの初期サイズ計算をおこなう // mrg_bottom : 下マージン // void DrawAreaBase::layout_one_img_node( LAYOUT* layout, int& x, int& y, int& br_size, const int width_view, const bool init_popupwin, const int mrg_bottom ) { #ifdef _DEBUG std::cout << "DrawAreaBase::layout_one_img_node link = " << layout->link << std::endl; #endif DBTREE::NODE* node = layout->node; if( ! node ) return; // 座標とサイズのセット RECTANGLE* rect = layout->rect; if( ! rect ) rect = layout->rect = m_layout_tree->create_rect(); rect->x = x; rect->y = y; rect->width = EIMG_ICONSIZE + 2; // +2 は枠の分 rect->height = EIMG_ICONSIZE + 2; // +2 は枠の分 // 既に表示済みの場合 DBIMG::Img* img = node->linkinfo->img; if( !img && init_popupwin ) img = node->linkinfo->img = DBIMG::get_img( layout->link ); if( img && img->is_cached() ){ rect->width = img->get_width_emb() + 2; // +2 は枠の分 rect->height = img->get_height_emb() + 2; // +2 は枠の分 } #ifdef _DEBUG std::cout << "x = " << rect->x << " y = " << rect->y << " w = " << rect->width << " h = " << rect->height << std::endl; #endif // wrap 処理用の閾値計算 // x が border よりも右に来たら wrap する LAYOUT* div = layout->div; int border = 0; if( div ) border = div->rect->x + div->rect->width - div->css->padding_right; else border = width_view; // wrap if( x + ( rect->width + EIMG_MRG ) >= border ){ x = 0; if( div ) x = div->rect->x + div->css->padding_left; y += br_size; br_size = m_font->br_size; rect->x = x; rect->y = y; } x += rect->width + mrg_bottom; if( br_size < rect->height + mrg_bottom ) br_size = rect->height + mrg_bottom; } // // 文字列の全角/半角モードの初期値を決定する関数 // bool DrawAreaBase::set_init_wide_mode( const char* str, const int pos_start, const int pos_to ) { if( ! m_strict_of_char ) return false; bool wide_mode = true; int i = pos_start; while( i < pos_to ){ int byte_tmp; MISC::utf8toucs2( str + i, byte_tmp ); // 文字列に全角が含まれていたら全角モードで開始 if( byte_tmp != 1 ) break; // アルファベットが含まれていたら半角モードで開始 if( IS_ALPHABET( str[ i ] ) ){ wide_mode = false; break; } // 数字など、全てアルファベットと全角文字以外の文字で出来ていたら // 全角モードにする i += byte_tmp; } return wide_mode; } // // 一文字の幅を取得 // // utfstr : 入力文字 (UTF-8) // byte : 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す // pre_char : 前の文字( 前の文字が全角なら = 0 ) // wide_mode : 全角半角モード( アルファベット以外の文字ではモードにしたがって幅を変える ) // mode : fontid.h で定義されているフォントのID // const int DrawAreaBase::get_width_of_one_char( const char* utfstr, int& byte, char& pre_char, bool& wide_mode, const int mode ) { int width = 0; int width_wide = 0; // キャッシュに無かったら幅を調べてキャッシュに登録 if( ! ARTICLE::get_width_of_char( utfstr, byte, pre_char, width, width_wide, mode ) ){ const std::string tmpchar( utfstr, byte ); #ifdef _DEBUG std::cout << "no cache [" << tmpchar << "] " << byte <<" byte "; if( pre_char == 0 ) std::cout << " p =[0] "; else if( pre_char > 0 ) std::cout << " p =[" << pre_char << "] "; #endif // 厳密な幅計算をしない場合 if( ! m_strict_of_char ){ m_pango_layout->set_text( tmpchar ); width = width_wide = m_pango_layout->get_logical_extents().get_width(); } // 厳密に幅計算する場合 else{ // 全角モードでの幅 if( ! width_wide ){ const std::string str_dummy( "ぁ" ); m_pango_layout->set_text( str_dummy + str_dummy ); int width_dummy = m_pango_layout->get_logical_extents().get_width() / 2; m_pango_layout->set_text( str_dummy + tmpchar ); width_wide = m_pango_layout->get_logical_extents().get_width() - width_dummy; if( byte != 1 ) width = width_wide; } // 半角モードでの幅 // 半角モードではひとつ前の文字によって幅が変わることに注意する if( ! width ){ std::string char_dummy( "a" ); if( pre_char && IS_ALPHABET( pre_char ) ) char_dummy[ 0 ] = pre_char; const std::string str_dummy( char_dummy + char_dummy ); m_pango_layout->set_text( str_dummy ); int width_dummy = m_pango_layout->get_logical_extents().get_width() / 2; const std::string str_tmp( char_dummy + tmpchar ); m_pango_layout->set_text( str_tmp ); width = m_pango_layout->get_logical_extents().get_width() - width_dummy; #ifdef _DEBUG std::cout << " dummy = " << str_dummy << " dw = " << PANGO_PIXELS( width_dummy ); std::cout << " str = " << str_tmp << " dw = " << PANGO_PIXELS( m_pango_layout->get_logical_extents().get_width() ); #endif } } #ifdef _DEBUG std::cout << " w = " << PANGO_PIXELS( width ) << " wide = " << PANGO_PIXELS( width_wide ) << std::endl; #endif // フォントが無い if( width_wide <= 0 ){ int byte_tmp; const unsigned int code = MISC::utf8toucs2( tmpchar.c_str(), byte_tmp ); std::stringstream ss_err; ss_err << "unknown font byte = " << byte_tmp << " ucs2 = " << code << " width = " << width; #ifdef _DEBUG std::cout << "DrawAreaBase::get_width_of_one_char " << "byte = " << byte << " byte_tmp = " << byte_tmp << " code = " << code << " [" << tmpchar << "]\n"; #endif MISC::ERRMSG( ss_err.str() ); ARTICLE::set_width_of_char( utfstr, byte, pre_char, -1, -1, mode ); width = width_wide = 0; } else ARTICLE::set_width_of_char( utfstr, byte, pre_char, width, width_wide, mode ); } int ret = 0; // 厳密に計算しない場合 if( ! m_strict_of_char ) ret = width_wide; else{ // 全角文字 if( byte != 1 ){ ret = width_wide; pre_char = 0; wide_mode = true; } // 半角文字 else{ ret = width; pre_char = utfstr[ 0 ]; // アルファベットならモードを半角モードに変更 if( IS_ALPHABET( utfstr[ 0 ] ) ) wide_mode = false; // アルファベット以外の文字では現在の全角/半角モードに // したがって幅を変える。モードは変更しない else if( wide_mode ) ret = width_wide; } } return ret; } // // スクリーン描画 // // y から height の高さ分だけ描画する // height == 0 ならスクロールした分だけ描画( y は無視 ) // const bool DrawAreaBase::draw_screen( const int y, const int height ) { if( ! m_enable_draw ) return false; if( ! m_gc ) return false; if( ! m_backscreen ) return false; if( ! m_layout_tree ) return false; if( ! m_layout_tree->top_header() ) return false; if( ! m_window ) return false; if( m_view.get_height() < LAYOUT_MIN_HEIGHT ) return false; // まだ画面に表示されていない // スクロールしていない if( ! height && m_pre_pos_y != -1 ){ const int pos_y = get_vscr_val(); const int dy = pos_y - m_pre_pos_y; if( ! dy ) return false; } // キューに expose イベントが溜まっている時は全画面再描画 Gdk::Region rg = m_window->get_update_area(); if( rg.gobj() ){ redraw_view_force(); return true; } #ifdef _DEBUG std::cout << "DrawAreaBase::draw_screen " << " y = " << y << " height " << height << std::endl; #endif m_drawinfo.draw = true; m_drawinfo.y = y; m_drawinfo.height = height; // expose イベント経由で exec_draw_screen() を呼び出す // gtk2.18以降は expose イベント内で描画処理しないと正しく描画されない様なので注意 m_view.queue_draw(); m_window->process_updates( false ); return true; } void DrawAreaBase::exec_draw_screen( const int y_redraw, const int height_redraw ) { const int width_view = m_view.get_width(); const int height_view = m_view.get_height(); const int pos_y = get_vscr_val(); // スクロール量 int dy = 0; // 画面上の描画開始領域のy座標と高さ int y_screen = y_redraw; int height_screen = height_redraw; // 描画範囲の上限、下限 int upper = pos_y + y_screen; int lower = upper + height_screen; if( m_pre_pos_y == -1 // 初回呼び出し時 // 高速スクロールモードでなく、バックスクリーンが全て描画されていない場合 || ( ! m_scroll_window && ( m_rect_backscreen.y != 0 || m_rect_backscreen.height != height_view ) ) ){ // 全画面再描画 dy = 0; y_screen = 0; height_screen = height_view; upper = pos_y; lower = pos_y + height_screen; } // スクロール中 else if( ! height_redraw ){ dy = pos_y - m_pre_pos_y; upper = pos_y; lower = pos_y + height_view; // 上にスクロールした if( dy > 0 ){ if( dy < height_view ) upper += ( height_view - dy ); y_screen = MAX( 0, height_view - dy ); height_screen = height_view - y_screen; } // 下にスクロールした else if( dy < 0 ){ if( -dy < height_view ) lower = upper - dy; y_screen = 0; height_screen = MIN( -dy, height_view ); } // 変化無し else{ #ifdef _DEBUG std::cout << "DrawAreaBase::exec_draw_screen canceled\n"; #endif return; } } #ifdef _DEBUG std::cout << "DrawAreaBase::exec_draw_screen " << " y_redraw = " << y_redraw << " height_redraw " << height_redraw << std::endl << "pos_y = " << pos_y << " dy = " << dy << " y_screen = " << y_screen << " h_screen = " << height_screen << " upper = " << upper << " lower = " << lower << " scrollmode = " << m_scrollinfo.mode << " scroll_window = " << m_scroll_window << " url = " << m_url << std::endl; #endif m_pre_pos_y = pos_y; m_rect_backscreen.x = 0; m_rect_backscreen.y = y_screen; m_rect_backscreen.width = width_view; m_rect_backscreen.height = height_screen; Gdk::Rectangle rect_clip( 0, y_screen, width_view, height_screen ); m_gc->set_clip_rectangle( rect_clip ); // バックスクリーンをスクロール処理する if( ! m_scroll_window ){ rect_clip.set_y( 0 ); rect_clip.set_height( height_view ); m_gc->set_clip_rectangle( rect_clip ); // 上にスクロールした if( dy > 0 && dy < height_view ) m_backscreen->draw_drawable( m_gc, m_backscreen, 0, dy, 0, 0, width_view , height_view - dy ); // 下にスクロールした else if( dy < 0 && -dy < height_view ) m_backscreen->draw_drawable( m_gc, m_backscreen, 0, 0, 0, -dy, width_view , height_view + dy ); m_rect_backscreen.y = 0; m_rect_backscreen.height = height_view; } // 一番最後のレスが半分以上表示されていたら最後のレス番号をm_seen_currentにセット m_seen_current = 0; const int max_res_number = m_layout_tree->max_res_number(); int num = max_res_number; const LAYOUT* lastheader = m_layout_tree->get_header_of_res_const( num ); // あぼーんなどで表示されていないときは前のレスを調べる if( !lastheader ){ while( ! m_layout_tree->get_header_of_res_const( num ) && num-- > 0 ); lastheader = m_layout_tree->get_header_of_res_const( num ); } if( lastheader && lastheader->rect && lastheader->rect->y + lastheader->rect->height/2 < pos_y + height_view ){ m_seen_current = m_layout_tree->max_res_number(); } struct timeval tv_before; struct timezone tz; gettimeofday( &tv_before, &tz ); // 2分探索で画面に表示されているノードの先頭を探す LAYOUT* header = NULL; int top = 1; int back = max_res_number; while( top <= back ){ const int pivot = ( top + back )/2; header = m_layout_tree->get_header_of_res( pivot ); if( ! header ) break; /* std::cout << "top = " << top << " back = " << back << " pivot = " << pivot << " pos_y = " << pos_y << " y = " << header->rect->y << " y + height = " << header->rect->y + header->rect->height << std::endl; */ if( header->next_header ){ if( header->rect->y <= pos_y && header->next_header->rect->y >= pos_y ) break; } else{ // 最後のレス if( header->rect->y <= pos_y ) break; } if( header->rect->y > pos_y ) back = pivot -1; else top = pivot + 1; header = NULL; } if( ! header ){ #ifdef _DEBUG std::cout << "not found\n"; #endif header = m_layout_tree->top_header(); } // バックスクリーンの背景クリア m_gc->set_foreground( m_color[ get_colorid_back() ] ); m_backscreen->draw_rectangle( m_gc, true, 0, y_screen, width_view, height_screen ); // 描画ループ bool relayout = false; while( header && header->rect->y < pos_y + height_view ){ // フォント設定 set_node_font( header ); // 現在みているレス番号取得 if( ! m_seen_current ){ if( ! header->next_header // 最後のレス || ( header->next_header->rect->y >= ( pos_y + m_font->br_size ) // 改行分下にずらす && header->rect->y <= ( pos_y + m_font->br_size ) ) ){ m_seen_current = header->res_number; } } // ヘッダが描画範囲に含まれてるなら描画 if( header->rect->y + header->rect->height > upper && header->rect->y < lower ){ // ノードが描画範囲に含まれてるなら描画 LAYOUT* layout = header; while ( layout ){ // フォント設定 set_node_font( layout ); RECTANGLE* rect = layout->rect; while( rect ){ if( rect->y + rect->height > upper && rect->y < lower ){ if( draw_one_node( layout, width_view, pos_y, upper, lower ) ) relayout = true; break; } rect = rect->next_rect; } layout = layout->next_layout; } } header = header->next_header; } // 処理落ちが起きていないかチェックする // exec_scroll()を参照せよ struct timeval tv_after; if( ! m_wait_scroll && ! gettimeofday( &tv_after, &tz ) ){ const time_t passed = ( tv_after.tv_sec * 1000000 + tv_after.tv_usec ) - ( tv_before.tv_sec * 1000000 + tv_before.tv_usec ); if( passed > TIMER_TIMEOUT * 1000 ){ m_scroll_time = tv_after; m_wait_scroll = TIMER_TIMEOUT * 1000; #ifdef _DEBUG std::cout << "DrawAreaBase::draw_screen_core : passed = " << passed << " wait = " << m_wait_scroll << std::endl; #endif } } // 再レイアウト & 再描画 if( relayout ){ #ifdef _DEBUG std::cout << "relayout\n"; #endif if( exec_layout() ){ redraw_view_force(); return; } } // 高速スクロール // DrawingAreaの領域が全て表示されているときは Gdk::Window::scroll() を使ってスクロール // 一部が隠れている時はバックスクリーン内でスクロール処理してバックスクリーン全体をウィンドウにコピーする // slot_visibility_notify_event()を参照せよ if( m_scroll_window ){ #ifdef _DEBUG std::cout << "rapid scroll\n"; #endif // 前回描画したオートスクロールマーカを消す if( m_ready_back_marker ){ m_ready_back_marker = false; // [gtkmm <= 2.8] Gdk::GC::set_clip_rectangle( Gdk::Rectangle& rectangle ) // Gdk::GC::set_clip_rectangle( const Gdk::Rectangle& rectangle ) Gdk::Rectangle rect_window( m_clip_marker.x, m_clip_marker.y, m_clip_marker.width, m_clip_marker.height ); m_gc->set_clip_rectangle( rect_window ); m_window->draw_drawable( m_gc, m_back_marker, 0, 0, m_clip_marker.x, m_clip_marker.y, m_clip_marker.width, m_clip_marker.height ); m_gc->set_clip_rectangle( rect_clip ); } // 前回描画したフレームを消す if( m_ready_back_frame ){ m_ready_back_frame = false; // [gtkmm <= 2.8] Gdk::GC::set_clip_rectangle( Gdk::Rectangle& rectangle ) // Gdk::GC::set_clip_rectangle( const Gdk::Rectangle& rectangle ) Gdk::Rectangle rect_frame( 0, 0, width_view, height_view ); m_gc->set_clip_rectangle( rect_frame ); m_window->draw_drawable( m_gc, m_back_frame, 0, 0, 0, 0, width_view, WIDTH_FRAME ); m_window->draw_drawable( m_gc, m_back_frame, 0, WIDTH_FRAME, 0, height_view - WIDTH_FRAME, width_view, WIDTH_FRAME ); m_gc->set_clip_rectangle( rect_clip ); } // ウィンドウをスクロール if( dy ){ m_window->scroll( 0, -dy ); m_window->get_update_area(); // スクロールすると expose イベントが生じるのでキャンセルする } // 更新した所だけバックスクリーンをウィンドウにコピー m_window->draw_drawable( m_gc, m_backscreen, 0, y_screen, 0, y_screen, width_view, height_screen ); } // バックスクリーンを全てウィンドウにコピー else{ #ifdef _DEBUG std::cout << "copy all\n"; #endif m_window->draw_drawable( m_gc, m_backscreen, 0, 0, 0, 0, width_view, height_view ); } // オートスクロールマーカと枠の描画 draw_marker(); draw_frame(); } // // ノードひとつを描画する関数 // // width_view : 描画領域の幅 // pos_y : 描画領域の開始座標 // // 戻り値 : true なら描画後に再レイアウトを実行する // bool DrawAreaBase::draw_one_node( LAYOUT* layout, const int width_view, const int pos_y, const int upper, const int lower ) { bool relayout = false; if( ! m_article ) return relayout; // ノード種類別の処理 switch( layout->type ){ // div case DBTREE::NODE_DIV: draw_div( layout, pos_y, upper, lower ); break; ////////////////////////////////////////// // リンクノード case DBTREE::NODE_LINK: // 画像リンクの場合、実際にリンクが表示される段階でノードツリーに DBIMG::Img // のポインタと色をセットする。 // // 結合度が激しく高くなるがスピードを重視 // if( layout->node && layout->node->linkinfo->image ){ DBTREE::NODE* node = layout->node; // 画像クラスのポインタ取得してノードツリーにセット if( ! node->linkinfo->img ){ node->linkinfo->img = DBIMG::get_img( layout->node->linkinfo->link ); } // 画像クラスが取得されてたら色を指定 DBIMG::Img* img = node->linkinfo->img; if( img ){ if( img->is_loading() ) node->color_text = COLOR_IMG_LOADING; else if( img->is_wait() ) node->color_text = COLOR_IMG_LOADING; else if( img->get_code() == HTTP_OK ) node->color_text = COLOR_IMG_CACHED; else if( img->get_code() == HTTP_INIT ){ if( img->get_abone() ) node->color_text = COLOR_IMG_ERR; else node->color_text = COLOR_IMG_NOCACHE; } else node->color_text = COLOR_IMG_ERR; } } ////////////////////////////////////////// // テキストノード case DBTREE::NODE_TEXT: draw_one_text_node( layout, width_view, pos_y ); break; ////////////////////////////////////////// // 発言回数ノード case DBTREE::NODE_IDNUM: if( set_num_id( layout ) ) draw_one_text_node( layout, width_view, pos_y ); break; ////////////////////////////////////////// // ヘッダ case DBTREE::NODE_HEADER: draw_div( layout, pos_y, upper, lower ); if( layout->res_number ){ const int y_org = layout->rect->y + layout->css->padding_top; int y = y_org; // ブックマークのマーク描画 if( m_article->is_bookmarked( layout->res_number ) ){ if( ! m_pixbuf_bkmk ) m_pixbuf_bkmk = ICON::get_icon( ICON::BKMARK_THREAD ); const int height_bkmk = m_pixbuf_bkmk->get_height(); y += ( m_font->height - height_bkmk ) / 2; const int s_top = MAX( 0, upper - y ); const int s_bottom = MIN( height_bkmk, lower - y ); const int height = s_bottom - s_top; if( height > 0 ) m_backscreen->draw_pixbuf( m_gc, m_pixbuf_bkmk, 0, s_top, 1, y - pos_y + s_top, m_pixbuf_bkmk->get_width(), height, Gdk::RGB_DITHER_NONE, 0, 0 ); y += height_bkmk; } if( CONFIG::get_show_post_mark() ){ // 書き込みのマーク表示 if( m_article->is_posted( layout->res_number ) ){ if( ! m_pixbuf_post ) m_pixbuf_post = ICON::get_icon( ICON::POST ); const int height_post = m_pixbuf_post->get_height(); if( y == y_org ) y += ( m_font->height - height_post ) / 2; const int s_top = MAX( 0, upper - y ); const int s_bottom = MIN( height_post, lower - y ); const int height = s_bottom - s_top; if( height > 0 ) m_backscreen->draw_pixbuf( m_gc, m_pixbuf_post, 0, s_top, 1, y - pos_y + s_top, m_pixbuf_post->get_width(), height, Gdk::RGB_DITHER_NONE, 0, 0 ); y += height_post; } // 自分の書き込みに対するレスのマーク表示 if( m_article->is_refer_posted( layout->res_number ) ){ if( ! m_pixbuf_refer_post ) m_pixbuf_refer_post = ICON::get_icon( ICON::POST_REFER ); const int height_refer_post = m_pixbuf_refer_post->get_height(); if( y == y_org ) y += ( m_font->height - height_refer_post ) / 2; const int s_top = MAX( 0, upper - y ); const int s_bottom = MIN( height_refer_post, lower - y ); const int height = s_bottom - s_top; if( height > 0 ) m_backscreen->draw_pixbuf( m_gc, m_pixbuf_refer_post, 0, s_top, 1, y - pos_y + s_top, m_pixbuf_refer_post->get_width(), height, Gdk::RGB_DITHER_NONE, 0, 0 ); y += height_refer_post; } } } break; ////////////////////////////////////////// // 画像ノード case DBTREE::NODE_IMG: case DBTREE::NODE_SSSP: if( draw_one_img_node( layout, pos_y, upper, lower ) ) relayout = true; break; ////////////////////////////////////////// // 水平線ノード case DBTREE::NODE_HR: if( layout->rect ){ const int x = layout->rect->x; const int y = layout->rect->y - pos_y; const int color_text = get_colorid_text(); m_gc->set_foreground( m_color[ color_text ] ); m_backscreen->draw_line( m_gc, x, y, x + layout->rect->width - 1, y ); } break; ////////////////////////////////////////// // ノードが増えたらここに追加していくこと default: break; } return relayout; } // // div 要素の描画 // void DrawAreaBase::draw_div( LAYOUT* layout_div, const int pos_y, const int upper, const int lower ) { if( ! lower ) return; int bg_color = layout_div->css->bg_color; int border_left_color = layout_div->css->border_left_color; int border_right_color = layout_div->css->border_right_color; int border_top_color = layout_div->css->border_top_color; int border_bottom_color = layout_div->css->border_bottom_color; if( bg_color < 0 && border_left_color < 0 && border_top_color < 0 && border_bottom_color < 0 ) return; int border_left = layout_div->css->border_left_width; int border_right = layout_div->css->border_right_width; int border_top = layout_div->css->border_top_width;; int border_bottom = layout_div->css->border_bottom_width;; int border_style = layout_div->css->border_style; int y_div = layout_div->rect->y; int height_div = layout_div->rect->height; if( y_div < upper ){ if( border_top && y_div + border_top > upper ) border_top -= ( upper - y_div ); else border_top = 0; height_div -= ( upper - y_div ); y_div = upper; } if( y_div + height_div > lower ){ if( border_bottom && y_div + height_div - border_bottom < lower ) border_bottom -= ( y_div + height_div - lower ); else border_bottom = 0; height_div = ( lower - y_div ); } // 背景 if( bg_color >= 0 ){ m_gc->set_foreground( m_color[ bg_color ] ); m_backscreen->draw_rectangle( m_gc, true, layout_div->rect->x, y_div - pos_y, layout_div->rect->width, height_div ); } // left if( border_style == CORE::BORDER_SOLID && border_left_color >= 0 && border_left ){ m_gc->set_foreground( m_color[ border_left_color ] ); m_backscreen->draw_rectangle( m_gc, true, layout_div->rect->x, y_div - pos_y, border_left, height_div ); } // right if( border_style == CORE::BORDER_SOLID && border_right_color >= 0 && border_right ){ m_gc->set_foreground( m_color[ border_right_color ] ); m_backscreen->draw_rectangle( m_gc, true, layout_div->rect->x + layout_div->rect->width - border_right, y_div - pos_y, border_right, height_div ); } // top if( border_style == CORE::BORDER_SOLID && border_top_color >= 0 && border_top ){ m_gc->set_foreground( m_color[ border_top_color ] ); m_backscreen->draw_rectangle( m_gc, true, layout_div->rect->x, y_div - pos_y, layout_div->rect->width, border_top ); } // bottom if( border_style == CORE::BORDER_SOLID && border_bottom_color >= 0 && border_bottom ){ m_gc->set_foreground( m_color[ border_bottom_color ] ); m_backscreen->draw_rectangle( m_gc, true, layout_div->rect->x, y_div + height_div - border_bottom - pos_y, layout_div->rect->width, border_bottom ); } } // // オートスクロールマーカの描画 // void DrawAreaBase::draw_marker() { if( m_scrollinfo.mode == SCROLL_NOT ) return; if( ! m_scrollinfo.show_marker ) return; const int width_view = m_view.get_width(); const int height_view = m_view.get_height(); const int x_marker = m_scrollinfo.x - AUTOSCR_CIRCLE/2; const int y_marker = m_scrollinfo.y - AUTOSCR_CIRCLE/2; m_clip_marker.x = x_marker; m_clip_marker.y = y_marker; m_clip_marker.width = AUTOSCR_CIRCLE; m_clip_marker.height = AUTOSCR_CIRCLE; if( m_clip_marker.x < 0 ){ m_clip_marker.width += m_clip_marker.x; m_clip_marker.x = 0; } if( m_clip_marker.x + m_clip_marker.width > width_view ){ m_clip_marker.width = width_view - m_clip_marker.x; } if( m_clip_marker.y < 0 ){ m_clip_marker.height += m_clip_marker.y; m_clip_marker.y = 0; } if( m_clip_marker.y + m_clip_marker.height > height_view ){ m_clip_marker.height = height_view - m_clip_marker.y; } // オートスクロールマーカを描く前に背景のバックアップを取っておきスクロールする前に描き直す // exec_draw_screen() 参照 if( m_scroll_window ){ // [gtkmm <= 2.8] Gdk::GC::set_clip_rectangle( Gdk::Rectangle& rectangle ) // Gdk::GC::set_clip_rectangle( const Gdk::Rectangle& rectangle ) Gdk::Rectangle rect_marker( 0, 0, m_clip_marker.width, m_clip_marker.height ); m_gc->set_clip_rectangle( rect_marker ); m_back_marker->draw_drawable( m_gc, m_window, m_clip_marker.x, m_clip_marker.y, 0, 0, m_clip_marker.width, m_clip_marker.height ); m_ready_back_marker = true; } // [gtkmm <= 2.8] Gdk::GC::set_clip_rectangle( Gdk::Rectangle& rectangle ) // Gdk::GC::set_clip_rectangle( const Gdk::Rectangle& rectangle ) Gdk::Rectangle rect_window( m_clip_marker.x, m_clip_marker.y, m_clip_marker.width, m_clip_marker.height ); m_gc->set_clip_rectangle( rect_window ); m_gc->set_foreground( m_color[ COLOR_MARKER ] ); m_window->draw_arc( m_gc, false, x_marker, y_marker, AUTOSCR_CIRCLE-1, AUTOSCR_CIRCLE-1, 0, 360 * 64 ); } // // 枠の描画 // void DrawAreaBase::draw_frame() { if( ! m_draw_frame ) return; const int width_win = m_view.get_width(); const int height_win = m_view.get_height(); if( m_scroll_window ){ // [gtkmm <= 2.8] Gdk::GC::set_clip_rectangle( Gdk::Rectangle& rectangle ) // Gdk::GC::set_clip_rectangle( const Gdk::Rectangle& rectangle ) Gdk::Rectangle rect_frame( 0, 0, width_win, WIDTH_FRAME * 2 ); m_gc->set_clip_rectangle( rect_frame ); m_back_frame->draw_drawable( m_gc, m_window, 0, 0, 0, 0, width_win, WIDTH_FRAME ); m_back_frame->draw_drawable( m_gc, m_window, 0, height_win - WIDTH_FRAME, 0, WIDTH_FRAME, width_win, WIDTH_FRAME ); m_ready_back_frame = true; } Gdk::Rectangle rect_clip( 0, 0, width_win, height_win ); m_gc->set_clip_rectangle( rect_clip ); m_gc->set_foreground( m_color[ COLOR_FRAME ] ); m_window->draw_rectangle( m_gc, false, WIDTH_FRAME-1, WIDTH_FRAME-1, width_win-WIDTH_FRAME, height_win-WIDTH_FRAME ); } // // 範囲選択の描画をする必要があるかどうかの判定( draw_one_text_node()で使用 ) // // 戻り値: 描画が必要かとどうか // byte_from : 描画開始位置 // byte_to : 描画終了位置 // const bool DrawAreaBase::get_selection_byte( const LAYOUT* layout, const SELECTION& selection, size_t& byte_from, size_t& byte_to ) { if( ! layout ) return false; if( ! selection.caret_from.layout ) return false; if( ! selection.caret_to.layout ) return false; const int id_header = layout->id_header; const int id = layout->id ; int id_header_from = 0; int id_from = 0; int id_header_to = 0; int id_to = 0; id_header_from = selection.caret_from.layout->id_header; id_from = selection.caret_from.layout->id; id_header_to = selection.caret_to.layout->id_header; id_to = selection.caret_to.layout->id; // 選択開始ノードの場合は selection.caret_from.byte から、それ以外は0バイト目から描画 byte_from = selection.caret_from.byte * ( id_header == id_header_from && id == id_from ); // 選択終了ノードの場合は selection.caret_to.byte から、それ以外は最後まで描画 byte_to = selection.caret_to.byte * ( id_header == id_header_to && id == id_to ); if( byte_to == 0 ) byte_to = strlen( layout->text ); if( byte_from == byte_to // このノードは範囲選択外なので範囲選択の描画をしない || ( id_header < id_header_from ) || ( id_header > id_header_to ) || ( id_header == id_header_from && id < id_from ) || ( id_header == id_header_to && id > id_to ) // キャレットが先頭にあるので範囲選択の描画をしない || ( id_header == id_header_to && id == id_to && selection.caret_to.byte == 0 ) ){ return false; } return true; } // // ノードのフォント設定 // void DrawAreaBase::set_node_font( LAYOUT* layout ) { char layout_fontid; if( ! layout->node ) return; // フォント設定 switch( layout->node->fontid ){ case FONT_AA: if( m_aafont_initialized ){ layout_fontid = layout->node->fontid; // AA用フォント情報 } else { layout_fontid = m_defaultfontid; // デフォルトフォント情報 } break; case FONT_EMPTY: // フォントID未決定 case FONT_DEFAULT: default: layout_fontid = m_defaultfontid; // デフォルトフォント情報 break; } if( m_fontid != layout_fontid ){ m_fontid = layout_fontid; // 新しいフォントIDをセット switch( m_fontid ){ case FONT_AA: m_font = &m_aafont; break; default: m_font = &m_defaultfont; break; } #if 0 // _DEBUG std::cout << "DrawAreaBase::set_node_font : fontid = " << (int)layout_fontid << " res = " << layout->header->res_number << " type = " << (int)(layout->node->type) << std::endl; #endif // layoutにフォントをセット m_pango_layout->set_font_description( m_font->pfd ); modify_font( m_font->pfd ); } } // // テキストの含まれているノードひとつを描画する関数 // // width_view : 描画領域の幅 // pos_y : 描画領域の開始座標 // void DrawAreaBase::draw_one_text_node( LAYOUT* layout, const int width_view, const int pos_y ) { // 範囲選択の描画をする必要があるかどうかの判定 // 二度書きすると重いので、ちょっと式は複雑になるけど同じ所を二度書きしないようにする size_t byte_from = 0; size_t byte_to = 0; const bool draw_selection = ( m_selection.select && get_selection_byte( layout, m_selection, byte_from, byte_to ) ); int color_text = get_colorid_text(); if( layout->color_text && *layout->color_text != COLOR_CHAR ) color_text = *layout->color_text; if( color_text == COLOR_CHAR && layout->div && layout->div->css->color >= 0 ) color_text = layout->div->css->color; int color_back = get_colorid_back(); if( layout->div && layout->div->css->bg_color >= 0 ) color_back = layout->div->css->bg_color; else if( layout->header && layout->header->css->bg_color >= 0 ) color_back = layout->header->css->bg_color; // 通常描画 if( ! draw_selection ) draw_string( layout, pos_y, width_view, color_text, color_back, 0, 0 ); else { // 範囲選択の前後描画 // 前 if( byte_from ) draw_string( layout, pos_y, width_view, color_text, color_back, 0, byte_from ); // 後 if( byte_to != strlen( layout->text ) ) draw_string( layout, pos_y, width_view, color_text, color_back, byte_to, strlen( layout->text ) ); } // 検索結果のハイライト if( m_multi_selection.size() > 0 ){ std::list< SELECTION >::const_iterator it; for( it = m_multi_selection.begin(); it != m_multi_selection.end(); ++it ){ size_t byte_from2; size_t byte_to2; if( get_selection_byte( layout, *it, byte_from2, byte_to2 )){ draw_string( layout, pos_y, width_view, COLOR_CHAR_HIGHLIGHT, COLOR_BACK_HIGHLIGHT, byte_from2, byte_to2 ); } } } // 範囲選択部分を描画 if( draw_selection && byte_from != byte_to ){ draw_string( layout, pos_y, width_view, COLOR_CHAR_SELECTION, COLOR_BACK_SELECTION, byte_from, byte_to ); } } // // 画像ノードひとつを描画する関数 // // width_view : 描画領域の幅 // pos_y : 描画領域の開始座標 // // 戻り値 : true なら描画後に再レイアウトを実行する // const bool DrawAreaBase::draw_one_img_node( LAYOUT* layout, const int pos_y, const int upper, const int lower ) { #ifdef _DEBUG std::cout << "DrawAreaBase::draw_one_img_node link = " << layout->link << std::endl; #endif bool relayout = false; if( ! layout->link ) return relayout; const RECTANGLE* rect = layout->rect; if( ! rect ) return relayout; const DBTREE::NODE* node = layout->node; if( ! node ) return relayout; DBIMG::Img* img = node->linkinfo->img; if( ! img ){ img = node->linkinfo->img = DBIMG::get_img( layout->link ); if( ! img ) return relayout; } int color = COLOR_IMG_ERR; const int code = img->get_code(); // 画像が削除された場合、埋め込み画像を削除してノードの座標を再計算 if( layout->eimg && ( img->is_loading() || code == HTTP_INIT ) ){ delete layout->eimg; m_eimgs.remove( layout->eimg ); layout->eimg = NULL; relayout = true; } if( img->is_loading() || img->is_wait() ) color = COLOR_IMG_LOADING; else if( code == HTTP_INIT ){ if( img->get_abone() ) color = COLOR_IMG_ERR; else color = COLOR_IMG_NOCACHE; } // 画像描画 else if( code == HTTP_OK ){ color = COLOR_IMG_CACHED; // 埋め込み画像を作成 if( ! layout->eimg ){ layout->eimg = new EmbeddedImage( layout->link ); // EmbeddedImageのアドレスを記憶しておいてDrawAreaBase::clear()でdeleteする m_eimgs.push_back( layout->eimg ); layout->eimg->show(); // 後のノードの座標を再計算 relayout = true; } // 描画 else{ Glib::RefPtr< Gdk::Pixbuf > pixbuf = layout->eimg->get_pixbuf(); if( pixbuf ){ const int s_top = MAX( 0, upper - ( rect->y + 1 ) ); const int s_bottom = MIN( pixbuf->get_height(), lower - ( rect->y + 1 ) ); const int height = s_bottom - s_top; // モザイク if( img->get_mosaic() ){ const int moswidth = img->get_width_mosaic(); const int mosheight = img->get_height_mosaic(); if( moswidth && mosheight ){ Glib::RefPtr< Gdk::Pixbuf > pixbuf2; pixbuf2 = pixbuf->scale_simple( moswidth, mosheight, Gdk::INTERP_NEAREST ); m_backscreen->draw_pixbuf( m_gc, pixbuf2->scale_simple( pixbuf->get_width(), pixbuf->get_height(), Gdk::INTERP_NEAREST ), 0, s_top, rect->x + 1, ( rect->y + 1 ) - pos_y + s_top, pixbuf->get_width(), height, Gdk::RGB_DITHER_NONE, 0, 0 ); } } // 通常 else{ m_backscreen->draw_pixbuf( m_gc, pixbuf, 0, s_top, rect->x + 1, ( rect->y + 1 ) - pos_y + s_top, pixbuf->get_width(), height, Gdk::RGB_DITHER_NONE, 0, 0 ); } } else color = COLOR_IMG_ERR; } } // 枠の描画 // !! draw_rectangle()の filled を false にすると、1 pixel 幅と高さが大きくなるのに注意 !! m_gc->set_foreground( m_color[ color ] ); m_backscreen->draw_rectangle( m_gc, false, rect->x , rect->y - pos_y, rect->width -1, rect->height -1 ); // 右上のアイコン if( code != HTTP_OK || img->is_loading() ){ const int x_tmp = rect->x + rect->width / 10 + 1; const int y_tmp = rect->y + rect->height / 10 + 1; const int width_tmp = rect->width / 4; const int height_tmp = rect->width / 4; m_backscreen->draw_rectangle( m_gc, true, x_tmp, y_tmp - pos_y, width_tmp, height_tmp ); } #ifdef _DEBUG std::cout << "code = " << code << " relayout = " << relayout << std::endl; #endif return relayout; } // // 文字を描画する関数 // // ノードの byte_from バイト目の文字から byte_to バイト目の「ひとつ前」の文字まで描画 // byte_to が 0 なら最後まで描画 // // たとえば node->text = "abcdefg" で byte_from = 1, byte_to = 3 なら "bc" を描画 // void DrawAreaBase::draw_string( LAYOUT* node, const int pos_y, const int width_view, const int color, const int color_back, const int byte_from, const int byte_to ) { assert( node->text != NULL ); assert( m_layout_tree ); if( ! node->lng_text ) return; if( byte_from >= node->lng_text ) return; RECTANGLE* rect = node->rect; while( rect ){ int x = rect->x; const int y = rect->y - pos_y; int width_line = rect->width; int pos_start = rect->pos_start; int n_byte = rect->n_byte; int n_ustr = rect->n_ustr; // 描画する位置が指定されている場合 if( byte_to && ! ( byte_from <= pos_start && pos_start + n_byte <= byte_to ) ){ if( pos_start > byte_to || pos_start + n_byte < byte_from ) width_line = 0; // 指定範囲外は描画しない else{ // この文字列の全角/半角モードの初期値を決定 bool wide_mode = set_init_wide_mode( node->text, pos_start, pos_start + n_byte ); // 左座標計算 char pre_char = 0; int byte_char; while( pos_start < byte_from ){ x += PANGO_PIXELS( get_width_of_one_char( node->text + pos_start, byte_char, pre_char, wide_mode, get_fontid() ) ); pos_start += byte_char; } // 幅とバイト数計算 int pos_to = pos_start; int byte_to_tmp = byte_to; if( rect->pos_start + n_byte < byte_to_tmp ) byte_to_tmp = rect->pos_start + n_byte; width_line = 0; n_byte = 0; n_ustr = 0; while( pos_to < byte_to_tmp ){ width_line += get_width_of_one_char( node->text + pos_to, byte_char, pre_char, wide_mode, get_fontid() ); pos_to += byte_char; n_byte += byte_char; ++n_ustr; } width_line = PANGO_PIXELS( width_line ); } } if( width_line ){ const int xx = x; #ifdef USE_PANGOLAYOUT // Pango::Layout を使って文字を描画 m_pango_layout->set_text( Glib::ustring( node->text + pos_start, n_ustr ) ); m_backscreen->draw_layout( m_gc,x, y, m_pango_layout, m_color[ color ], m_color[ color_back ] ); if( node->bold ){ m_gc->set_foreground( m_color[ color ] ); m_backscreen->draw_layout( m_gc, x+1, y, m_pango_layout ); } #else // Pango::GlyphString を使って文字を描画 assert( m_context ); m_gc->set_foreground( m_color[ color_back ] ); m_backscreen->draw_rectangle( m_gc, true, x, y, width_line, m_font->height ); m_gc->set_foreground( m_color[ color ] ); Pango::AttrList attr; std::string text = std::string( node->text + pos_start, n_byte ); std::list< Pango::Item > list_item = m_context->itemize( text, attr ); std::list< Pango::Item >::iterator it = list_item.begin(); for( ; it != list_item.end(); ++it ){ Pango::Item &item = *it; Pango::GlyphString grl = item.shape( text.substr( item.get_offset(), item.get_length() ) ) ; Pango::Rectangle pango_rect = grl.get_logical_extents( item.get_analysis().get_font() ); int width = PANGO_PIXELS( pango_rect.get_width() ); m_backscreen->draw_glyphs( m_gc, item.get_analysis().get_font(), x, y + m_font->ascent, grl ); if( node->bold ) m_backscreen->draw_glyphs( m_gc, item.get_analysis().get_font(), x +1, y + m_font->ascent, grl ); x += width; } // 実際のラインの長さ(x - rect->x)とlayout_one_text_node()で計算した // 近似値(rect->width)を一致させる ( 応急処置 ) if( ! byte_to && abs( ( x - rect->x ) - rect->width ) > 2 ) rect->width = x - rect->x; #endif // リンクの時は下線を引く if( node->link && CONFIG::get_draw_underline() ){ m_gc->set_foreground( m_color[ color ] ); m_backscreen->draw_line( m_gc, xx, y + m_font->underline_pos, xx + width_line, y + m_font->underline_pos ); } } if( rect->end ) break; rect = rect->next_rect; } } // 整数 -> 文字変換してノードに発言数をセット // 最大4桁を想定 int DrawAreaBase::set_num_id( LAYOUT* layout ) { int pos = 0; int num_id = layout->header->node->headinfo->num_id_name; if( num_id >= 2 ){ layout->node->text[ pos++] = ' '; layout->node->text[ pos++] = '('; int div_tmp = 1; if( num_id / 1000 ) div_tmp = 1000; else if( num_id / 100 ) div_tmp = 100; else if( num_id / 10 ) div_tmp = 10; while( div_tmp ){ int tmp_val = num_id / div_tmp; num_id -= tmp_val * div_tmp; div_tmp /= 10; layout->node->text[ pos++] = '0' + tmp_val; } layout->node->text[ pos++] = ')'; layout->node->text[ pos ] = '\0'; layout->lng_text = pos; } return pos; } // // スクロール方向指定 // // 実際にスクロールして描画を実行するのは exec_scroll() // const bool DrawAreaBase::set_scroll( const int control ) { // スクロール系の操作でないときは関数を抜ける switch( control ){ case CONTROL::DownFast: case CONTROL::DownMid: case CONTROL::Down: case CONTROL::NextRes: case CONTROL::UpFast: case CONTROL::UpMid: case CONTROL::Up: case CONTROL::PrevRes: case CONTROL::Home: case CONTROL::End: case CONTROL::GotoNew: case CONTROL::Back: break; default: return false; } if( !m_vscrbar ){ m_scrollinfo.reset(); return true; } double dy = 0; const int y = get_vscr_val(); const bool enable_down = ( y < get_vscr_maxval() ); const bool enable_up = ( y > 0 ); if( m_scrollinfo.mode == SCROLL_NOT ){ switch( control ){ // 下 case CONTROL::DownFast: if( enable_down ) dy = SCROLLSPEED_FAST; break; case CONTROL::DownMid: if( enable_down ) dy = SCROLLSPEED_MID; break; case CONTROL::Down: if( enable_down ) dy = SCROLLSPEED_SLOW; break; case CONTROL::NextRes: if( enable_down ) goto_next_res(); break; // 上 case CONTROL::UpFast: if( enable_up ) dy = - SCROLLSPEED_FAST; break; case CONTROL::UpMid: if( enable_up )dy = - SCROLLSPEED_MID; break; case CONTROL::Up: if( enable_up )dy = - SCROLLSPEED_SLOW; break; case CONTROL::PrevRes: if( enable_up ) goto_pre_res(); break; // Home, End, New case CONTROL::Home: if( enable_up ) goto_top(); break; case CONTROL::End: if( enable_down ) goto_bottom(); break; case CONTROL::GotoNew: goto_new(); break; // ジャンプ元に戻る case CONTROL::Back: goto_back(); break; } if( dy ){ m_scrollinfo.reset(); m_scrollinfo.dy = ( int ) dy; // キーを押しっぱなしにしてる場合スクロールロックする if( m_key_locked ) m_scrollinfo.mode = SCROLL_LOCKED; // レスポンスを上げるため押した直後はすぐ描画 else{ m_scrollinfo.mode = SCROLL_NORMAL; exec_scroll(); } } } return true; } // // マウスホイールの処理 // void DrawAreaBase::wheelscroll( GdkEventScroll* event ) { const int speed = CONFIG::get_scroll_size(); const int time_cancel = 15; // msec if( !m_vscrbar ) return; // あまり速く動かしたならキャンセル const int time_tmp = event->time - m_wheel_scroll_time; if( ( ! m_wheel_scroll_time || time_tmp >= time_cancel ) && event->type == GDK_SCROLL ){ m_wheel_scroll_time = event->time; if( m_vscrbar && ( m_scrollinfo.mode == SCROLL_NOT || m_scrollinfo.mode == SCROLL_NORMAL ) ){ Gtk::Adjustment* adjust = m_vscrbar->get_adjustment(); const int current_y = ( int ) adjust->get_value(); if( event->direction == GDK_SCROLL_UP && current_y == 0 ) return; if( event->direction == GDK_SCROLL_DOWN && current_y == adjust->get_upper() - adjust->get_page_size() ) return; m_scrollinfo.reset(); m_scrollinfo.mode = SCROLL_NORMAL; // ホイールのスクロールの場合は必ずスクロール処理を実施する m_wait_scroll = 0; if( event->direction == GDK_SCROLL_UP ) m_scrollinfo.dy = -( int ) adjust->get_step_increment() * speed; else if( event->direction == GDK_SCROLL_DOWN ) m_scrollinfo.dy = ( int ) adjust->get_step_increment() * speed; exec_scroll(); // スクロール終了直後にポインタがリンクの上にある時はマウスをある程度動かすまでモーションイベントをキャンセルする // slot_motion_notify_event() を参照 if( m_layout_current && m_layout_current->link ){ m_scrollinfo.counter_nomotion = COUNTER_NOMOTION; m_scrollinfo.x = m_x_pointer; m_scrollinfo.y = m_y_pointer; } } } } // // スクロールやジャンプを実行して再描画 // // clock_in()からクロック入力される度にスクロールする // void DrawAreaBase::exec_scroll() { if( ! m_layout_tree ) return; if( ! m_vscrbar ) return; if( m_scrollinfo.mode == SCROLL_NOT && ! m_scrollinfo.live ) return; // 描画で処理落ちしている時はスクロール処理をキャンセルする if( m_wait_scroll ){ struct timeval tv; struct timezone tz; if( ! gettimeofday( &tv, &tz ) ){ const time_t current = tv.tv_sec * 1000000 + tv.tv_usec; const time_t before = m_scroll_time.tv_sec * 1000000 + m_scroll_time.tv_usec; if( current < before ) m_wait_scroll = 0; else{ const time_t passed = current - before; m_scroll_time = tv; m_wait_scroll = MAX( 0, m_wait_scroll - passed ); if( m_wait_scroll ){ #ifdef _DEBUG std::cout << "cancel scroll passed = " << passed << " wait = " << m_wait_scroll << std::endl; #endif return; } } } else m_wait_scroll = 0; } #ifdef _DEBUG std::cout << "exec scroll\n"; #endif bool redraw_all = false; CARET_POSITION caret_pos; bool selection = false; // 移動後のスクロール位置を計算 int y = 0; Gtk::Adjustment* adjust = m_vscrbar->get_adjustment(); const int current_y = ( int ) adjust->get_value(); switch( m_scrollinfo.mode ){ case SCROLL_TO_NUM: // 指定したレス番号にジャンプ { #ifdef _DEBUG std::cout << "DrawAreaBase::exec_scroll : goto " << m_scrollinfo.res << std::endl; #endif const LAYOUT* layout = m_layout_tree->get_header_of_res_const( m_scrollinfo.res ); if( layout ) y = layout->rect->y; m_scrollinfo.reset(); } break; // 先頭に移動 case SCROLL_TO_TOP: y = 0; m_scrollinfo.reset(); redraw_all = true; break; // 最後に移動 case SCROLL_TO_BOTTOM: y = (int) adjust->get_upper(); m_scrollinfo.reset(); redraw_all = true; break; // y 座標に移動 case SCROLL_TO_Y: y = m_scrollinfo.y; m_scrollinfo.reset(); #ifdef _DEBUG std::cout << "DrawAreaBase::exec_scroll : y = " << y << std::endl; #endif break; case SCROLL_NORMAL: // 1 回だけスクロール y = current_y + m_scrollinfo.dy; m_scrollinfo.reset(); break; case SCROLL_LOCKED: // ロックが外れるまでスクロールを続ける y = current_y + m_scrollinfo.dy; break; case SCROLL_AUTO: // オートスクロールモード { // 現在のポインタの位置取得 int x_point, y_point; m_view.get_pointer( x_point, y_point ); double dy = m_scrollinfo.y - y_point; if( dy >= 0 && ! m_scrollinfo.enable_up ) dy = 0; else if( dy < 0 && ! m_scrollinfo.enable_down ) dy = 0; else{ // この辺の式は経験的に決定 if( -AUTOSCR_CIRCLE/4 <= dy && dy <= AUTOSCR_CIRCLE/4 ) dy = 0; else dy = ( dy / fabs( dy ) ) * MIN( ( exp( ( fabs( dy ) - AUTOSCR_CIRCLE/4 ) /50 ) -1 ) * 5, adjust->get_page_size() * 3 ); if( m_drugging ) dy *= 4; // 範囲選択中ならスピード上げる } y = current_y -( int ) dy; // 範囲選択中ならキャレット移動して選択範囲更新 if( m_drugging ){ int y_tmp = MIN( MAX( 0, y_point ), m_view.get_height() ); set_caret( caret_pos, x_point , y + y_tmp ); selection = true; // スクロールさせてから対応する範囲を描画 } } break; default: // 実況モード if( m_scrollinfo.live ){ // 通常スクロール if( m_scrollinfo.live_speed < CONFIG::get_live_threshold() ){ const int mode = CONFIG::get_live_mode(); if( mode == LIVE_SCRMODE_VARIABLE ) y = ( int ) ( current_y + m_scrollinfo.live_speed ); else if( mode == LIVE_SCRMODE_STEADY ) y = ( int ) ( current_y + CONFIG::get_live_speed() ); } // 行単位スクロール else{ const int step_move = 4; const int step_stop = 10; const double step = ( m_scrollinfo.live_speed * ( step_move + step_stop ) ) / step_move; ++m_scrollinfo.live_counter; // スクロール中 if( m_scrollinfo.live_counter <= step_move ){ y = ( int ) ( current_y + step ); } // 停止中 else{ if( m_scrollinfo.live_counter == step_move + step_stop ) m_scrollinfo.live_counter = 0; return; } } } break; } const int y_new = (int)MAX( 0, MIN( adjust->get_upper() - adjust->get_page_size() , y ) ); if( current_y != y_new ){ m_cancel_change_adjust = true; adjust->set_value( y_new ); m_cancel_change_adjust = false; // キーを押しっぱなしの時に一番上か下に着いたらスクロール停止して全画面再描画 if( m_scrollinfo.mode == SCROLL_LOCKED && ( y_new <= 0 || y_new >= adjust->get_upper() - adjust->get_page_size() ) ){ m_scrollinfo.reset(); redraw_all = true; } } // 選択範囲のセット RECTANGLE rect_selection; if( selection ){ if( ! set_selection( caret_pos, &rect_selection ) ) selection = false; } // 描画 const int height_redraw = ( redraw_all ? m_view.get_height() : 0 ); if( draw_screen( 0, height_redraw ) ){ // 選択範囲描画 if( selection // 既に描画済みならキャンセル && ! ( m_rect_backscreen.y <= rect_selection.y && m_rect_backscreen.y + m_rect_backscreen.height >= rect_selection.y + rect_selection.height ) ){ // 描画済みの範囲を除く if( m_rect_backscreen.y <= rect_selection.y && m_rect_backscreen.y + m_rect_backscreen.height >= rect_selection.y ){ const int dh = ( m_rect_backscreen.y + m_rect_backscreen.height ) - rect_selection.y; rect_selection.y += dh; rect_selection.height -= dh; } else if( m_rect_backscreen.y <= rect_selection.y + rect_selection.height && m_rect_backscreen.y + m_rect_backscreen.height >= rect_selection.y + rect_selection.height ){ const int dh = ( rect_selection.y + rect_selection.height ) - m_rect_backscreen.y; rect_selection.height -= dh; } draw_screen( rect_selection.y, rect_selection.height ); } // カーソル形状の更新 CARET_POSITION caret_pos; m_layout_current = set_caret( caret_pos, m_x_pointer , m_y_pointer + get_vscr_val() ); change_cursor( get_cursor_type() ); } } // // スクロールバーの現在値 // int DrawAreaBase::get_vscr_val() { if( m_vscrbar ) return ( int ) m_vscrbar->get_adjustment()->get_value(); return 0; } // // スクロールバーの最大値値 // int DrawAreaBase::get_vscr_maxval() { if( m_vscrbar ) return ( int ) ( m_vscrbar->get_adjustment()->get_upper() - m_vscrbar->get_adjustment()->get_page_size() ); return 0; } // // num 番にジャンプ // void DrawAreaBase::goto_num( int num ) { #ifdef _DEBUG std::cout << "DrawAreaBase::goto_num num = " << num << std::endl; #endif if( num <= 0 ) return; if( ! m_vscrbar ) return; // ジャンプ予約 // まだ初期化中の場合はジャンプの予約をしておいて、初期化が終わったら時点でもう一回呼び出し if( ! m_backscreen ){ m_goto_num_reserve = num; #ifdef _DEBUG std::cout << "reserve goto_num(1) num = " << m_goto_num_reserve << std::endl; #endif return; } // 表示範囲を越えていたら再レイアウトしたときにもう一度呼び出し else if( num > max_number() ){ m_goto_num_reserve = num; #ifdef _DEBUG std::cout << "reserve goto_num(2) num = " << m_goto_num_reserve << std::endl;; #endif return; } else m_goto_num_reserve = 0; // ロード数を越えている場合 int number_load = DBTREE::article_number_load( m_url ); if( number_load < num ) num = number_load; // num番が表示されていないときは近くの番号をセット while( ! m_layout_tree->get_header_of_res_const( num ) && num++ < number_load ); while( ! m_layout_tree->get_header_of_res_const( num ) && num-- > 1 ); #ifdef _DEBUG std::cout << "exec goto_num num = " << num << std::endl; #endif // スクロール実行 m_scrollinfo.reset(); m_scrollinfo.mode = SCROLL_TO_NUM; m_scrollinfo.res = num; exec_scroll(); } // // ジャンプ履歴にスレ番号を登録 // void DrawAreaBase::set_jump_history( const int num ) { m_jump_history.push_back( num ); } // // 次のレスに移動 // void DrawAreaBase::goto_next_res() { if( m_seen_current == max_number() ) goto_bottom(); else goto_num( m_seen_current + 1 ); } // // 前のレスに移動 // void DrawAreaBase::goto_pre_res() { // 表示するレスを検索 const LAYOUT* header; int num = m_seen_current; int pos_y = get_vscr_val(); do{ header = m_layout_tree->get_header_of_res_const( --num ); } while( num && ( ! header || header->rect->y >= pos_y ) ); goto_num( num ); } // // 先頭、新着、最後に移動 // void DrawAreaBase::goto_top() { if( m_vscrbar ){ m_jump_history.push_back( get_seen_current() ); m_scrollinfo.reset(); m_scrollinfo.mode = SCROLL_TO_TOP; exec_scroll(); } } void DrawAreaBase::goto_new() { if( ! m_layout_tree ) return; const int separator_new = m_layout_tree->get_separator_new(); if( separator_new ){ m_jump_history.push_back( get_seen_current() ); const int num = separator_new > 1 ? separator_new -1 : 1; #ifdef _DEBUG std::cout << "DrawAreaBase::goto_new num = " << num << std::endl; #endif goto_num( num ); } } void DrawAreaBase::goto_bottom() { #ifdef _DEBUG std::cout << "DrawAreaBase::goto_bottom\n"; #endif if( m_vscrbar ){ // まだ初期化中の場合はジャンプの予約をしておいて、初期化が終わったら時点でもう一回呼び出し if( ! m_backscreen ){ m_goto_bottom_reserve = true; #ifdef _DEBUG std::cout << "goto_bottom : reserve\n"; #endif return; } m_goto_bottom_reserve = false; m_jump_history.push_back( get_seen_current() ); m_scrollinfo.reset(); m_scrollinfo.mode = SCROLL_TO_BOTTOM; exec_scroll(); } } // // ジャンプした場所に戻る // void DrawAreaBase::goto_back() { if( ! m_jump_history.size() ) return; int num = *m_jump_history.rbegin(); m_jump_history.pop_back(); #ifdef _DEBUG std::cout << "DrawAreaBase::goto_back history = " << m_jump_history.size() << " num = " << num << std::endl; #endif goto_num( num ); } // // 検索実行 // // 戻り値: ヒット数 // const int DrawAreaBase::search( const std::list< std::string >& list_query, const bool reverse ) { assert( m_layout_tree ); if( list_query.size() == 0 ) return 0; std::list< JDLIB::Regex > list_regex; const bool icase = true; // 大文字小文字区別しない const bool newline = true; // . に改行をマッチさせない const bool usemigemo = true; // migemo使用 const bool wchar = true; // 全角半角の区別をしない #ifdef _DEBUG std::cout << "ArticleViewBase::search size = " << list_query.size() << std::endl; #endif std::list< std::string >::const_iterator it_query; for( it_query = list_query.begin(); it_query != list_query.end() ; ++it_query ){ const std::string &query = ( *it_query ); list_regex.push_back( JDLIB::Regex() ); list_regex.back().compile( query, icase, newline, usemigemo, wchar ); } m_multi_selection.clear(); std::vector< LAYOUT_TABLE > layout_table; const char *target; char *buffer = NULL; size_t buffer_lng = 0; // 先頭ノードから順にサーチして m_multi_selection に選択箇所をセットしていく LAYOUT* tmpheader = m_layout_tree->top_header(); while( tmpheader ){ LAYOUT* tmplayout = tmpheader->next_layout; while( tmplayout ){ if( HAS_TEXT( tmplayout ) ){ layout_table.clear(); buffer_lng = 0; target = tmplayout->text; // 次のノードもテキストを含んでいたら変換テーブルを作成しながらバッファに連結コピー if( tmplayout->next_layout && HAS_TEXT( tmplayout->next_layout ) ){ if( ! buffer ) buffer = ( char* )malloc( SEARCH_BUFFER_SIZE ); target = buffer; do{ LAYOUT_TABLE tbl; tbl.layout = tmplayout; tbl.offset = buffer_lng;; layout_table.push_back( tbl ); const size_t lng = strlen( tmplayout->text ); if( buffer_lng + lng > SEARCH_BUFFER_SIZE ){ MISC::ERRMSG( "DrawAreaBase::search : buffer overflow." ); break; } memcpy( buffer + buffer_lng, tmplayout->text, lng ); buffer_lng += lng; buffer[ buffer_lng ] = '\0'; tmplayout = tmplayout->next_layout; } while( tmplayout && HAS_TEXT( tmplayout ) ); #ifdef _DEBUG std::cout << "use buffer lng = " << buffer_lng << std::endl << buffer << std::endl; #endif } ///////////////////////////////// size_t offset = 0; for(;;){ int min_offset = -1; int lng = 0; std::list< JDLIB::Regex >::iterator it_regex; for( it_regex = list_regex.begin(); it_regex != list_regex.end() ; ++it_regex ){ JDLIB::Regex ®ex = ( *it_regex ); if( regex.exec( target, offset ) ){ if( min_offset == -1 || regex.pos( 0 ) <= min_offset ){ min_offset = regex.pos( 0 ); lng = regex.str( 0 ).length(); } } } if( lng == 0 ) break; offset = min_offset; LAYOUT* layout_from = tmplayout; LAYOUT* layout_to = tmplayout; size_t offset_from = min_offset; size_t offset_to = min_offset + lng; // 変換テーブルを参照して開始位置と終了位置を求める if( layout_table.size() ){ std::vector< LAYOUT_TABLE >::reverse_iterator it = layout_table.rbegin(); for( ; it != layout_table.rend(); ++it ){ if( ( *it ).offset < offset_to ){ layout_to = ( *it ).layout; offset_to -= ( *it ).offset; break; } } for( ; it != layout_table.rend(); ++it ){ if( ( *it ).offset <= offset_from ){ layout_from = ( *it ).layout; offset_from -= ( *it ).offset; break; } } } #ifdef _DEBUG std::cout << "id_from = " << layout_from->id << " offset_from = " << offset_from << " -> id_to = " << layout_to->id << " offset_to = " << offset_to << std::endl; const std::string text_from = std::string( layout_from->text ).substr( offset_from ); const std::string text_to = std::string( layout_to->text ).substr( 0, offset_to ); std::cout << text_from << std::endl << text_to << std::endl; #endif // 選択設定 SELECTION selection; selection.select = false; selection.caret_from.set( layout_from, offset_from ); selection.caret_to.set( layout_to, offset_to ); m_multi_selection.push_back( selection ); offset += lng; } } if( tmplayout ) tmplayout = tmplayout->next_layout; } tmpheader = tmpheader->next_header; } if( buffer ) free( buffer ); #ifdef _DEBUG std::cout << "m_multi_selection.size = " << m_multi_selection.size() << std::endl; #endif if( m_multi_selection.size() == 0 ) return 0; // 初期位置をセット // selection.select = true のアイテムが現在選択中 std::list< SELECTION >::iterator it; for( it = m_multi_selection.begin(); it != m_multi_selection.end(); ++it ){ if( ( *it ).caret_from < m_caret_pos ) continue; ( *it ).select = true; break; } if( it == m_multi_selection.end() ) m_multi_selection.back().select = true; // search_move でひとつ進めるのでひとつ前に戻しておく if( ! reverse ){ if( it != m_multi_selection.end() ) ( *it ).select = false; if( it == m_multi_selection.begin() ) m_multi_selection.back().select = true; else ( *( --it ) ).select = true; } redraw_view_force(); return m_multi_selection.size(); } // // 次の検索結果に移動 // // 戻り値: ヒット数 // const int DrawAreaBase::search_move( const bool reverse ) { #ifdef _DEBUG std::cout << "ArticleViewBase::search_move " << m_multi_selection.size() << std::endl; #endif if( m_multi_selection.size() == 0 ) return 0; if( ! m_vscrbar ) return m_multi_selection.size(); std::list< SELECTION >::iterator it; for( it = m_multi_selection.begin(); it != m_multi_selection.end(); ++it ){ if( ( *it ).select ){ ( *it ).select = false; // 前に移動 if( reverse ){ if( it == m_multi_selection.begin() ) it = m_multi_selection.end(); --it; } // 次に移動 else{ if( ( ++it ) == m_multi_selection.end() ) it = m_multi_selection.begin(); } ( *it ).select = true; // 移動先を範囲選択状態にする m_caret_pos_dragstart = ( *it ).caret_from; set_selection( ( *it ).caret_to ); int y = MAX( 0, ( *it ).caret_from.layout->rect->y - 10 ); #ifdef _DEBUG std::cout << "move to y = " << y << std::endl; #endif Gtk::Adjustment* adjust = m_vscrbar->get_adjustment(); if( ( int ) adjust->get_value() > y || ( int ) adjust->get_value() + ( int ) adjust->get_page_size() - m_font->br_size < y ){ m_cancel_change_adjust = true; adjust->set_value( y ); m_cancel_change_adjust = false; } redraw_view_force(); return m_multi_selection.size(); } } return m_multi_selection.size(); } // // ハイライト解除 // void DrawAreaBase::clear_highlight() { m_multi_selection.clear(); redraw_view_force(); } // // 実況開始 // void DrawAreaBase::live_start() { m_scrollinfo.live = true; } // // 実況停止 // void DrawAreaBase::live_stop() { m_scrollinfo.reset(); m_scrollinfo.live = false; } // // 実況時のスクロール速度更新 // // sec : 更新間隔(秒) // void DrawAreaBase::update_live_speed( const int sec ) { if( ! m_scrollinfo.live ) return; if( sec <= 0 ) return; const int min_live_speed = CONFIG::get_live_speed(); if( ! min_live_speed ) m_scrollinfo.live_speed = 0; else{ double speed = ( get_vscr_maxval() - get_vscr_val() ) / ( sec * 1000/TIMER_TIMEOUT_SMOOTH_SCROLL ); m_scrollinfo.live_speed = MAX( min_live_speed, speed ); } m_scrollinfo.live_counter = 0; #ifdef _DEBUG std::cout << "DrawAreaBase::update_live_speed sec = " << sec << " speed = " << m_scrollinfo.live_speed << std::endl; #endif } // // ポインタがRECTANGLEの上にあるか判定 // // int& pos, int& width_line, int& char_width, int& byte_char // はそれぞれポインタの下の文字の位置(バイト)とその文字までの長さ(ピクセル)、文字の幅(ピクセル)、バイト // bool DrawAreaBase::is_pointer_on_rect( const RECTANGLE* rect, const char* text, const int pos_start, const int pos_to, const int x, const int y, int& pos, int& width_line, int& char_width, int& byte_char ) { pos = pos_start; width_line = 0; char_width = 0; byte_char = 0; if( ! ( rect->y <= y && y <= rect->y + rect->height ) ) return false; // この文字列の全角/半角モードの初期値を決定 bool wide_mode = set_init_wide_mode( text, pos_start, pos_to ); char pre_char = 0; while( pos < pos_to ){ char_width = get_width_of_one_char( text + pos, byte_char, pre_char, wide_mode, get_fontid() ); // マウスポインタの下にノードがある場合 if( rect->x + PANGO_PIXELS( width_line ) <= x && x <= rect->x + PANGO_PIXELS( width_line + char_width ) ){ width_line = PANGO_PIXELS( width_line ); char_width = PANGO_PIXELS( char_width ); return true; } // 次の文字へ pos += byte_char; width_line += char_width; } return false; } // // 座標(x,y)を与えてキャレットの位置を計算してCARET_POSITIONに値をセット //、ついでに(x,y)の下にあるレイアウトノードも調べる // // CARET_POSITION& caret_pos : キャレットの位置が計算されて入る // // 戻り値: 座標(x,y)の下のレイアウトノード。ノード外にある場合はNULL // LAYOUT* DrawAreaBase::set_caret( CARET_POSITION& caret_pos, int x, int y ) { if( ! m_layout_tree ) return NULL; #ifdef _DEBUG_CARETMOVE std::cout << "DrawAreaBase::set_caret x = " << x << " y = " << y << std::endl; #endif // 先頭のレイアウトブロックから順に調べる LAYOUT* header = m_layout_tree->top_header(); if( ! header ) return NULL; // まだレイアウト計算していない if( ! header->rect ) return NULL; if( header->next_header && ! header->next_header->rect ) return NULL; while( header ){ // y が含まれているヘッダブロックだけチェックする int height_block = header->next_header ? ( header->next_header->rect->y - header->rect->y ) : BIG_HEIGHT; if( ! ( header->rect->y <= y && header->rect->y + height_block >= y ) ){ header = header->next_header; continue; } // ヘッダブロック内のノードを順に調べていく LAYOUT* layout = header->next_layout; while( layout ){ const RECTANGLE* rect = layout->rect; if( ! rect ){ layout = layout->next_layout; continue; } int tmp_x = rect->x; int tmp_y = rect->y; int width = rect->width; int height = rect->height; int pos_start = rect->pos_start; int n_byte = rect->n_byte; // テキストノードでは無い if( ! layout->text ){ layout = layout->next_layout; continue; } // フォント設定 set_node_font( layout ); ////////////////////////////////////////////// // // 現在のノードの中、又は左か右にあるか調べる // for(;;){ int pos; int width_line; int char_width; int byte_char; // ノードの中にある場合 if( is_pointer_on_rect( rect, layout->text, pos_start, pos_start + n_byte, x, y, pos, width_line, char_width, byte_char ) ){ #ifdef _DEBUG_CARETMOVE std::cout << "found: on node\n"; std::cout << "header id = " << header->id_header << std::endl; std::cout << "node id = " << layout->id << std::endl; std::cout << "pos = " << pos << std::endl; std::cout << "tmp_x = " << tmp_x << std::endl; std::cout << "tmp_y = " << tmp_y << std::endl; std::cout << layout->text << std::endl; #endif // キャレットをセットして終了 caret_pos.set( layout, pos, x, tmp_x + width_line, tmp_y, char_width, byte_char ); return layout; } else if( tmp_y <= y && y <= tmp_y + height ){ // 左のマージンの上にポインタがある場合 if( x < tmp_x ){ #ifdef _DEBUG_CARETMOVE std::cout << "found: left\n"; std::cout << "header id = " << header->id_header << std::endl; std::cout << "node id = " << layout->id << std::endl; std::cout << "pos = " << pos_start << std::endl; #endif // 左端にキャレットをセットして終了 caret_pos.set( layout, pos_start, x, tmp_x, tmp_y ); return NULL; } // 右のマージンの上にポインタがある場合 else if( layout->next_layout == NULL || layout->next_layout->type == DBTREE::NODE_BR ){ #ifdef _DEBUG_CARETMOVE std::cout << "found: right\n"; std::cout << "header id = " << header->id_header << std::endl; std::cout << "node id = " << layout->id << std::endl; std::cout << "pos = " << pos_start + n_byte << std::endl; #endif // 右端にキャレットをセットして終わり caret_pos.set( layout, pos_start + n_byte, x, tmp_x + width, tmp_y ); return NULL; } } // 折り返し無し if( rect->end ) break; rect = rect->next_rect; if( ! rect ) break; tmp_x = rect->x; tmp_y = rect->y; width = rect->width; height = rect->height; pos_start = rect->pos_start; n_byte = rect->n_byte; } ////////////////////////////////////////////// // // 現在のノードと次のノード、又はヘッダブロックの間にポインタがあるか調べる // int next_y = -1; // 次のノード or ブロックのy座標 // 次のノードを取得する LAYOUT* layout_next = layout->next_layout; while( layout_next && ! ( layout_next->rect && layout_next->text ) ){ layout_next = layout_next->next_layout; // 次のノードが画像ノード場合 // 現在のノードの右端にキャレットをセットして画像ノードを返す if( layout_next && ( layout_next->type == DBTREE::NODE_IMG || layout_next->type == DBTREE::NODE_SSSP ) && ( layout_next->rect->x <= x && x <= layout_next->rect->x + layout_next->rect->width ) && ( layout_next->rect->y <= y && y <= layout_next->rect->y + layout_next->rect->height ) ){ caret_pos.set( layout, pos_start + n_byte, x, tmp_x + width, tmp_y ); return layout_next; } } // 次のノードのy座標を取得 if( layout_next ) next_y = layout_next->rect->y; else next_y = y + BIG_HEIGHT; if( next_y > y ){ #ifdef _DEBUG_CARETMOVE std::cout << "found: between\n"; std::cout << "header id = " << header->id_header << std::endl; std::cout << "node id = " << layout->id << std::endl; #endif // 現在のノードの右端にキャレットをセット caret_pos.set( layout, pos_start + n_byte, x, tmp_x + width, tmp_y ); return NULL; } // 次のノードへ layout = layout->next_layout; } // 次のブロックへ header = header->next_header; } return NULL; } // // (x,y)地点をダブルクリック時の範囲選択のためのキャレット位置を取得 // // caret_left : 左側のキャレット位置 // caret_left : 右側のキャレット位置 // // 戻り値 : 成功すると true // // 区切り文字 bool is_separate_char( const int ucs2 ) { if( ucs2 == ' ' || ucs2 == '.' || ucs2 == ',' || ucs2 == '(' || ucs2 == ')' || ucs2 == '=' // 全角空白 || ucs2 == 0x3000 // 。、 || ucs2 == 0x3001 || ucs2 == 0x3002 // ., || ucs2 == 0xff0c || ucs2 == 0xff0e // 全角() || ucs2 == 0xff08 || ucs2 == 0xff09 // 全角 = || ucs2 == 0xff1d // 「」 || ucs2 == 0x300c || ucs2 == 0x300d || ucs2 == 0x300e || ucs2 == 0x300f ) return true; return false; } // // ダブルクリック時にキャレット位置を決める // const bool DrawAreaBase::set_carets_dclick( CARET_POSITION& caret_left, CARET_POSITION& caret_right ,const int x, const int y, const bool triple ) { if( ! m_layout_tree ) return false; #ifdef _DEBUG std::cout << "DrawAreaBase::set_carets_dclick\n"; #endif // 先頭のヘッダブロックから順に調べる LAYOUT* header = m_layout_tree->top_header(); while( header ){ // y が含まれているブロックだけチェックする if( header->rect->y <= y && y <= header->rect->y + header->rect->height ){ LAYOUT* layout = header->next_layout; LAYOUT* layout_before = layout; while( layout ){ RECTANGLE* rect = layout->rect; if( ! layout->text || ! rect ){ layout = layout->next_layout; if( layout && layout->text ) layout_before = layout; else layout_before = NULL; continue; } // フォント設定 set_node_font( layout ); // ポインタの下にあるノードを探す int pos; while( rect ){ int width_line; int char_width; int byte_char; if( is_pointer_on_rect( rect, layout->text, rect->pos_start, rect->pos_start + rect->n_byte, x, y, pos, width_line, char_width, byte_char ) ) break; rect = rect->next_rect; } if( ! rect ){ layout = layout->next_layout; continue; } // トリプルクリック if( triple ){ LAYOUT* layout_after = layout; while( layout_after->next_layout && layout_after->next_layout->text ) layout_after = layout_after->next_layout; if( layout_before ) caret_left.set( layout_before, 0 ); else caret_left.set( layout, 0 ); caret_right.set( layout_after, layout_after->lng_text ); return true; } int byte_char_pointer; const int ucs2_pointer = MISC::utf8toucs2( layout->text + pos, byte_char_pointer ); const int ucs2mode_pointer = MISC::get_ucs2mode( ucs2_pointer ); #ifdef _DEBUG std::cout << "ucs2 = " << std::hex << ucs2_pointer << std::dec << " mode = " << ucs2mode_pointer << " pos = " << pos << std::endl; #endif // 区切り文字をダブルクリックした if( is_separate_char( ucs2_pointer ) ){ caret_left.set( layout, pos ); caret_right.set( layout, pos + byte_char_pointer ); return true; } // 左位置を求める int pos_left = 0; int pos_tmp = 0; while( pos_tmp < pos ){ int byte_char; const int ucs2 = MISC::utf8toucs2( layout->text + pos_tmp, byte_char ); const int ucs2mode = MISC::get_ucs2mode( ucs2 ); int byte_char_next; const int ucs2_next = MISC::utf8toucs2( layout->text + pos_tmp + byte_char, byte_char_next ); const int ucs2mode_next = MISC::get_ucs2mode( ucs2_next ); // 区切り文字が来たら左位置を移動する if( ucs2_next == '\0' || is_separate_char( ucs2 ) // 文字種が変わった || ( ucs2mode != ucs2mode_pointer && ucs2mode_next == ucs2mode_pointer ) ) pos_left = pos_tmp + byte_char; pos_tmp += byte_char; } // 右位置を求める int pos_right = pos; while( pos_right < layout->lng_text ){ int byte_char; const int ucs2 = MISC::utf8toucs2( layout->text + pos_right, byte_char ); const int ucs2mode = MISC::get_ucs2mode( ucs2 ); int byte_char_next; const int ucs2_next = MISC::utf8toucs2( layout->text + pos_right + byte_char, byte_char_next ); const int ucs2mode_next = MISC::get_ucs2mode( ucs2_next ); // 区切り文字が来たらbreak if( is_separate_char( ucs2 ) ) break; pos_right += byte_char; // 文字種が変わった if( ucs2_next == '\0' || ( ucs2mode == ucs2mode_pointer && ucs2mode_next != ucs2mode_pointer ) ) break; } #ifdef _DEBUG std::cout << "pos_left = " << pos_left << " pos_right = " << pos_right << std::endl; #endif // キャレット設定 caret_left.set( layout, pos_left ); caret_right.set( layout, pos_right ); return true; } } // 次のブロックへ header = header->next_header; } return false; } // // 範囲選択の範囲を計算してm_selectionにセット & 範囲選択箇所の再描画 // // caret_left から caret_right まで範囲選択状態にする // const bool DrawAreaBase::set_selection( const CARET_POSITION& caret_left, const CARET_POSITION& caret_right ) { m_caret_pos_pre = caret_left; m_caret_pos = caret_left; m_caret_pos_dragstart = caret_left; return set_selection( caret_right, NULL ); } // // 範囲選択の範囲を計算してm_selectionにセット // // caret_pos : 移動後のキャレット位置、m_caret_pos_pre から caret_pos まで範囲選択状態にする // const bool DrawAreaBase::set_selection( const CARET_POSITION& caret_pos ) { return set_selection( caret_pos, NULL ); } // rect に再描画範囲を計算して入れる( NULL なら入らない ) // その後 draw_screen( rect.y, rect.height ) で選択範囲を描画する const bool DrawAreaBase::set_selection( const CARET_POSITION& caret_pos, RECTANGLE* rect ) { if( ! caret_pos.layout ) return false; if( ! m_caret_pos_dragstart.layout ) return false; // 前回の呼び出しからキャレット位置が変わってない if( m_caret_pos == caret_pos ) return false; m_caret_pos_pre = m_caret_pos;; m_caret_pos = caret_pos; #ifdef _DEBUG std::cout << "DrawAreaBase::set_selection()\n"; std::cout << "start header = " << m_caret_pos_dragstart.layout->id_header << " node = " << m_caret_pos_dragstart.layout->id; std::cout << " byte = " << m_caret_pos_dragstart.byte << std::endl; std::cout << "current header = " << m_caret_pos.layout->id_header << " node = " << m_caret_pos.layout->id; std::cout << " byte = " << m_caret_pos.byte << std::endl; #endif // ドラッグ開始位置と現在のキャレット位置が同じなら選択解除 if( m_caret_pos_dragstart == m_caret_pos ) m_selection.select = false; // 範囲計算 else{ m_selection.select = true; if( m_caret_pos_dragstart > m_caret_pos ){ m_selection.caret_from = m_caret_pos;; m_selection.caret_to = m_caret_pos_dragstart; } else{ m_selection.caret_from = m_caret_pos_dragstart; m_selection.caret_to = m_caret_pos; } } if( ! rect ) return true; // 再描画範囲計算 const int pos_y = get_vscr_val(); const int height_view = m_view.get_height(); int y_redraw = 0; int height_redraw = height_view; LAYOUT* layout = m_caret_pos_pre.layout; LAYOUT* layout_to = m_caret_pos.layout; if( ! layout ) layout = m_caret_pos_dragstart.layout; // layout_toの方が前だったらポインタを入れ換え if( layout_to->id_header < layout->id_header || ( layout_to->id_header == layout->id_header && layout_to->id < layout->id ) ){ LAYOUT* layout_tmp = layout_to; layout_to = layout; layout = layout_tmp; } RECTANGLE* rect_from = layout->rect; RECTANGLE* rect_to = layout_to->rect; if( ! rect_from | ! rect_to ) return false; while( rect_to->next_rect ) rect_to = rect_to->next_rect; // 範囲外 if( rect_from->y > pos_y + height_view ) return false; if( rect_to->y + rect_to->height < pos_y ) return false; if( rect_from->y > pos_y ){ y_redraw = rect_from->y - pos_y; height_redraw = height_view - y_redraw; } if( rect_to->y + rect_to->height < pos_y + height_view ){ height_redraw -= ( pos_y + height_view ) - ( rect_to->y + rect_to->height ); } #ifdef _DEBUG std::cout << "redraw layout from : " << layout->id_header << ":" << layout->id << " to " << layout_to->id_header << ":" << layout_to->id << " y_redraw = " << y_redraw << " height_redraw = " << height_redraw << std::endl; #endif rect->y = y_redraw; rect->height = height_redraw; return true; } // // 範囲選択の文字列取得 // // set_selection()の中で毎回やると重いので、ボタンのリリース時に一回だけ呼び出すこと // const bool DrawAreaBase::set_selection_str() { assert( m_layout_tree ); if( ! m_selection.str.empty() ) m_selection.str_pre = m_selection.str; m_selection.str.clear(); m_selection.imgurls.clear(); if( !m_selection.select ) return false; #ifdef _DEBUG std::cout << "DrawAreaBase::set_selection_str\n"; std::cout << "from header = " << m_selection.caret_from.layout->id_header << " node = " << m_selection.caret_from.layout->id; std::cout << " byte = " << m_selection.caret_from.byte << std::endl; std::cout << "to header = " << m_selection.caret_to.layout->id_header << " node = " << m_selection.caret_to.layout->id; std::cout << " byte = " << m_selection.caret_to.byte << std::endl; #endif std::vector< URLINFO > urls; bool start_copy = false; // 面倒臭いんで先頭のレイアウトブロックから順に調べていく LAYOUT* tmpheader = m_layout_tree->top_header(); while( tmpheader ){ // ブロック内のノードを順に調べていく LAYOUT* tmplayout = tmpheader->next_layout; while( tmplayout ){ int copy_from = 0, copy_to = 0; // 開始ノード if( tmplayout == m_selection.caret_from.layout ){ start_copy = true; copy_from = m_selection.caret_from.byte; copy_to = strlen( tmplayout->text ); } // 終了ノード if( tmplayout == m_selection.caret_to.layout ) copy_to = m_selection.caret_to.byte; // 文字列コピー if( start_copy ){ if( tmplayout->type == DBTREE::NODE_BR ) m_selection.str += "\n"; else if( tmplayout->type == DBTREE::NODE_DIV ) m_selection.str += "\n"; else if( tmplayout->type == DBTREE::NODE_HTAB ) m_selection.str += "\t"; else if( tmplayout->text ){ if( copy_from || copy_to ) m_selection.str += std::string( tmplayout->text ).substr( copy_from, copy_to - copy_from ); else m_selection.str += tmplayout->text; if( tmplayout->type == DBTREE::NODE_LINK && tmplayout->link ){ URLINFO urlinfo; urlinfo.url = std::string( tmplayout->link ); urlinfo.res_number = tmplayout->res_number; urls.push_back( urlinfo ); } } } // 終了 if( tmplayout == m_selection.caret_to.layout ){ // 画像のURLだけ抽出する if( urls.size() ){ std::vector< URLINFO >::const_iterator it = urls.begin(); for( ; it != urls.end(); ++it ){ if( DBIMG::get_type_ext( (*it).url ) != DBIMG::T_UNKNOWN ){ std::vector< URLINFO >::const_iterator it2 = m_selection.imgurls.begin(); for( ; it2 != m_selection.imgurls.end(); ++it2 ){ if( (*it).url == (*it2).url ) break; } if( it2 == m_selection.imgurls.end() ) m_selection.imgurls.push_back( *it ); } } } return true; } tmplayout = tmplayout->next_layout; } tmpheader = tmpheader->next_header; if( start_copy ){ m_selection.str += "\n"; if( tmpheader ) m_selection.str += "\n"; } } return false; } // // caret_pos が範囲選択の上にあるか // // const bool DrawAreaBase::is_caret_on_selection( const CARET_POSITION& caret_pos ) { LAYOUT* layout = caret_pos.layout; if( !layout || ! m_selection.select || m_selection.str.empty() ) return false; if( layout->id_header != m_selection.caret_from.layout->id_header ) return false; const int from_id = m_selection.caret_from.layout->id; const int from_byte = m_selection.caret_from.byte; const int to_id = m_selection.caret_to.layout->id; const int to_byte = m_selection.caret_to.byte; if( to_id < layout->id ) return false; if( to_id == layout->id && to_byte < caret_pos.byte ) return false; if( from_id > layout->id ) return false; if( from_id == layout->id && from_byte > caret_pos.byte ) return false; return true; } // // 範囲選択範囲にcaret_posが含まれていて、かつ条件(IDや数字など)を満たしていたらURLとして範囲選択文字を返す // std::string DrawAreaBase::get_selection_as_url( const CARET_POSITION& caret_pos ) { std::string url; if( is_caret_on_selection( caret_pos ) ){ size_t n,dig; std::string select_str = MISC::remove_space( m_selection.str ); select_str = MISC::remove_str( select_str, "\n" ); int num = MISC::str_to_uint( select_str.c_str(), dig, n ); // 数字 if( dig && num ){ url = PROTO_ANCHORE + MISC::itostr( num ); for(;;){ select_str = select_str.substr( n ); if( select_str.empty() ) break; std::string tmpstr, tmpstr2; if( select_str.find( "-" ) == 0 ) tmpstr = tmpstr2 = "-"; else if ( select_str.find( "=" ) == 0 ) tmpstr = tmpstr2 = "="; else if ( select_str.find( "," ) == 0 ) tmpstr = tmpstr2 = ","; else if( select_str.find( "-" ) == 0 ){ tmpstr = "-"; tmpstr2 = "-"; } else if( select_str.find( "−" ) == 0 ){ tmpstr = "−"; tmpstr2 = "-"; } else if ( select_str.find( "=" ) == 0 ){ tmpstr = "="; tmpstr2 = "="; } else if ( select_str.find( "," ) == 0 ){ tmpstr = ","; tmpstr2 = ","; } select_str = select_str.substr( tmpstr.length() ); num = MISC::str_to_uint( select_str.c_str(), dig, n ); if( dig && num ) url += tmpstr2 + MISC::itostr( num ); else break; } } // ID else if( select_str.find( "ID:" ) == 0 ) url = select_str; } #ifdef _DEBUG if( !url.empty() ) std::cout << "DrawAreaBase::get_selection_as_url : " << url << std::endl; #endif return url; } // 全選択 void DrawAreaBase::select_all() { #ifdef _DEBUG std::cout << "DrawAreaBase::select_all\n"; #endif CARET_POSITION caret_left, caret_right; LAYOUT* layout = NULL; LAYOUT* layout_back = NULL; // 先頭 LAYOUT* header = m_layout_tree->top_header(); while( header ){ layout = header->next_layout; while( layout && ! layout->text ){ layout = layout->next_layout; } if( layout ) break; header = header->next_header; } if( ! layout ) return; #ifdef _DEBUG std::cout << "id = " << layout->id_header << "-" << layout->id << " text = " << layout->text << std::endl; #endif caret_left.set( layout, 0 ); // 最後 while( header ){ layout = header->next_layout; while( layout ){ if( layout->text ) layout_back = layout; layout = layout->next_layout; } header = header->next_header; } if( ! layout_back ) return; #ifdef _DEBUG std::cout << "-> id = " << layout_back->id_header << "-" << layout_back->id << " text = " << layout_back->text << std::endl; #endif caret_right.set( layout_back, layout_back->lng_text ); set_selection( caret_left, caret_right ); set_selection_str(); redraw_view_force(); } // // VScrollbar が動いた // void DrawAreaBase::slot_change_adjust() { if( m_cancel_change_adjust ) return; if( m_scrollinfo.mode != SCROLL_NOT ) return; // スクロール中 #ifdef _DEBUG std::cout << "slot_change_adjust\n"; #endif m_scrollinfo.reset(); m_scrollinfo.mode = SCROLL_NORMAL; exec_scroll(); } // // drawarea がリサイズした // bool DrawAreaBase::slot_configure_event( GdkEventConfigure* event ) { // 表示されていないview(is_drawable() != true ) は表示された段階で // redraw_view() したときに configure_impl() を呼び出す m_configure_reserve = true; configure_impl(); return true; } // // drawarea がリサイズ実行 // void DrawAreaBase::configure_impl() { if( ! m_configure_reserve ) return; if( ! m_view.is_drawable() ) return; m_configure_reserve = false; const int width = m_view.get_width(); const int height = m_view.get_height(); if( height < LAYOUT_MIN_HEIGHT ) return; // サイズが変わっていないときは再レイアウトしない if( m_configure_width == width && m_configure_height == height ) return; // リサイズする前のレス番号を保存しておいて // redrawした後にジャンプ const int seen_current = m_seen_current; // リサイズ前と横幅が同じ場合はスクロールバーの位置を変えない const int pos_y = ( m_configure_width == width ? get_vscr_val() : 0 ); #ifdef _DEBUG std::cout << "DrawAreaBase::configure_impl : url = " << m_url << std::endl << "seen_current = " << seen_current << " pos_y = " << pos_y << " width = " << width << " heigth = " << height << " pre_width = " << m_configure_width << " pre_height = " << m_configure_height << std::endl; #endif m_configure_width = width; m_configure_height = height; if( exec_layout() ){ // スクロール実行 if( pos_y ){ m_scrollinfo.reset(); m_scrollinfo.mode = SCROLL_TO_Y; m_scrollinfo.y = pos_y; exec_scroll(); } else if( seen_current ) goto_num( seen_current ); else redraw_view_force(); } } // // drawarea の再描画イベント // bool DrawAreaBase::slot_expose_event( GdkEventExpose* event ) { const int x = event->area.x; const int y = event->area.y; const int width = event->area.width; const int height = event->area.height; // タブ操作中は再描画しない if( SESSION::is_tab_operating( URL_ARTICLEADMIN ) ) return true; #ifdef _DEBUG std::cout << "DrawAreaBase::slot_expose_event" << " y = " << y << " height = " << height << " draw_screen = " << m_drawinfo.draw << " url = " << m_url << std::endl; #endif // draw_screen からの呼び出し if( m_drawinfo.draw ){ #ifdef _DEBUG std::cout << "draw\n"; #endif m_drawinfo.draw = false; exec_draw_screen( m_drawinfo.y, m_drawinfo.height ); } // バックスクリーンに描画済みならコピー else if( y >= m_rect_backscreen.y && y + height <= m_rect_backscreen.y + m_rect_backscreen.height ){ #ifdef _DEBUG std::cout << "copy from backscreen\n"; #endif // [gtkmm <= 2.8] Gdk::GC::set_clip_rectangle( Gdk::Rectangle& rectangle ) // Gdk::GC::set_clip_rectangle( const Gdk::Rectangle& rectangle ) Gdk::Rectangle rect( x, y, width, height ); m_gc->set_clip_rectangle( rect ); m_window->draw_drawable( m_gc, m_backscreen, x, y, x, y, width, height ); // オートスクロールマーカと枠の描画 draw_marker(); draw_frame(); } // レイアウトがセットされていない or まだリサイズしていない( m_backscreen == NULL )なら画面消去 else if( ! m_layout_tree->top_header() || ! m_backscreen ){ #ifdef _DEBUG std::cout << "clear window\n"; #endif m_window->set_background( m_color[ get_colorid_back() ] ); m_window->clear(); return false; } // 必要な所だけ再描画 else{ #ifdef _DEBUG std::cout << "expose\n"; #endif exec_draw_screen( y, height ); } return true; } // // drawarea でマウスホイールが動いた // bool DrawAreaBase::slot_scroll_event( GdkEventScroll* event ) { m_sig_scroll_event.emit( event ); return true; } // // マウスが領域外に出た // bool DrawAreaBase::slot_leave_notify_event( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "DrawAreaBase::slot_leave_notify_event\n"; #endif // 右ドラッグ中はシグナルを発行しない if( ! m_r_drugging ) m_sig_leave_notify.emit( event ); return false; } // // ウィンドウの重なり状態が変わった // // スクロール時の描画モードを変更する // // DrawingAreaの領域が全て表示されているときは Gdk::Window::scroll() を使ってスクロール // 一部が隠れている時はバックスクリーン内でスクロール処理してバックスクリーン全体をウィンドウにコピーする // bool DrawAreaBase::slot_visibility_notify_event(GdkEventVisibility* event) { #ifdef _DEBUG std::cout << "DrawAreaBase::slot_visibility_notify_event\n"; #endif m_scroll_window = false; if (event->state == GDK_VISIBILITY_UNOBSCURED) { #ifdef _DEBUG std::cout << "unobscured\n"; #endif m_scroll_window = true; } else if ( event->state == GDK_VISIBILITY_PARTIAL ){ #ifdef _DEBUG std::cout << "partial\n"; #endif } #ifdef _DEBUG else std::cout << "invisible\n"; #endif return true; } // // realize // // GCを作成してレイアウト // void DrawAreaBase::slot_realize() { #ifdef _DEBUG std::cout << "DrawAreaBase::slot_realize()" << std::endl; #endif m_window = m_view.get_window(); assert( m_window ); m_gc = Gdk::GC::create( m_window ); assert( m_gc ); // 色初期化 init_color(); m_back_marker = Gdk::Pixmap::create( m_window, AUTOSCR_CIRCLE, AUTOSCR_CIRCLE ); assert( m_back_marker ); exec_layout(); m_view.grab_focus(); } // // マウスボタンを押した // bool DrawAreaBase::slot_button_press_event( GdkEventButton* event ) { m_clicked = true; std::string url; int res_num = 0; bool redraw_force = false; if( m_layout_current && m_layout_current->link ) url = m_layout_current->link; if( m_layout_current ) res_num = m_layout_current->res_number; const int pos = get_vscr_val(); const int x = ( int ) event->x; const int y = ( int ) event->y + pos; CARET_POSITION caret_pos; set_caret( caret_pos, x, y ); m_view.grab_focus(); // オートスクロール中ならオートスクロール解除 if( m_scrollinfo.mode == SCROLL_AUTO ){ m_scrollinfo.reset(); // リンクのクリックを認識させないためオートスクロール解除直後はリンククリックの処理をしない // 直後に slot_button_release_event() が呼び出されて m_scrollinfo がリセットされる m_scrollinfo.autoscroll_finished = true; change_cursor( Gdk::ARROW ); } else { // 範囲選択解除、及びドラッグ開始 if( m_control.button_alloted( event, CONTROL::ClickButton ) ){ m_drugging = true; m_selection.select = false; if( ! m_selection.str.empty() ) m_selection.str_pre = m_selection.str; m_selection.str.clear(); m_selection.imgurls.clear(); m_caret_pos_pre = m_caret_pos; m_caret_pos = caret_pos; m_caret_pos_dragstart = caret_pos; redraw_force = true; } // マウスジェスチャ(右ドラッグ)開始 else if( m_control.button_alloted( event, CONTROL::GestureButton ) ) m_r_drugging = true; // オートスクロールボタン else if( m_control.button_alloted( event, CONTROL::AutoScrollButton ) ){ if ( ! ( m_layout_current && m_layout_current->link ) ){ // リンク上で無いなら change_cursor( Gdk::DOUBLE_ARROW ); m_scrollinfo.reset(); m_scrollinfo.mode = SCROLL_AUTO; m_scrollinfo.show_marker = true; m_scrollinfo.enable_up = true; m_scrollinfo.enable_down = true; m_scrollinfo.x = ( int ) event->x; m_scrollinfo.y = ( int ) event->y; } } // ダブル、トリプルクリックしたら範囲選択 else if( m_control.button_alloted( event, CONTROL::DblClickButton ) || m_control.button_alloted( event, CONTROL::TrpClickButton ) ){ const bool triple = m_control.button_alloted( event, CONTROL::TrpClickButton ); CARET_POSITION caret_left, caret_right; if( set_carets_dclick( caret_left, caret_right, x, y, triple ) ){ set_selection( caret_left, caret_right ); redraw_force = true; } } } // 再描画 if( redraw_force ) redraw_view_force(); else redraw_view(); m_sig_button_press.emit( url, res_num, event ); return true; } // // マウスボタンを離した // bool DrawAreaBase::slot_button_release_event( GdkEventButton* event ) { if( ! m_clicked ) return true; m_clicked = false; // リンクの上でコンテキストメニューを表示してからマウスを移動すると // slot_motion_notify_eventが呼び出されず m_layout_current が変わらないため // リンクを開いてしまう CARET_POSITION caret_pos; m_x_pointer = ( int ) event->x; m_y_pointer = ( int ) event->y; m_layout_current = set_caret( caret_pos, m_x_pointer , m_y_pointer + get_vscr_val() ); std::string url; int res_num = 0; if( m_layout_current && m_layout_current->link ){ url = m_layout_current->link; // ssspの場合は PROTO_SSSP を前に付ける if( m_layout_current->type == DBTREE::NODE_SSSP ) url = std::string( PROTO_SSSP ) + url; } if( m_layout_current ) res_num = m_layout_current->res_number; if( event->type == GDK_BUTTON_RELEASE ){ // 範囲選択中だったら選択文字確定 & スクロール停止 if( m_drugging && set_selection_str() ){ // X のコピーバッファにコピー Glib::RefPtr< Gtk::Clipboard > clip = Gtk::Clipboard::get( GDK_SELECTION_PRIMARY ); clip->set_text( m_selection.str ); redraw_view(); m_scrollinfo.reset(); // リンククリック処理をキャンセル url = std::string(); } // リンクのクリックを認識させないためオートスクロール解除直後はリンククリックの処理をしない if( m_scrollinfo.autoscroll_finished ){ m_scrollinfo.reset(); url = std::string(); } m_drugging = false; m_r_drugging = false; // ダブルクリックで数字やID〜を範囲選択したときにon_urlシグナルを出す motion_mouse(); } m_sig_button_release.emit( url, res_num, event ); return true; } // // マウスが動いた // bool DrawAreaBase::slot_motion_notify_event( GdkEventMotion* event ) { if( m_x_pointer == ( int ) event->x && m_y_pointer == ( int ) event->y ) return true; m_x_pointer = ( int ) event->x; m_y_pointer = ( int ) event->y; // ホイールスクロール終了直後はある程度マウスを動かすまでモーションイベントをキャンセル if( m_scrollinfo.counter_nomotion ){ #ifdef _DEBUG std::cout << "counter_nomotion = " << m_scrollinfo.counter_nomotion << " x = " << m_scrollinfo.x << " y = " << m_scrollinfo.x << " xp = " << m_x_pointer << " yp = " << m_x_pointer; #endif m_scrollinfo.counter_nomotion = MAX( 0, m_scrollinfo.counter_nomotion - abs( m_scrollinfo.x - m_x_pointer ) - abs( m_scrollinfo.y - m_y_pointer ) ); if( m_scrollinfo.x != m_x_pointer ) m_scrollinfo.x = m_x_pointer; if( m_scrollinfo.y != m_y_pointer ) m_scrollinfo.y = m_y_pointer; #ifdef _DEBUG std::cout << " -> " << m_scrollinfo.counter_nomotion << std::endl; #endif if( m_scrollinfo.counter_nomotion ) return true; m_scrollinfo.reset(); } motion_mouse(); m_sig_motion_notify.emit( event ); return true; } // // マウスが動いた時の処理 // bool DrawAreaBase::motion_mouse() { const int pos = get_vscr_val(); CARET_POSITION caret_pos; // 現在のマウスポインタの下にあるレイアウトノードとキャレットの取得 m_layout_current = set_caret( caret_pos, m_x_pointer , m_y_pointer + pos ); int res_num = 0; std::string link_current; if( m_layout_current ){ // 現在のポインタの下にあるレス番号取得 res_num = m_layout_current->res_number; // 現在のポインタの下にあるリンクの文字列を更新 // IDや数字だったらポップアップ表示する // リンクの上にポインタがある if( m_layout_current->link ){ link_current = m_layout_current->link; } // IDや数字などの範囲選択の上にポインタがある else link_current = get_selection_as_url( caret_pos ); } bool link_changed = false; if( link_current != m_link_current ) link_changed = true; // 前回とリンクの文字列が変わった m_link_current = link_current; // ドラッグ中なら範囲選択 if( m_drugging ){ // ポインタが画面外に近かったらオートスクロールを開始する const int mrg = ( int )( (double)m_font->br_size*0.5 ); // スクロールのリセット if ( // スクロールページの一番上 ( pos == 0 && m_y_pointer < m_view.get_height() - mrg ) // スクロールページの一番下 || ( pos >= get_vscr_maxval() && m_y_pointer > mrg ) // ページの中央 || ( m_y_pointer > mrg && m_y_pointer < m_view.get_height() - mrg ) ){ m_scrollinfo.reset(); } // スクロールモードをセット else if( m_scrollinfo.mode == SCROLL_NOT ){ m_scrollinfo.mode = SCROLL_AUTO; m_scrollinfo.show_marker = false; m_scrollinfo.x = m_x_pointer; if( m_y_pointer <= mrg ){ m_scrollinfo.enable_up = true; m_scrollinfo.enable_down = false; m_scrollinfo.y = mrg*6; } else{ m_scrollinfo.enable_up = false; m_scrollinfo.enable_down = true; m_scrollinfo.y = m_view.get_height() - mrg*6; } } // スクロール中の場合は exec_scroll() で選択部分を描画する if( m_scrollinfo.mode == SCROLL_NOT ){ RECTANGLE rect; if( set_selection( caret_pos, &rect ) ) draw_screen( rect.y, rect.height ); } } // 右ドラッグしていないとき // 右ドラッグ中はリンクへの出入りを監視しない else if( ! m_r_drugging ){ if( link_changed ){ m_sig_leave_url.emit(); // (別の)リンクノードに入った if( !m_link_current.empty() && m_scrollinfo.mode == SCROLL_NOT // スクロール中はon_urlシグナルを出さない ){ std::string imgurl; const DBTREE::NODE* node = m_layout_current->node; if( node && node->linkinfo && node->linkinfo->imglink ) imgurl = node->linkinfo->imglink; #ifdef _DEBUG std::cout << "slot_motion_notify_drawarea : enter link = " << m_link_current << " imgurl = " << imgurl << std::endl;; #endif m_sig_on_url.emit( m_link_current, imgurl, res_num ); } // リンクノードからでた else{ #ifdef _DEBUG std::cout << "slot_motion_notify_drawarea : leave\n"; #endif } } } change_cursor( get_cursor_type() ); return true; } // // 現在のポインターの下のノードからカーソルのタイプを決定する // const Gdk::CursorType DrawAreaBase::get_cursor_type() { Gdk::CursorType cursor_type = Gdk::ARROW; if( m_layout_current ){ // テキストの上ではカーソルを I に変える if( m_layout_current->text && ! m_layout_current->link ) cursor_type = Gdk::XTERM; // リンクの上にポインタがある if( m_layout_current->link ) cursor_type = Gdk::HAND2; } return cursor_type; } // // カーソルの形状の変更 // void DrawAreaBase::change_cursor( const Gdk::CursorType type ) { //オートスクロール中 if( m_scrollinfo.mode == SCROLL_AUTO ) return; if( m_cursor_type != type ){ m_cursor_type = type; if( m_cursor_type == Gdk::ARROW ) m_window->set_cursor(); else m_window->set_cursor( Gdk::Cursor( m_cursor_type ) ); } } // // キーを押した // const bool DrawAreaBase::slot_key_press_event( GdkEventKey* event ) { //オートスクロール中なら無視 if( m_scrollinfo.mode == SCROLL_AUTO ) return true; #ifdef _DEBUG std::cout << "DrawAreaBase::slot_key_press_event\n"; #endif if( m_key_press && m_keyval == event->keyval ) m_key_locked = true; m_key_press = true; m_keyval = event->keyval; return m_sig_key_press.emit( event ); } // // キーを離した // bool DrawAreaBase::slot_key_release_event( GdkEventKey* event ) { if( !m_key_press ) return true; #ifdef _DEBUG std::cout << "DrawAreaBase::slot_key_release_event\n"; #endif m_scrollinfo.reset(); if( m_key_locked ) redraw_view(); m_key_press = false; m_key_locked = false; m_keyval = 0; m_sig_key_release.emit( event ); return true; } jd-2.8.7-140104/src/article/drawareabase.h0000644000076400010400000004504712174772063014617 0ustar // ライセンス: GPL2 // スレ表示部のベースクラス #ifndef _DRAWAREABASE_H #define _DRAWAREABASE_H #include "caret.h" #include "scrollinfo.h" #include "jdlib/refptr_lock.h" #include "control/control.h" #include "colorid.h" #include "cssmanager.h" #include #include #include namespace ARTICLE { struct LAYOUT; class LayoutTree; class EmbeddedImage; // マウスボタンプレスとリリースのシグナル。リリース時にマウスがリンクの上にある時そのURLを渡す typedef sigc::signal< bool, std::string, int, GdkEventButton* > SIG_BUTTON_PRESS; typedef sigc::signal< bool, std::string, int, GdkEventButton* > SIG_BUTTON_RELEASE; typedef sigc::signal< bool, GdkEventCrossing* > SIG_LEAVE_NOTIFY; typedef sigc::signal< bool, GdkEventMotion* > SIG_MOTION_NOTIFY; typedef sigc::signal< bool, GdkEventKey* > SIG_KEY_PRESS; typedef sigc::signal< bool, GdkEventKey* > SIG_KEY_RELEASE; typedef sigc::signal< bool, GdkEventScroll* > SIG_SCROLL_EVENT; typedef sigc::signal< void, std::string, std::string, int > SIG_ON_URL; typedef sigc::signal< void > SIG_LEAVE_URL; struct URLINFO { std::string url; int res_number; }; // 範囲選択用 struct SELECTION { bool select; CARET_POSITION caret_from; CARET_POSITION caret_to; std::string str; // 現在の選択文字列 std::string str_pre; // 一つ前の選択文字列 std::vector< URLINFO > imgurls;// 選択範囲に含まれる画像URL }; // 描画情報 struct DRAWINFO { bool draw; int y; int height; }; // フォント情報 struct FONTINFO { std::string fontname; Pango::FontDescription pfd; int ascent; int descent; int height; int underline_pos; // 下線の位置(文字の上からのピクセル値) int br_size; // 改行量 (ピクセル値) int mrg_right; // wrap計算のときに使用する右マージン幅 (ピクセル値) }; /////////////////////////////////// class DrawAreaBase : public Gtk::HBox { SIG_BUTTON_PRESS m_sig_button_press; SIG_BUTTON_RELEASE m_sig_button_release; SIG_SCROLL_EVENT m_sig_scroll_event; SIG_LEAVE_NOTIFY m_sig_leave_notify; SIG_MOTION_NOTIFY m_sig_motion_notify; SIG_KEY_PRESS m_sig_key_press; SIG_KEY_RELEASE m_sig_key_release; SIG_ON_URL m_sig_on_url; SIG_LEAVE_URL m_sig_leave_url; std::string m_url; // スピードを稼ぐためデータベースに直接アクセスする JDLIB::RefPtr_Lock< DBTREE::ArticleBase > m_article; // HBoxに張り付けるウイジット Gtk::DrawingArea m_view; Gtk::EventBox* m_event; Gtk::VScrollbar* m_vscrbar; // レイアウトツリー LayoutTree* m_layout_tree; // 描画領域の幅、高さ( != ウィンドウサイズ ) int m_width_client; int m_height_client; //現在見ているレスの番号 int m_seen_current; // 描画用 Glib::RefPtr< Gdk::Window > m_window; Glib::RefPtr< Gdk::GC > m_gc; Glib::RefPtr< Gdk::Pixmap > m_backscreen; Glib::RefPtr< Pango::Layout > m_pango_layout; Glib::RefPtr< Pango::Context > m_context; RECTANGLE m_rect_backscreen; // バックスクリーンが描画されている範囲 bool m_enable_draw; DRAWINFO m_drawinfo; // 高速スクロール描画実行 // DrawingAreaの領域が全て表示されているときは Gdk::Window::scroll() を使ってスクロール // 一部が隠れている時はバックスクリーン内でスクロール処理してバックスクリーン全体をウィンドウにコピーする bool m_scroll_window; // キャレット情報 CARET_POSITION m_caret_pos; // 現在のキャレットの位置(クリックやドラッグすると移動) CARET_POSITION m_caret_pos_pre; // 移動前のキャレットの位置(選択範囲の描画などで使用する) CARET_POSITION m_caret_pos_dragstart; // ドラッグを開始したキャレット位置 // 色 int m_colorid_text; // デフォルトの文字色 int m_colorid_back; // デフォルトの背景色 std::vector< Gdk::Color > m_color; // 枠 bool m_draw_frame; // 枠を描画する Glib::RefPtr< Gdk::Pixmap > m_back_frame; // 枠の背景 bool m_ready_back_frame; // 範囲選択 SELECTION m_selection; // 検索結果のハイライト範囲 std::list< SELECTION > m_multi_selection; // レイアウト用 CORE::CSS_PROPERTY m_css_body; // body の cssプロパティ int m_fontid; int m_defaultfontid; FONTINFO *m_font; // カレントフォント情報 FONTINFO m_defaultfont; // デフォルトフォント情報 bool m_aafont_initialized; FONTINFO m_aafont; // AA用フォント情報 // スレビューで文字幅の近似を厳密にするか bool m_strict_of_char; // ビューのリサイズ用 bool m_configure_reserve; // true の時は再描画する前に再レイアウトする int m_configure_width; int m_configure_height; // スクロール情報 SCROLLINFO m_scrollinfo; guint32 m_wheel_scroll_time; // 前回ホイールを回した時刻 int m_goto_num_reserve; // 初期化時のジャンプ予約(レス番号) bool m_goto_bottom_reserve; // 初期化時のジャンプ予約(底) int m_pre_pos_y; // ひとつ前のスクロールバーの位置。スクロールした時の差分量計算に使用する std::vector< int > m_jump_history; // ジャンプ履歴 bool m_cancel_change_adjust; // adjust の値変更イベントをキャンセル Glib::RefPtr< Gdk::Pixmap > m_back_marker; // オートスクロールマーカの背景 RECTANGLE m_clip_marker; bool m_ready_back_marker; time_t m_wait_scroll; // 処理落ちした時にスクロールにウエイトを入れる struct timeval m_scroll_time; // ウエイト時に最後にスクロールした時刻 // 状態 int m_x_pointer, m_y_pointer; // 現在のマウスポインタの位置 bool m_key_press; // キーを押している bool m_key_locked; // 同じキーを押したままにしている guint m_keyval; bool m_clicked; bool m_drugging; // ドラッグ中 bool m_r_drugging; // 右ドラッグ中 std::string m_link_current; // 現在マウスポインタの下にあるリンクの文字列 LAYOUT* m_layout_current; // 現在マウスポインタの下にあるlayoutノード(下が空白ならNULL) Gdk::CursorType m_cursor_type; // カーソルの形状 // 入力コントローラ CONTROL::Control m_control; // 埋め込み画像のポインタ std::list< EmbeddedImage* > m_eimgs; // ブックマークアイコン Glib::RefPtr< Gdk::Pixbuf > m_pixbuf_bkmk; // 書き込みマークアイコン Glib::RefPtr< Gdk::Pixbuf > m_pixbuf_post; // 自分の書き込みに対するレスマークアイコン Glib::RefPtr< Gdk::Pixbuf > m_pixbuf_refer_post; public: SIG_BUTTON_PRESS sig_button_press(){ return m_sig_button_press; } SIG_BUTTON_RELEASE sig_button_release(){ return m_sig_button_release; } SIG_SCROLL_EVENT sig_scroll_event(){ return m_sig_scroll_event; } SIG_LEAVE_NOTIFY sig_leave_notify(){ return m_sig_leave_notify; } SIG_MOTION_NOTIFY sig_motion_notify(){ return m_sig_motion_notify; } SIG_KEY_PRESS sig_key_press(){ return m_sig_key_press; } SIG_KEY_RELEASE sig_key_release(){ return m_sig_key_release; } SIG_ON_URL sig_on_url(){ return m_sig_on_url; } SIG_LEAVE_URL sig_leave_url(){ return m_sig_leave_url; } DrawAreaBase( const std::string& url ); virtual ~DrawAreaBase(); const std::string& get_url() const { return m_url; } const int& width_client() const { return m_width_client; } const int& height_client() const { return m_height_client; } void clock_in(); void clock_in_smooth_scroll(); void focus_view(); void focus_out(); void set_enable_draw( const bool enable ){ m_enable_draw = enable; } // フォントID( fontid.h にある ID を指定) const int get_fontid() const { return m_fontid; } void set_fontid( int id ){ m_fontid = id; m_defaultfontid = id; } // 新着セパレータのあるレス番号の取得とセット const int get_separator_new(); void set_separator_new( int num ); void hide_separator_new(); // セパレータが画面に表示されているか const bool is_separator_on_screen(); // 現在のポインタの下にあるレス番号取得 const int get_current_res_num(); // 全選択 void select_all(); // 範囲選択中の文字列 const std::string str_selection(); const std::string& str_pre_selection() const { return m_selection.str_pre; } // 一つ前の選択文字列 // 範囲選択を開始したレス番号 const int get_selection_resnum_from(); // 範囲選択を終了したレス番号 const int get_selection_resnum_to(); // 範囲選択に含まれる画像URLのリスト const std::vector< URLINFO >& get_selection_imgurls() const { return m_selection.imgurls; } const int get_seen_current() const { return m_seen_current; } // 現在見ているレスの番号 const int get_goto_num_reserve() const { return m_goto_num_reserve; } // 初期化時のジャンプ予約(レス番号) int max_number(); // 表示されている最後のレスの番号 // レスをappendして再レイアウト void append_res( const int from_num, const int to_num ); // リストで指定したレスをappendして再レイアウト void append_res( const std::list< int >& list_resnum ); // リストで指定したレスをappendして再レイアウト( 連結情報付き ) // list_joint で連結指定したレスはヘッダを取り除いて前のレスに連結する void append_res( const std::list< int >& list_resnum, const std::list< bool >& list_joint ); // html をappendして再レイアウト void append_html( const std::string& html ); // datをappendして再レイアウト void append_dat( const std::string& dat, int num ); // 全画面消去 void clear_screen(); // 再描画 // 再レイアウトはしないが configureの予約がある場合は再レイアウトしてから再描画する void redraw_view_force(); void redraw_view(); // スクロール方向指定 const bool set_scroll( const int control ); // マウスホイールの処理 void wheelscroll( GdkEventScroll* event ); // ジャンプ void set_jump_history( const int num ); // ジャンプ履歴にスレ番号を登録 void goto_num( int num ); void goto_next_res(); void goto_pre_res(); void goto_new(); void goto_top(); void goto_bottom(); void goto_back(); // 検索 const int search( const std::list< std::string >& list_query, const bool reverse ); const int search_move( const bool reverse ); void clear_highlight(); // 実況モード void live_start(); void live_stop(); void update_live_speed( const int sec ); protected: // リアライズしたか // Gtk::Widget::is_realized() はうまく動作しない const bool is_drawarea_realized(){ return m_window; } // 文字色のID( colorid.h にある ID を指定) const int get_colorid_text() const{ return m_colorid_text; } void set_colorid_text( int id ){ m_colorid_text = id; } // 背景色のID( colorid.h にある ID を指定) const int get_colorid_back(); void set_colorid_back( int id ){ m_colorid_back = id; } // 共通セットアップ // show_abone : あぼーんされたスレも表示 // show_scrbar : スクロールバーを最初から表示 // show_multispace : 連続空白も表示 void setup( const bool show_abone, const bool show_scrbar, const bool show_multispace ); // レイアウト処理 virtual bool exec_layout(); const bool exec_layout_impl( const bool is_popup, const int offset_y ); // DrawAreaに枠を描画する void set_draw_frame( bool draw_frame ){ m_draw_frame = draw_frame; } // リサイズした virtual bool slot_configure_event( GdkEventConfigure* event ); Gtk::DrawingArea* get_view(){ return &m_view; } Gtk::VScrollbar* get_vscrbar(){ return m_vscrbar; } private: // 初期化関係 void clear(); void create_scrbar(); void init_color(); void init_font(); void init_fontinfo( FONTINFO& fi, std::string& fontname ); // レイアウト処理 void set_align( LAYOUT* div, int id_end, int align ); void set_align_line( LAYOUT* div, LAYOUT* layout_from, LAYOUT* layout_to, RECTANGLE* rect_from, RECTANGLE* rect_to, int width_line, int align ); void layout_one_text_node( LAYOUT* node, int& node_x, int& node_y, int& br_size, const int width_view ); void layout_one_img_node( LAYOUT* node, int& node_x, int& node_y, int& brsize, const int width_view, const bool init_popupwin, const int mrg_bottom ); // 文字の幅などの情報 const int get_width_of_one_char( const char* str, int& byte, char& pre_char, bool& wide_mode, const int mode ); bool set_init_wide_mode( const char* str, const int pos_start, const int pos_to ); bool is_wrapped( const int x, const int border, const char* str ); // スクリーン描画 // y から height の高さ分だけ描画する // height == 0 ならスクロールした分だけ描画( y は無視 ) const bool draw_screen( const int y, const int height ); void exec_draw_screen( const int y_redraw, const int height_redraw ); bool draw_one_node( LAYOUT* layout, const int width_win, const int pos_y, const int upper, const int lower ); void draw_div( LAYOUT* layout_div, const int pos_y, const int upper, const int lower ); const bool get_selection_byte( const LAYOUT* layout, const SELECTION& selection, size_t& byte_from, size_t& byte_to ); void draw_one_text_node( LAYOUT* layout, const int width_win, const int pos_y ); void draw_string( LAYOUT* node, const int pos_y, const int width_view, const int color, const int color_back, const int byte_from, const int byte_to ); const bool draw_one_img_node( LAYOUT* layout, const int pos_y, const int upper, const int lower ); void set_node_font( LAYOUT* layout ); // drawarea がリサイズ実行 void configure_impl(); // 整数 -> 文字変換してノードに発言数をセット int set_num_id( LAYOUT* layout ); // スクロール関係 void exec_scroll(); // スクロールやジャンプを実行して再描画 int get_vscr_val(); int get_vscr_maxval(); // キャレット関係 bool is_pointer_on_rect( const RECTANGLE* rect, const char* text, const int pos_start, const int pos_to, const int x, const int y, int& pos, int& width_line, int& char_width, int& byte_char ); LAYOUT* set_caret( CARET_POSITION& caret_pos, int x, int y ); const bool set_carets_dclick( CARET_POSITION& caret_left, CARET_POSITION& caret_right, const int x, const int y, const bool triple ); // 範囲選択関係 const bool set_selection( const CARET_POSITION& caret_left, const CARET_POSITION& caret_right ); const bool set_selection( const CARET_POSITION& caret_pos ); const bool set_selection( const CARET_POSITION& caret_pos, RECTANGLE* rect ); const bool set_selection_str(); const bool is_caret_on_selection( const CARET_POSITION& caret_pos ); std::string get_selection_as_url( const CARET_POSITION& caret_pos ); // マウスが動いた時の処理 bool motion_mouse(); // 現在のポインターの下のノードからカーソルのタイプを決定する const Gdk::CursorType get_cursor_type(); // カーソルの形状の変更 void change_cursor( const Gdk::CursorType type ); // スクロールマーカの描画 void draw_marker(); // 枠の描画 void draw_frame(); // スロット void slot_change_adjust(); bool slot_expose_event( GdkEventExpose* event ); bool slot_scroll_event( GdkEventScroll* event ); bool slot_leave_notify_event( GdkEventCrossing* event ); bool slot_visibility_notify_event( GdkEventVisibility* event ); void slot_realize(); bool slot_button_press_event( GdkEventButton* event ); bool slot_button_release_event( GdkEventButton* event ); bool slot_motion_notify_event( GdkEventMotion* event ); const bool slot_key_press_event( GdkEventKey* event ); bool slot_key_release_event( GdkEventKey* event ); }; // // 文字列を wrap するか判定する関数 // // str != NULL なら禁則処理も考える // inline bool DrawAreaBase::is_wrapped( const int x, const int border, const char* str ) { const unsigned char* tmpchar = ( const unsigned char* ) str; if( x < border ) return false; if( ! tmpchar ) return true; // 禁則文字 if( ( tmpchar[ 0 ] == ',' ) || ( tmpchar[ 0 ] == '.' ) // UTF-8で"。" || ( tmpchar[ 0 ] == 0xe3 && tmpchar[ 1 ] == 0x80 && tmpchar[ 2 ] == 0x82 ) // UTF-8で"、" || ( tmpchar[ 0 ] == 0xe3 && tmpchar[ 1 ] == 0x80 && tmpchar[ 2 ] == 0x81 ) ) return false; return true; } } #endif jd-2.8.7-140104/src/article/drawareainfo.cpp0000644000076400010400000000125511454101100015136 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "drawareainfo.h" #include "fontid.h" using namespace ARTICLE; DrawAreaInfo::DrawAreaInfo( const std::string& url ) : DrawAreaBase( url ) { #ifdef _DEBUG std::cout << "DrawAreaInfo::DrawAreaInfo url = " << url << std::endl; #endif // フォント設定 set_fontid( FONT_ENTRY_DEFAULT ); // 文字色 set_colorid_text( COLOR_CHAR_ENTRY_DEFAULT ); // 背景色 set_colorid_back( COLOR_BACK_ENTRY_DEFAULT ); const bool show_abone = false; const bool show_scrbar = true; const bool show_multispace = false; setup( show_abone, show_scrbar, show_multispace ); } jd-2.8.7-140104/src/article/drawareainfo.h0000644000076400010400000000043310654637723014632 0ustar // ライセンス: GPL2 // 情報表示部 #ifndef _DRAWAREAINFO_H #define _DRAWAREAINFO_H #include "drawareabase.h" namespace ARTICLE { class DrawAreaInfo : public ARTICLE::DrawAreaBase { public: DrawAreaInfo( const std::string& url ); }; } #endif jd-2.8.7-140104/src/article/drawareamain.cpp0000644000076400010400000000071711454101100015131 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "drawareamain.h" using namespace ARTICLE; DrawAreaMain::DrawAreaMain( const std::string& url ) : DrawAreaBase( url ) { #ifdef _DEBUG std::cout << "DrawAreaMain::DrawAreaMain url = " << url << std::endl; #endif const bool show_abone = false; const bool show_scrbar = true; const bool show_multispace = false; setup( show_abone, show_scrbar, show_multispace ); } jd-2.8.7-140104/src/article/drawareamain.h0000644000076400010400000000043610540252733014612 0ustar // ライセンス: GPL2 // メイン表示部 #ifndef _DRAWAREAMAIN_H #define _DRAWAREAMAIN_H #include "drawareabase.h" namespace ARTICLE { class DrawAreaMain : public ARTICLE::DrawAreaBase { public: DrawAreaMain( const std::string& url ); }; } #endif jd-2.8.7-140104/src/article/drawareapopup.cpp0000644000076400010400000000276111454101100015351 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "drawareapopup.h" #include "config/globalconf.h" #include "colorid.h" #include "fontid.h" using namespace ARTICLE; // スクロールバーが付くとレイアウトがずれるのでクライアント領域の横幅をその分広げる enum { POPUP_OFFSET_Y = 1 }; // show_abone == true ならあぼーんされたスレも表示 DrawAreaPopup::DrawAreaPopup( const std::string& url, bool show_abone ) : DrawAreaBase( url ) { #ifdef _DEBUG std::cout << "DrawAreaPopup::DrawAreaPopup url = " << url << std::endl; #endif // フォント設定 set_fontid( FONT_POPUP ); // 背景色 set_colorid_back( COLOR_BACK_POPUP ); const bool show_scrbar = false; const bool show_multispace = true; setup( show_abone, show_scrbar, show_multispace ); set_draw_frame( true ); } // // レイアウト実行 // bool DrawAreaPopup::exec_layout() { #ifdef _DEBUG std::cout << "DrawAreaPopup::exec_layout() " << get_url() << std::endl; #endif // is_popup = true return exec_layout_impl( true, POPUP_OFFSET_Y ); } // // drawarea がリサイズした // // ポップアップの場合は先頭に戻る // bool DrawAreaPopup::slot_configure_event( GdkEventConfigure* event ) { if( ! is_drawarea_realized() ) return true; #ifdef _DEBUG std::cout << "DrawAreaPopup::slot_configure_event\n"; #endif if( exec_layout() ) redraw_view(); DrawAreaBase::goto_top(); return true; } jd-2.8.7-140104/src/article/drawareapopup.h0000644000076400010400000000110710613123466015026 0ustar // ライセンス: GPL2 // ポップアップの表示部 #ifndef _DRAWAREAPOPUP_H #define _DRAWAREAPOPUP_H #include "drawareabase.h" namespace ARTICLE { class DrawAreaPopup : public ARTICLE::DrawAreaBase { public: // show_abone == true ならあぼーんされたスレも表示 DrawAreaPopup( const std::string& url, bool show_abone ); protected: // レイアウト実行 virtual bool exec_layout(); // リサイズした virtual bool slot_configure_event( GdkEventConfigure* event ); }; } #endif jd-2.8.7-140104/src/article/embeddedimage.cpp0000644000076400010400000000736511302336425015254 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "embeddedimage.h" #include "articleadmin.h" #include "jdlib/imgloader.h" #include "jdlib/miscmsg.h" #include "dbimg/imginterface.h" #include "dbimg/img.h" #include "config/globalconf.h" #include "message/messageadmin.h" // // スレッドのランチャ // Glib::StaticMutex eimg_launcher_mutex = GLIBMM_STATIC_MUTEX_INIT; int redraw_counter = 0; // 0 になったとき再描画する void* eimg_launcher( void* dat ) { ++redraw_counter; // 遅いCPUの場合は同時に画像をリサイズしようとすると固まった様になるので // mutexをかけて同時にリサイズしないようにする Glib::Mutex::Lock lock( eimg_launcher_mutex ); #ifdef _DEBUG std::cout << "start eimg_launcher" << std::endl; #endif ARTICLE::EmbeddedImage* eimg = (ARTICLE::EmbeddedImage* )( dat ); eimg->resize_thread(); // 再描画 --redraw_counter; if( ! redraw_counter ){ ARTICLE::get_admin()->set_command( "redraw_current_view" ); MESSAGE::get_admin()->set_command( "redraw_current_view" ); } #ifdef _DEBUG std::cout << "end" << std::endl; #endif return 0; } ///////////////////////////////// using namespace ARTICLE; EmbeddedImage::EmbeddedImage( const std::string& url ) : m_url( url ), m_img ( DBIMG::get_img( m_url ) ) {} EmbeddedImage::~EmbeddedImage() { #ifdef _DEBUG std::cout << "EmbeddedImage::~EmbeddedImage url = " << m_url << std::endl; #endif // デストラクタの中からdispatchを呼ぶと落ちるので dispatch不可にする set_dispatchable( false ); stop(); wait(); } void EmbeddedImage::stop() { #ifdef _DEBUG std::cout << "EmbeddedImage::stop" << std::endl; #endif if( m_imgloader ) m_imgloader->request_stop(); } void EmbeddedImage::wait() { #ifdef _DEBUG std::cout << "EmbeddedImage::wait" << std::endl; #endif m_thread.join(); } void EmbeddedImage::show() { #ifdef _DEBUG std::cout << "EmbeddedImage::show url = " << m_url << std::endl; #endif if( m_thread.is_running() ) return; // 画像読み込み if( ! m_img->is_cached() ) return; const int width = m_img->get_width_emb(); const int height = m_img->get_height_emb(); if( ! width || ! height ) return; // スレッド起動して縮小 if( ! m_thread.create( eimg_launcher, ( void* )this, JDLIB::NODETACH ) ){ MISC::ERRMSG( "EmbeddedImage::show : could not start thread" ); } } // リサイズのスレッド void EmbeddedImage::resize_thread() { #ifdef _DEBUG std::cout << "EmbeddedImage::resize_thread url = " << m_url << std::endl; #endif const int width = m_img->get_width_emb(); const int height = m_img->get_height_emb(); std::string errmsg; bool pixbufonly = true; if( m_img->get_type() == DBIMG::T_BMP ) pixbufonly = false; // BMP の場合 pixbufonly = true にすると真っ黒になる m_imgloader = JDLIB::ImgLoader::get_loader( m_img->get_cache_path() ); Glib::RefPtr pixbuf = m_imgloader->get_pixbuf( pixbufonly ); if( pixbuf ){ Gdk::InterpType interptype = Gdk::INTERP_NEAREST; if( CONFIG::get_imgemb_interp() == 1 ) interptype = Gdk::INTERP_BILINEAR; else if( CONFIG::get_imgemb_interp() >= 2 ) interptype = Gdk::INTERP_HYPER; m_pixbuf = pixbuf->scale_simple( width, height, interptype ); } m_imgloader.clear(); // メインスレッドにリサイズが終わったことを知らせて // メインスレッドがpthread_join()を呼び出す // そうしないとメモリを食い潰す dispatch(); } // // ディスパッチャのコールバック関数 // void EmbeddedImage::callback_dispatch() { wait(); } jd-2.8.7-140104/src/article/embeddedimage.h0000644000076400010400000000161611275071177014723 0ustar // ライセンス: GPL2 // // 埋め込み画像クラス // #ifndef _EMVEDDEDIMAGE_H #define _EMVEDDEDIMAGE_H #include #include "skeleton/dispatchable.h" #include "jdlib/constptr.h" #include "jdlib/jdthread.h" #include "jdlib/imgloader.h" namespace DBIMG { class Img; } namespace ARTICLE { class EmbeddedImage : public SKELETON::Dispatchable { std::string m_url; Glib::RefPtr< Gdk::Pixbuf > m_pixbuf; JDLIB::ConstPtr< DBIMG::Img > m_img; JDLIB::Thread m_thread; Glib::RefPtr< JDLIB::ImgLoader > m_imgloader; public: EmbeddedImage( const std::string& url ); ~EmbeddedImage(); Glib::RefPtr< Gdk::Pixbuf > get_pixbuf(){ return m_pixbuf; } void show(); void resize_thread(); private: void stop(); void wait(); virtual void callback_dispatch(); }; } #endif jd-2.8.7-140104/src/article/font.cpp0000644000076400010400000000674412074477453013504 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "font.h" #include "jdlib/miscutil.h" #include "fontid.h" #include "config/globalconf.h" #include #include struct WIDTH_DATA { // 半角モードの時の幅 unsigned int *width; // 全角モードの時の幅 unsigned int width_wide; }; static WIDTH_DATA* width_of_char[ FONT_NUM ]; static bool strict_of_char = false; enum { UCS2_MAX = 65536 }; // // 初期化 // void ARTICLE::init_font() { // スレビューで文字幅の近似を厳密にするか strict_of_char = CONFIG::get_strict_char_width(); for( int i = 0; i< FONT_NUM ; i++ ){ if( width_of_char[ i ] ){ for( int j = 0; j < UCS2_MAX; ++j ){ if( width_of_char[ i ][ j ].width ) delete width_of_char[ i ][ j ].width; } delete width_of_char[ i ]; } width_of_char[ i ] = NULL; } } // // 登録された文字の幅を返す関数 // // utfstr : 入力文字 (UTF-8) // byte : 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す // pre_char : ひとつ前の文字 ( 前の文字が全角の場合は 0 ) // width : 半角モードでの幅 // width_wide : 全角モードでの幅 // mode : fontid.h で定義されているフォントのID // 戻り値 : 登録されていればtrue // const bool ARTICLE::get_width_of_char( const char* utfstr, int& byte, const char pre_char, int& width, int& width_wide, const int mode ) { byte = 0; width = 0; width_wide = 0; if( ! width_of_char[ mode ] ){ const int size = sizeof( WIDTH_DATA ) * UCS2_MAX; width_of_char[ mode ] = ( WIDTH_DATA* ) malloc( size ); memset( width_of_char[ mode ], 0, size ); } const int ucs2 = MISC::utf8toucs2( utfstr, byte ); if( byte && ucs2 < UCS2_MAX ){ // 全角モードの幅 width_wide = width_of_char[ mode ][ ucs2 ].width_wide; // 半角モードの幅 width = width_wide; // 厳密に求める場合 if( byte == 1 && strict_of_char ){ if( ! width_of_char[ mode ][ ucs2 ].width ){ const int size = sizeof( unsigned int ) * 128; width_of_char[ mode ][ ucs2 ].width = ( unsigned int* ) malloc( size ); memset( width_of_char[ mode ][ ucs2 ].width, 0, size ); } const int pre_char_num = ( const int ) pre_char; if( pre_char_num < 128 ) width = width_of_char[ mode ][ ucs2 ].width[ pre_char_num ]; } } if( width && width_wide ) return true; else if( width == -1 ){ // フォント幅の取得に失敗した場合 width = width_wide = 0; return true; } return false; } // // 文字幅を登録する関数 // // width == -1 はフォント幅の取得に失敗した場合 // void ARTICLE::set_width_of_char( const char* utfstr, int& byte, const char pre_char, const int width, const int width_wide, const int mode ) { const int ucs2 = MISC::utf8toucs2( utfstr, byte ); if( ! byte ) return; if( ucs2 >= UCS2_MAX ) return; // 半角モードの幅を厳密に求める場合 if( byte == 1 && strict_of_char ){ const int pre_char_num = ( const int ) pre_char; if( pre_char_num < 128 ) width_of_char[ mode ][ ucs2 ].width[ pre_char_num ] = width; } // 全角モードの幅 width_of_char[ mode ][ ucs2 ].width_wide = width_wide; } jd-2.8.7-140104/src/article/font.h0000644000076400010400000000200011202316254013105 0ustar // ライセンス: GPL2 // 文字の幅とかを記録しておくデータベース #ifndef _FONT_H #define _FONT_H namespace ARTICLE { void init_font(); // 登録された文字の幅を返す関数 // utfstr : 入力文字 (UTF-8) // byte : 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す // pre_char : ひとつ前の文字 ( 前の文字が全角の場合は 0 ) // width : 半角モードでの幅 // width_wide : 全角モードでの幅 // mode : fontid.h で定義されているフォントのID // 戻り値 : 登録されていればtrue const bool get_width_of_char( const char* utfstr, int& byte, const char pre_char, int& width, int& width_wide, const int mode ); // 文字幅を登録する関数 // width == -1 はフォント幅の取得に失敗した場合 void set_width_of_char( const char* utfstr, int& byte, const char pre_char, const int width, const int width_wide, const int mode ); } #endif jd-2.8.7-140104/src/article/layouttree.cpp0000644000076400010400000004205012131312267014702 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "layouttree.h" #include "dbtree/interface.h" #include "dbtree/articlebase.h" #include "dbtree/nodetreedummy.h" #include "jdlib/miscutil.h" #include "config/globalconf.h" #include "global.h" #include "colorid.h" #include "fontid.h" #include "cssmanager.h" enum { SIZE_OF_HEAP = 256 * 1024, STEP_ID = 10, STEP_SEPARATOR = 1, MAX_IMGITEM = 512 // struct IMGDATA.item[] のサイズ }; // 埋め込み画像用構造体 namespace ARTICLE { struct IMGITEM { char* link; DBTREE::NODE* node; }; struct IMGDATA { IMGITEM item[ MAX_IMGITEM ]; int num; }; } using namespace ARTICLE; // show_abone : true ならあぼーんしたレスも表示する // show_multispace : true なら連続空白ノードも表示 LayoutTree::LayoutTree( const std::string& url, const bool show_abone, const bool show_multispace ) : m_heap( SIZE_OF_HEAP ), m_url( url ), m_vec_header( NULL ), m_local_nodetree( 0 ), m_separator_header( NULL ), m_show_abone( show_abone ), m_show_multispace( show_multispace ) { #ifdef _DEBUG std::cout << "LayoutTree::LayoutTree : url = " << url << " show_abone = " << m_show_abone << std::endl; #endif m_article = DBTREE::get_article( m_url ); assert( m_article ); clear(); } LayoutTree::~LayoutTree() { #ifdef _DEBUG std::cout << "LayoutTree::~LayoutTree : url = " << m_url << std::endl; #endif clear(); } void LayoutTree::clear() { m_heap.clear(); m_vec_header = NULL; m_last_header = NULL; m_max_res_number = 0; m_id_header = -STEP_ID; // ルートヘッダのIDが 0 になるように -STEP_ID を入れておく m_root_header = create_layout_header(); if( m_local_nodetree ) delete m_local_nodetree; m_local_nodetree = NULL; m_last_div = NULL; // 新着セパレータ作成 m_separator_new = 0; m_separator_new_reserve = 0; m_separator_header = create_separator(); } // RECTANGLE型のメモリ確保 RECTANGLE* LayoutTree::create_rect() { RECTANGLE* rect = ( RECTANGLE* ) m_heap.heap_alloc( sizeof( RECTANGLE ) ); rect->end = true; return rect; } // // 基本レイアウトノード作成 // LAYOUT* LayoutTree::create_layout( const int type ) { LAYOUT* tmplayout = ( LAYOUT* ) m_heap.heap_alloc( sizeof( LAYOUT ) ); tmplayout->type = type; tmplayout->id_header = m_id_header; tmplayout->id = m_id_layout++; tmplayout->header = m_last_header; tmplayout->div = m_last_div; return tmplayout; } // // ヘッダノード作成 // // ヘッダ自体もdiv要素 // LAYOUT* LayoutTree::create_layout_header() { m_last_layout = NULL; m_id_layout = 0; m_id_header += STEP_ID; int classid = CORE::get_css_manager()->get_classid( "res" ); LAYOUT* header = create_layout_div( classid ); header->type = DBTREE::NODE_HEADER; m_last_layout = header; if( m_last_header ) m_last_header->next_header = header; m_last_header = header; header->header = header; return header; } // // テキストノード作成 // LAYOUT* LayoutTree::create_layout_text( const char* text, const unsigned char* color_text, bool bold ) { LAYOUT* tmplayout = create_layout( DBTREE::NODE_TEXT ); m_last_layout->next_layout = tmplayout; m_last_layout = tmplayout; tmplayout->text = text; tmplayout->color_text = color_text; tmplayout->bold = bold; return tmplayout; } // // リンクノード作成 // LAYOUT* LayoutTree::create_layout_link( const char* text, const char* link, const unsigned char* color_text, bool bold ) { LAYOUT* tmplayout = create_layout_text( text, color_text, bold ); tmplayout->type = DBTREE::NODE_LINK; tmplayout->link = link; return tmplayout; } // 発言回数(IDの出現数)ノード // LAYOUT* LayoutTree::create_layout_idnum( const char* text, const unsigned char* color_text, bool bold ) { LAYOUT* tmplayout = create_layout_text( text, color_text, bold ); tmplayout->type = DBTREE::NODE_IDNUM; return tmplayout; } // // 改行ノード作成 // LAYOUT* LayoutTree::create_layout_br() { LAYOUT* tmplayout = create_layout( DBTREE::NODE_BR ); m_last_layout->next_layout = tmplayout; m_last_layout = tmplayout; return tmplayout; } // // 水平線ノード作成 // LAYOUT* LayoutTree::create_layout_hr() { LAYOUT* tmplayout = create_layout( DBTREE::NODE_HR ); m_last_layout->next_layout = tmplayout; m_last_layout = tmplayout; return tmplayout; } // // 水平スペースノード作成 // LAYOUT* LayoutTree::create_layout_hspace( const int type ) { LAYOUT* tmplayout = create_layout( type ); m_last_layout->next_layout = tmplayout; m_last_layout = tmplayout; return tmplayout; } // // divノード作成 // LAYOUT* LayoutTree::create_layout_div( const int id ) { LAYOUT* div = create_layout( DBTREE::NODE_DIV ); if( m_last_layout ) m_last_layout->next_layout = div; m_last_layout = div; m_last_div = div; div->css = ( CORE::CSS_PROPERTY* ) m_heap.heap_alloc( sizeof( CORE::CSS_PROPERTY ) ); *div->css = CORE::get_css_manager()->get_property( id ); return div; } // // img ノード作成 // LAYOUT* LayoutTree::create_layout_img( const char* link ) { LAYOUT* tmplayout = create_layout( DBTREE::NODE_IMG ); m_last_layout->next_layout = tmplayout; m_last_layout = tmplayout; tmplayout->link = link; return tmplayout; } // // sssp ノード作成 // LAYOUT* LayoutTree::create_layout_sssp( const char* link ) { LAYOUT* tmplayout = create_layout_img( link ); tmplayout->type = DBTREE::NODE_SSSP; return tmplayout; } // // nodetreeのノード構造をコピーし、レイアウトツリーの一番最後に加える // // joint == true の時はヘッダを作らないで、本文を前のツリーの続きに連結する // void LayoutTree::append_node( DBTREE::NODE* node_header, const bool joint ) { if( ! node_header ) return; DBTREE::HEADERINFO* headinfo = node_header->headinfo; if( ! headinfo ) return; const int res_number = node_header->id_header; #ifdef _DEBUG std::cout << "LayoutTree::append_node num = " << res_number << " show_abone = " << m_show_abone << std::endl; #endif // あぼーん if( ! m_article->empty() && ! m_show_abone && m_article->get_abone( res_number ) ){ append_abone_node( node_header ); return; } // 連結モード // 本文ブロックだけ追加 if( joint ){ create_layout_br(); append_block( headinfo->block[ DBTREE::BLOCK_MES ], res_number, NULL ); } else{ const CORE::DOM* dom = CORE::get_css_manager()->get_dom(); IMGDATA imgdata; imgdata.num = 0; LAYOUT* header = create_layout_header(); header->res_number = res_number; header->node = node_header; if( res_number > m_max_res_number ) m_max_res_number = res_number; if( ! m_vec_header ) m_vec_header = ( LAYOUT** ) m_heap.heap_alloc( sizeof( LAYOUT* ) * MAX_RESNUMBER ); m_vec_header[ res_number ] = header; while( dom ){ switch( dom->nodetype ){ case CORE::DOMNODE_DIV: create_layout_div( dom->dat ); break; case CORE::DOMNODE_BLOCK: append_block( headinfo->block[ dom->dat ], res_number, &imgdata ); break; case CORE::DOMNODE_TEXT: create_layout_text( dom->chardat, NULL, false ); break; case CORE::DOMNODE_IMAGE: // インライン画像 if( imgdata.num && CONFIG::get_use_inline_image() ){ #ifdef _DEBUG std::cout << "LayoutTree::append_node : create image\n"; #endif create_layout_br(); create_layout_br(); for( int i = 0; i < imgdata.num; ++i ){ #ifdef _DEBUG std::cout << imgdata.item[ i ].link << std::endl; #endif LAYOUT* tmplayout = create_layout_img( imgdata.item[ i ].link ); tmplayout->res_number = res_number; tmplayout->link = imgdata.item[ i ].link; tmplayout->node = imgdata.item[ i ].node; } } break; } dom = dom->next_dom; } } } // // 名前やメールなどのブロックのコピー // void LayoutTree::append_block( DBTREE::NODE* block, const int res_number, IMGDATA* imgdata ) { if( ! block ) return; DBTREE::NODE* tmpnode = block->next_node; while( tmpnode ){ LAYOUT* tmplayout = NULL; switch( tmpnode->type ){ case DBTREE::NODE_TEXT: tmplayout = create_layout_text( tmpnode->text, &tmpnode->color_text, tmpnode->bold ); break; case DBTREE::NODE_LINK: tmplayout = create_layout_link( tmpnode->text, tmpnode->linkinfo->link, &tmpnode->color_text, tmpnode->bold ); // 画像リンクのurlを集める if( imgdata && tmpnode->linkinfo->imglink && imgdata->num < MAX_IMGITEM ){ imgdata->item[ imgdata->num ].link = tmpnode->linkinfo->imglink; imgdata->item[ imgdata->num++ ].node = tmpnode; } break; case DBTREE::NODE_SSSP: if( CONFIG::get_show_ssspicon() ){ tmplayout = create_layout_sssp( tmpnode->linkinfo->link ); tmplayout->link = tmpnode->linkinfo->link; } else{ // 次が改行ノードの時は飛ばす if( tmpnode->next_node && tmpnode->next_node->type == DBTREE::NODE_BR ) tmpnode = tmpnode->next_node; } break; case DBTREE::NODE_IDNUM: tmplayout = create_layout_idnum( tmpnode->text, &tmpnode->color_text, tmpnode->bold ); break; case DBTREE::NODE_BR: tmplayout = create_layout_br(); break; case DBTREE::NODE_HR: tmplayout = create_layout_hr(); break; case DBTREE::NODE_ZWSP: // 幅0スペース tmplayout = create_layout_hspace( tmpnode->type ); break; case DBTREE::NODE_MULTISP: // 連続半角スペース if( m_show_multispace ) tmplayout = create_layout_text( tmpnode->text, &tmpnode->color_text, tmpnode->bold ); break; case DBTREE::NODE_HTAB: // 水平タブ tmplayout = create_layout_hspace( tmpnode->type ); break; } if( tmplayout ){ tmplayout->res_number = res_number; tmplayout->node = tmpnode; } tmpnode = tmpnode->next_node; } } // // レイアウトツリーの一番最後にあぼーんノード追加 // void LayoutTree::append_abone_node( DBTREE::NODE* node_header ) { const int res_number = node_header->id_header; if( res_number > m_max_res_number ) m_max_res_number = res_number; if( ! m_vec_header ) m_vec_header = ( LAYOUT** ) m_heap.heap_alloc( sizeof( LAYOUT* ) * MAX_RESNUMBER ); #ifdef _DEBUG std::cout << "LayoutTree::append_abone_node num = " << res_number << std::endl; #endif // 透明あぼーん if( ! m_show_abone && m_article->get_abone_transparent() ) return; LAYOUT* head = create_layout_header(); m_vec_header[ res_number ] = head; head->res_number = res_number; int classid = CORE::get_css_manager()->get_classid( "title" ); create_layout_div( classid ); DBTREE::NODE* node = node_header->headinfo->block[ DBTREE::BLOCK_NUMBER ]->next_node; create_layout_link( node->text, node->linkinfo->link, &node->color_text, node->bold ); create_layout_text( " ", NULL, false ); create_layout_link( "あぼ〜ん", PROTO_ABONE, NULL, false ); classid = CORE::get_css_manager()->get_classid( "mes" ); create_layout_div( classid ); create_layout_link( "あぼ〜ん", PROTO_ABONE, NULL, false ); } // // HTML追加 // // 一時的にローカルなノードツリーを作ってHTMLをパースして append_node() で作ったノードをコピー // void LayoutTree::append_html( const std::string& html ) { #ifdef _DEBUG std::cout << "LayoutTree::append_html url = " << m_url << " html = " << html << std::endl; #endif if( ! m_local_nodetree ) m_local_nodetree = new DBTREE::NodeTreeDummy( m_url ); DBTREE::NODE* node_header = m_local_nodetree->append_html( html ); LAYOUT* header = create_layout_header(); header->node = node_header; int classid = CORE::get_css_manager()->get_classid( "comment" ); *header->css = CORE::get_css_manager()->get_property( classid ); append_block( node_header->headinfo->block[ DBTREE::BLOCK_MES ], 0, NULL ); } // // dat追加 // // 一時的にローカルなノードツリーを作ってdatをパースして append_node() で作ったノードをコピー // num: レス番号、0なら通し番号で // void LayoutTree::append_dat( const std::string& dat, int num ) { if( dat.empty() ) return; if( ! m_local_nodetree ) m_local_nodetree = new DBTREE::NodeTreeBase( m_url, std::string() ); // ダミーのノードを作って番号を調整する int res_num = m_local_nodetree->get_res_number(); if( num && res_num < num ){ for(int i = res_num +1 ; i <= num -1; ++i ) m_local_nodetree->append_dat( "<>broken<>\n" ); } // 改行毎に dat を分割して追加 std::list< std::string > lines = MISC::get_lines( dat ); std::list< std::string >::iterator it = lines.begin(); for( ; it != lines.end(); ++it ){ if( ! ( *it ).empty() ){ DBTREE::NODE* node = m_local_nodetree->append_dat( (*it) + "\n" ); append_node( node, false ); } } } // // レス番号 number のヘッダを返す // const LAYOUT* LayoutTree::get_header_of_res_const( const int number ){ return get_header_of_res( number ); } LAYOUT* LayoutTree::get_header_of_res( const int number ) { if( ! m_vec_header ) return NULL; if( number > m_max_res_number || number <= 0 ) return NULL; return m_vec_header[ number ]; } // // 新着セパレータ作成 // LAYOUT* LayoutTree::create_separator() { m_last_layout = NULL; m_id_layout = 0; int classid = CORE::get_css_manager()->get_classid( "separator" ); LAYOUT* header = create_layout_div( classid ); header->type = DBTREE::NODE_HEADER; DBTREE::NODE* node = ( DBTREE::NODE* ) m_heap.heap_alloc( sizeof( DBTREE::NODE ) ); node->fontid = FONT_DEFAULT; // デフォルトフォントを設定 header->node = node; if( header->css->bg_color < 0 ) header->css->bg_color = COLOR_SEPARATOR_NEW; LAYOUT* layout = create_layout_text( "ここまで読んだ", NULL, false ); layout->header = header; return header; } // // 新着セパレータ移動 // void LayoutTree::move_separator() { int num = m_separator_new_reserve; #ifdef _DEBUG std::cout << "LayoutTree::set_separator num = " << num << " max = " << m_max_res_number << std::endl; #endif if( num == m_separator_new ) return; // header_before と header_after の間に挿入する LAYOUT* header_before; LAYOUT* header_after; hide_separator(); if( ! num ) return; // 透明あぼーんしているレスは飛ばす int num_tmp = num; while( ! ( header_after = get_header_of_res( num_tmp ) ) && num_tmp++ < m_max_res_number ); if( ! header_after ) return; num_tmp = num-1; while( ! ( header_before = get_header_of_res( num_tmp ) ) && num_tmp-- > 1 ); if( ! header_before ) return; m_separator_new = num; header_before->next_header = m_separator_header; m_separator_header->next_header = header_after; // セパレータのヘッダID変更 int id_header = header_before->id_header + STEP_SEPARATOR; LAYOUT* layout = m_separator_header; while( layout ){ layout->id_header = id_header; layout = layout->next_layout; } #ifdef _DEBUG std::cout << "set before = " << num_tmp << " after = " << m_separator_new << std::endl; #endif } // // 新着セパレータ消去 // void LayoutTree::hide_separator() { // 表示中なら取り除く if( m_separator_new ){ #ifdef _DEBUG std::cout << "LayoutTree::hide_separator num = " << m_separator_new << " next = " << m_separator_header->next_header->res_number << std::endl; #endif // あぼーんしているレスは飛ばす LAYOUT* header_before; int num_tmp = m_separator_new -1;; while( ! ( header_before = get_header_of_res( num_tmp ) ) && num_tmp-- > 1 ); if( header_before ) header_before->next_header = m_separator_header->next_header; } m_separator_new = 0; } jd-2.8.7-140104/src/article/layouttree.h0000644000076400010400000001337011454101100014337 0ustar // ライセンス: GPL2 // 実際の描画レイアウト時に使うノードのツリー構造クラス #ifndef _LAYOUTTREE_H #define _LAYOUTTREE_H #include #include "jdlib/refptr_lock.h" #include "jdlib/heap.h" #include "cssmanager.h" namespace DBTREE { class ArticleBase; class NodeTreeBase; struct NODE; } namespace ARTICLE { class EmbeddedImage; struct IMGDATA; // 描画時のノードの座標情報 struct RECTANGLE { bool end; RECTANGLE* next_rect; // テキストノードでwrapが起きたらリストで繋ぐ int x; int y; int width; int height; int align; // テキストノードで使用する情報 int pos_start; int n_byte; int n_ustr; }; // 描画レイアウト用ノード struct LAYOUT { unsigned char type; // dbtree/node.hで定義されているノードタイプ int id_header; // ヘッダ番号、コメントなどもあるので必ずしも id_header = res_number とはならない int id; // ヘッダノードから順に 0,1,2,.. int res_number; // スレ内のレス番号、0の時はコメント LAYOUT* header; // 親ヘッダーへのポインタ LAYOUT* div; // 所属するdivへのポインタ LAYOUT* next_layout; // 次のノード、最終ノードではNULL LAYOUT* next_header; // 次のヘッダノード、ヘッダノード以外ではNULL RECTANGLE* rect; // 描画時のノード座標、幅、高さ情報 CORE::CSS_PROPERTY* css; // cssプロパティ DBTREE::NODE* node; // 文字情報( 実際にはノード情報(DBTREE::NODE)のtext情報へのポインタ) const char* text; int lng_text; // テキストの長さ const char* link; const unsigned char* color_text; bool bold; // 埋め込み画像のポインタ // deleteは DrawAreaBase::clear()でおこなう EmbeddedImage* eimg; }; // レイアウトツリー class LayoutTree { // 高速化のため直接アクセス JDLIB::RefPtr_Lock< DBTREE::ArticleBase > m_article; JDLIB::HEAP m_heap; std::string m_url; LAYOUT** m_vec_header; // ヘッダのポインタの配列 // コメントノードやプレビュー表示時に使うローカルなノードツリー DBTREE::NodeTreeBase* m_local_nodetree; LAYOUT* m_root_header; LAYOUT* m_last_header; LAYOUT* m_last_layout; LAYOUT* m_last_div; // 新着セパレータ LAYOUT* m_separator_header; // 新着セパレータの位置(レス番号), 0の時は表示していない int m_separator_new; int m_separator_new_reserve; // これにレス番号をセットしてから move_separator()を呼ぶ // 表示中の最大のレス番号 int m_max_res_number; int m_id_header; int m_id_layout; // true ならあぼーんしたレスも表示 bool m_show_abone; // true なら連続空白ノードも表示 bool m_show_multispace; public: // show_abone : true ならあぼーんしたレスも表示する // show_multispace : true なら連続空白ノードも表示 LayoutTree( const std::string& url, const bool show_abone, const bool show_multispace ); ~LayoutTree(); void clear(); // RECTANGLE型のメモリ確保 RECTANGLE* create_rect(); LAYOUT* top_header() const { return m_root_header->next_header; } const LAYOUT* last_header() const { return m_last_header; } const int max_res_number() const { return m_max_res_number; } const LAYOUT* get_separator() const{ return m_separator_header; } // nodetreeのノード構造をコピーし、ツリーの一番最後に加える // joint == true の時はヘッダを作らないで、本文を前のツリーの続きに連結する void append_node( DBTREE::NODE* node_header, const bool joint ); void append_block( DBTREE::NODE* block, const int res_number, IMGDATA* imgdata ); // html をパースして追加 void append_html( const std::string& html ); // dat をパースして追加 void append_dat( const std::string& dat, int num ); // レス番号 number のヘッダを返す const LAYOUT* get_header_of_res_const( const int number ); LAYOUT* get_header_of_res( const int number ); // 新着セパレータ移動 // set_separator_new()にレス番号をセットしてからmove_separator()を呼ぶ void set_separator_new( int num ){ m_separator_new_reserve = num; } void move_separator(); void hide_separator(); const int get_separator_new() const { return m_separator_new; } private: LAYOUT* create_layout( const int type ); LAYOUT* create_layout_header(); LAYOUT* create_layout_text( const char* text, const unsigned char* color_text, bool bold ); LAYOUT* create_layout_link( const char* text, const char* link, const unsigned char* color_text, bool bold ); LAYOUT* create_layout_idnum( const char* text, const unsigned char* color_text, bool bold ); LAYOUT* create_layout_br(); LAYOUT* create_layout_hr(); LAYOUT* create_layout_hspace( const int type ); LAYOUT* create_layout_div( const int id ); LAYOUT* create_layout_img( const char* link ); LAYOUT* create_layout_sssp( const char* link ); void append_abone_node( DBTREE::NODE* node_header ); LAYOUT* create_separator(); }; } #endif jd-2.8.7-140104/src/article/Makefile.am0000644000076400010400000000162512072045132014036 0ustar noinst_LIBRARIES = libarticle.a libarticle_a_SOURCES = \ articleadmin.cpp \ \ drawareabase.cpp \ drawareamain.cpp \ drawareainfo.cpp \ drawareapopup.cpp \ embeddedimage.cpp \ \ articleviewbase.cpp \ articleview.cpp \ articleviewsearch.cpp \ articleviewpreview.cpp \ articleviewinfo.cpp \ articleviewpopup.cpp \ articleviewetc.cpp \ \ layouttree.cpp \ font.cpp \ preference.cpp \ toolbar.cpp \ toolbarsimple.cpp \ toolbarsearch.cpp noinst_HEADERS = \ articleadmin.h \ \ drawareabase.h \ drawareamain.h \ drawareainfo.h \ drawareapopup.h \ embeddedimage.h \ \ articleviewbase.h \ articleview.h \ articleviewsearch.h \ articleviewpreview.h \ articleviewinfo.h \ articleviewpopup.h \ articleviewetc.h \ \ layouttree.h \ font.h \ preference.h \ caret.h \ scrollinfo.h \ toolbar.h \ toolbarsimple.h \ toolbarsearch.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/article/preference.cpp0000644000076400010400000002736011615011401014622 0ustar // ライセンス: GPL2 #include "preference.h" #include "dbtree/interface.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "config/globalconf.h" #include "skeleton/msgdiag.h" #include "cache.h" #include "command.h" #include #include using namespace ARTICLE; Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std::string command ) : SKELETON::PrefDiag( parent, url ) ,m_label_name( false, "スレタイトル : ", DBTREE::article_subject( get_url() ) ) ,m_label_url( false, "スレのURL : ", DBTREE:: url_readcgi( get_url(),0,0 ) ) ,m_label_url_dat( false, "DATファイルのURL : ", DBTREE:: url_dat( get_url() ) ) ,m_label_cache( false, "ローカルキャッシュパス : ", std::string() ) ,m_label_size( false, "サイズ( byte / Kbyte ) : ", std::string() ) ,m_check_transpabone( "透明あぼ〜ん" ) ,m_check_chainabone( "連鎖あぼ〜ん" ) ,m_check_ageabone( "sage以外をあぼ〜ん" ) ,m_check_boardabone( "板レベルでのあぼ〜んを有効にする" ) ,m_check_globalabone( "全体レベルでのあぼ〜んを有効にする" ) ,m_label_since( false, "スレ立て日時 : ", std::string() ) ,m_label_modified( false, "最終更新日時 : ", std::string() ) ,m_button_clearmodified( "日時クリア" ) ,m_label_write( false, "最終書き込み日時 : ", std::string() ) ,m_bt_clear_post_history( "書き込み履歴クリア" ) ,m_label_write_name( false, "名前 : ", std::string() ) ,m_label_write_mail( false, "メール : ", std::string() ) { // 一般 if( DBTREE::article_is_cached( get_url() ) ){ int size = DBTREE::article_lng_dat( get_url() ); m_label_cache.set_text( CACHE::path_dat( get_url() ) ); m_label_size.set_text( MISC::itostr( size ) + " / " + MISC::itostr( size/1024 ) ); if( DBTREE::article_date_modified( get_url() ).empty() ) m_label_modified.set_text( "未取得" ); else m_label_modified.set_text( MISC::timettostr( DBTREE::article_time_modified( get_url() ), MISC::TIME_WEEK ) + " ( " + MISC::timettostr( DBTREE::article_time_modified( get_url() ), MISC::TIME_PASSED ) + " )" ); if( DBTREE::article_write_time( get_url() ) ) m_label_write.set_text( MISC::timettostr( DBTREE::article_write_time( get_url() ), MISC::TIME_WEEK ) + " ( " + MISC::timettostr( DBTREE::article_write_time( get_url() ), MISC::TIME_PASSED ) + " )" ); } m_label_since.set_text( MISC::timettostr( DBTREE::article_since_time( get_url() ), MISC::TIME_WEEK ) + " ( " + MISC::timettostr( DBTREE::article_since_time( get_url() ), MISC::TIME_PASSED ) + " )" ); m_button_clearmodified.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_clear_modified ) ); m_hbox_modified.pack_start( m_label_modified ); m_hbox_modified.pack_start( m_button_clearmodified, Gtk::PACK_SHRINK ); m_bt_clear_post_history.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_clear_post_history ) ); m_hbox_write.pack_start( m_label_write ); m_hbox_write.pack_start( m_bt_clear_post_history, Gtk::PACK_SHRINK ); m_vbox_info.set_border_width( 16 ); m_vbox_info.set_spacing( 8 ); m_vbox_info.pack_start( m_label_name, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_url, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_url_dat, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_cache, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_size, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_since, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_hbox_modified, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_hbox_write, Gtk::PACK_SHRINK ); if( DBTREE::write_fixname( get_url() ) ) m_label_write_name.set_text( DBTREE::write_name( get_url() ) ); if( DBTREE::write_fixmail( get_url() ) ) m_label_write_mail.set_text( DBTREE::write_mail( get_url() ) ); m_vbox_info.pack_start( m_label_write_name, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_write_mail, Gtk::PACK_SHRINK ); // あぼーん設定 m_vbox_abone.set_border_width( 16 ); m_vbox_abone.set_spacing( 8 ); // 透明あぼーん m_check_transpabone.set_active( DBTREE::get_abone_transparent( get_url() ) ); // 連鎖あぼーん m_check_chainabone.set_active( DBTREE::get_abone_chain( get_url() ) ); // ageあぼーん m_check_ageabone.set_active( DBTREE::get_abone_age( get_url() ) ); // 板レベルあぼーん m_check_boardabone.set_active( DBTREE::get_abone_board( get_url() ) ); // 全体レベルあぼーん m_check_globalabone.set_active( DBTREE::get_abone_global( get_url() ) ); if( CONFIG::get_abone_transparent() ) m_check_transpabone.set_sensitive( false ); if( CONFIG::get_abone_chain() ) m_check_chainabone.set_sensitive( false ); m_vbox_abone.pack_start( m_check_transpabone, Gtk::PACK_SHRINK ); m_vbox_abone.pack_start( m_check_chainabone, Gtk::PACK_SHRINK ); m_vbox_abone.pack_start( m_check_ageabone, Gtk::PACK_SHRINK ); m_vbox_abone.pack_start( m_check_boardabone, Gtk::PACK_SHRINK ); m_vbox_abone.pack_start( m_check_globalabone, Gtk::PACK_SHRINK ); if( CONFIG::get_abone_transparent() || CONFIG::get_abone_chain() ){ m_label_abone.set_text( "チェック出来ない場合は設定メニューから「デフォルトで透明/連鎖あぼ〜ん」を解除して下さい" ); m_label_abone.set_alignment( Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER ); m_vbox_abone.pack_start( m_label_abone, Gtk::PACK_SHRINK ); } if( DBTREE::article_is_cached( get_url() ) ){ std::string str_id, str_res, str_name, str_word, str_regex; std::list< std::string >::iterator it; // id std::list< std::string > list_id = DBTREE::get_abone_list_id( get_url() ); for( it = list_id.begin(); it != list_id.end(); ++it ) if( ! ( *it ).empty() ) str_id += ( *it ) + "\n"; m_edit_id.set_text( str_id ); // あぼーんレス番号 // 連番は 12-34 の様なフォーマットに変換 std::vector< char > vec_res = DBTREE::get_abone_vec_res( get_url() ); std::vector< char >::iterator it_res = vec_res.begin(); int res = 0; int pre_res = 0; int count = 0; for( ; it_res != vec_res.end(); ++res ){ if( ( *it_res ) ){ if( ! pre_res ) pre_res = res; ++count; } ++it_res; if( !( *it_res ) || it_res == vec_res.end() ){ if( pre_res ){ str_res += MISC::itostr( pre_res ); if( count > 1 ) str_res += "-" + MISC::itostr( pre_res + count -1 ); str_res += "\n"; pre_res = 0; count = 0; } } } m_edit_res.set_text( str_res ); // name std::list< std::string > list_name = DBTREE::get_abone_list_name( get_url() ); for( it = list_name.begin(); it != list_name.end(); ++it ) if( ! ( *it ).empty() ) str_name += ( *it ) + "\n"; m_edit_name.set_text( str_name ); // word std::list< std::string > list_word = DBTREE::get_abone_list_word( get_url() ); for( it = list_word.begin(); it != list_word.end(); ++it ) if( ! ( *it ).empty() ) str_word += ( *it ) + "\n"; m_edit_word.set_text( str_word ); // regex std::list< std::string > list_regex = DBTREE::get_abone_list_regex( get_url() ); for( it = list_regex.begin(); it != list_regex.end(); ++it ) if( ! ( *it ).empty() ) str_regex += ( *it ) + "\n"; m_edit_regex.set_text( str_regex ); } else{ m_edit_id.set_editable( false ); m_edit_res.set_editable( false ); m_edit_name.set_editable( false ); m_edit_word.set_editable( false ); m_edit_regex.set_editable( false ); } m_label_abone_id.set_text( "ここでIDを削除してもレスが表示されない場合は板全体に対してIDがあぼーん指定されている可能性があります。\n板のプロパティのあぼーん設定も確認してください。" ); m_vbox_abone.set_spacing( 8 ); m_vbox_abone_id.pack_start( m_label_abone_id, Gtk::PACK_SHRINK ); m_vbox_abone_id.pack_start( m_edit_id ); m_notebook_abone.append_page( m_vbox_abone, "一般" ); m_notebook_abone.append_page( m_vbox_abone_id, "NG ID" ); m_notebook_abone.append_page( m_edit_res, "NG レス番号" ); m_notebook_abone.append_page( m_edit_name, "NG 名前" ); m_notebook_abone.append_page( m_edit_word, "NG ワード" ); m_notebook_abone.append_page( m_edit_regex, "NG 正規表現" ); m_notebook.append_page( m_vbox_info, "一般" ); const int page_abone = 1; m_notebook.append_page( m_notebook_abone, "あぼ〜ん設定" ); get_vbox()->pack_start( m_notebook ); set_title( "「" + DBTREE::article_subject( get_url() ) + "」のプロパティ" ); resize( 600, 400 ); show_all_children(); if( command == "show_abone" ) m_notebook.set_current_page( page_abone ); } Preferences::~Preferences() {} // // OK 押した // void Preferences::slot_ok_clicked() { // あぼーん再設定 std::list< std::string > list_id = MISC::get_lines( m_edit_id.get_text() ); std::list< std::string > list_name = MISC::get_lines( m_edit_name.get_text() ); std::list< std::string > list_word = MISC::get_lines( m_edit_word.get_text() ); std::list< std::string > list_regex = MISC::get_lines( m_edit_regex.get_text() ); // あぼーんレス番号 std::vector< char > vec_abone_res; vec_abone_res.resize( DBTREE::article_number_load( get_url() ) + 1 ); std::list< std::string > list_res = MISC::get_lines( m_edit_res.get_text() ); std::list< std::string >::iterator it = list_res.begin(); for( ; it != list_res.end(); ++it ){ std::string num_str = ( *it ); int number = atoi( num_str.c_str() ); if( number >= 1 ){ int number_end = number; size_t pos = num_str.find( "-" ); if( pos != std::string::npos ) number_end = MIN( (int)vec_abone_res.size(), MAX( number, atoi( num_str.substr( pos + 1 ).c_str() ) ) ); for( int i = number; i <= number_end; ++i ) vec_abone_res[ i ] = true; } } DBTREE::reset_abone( get_url(), list_id, list_name, list_word, list_regex, vec_abone_res , m_check_transpabone.get_active(), m_check_chainabone.get_active(), m_check_ageabone.get_active(), m_check_boardabone.get_active(), m_check_globalabone.get_active() ); // viewの再レイアウト CORE::core_set_command( "relayout_article", get_url() ); } void Preferences::slot_clear_modified() { DBTREE::article_set_date_modified( get_url(), "" ); if( DBTREE::article_date_modified( get_url() ).empty() ) m_label_modified.set_text( "未取得" ); else m_label_modified.set_text( MISC::timettostr( DBTREE::article_time_modified( get_url() ), MISC::TIME_WEEK ) + " ( " + MISC::timettostr( DBTREE::article_time_modified( get_url() ), MISC::TIME_PASSED ) + " )" ); } void Preferences::slot_clear_post_history() { if( m_label_write.get_text().empty() ) return; SKELETON::MsgDiag mdiag( NULL, "書き込み履歴を削除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; DBTREE::article_clear_post_history( get_url() ); m_label_write.set_text( "" ); CORE::core_set_command( "redraw_article" ); // BoardViewの行を更新 CORE::core_set_command( "update_board_item", DBTREE::url_subject( get_url() ), DBTREE::article_id( get_url() ) ); } jd-2.8.7-140104/src/article/preference.h0000644000076400010400000000376511615011401014272 0ustar // ライセンス: GPL2 #ifndef _ARTICLE_PREFERENCES_H #define _ARTICLE_PREFERENCES_H #include "skeleton/prefdiag.h" #include "skeleton/editview.h" #include "skeleton/label_entry.h" namespace ARTICLE { class Preferences : public SKELETON::PrefDiag { Gtk::Notebook m_notebook; // 情報 Gtk::VBox m_vbox_info; SKELETON::LabelEntry m_label_name; SKELETON::LabelEntry m_label_url; SKELETON::LabelEntry m_label_url_dat; SKELETON::LabelEntry m_label_cache; SKELETON::LabelEntry m_label_size; // あぼーん Gtk::VBox m_vbox_abone; Gtk::Notebook m_notebook_abone; Gtk::VBox m_vbox_abone_id; Gtk::Label m_label_abone_id; SKELETON::EditView m_edit_id, m_edit_res, m_edit_name, m_edit_word, m_edit_regex; Gtk::Label m_label_abone; // 透明あぼーん Gtk::CheckButton m_check_transpabone; // 連鎖あぼーん Gtk::CheckButton m_check_chainabone; // ageあぼーん Gtk::CheckButton m_check_ageabone; // 板レベルでのあぼーん Gtk::CheckButton m_check_boardabone; // 全体レベルでのあぼーん Gtk::CheckButton m_check_globalabone; SKELETON::LabelEntry m_label_since; // 最終更新日時 Gtk::HBox m_hbox_modified; SKELETON::LabelEntry m_label_modified; Gtk::Button m_button_clearmodified; // 書き込み日時 Gtk::HBox m_hbox_write; SKELETON::LabelEntry m_label_write; Gtk::Button m_bt_clear_post_history; // 名前とメール SKELETON::LabelEntry m_label_write_name; SKELETON::LabelEntry m_label_write_mail; public: Preferences( Gtk::Window* parent, const std::string& url, const std::string command ); virtual ~Preferences(); private: virtual void slot_ok_clicked(); void slot_clear_modified(); void slot_clear_post_history(); }; } #endif jd-2.8.7-140104/src/article/scrollinfo.h0000644000076400010400000000347511421057575014345 0ustar // ライセンス: GPL2 // スクロール情報 #ifndef _SCROLLINFO_H #define _SCROLLINFO_H namespace ARTICLE { // スクロールモード enum { SCROLL_NOT = 0, SCROLL_NORMAL, // dy の量だけ 1 回だけスクロール SCROLL_LOCKED, // 常に dy の量だけスクロール SCROLL_TO_NUM, // レス番号 res にジャンプ SCROLL_TO_TOP, // 先頭にジャンプ SCROLL_TO_BOTTOM, // 最後にジャンプ SCROLL_TO_Y, // y 座標にジャンプ SCROLL_AUTO // マーカを中心にしてオートスクロール }; class SCROLLINFO { public: int mode; int dy; // スクロール量 int res; // レス番号 // オートスクロールモード(マウスの中ボタン押し)用の変数 int x; // 中心のx座標 int y; // 中心のy座標 bool show_marker; // true ならマーカを出す bool enable_up; // true なら上方向にスクロール可 bool enable_down; // true なら下方向にスクロール可 bool autoscroll_finished; // オートスクロールが終わった // > 0 の間はモーションイベントをキャンセルする int counter_nomotion; // 実況モード用変数 bool live; double live_speed; int live_counter; SCROLLINFO() : live( false ) { reset(); } void reset() { mode = SCROLL_NOT; dy = 0; res = 0; x = 0; y = 0; show_marker = false; enable_up = false; enable_down = false; autoscroll_finished = false; counter_nomotion = 0; } }; } #endif jd-2.8.7-140104/src/article/toolbar.cpp0000644000076400010400000001347111570731371014163 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "toolbar.h" #include "articleadmin.h" #include "articleviewbase.h" #include "skeleton/imgtoggletoolbutton.h" #include "control/controlutil.h" #include "control/controlid.h" #include "icons/iconmanager.h" #include "command.h" #include "session.h" #include "compmanager.h" #include "global.h" using namespace ARTICLE; ArticleToolBar::ArticleToolBar() : SKELETON::ToolBar( ARTICLE::get_admin() ), m_enable_slot( true ), m_button_drawout_and( ICON::SEARCH_AND ), m_button_drawout_or( ICON::SEARCH_OR ), m_button_live_play_stop( NULL ) { // 検索バー set_tooltip( m_button_drawout_and, CONTROL::get_label_motions( CONTROL::DrawOutAnd ) ); set_tooltip( m_button_drawout_or, CONTROL::get_label_motions( CONTROL::DrawOutOr ) ); get_searchbar()->append( *get_tool_search( CORE::COMP_SEARCH_ARTICLE ) ); get_searchbar()->append( *get_button_down_search() ); get_searchbar()->append( *get_button_up_search() ); get_searchbar()->append( m_button_drawout_and ); get_searchbar()->append( m_button_drawout_or ); get_searchbar()->append( *get_button_clear_highlight() ); get_searchbar()->append( *get_button_close_searchbar() ); m_button_drawout_or.signal_clicked().connect( sigc::mem_fun(*this, &ArticleToolBar::slot_drawout_or ) ); m_button_drawout_and.signal_clicked().connect( sigc::mem_fun(*this, &ArticleToolBar::slot_drawout_and ) ); pack_buttons(); } // // タブが切り替わった時にDragableNoteBook::set_current_toolbar()から呼び出される( Viewの情報を取得する ) // // virtual void ArticleToolBar::set_view( SKELETON::View * view ) { SKELETON::ToolBar::set_view( view ); m_enable_slot = false; // ArticleViewBase固有の情報をコピー ArticleViewBase* articleview = dynamic_cast< ArticleViewBase* >( view ); if( articleview ){ m_url_article = articleview->url_article(); if( m_button_live_play_stop ){ bool sensitive = true; if( ! articleview->get_enable_live() ) sensitive = false; m_button_live_play_stop->set_sensitive( sensitive ); if( articleview->get_live() ) m_button_live_play_stop->set_active( true ); else m_button_live_play_stop->set_active( false ); } } m_enable_slot = true; } // // ボタンのパッキング // // virtual void ArticleToolBar::pack_buttons() { int num = 0; for(;;){ int item = SESSION::get_item_article_toolbar( num ); if( item == ITEM_END ) break; switch( item ){ case ITEM_WRITEMSG: get_buttonbar().append( *get_button_write() ); break; case ITEM_OPENBOARD: get_buttonbar().append( *get_button_board() ); break; case ITEM_NAME: pack_transparent_separator(); get_buttonbar().append( *get_label() ); pack_transparent_separator(); break; case ITEM_SEARCH: get_buttonbar().append( *get_button_open_searchbar() ); break; case ITEM_RELOAD: get_buttonbar().append( *get_button_reload() ); break; case ITEM_STOPLOADING: get_buttonbar().append( *get_button_stop() ); break; case ITEM_APPENDFAVORITE: get_buttonbar().append( *get_button_favorite() ); set_tooltip( *get_button_favorite(), CONTROL::get_label_motions( CONTROL::AppendFavorite ) + "\n\nスレのタブをお気に入りに直接D&Dしても登録可能" ); break; case ITEM_DELETE: get_buttonbar().append( *get_button_delete() ); break; case ITEM_QUIT: get_buttonbar().append( *get_button_close() ); break; case ITEM_BACK: get_buttonbar().append( *get_button_back() ); break; case ITEM_FORWARD: get_buttonbar().append( *get_button_forward() ); break; case ITEM_LOCK: get_buttonbar().append( *get_button_lock() ); break; case ITEM_LIVE: if( ! m_button_live_play_stop ){ m_button_live_play_stop = Gtk::manage( new SKELETON::ImgToggleToolButton( ICON::LIVE ) ); set_tooltip( *m_button_live_play_stop, CONTROL::get_label_motions( CONTROL::LiveStartStop ) ); m_button_live_play_stop->set_label( CONTROL::get_label( CONTROL::LiveStartStop ) ); m_button_live_play_stop->signal_clicked().connect( sigc::mem_fun(*this, &ArticleToolBar::slot_live_play_stop ) ); } get_buttonbar().append( *m_button_live_play_stop ); break; case ITEM_SEPARATOR: pack_separator(); break; } ++num; } set_relief(); show_all_children(); } // // キーワード抽出 (AND) // void ArticleToolBar::slot_drawout_and() { if( ! m_enable_slot ) return; std::string query = get_search_text(); if( query.empty() ) return; CORE::core_set_command( "open_article_keyword" ,m_url_article, query, "false" ); } // // キーワード抽出 (OR) // void ArticleToolBar::slot_drawout_or() { if( ! m_enable_slot ) return; std::string query = get_search_text(); if( query.empty() ) return; CORE::core_set_command( "open_article_keyword" ,m_url_article, query, "true" ); } // // 実況開始/停止 // void ArticleToolBar::slot_live_play_stop() { if( ! m_enable_slot ) return; ARTICLE::get_admin()->set_command( "live_start_stop", get_url() ); } jd-2.8.7-140104/src/article/toolbar.h0000644000076400010400000000220211570731371013616 0ustar // ライセンス: GPL2 // ツールバーのクラス // // ARTICLE::ArticleView* 以外では使わない // #ifndef _ARTICLE_TOOLBAR_H #define _ARTICLE_TOOLBAR_H #include "skeleton/toolbar.h" #include "skeleton/imgtoolbutton.h" namespace SKELETON { class ImgToggleToolButton; } namespace ARTICLE { class ArticleToolBar : public SKELETON::ToolBar { std::string m_url_article; bool m_enable_slot; SKELETON::ImgToolButton m_button_drawout_and; SKELETON::ImgToolButton m_button_drawout_or; // 実況 SKELETON::ImgToggleToolButton* m_button_live_play_stop; public: ArticleToolBar(); virtual ~ArticleToolBar(){} // タブが切り替わった時に呼び出される( Viewの情報を取得する ) virtual void set_view( SKELETON::View * view ); protected: virtual void pack_buttons(); // ボタンを押したときのslot関数 void slot_open_board(); void slot_drawout_and(); void slot_drawout_or(); void slot_clear_highlight(); void slot_live_play_stop(); }; } #endif jd-2.8.7-140104/src/article/toolbarsearch.cpp0000644000076400010400000000577011571723321015351 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "toolbarsearch.h" #include "articleadmin.h" #include "articleviewsearch.h" #include "skeleton/compentry.h" #include "control/controlutil.h" #include "control/controlid.h" #include "compmanager.h" #include "session.h" #include "global.h" using namespace ARTICLE; SearchToolBar::SearchToolBar() : SKELETON::ToolBar( ARTICLE::get_admin() ), m_searchview( NULL ), m_check_bm( "しおり" ) { m_tool_bm.add( m_check_bm ); m_tool_bm.set_expand( false ); m_check_bm.signal_toggled().connect( sigc::mem_fun(*this, &SearchToolBar::slot_toggle_bm ) ); // 検索バー get_searchbar()->append( *get_tool_search( CORE::COMP_SEARCH_ARTICLE ) ); get_searchbar()->append( m_tool_bm ); get_searchbar()->append( *get_button_close_searchbar() ); pack_buttons(); } // // ボタンのパッキング // void SearchToolBar::pack_buttons() { int num = 0; for(;;){ int item = SESSION::get_item_search_toolbar( num ); if( item == ITEM_END ) break; switch( item ){ case ITEM_NAME: pack_transparent_separator(); get_buttonbar().append( *get_label() ); pack_transparent_separator(); break; case ITEM_SEARCH: get_buttonbar().append( *get_button_open_searchbar() ); break; case ITEM_RELOAD: get_buttonbar().append( *get_button_reload() ); set_tooltip( *get_button_reload(), "再検索 " + CONTROL::get_str_motions( CONTROL::Reload ) ); break; case ITEM_STOPLOADING: get_buttonbar().append( *get_button_stop() ); set_tooltip( *get_button_stop(), "検索中止 " + CONTROL::get_str_motions( CONTROL::StopLoading ) ); break; case ITEM_QUIT: get_buttonbar().append( *get_button_close() ); break; case ITEM_SEPARATOR: pack_separator(); break; } ++num; } set_relief(); show_all_children(); } // // タブが切り替わった時にDragableNoteBook::set_current_toolbar()から呼び出される( Viewの情報を取得する ) // // virtual void SearchToolBar::set_view( SKELETON::View * view ) { SKELETON::ToolBar::set_view( view ); m_enable_slot = false; // ArticleViewSearch固有の情報をコピー m_searchview = dynamic_cast< ArticleViewSearch* >( view ); if( m_searchview ){ if( m_searchview->get_enable_bm() ){ m_check_bm.set_sensitive( true ); m_check_bm.set_active( m_searchview->get_bm() ); } else{ m_check_bm.set_sensitive( false ); m_check_bm.set_active( false ); } } m_enable_slot = true; } void SearchToolBar::slot_toggle_bm() { if( ! m_enable_slot ) return; if( m_searchview ) m_searchview->set_bm( m_check_bm.get_active() ); } jd-2.8.7-140104/src/article/toolbarsearch.h0000644000076400010400000000150411376762460015017 0ustar // ライセンス: GPL2 // ログ検索などのツールバーのクラス // // ARTICLE::ArticleViewSearch 以外では使わない // #ifndef _ARTICLE_TOOLBARSEARCH_H #define _ARTICLE_TOOLBARSEARCH_H #include "skeleton/toolbar.h" namespace ARTICLE { class ArticleViewSearch; class SearchToolBar : public SKELETON::ToolBar { ArticleViewSearch* m_searchview; bool m_enable_slot; Gtk::ToolItem m_tool_bm; Gtk::CheckButton m_check_bm; public: SearchToolBar(); virtual ~SearchToolBar(){} // タブが切り替わった時に呼び出される( Viewの情報を取得する ) virtual void set_view( SKELETON::View * view ); protected: virtual void pack_buttons(); private: void slot_toggle_bm(); }; } #endif jd-2.8.7-140104/src/article/toolbarsimple.cpp0000644000076400010400000000173411376762460015403 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "toolbarsimple.h" #include "articleadmin.h" #include "compmanager.h" using namespace ARTICLE; ArticleToolBarSimple::ArticleToolBarSimple() : SKELETON::ToolBar( ARTICLE::get_admin() ) { // 検索バー get_searchbar()->append( *get_tool_search( CORE::COMP_SEARCH_ARTICLE ) ); get_searchbar()->append( *get_button_down_search() ); get_searchbar()->append( *get_button_up_search() ); get_searchbar()->append( *get_button_close_searchbar() ); pack_buttons(); } // // ボタンのパッキング // void ArticleToolBarSimple::pack_buttons() { pack_transparent_separator(); get_buttonbar().append( *get_label() ); get_buttonbar().append( *get_button_open_searchbar() ); get_buttonbar().append( *get_button_reload() ); get_buttonbar().append( *get_button_stop() ); get_buttonbar().append( *get_button_close() ); set_relief(); show_all_children(); } jd-2.8.7-140104/src/article/toolbarsimple.h0000644000076400010400000000063311376762460015045 0ustar // ライセンス: GPL2 // 簡易版ツールバーのクラス #ifndef _ARTICLE_TOOLBARSIMPLE_H #define _ARTICLE_TOOLBARSIMPLE_H #include "skeleton/toolbar.h" namespace ARTICLE { class ArticleToolBarSimple : public SKELETON::ToolBar { public: ArticleToolBarSimple(); virtual ~ArticleToolBarSimple(){} protected: virtual void pack_buttons(); }; } #endif jd-2.8.7-140104/src/articleitemmenupref.cpp0000644000076400010400000000403611567465065015151 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articleitemmenupref.h" #include "icons/iconmanager.h" #include "skeleton/msgdiag.h" #include "global.h" #include "session.h" #include "command.h" using namespace CORE; ArticleItemMenuPref::ArticleItemMenuPref( Gtk::Window* parent, const std::string& url ) : SKELETON::SelectItemPref( parent, url ) { // デフォルトの項目を設定 append_default_pair( ITEM_NAME_DRAWOUT ); append_default_pair( ITEM_NAME_GO ); append_default_pair( ITEM_NAME_SEARCH ); append_default_pair( ITEM_NAME_NGWORD ); append_default_pair( ITEM_NAME_QUOTE_SELECTION ); append_default_pair( ITEM_NAME_OPEN_BROWSER ); append_default_pair( ITEM_NAME_USER_COMMAND ); append_default_pair( ITEM_NAME_COPY_URL ); append_default_pair( ITEM_NAME_COPY_TITLE_URL_THREAD ); append_default_pair( ITEM_NAME_COPY ); append_default_pair( ITEM_NAME_ETC ); append_default_pair( ITEM_NAME_RELOAD ); append_default_pair( ITEM_NAME_DELETE ); append_default_pair( ITEM_NAME_SAVE_DAT ); append_default_pair( ITEM_NAME_COPY_THREAD_INFO ); append_default_pair( ITEM_NAME_APPENDFAVORITE ); append_default_pair( ITEM_NAME_ABONE_SELECTION ); append_default_pair( ITEM_NAME_SELECTIMG ); append_default_pair( ITEM_NAME_SELECTDELIMG ); append_default_pair( ITEM_NAME_SELECTABONEIMG ); append_default_pair( ITEM_NAME_PREF_THREAD ); append_default_pair( ITEM_NAME_SEPARATOR ); // 文字列を元に行を追加 append_rows( SESSION::get_items_article_menu_str() ); set_title( "コンテキストメニュー項目設定(スレビュー)" ); } // // OKを押した // void ArticleItemMenuPref::slot_ok_clicked() { SKELETON::MsgDiag mdiag( NULL, "次に開いたスレビューから有効になります" ); mdiag.run(); SESSION::set_items_article_menu_str( get_items() ); } // // デフォルトボタン // void ArticleItemMenuPref::slot_default() { append_rows( SESSION::get_items_article_menu_default_str() ); } jd-2.8.7-140104/src/articleitemmenupref.h0000644000076400010400000000112011235056116014566 0ustar // ライセンス: GPL2 // スレビューのコンテキストメニューの表示項目設定 #ifndef _ARTICLEITEMMENUPREF_H #define _ARTICLEITEMMENUPREF_H #include "skeleton/selectitempref.h" namespace CORE { class ArticleItemMenuPref : public SKELETON::SelectItemPref { public: ArticleItemMenuPref( Gtk::Window* parent, const std::string& url ); virtual ~ArticleItemMenuPref(){} private: // OKボタン virtual void slot_ok_clicked(); // デフォルトボタン virtual void slot_default(); }; } #endif jd-2.8.7-140104/src/articleitempref.cpp0000644000076400010400000000371711506370702014253 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articleitempref.h" #include "icons/iconmanager.h" #include "global.h" #include "session.h" #include "command.h" using namespace CORE; ArticleItemPref::ArticleItemPref( Gtk::Window* parent, const std::string& url ) : SKELETON::SelectItemPref( parent, url ) { // デフォルトの項目を設定 append_default_pair( ITEM_NAME_WRITEMSG, ICON::get_icon( ICON::WRITE ) ); append_default_pair( ITEM_NAME_OPENBOARD, ICON::get_icon( ICON::TRANSPARENT ) ); append_default_pair( ITEM_NAME_NAME, ICON::get_icon( ICON::TRANSPARENT ) ); append_default_pair( ITEM_NAME_SEARCH, ICON::get_icon( ICON::SEARCH ) ); append_default_pair( ITEM_NAME_RELOAD, ICON::get_icon( ICON::RELOAD ) ); append_default_pair( ITEM_NAME_STOPLOADING, ICON::get_icon( ICON::STOPLOADING ) ); append_default_pair( ITEM_NAME_APPENDFAVORITE, ICON::get_icon( ICON::APPENDFAVORITE ) ); append_default_pair( ITEM_NAME_DELETE, ICON::get_icon( ICON::DELETE ) ); append_default_pair( ITEM_NAME_QUIT, ICON::get_icon( ICON::QUIT ) ); append_default_pair( ITEM_NAME_BACK, ICON::get_icon( ICON::BACK ) ); append_default_pair( ITEM_NAME_FORWARD, ICON::get_icon( ICON::FORWARD ) ); append_default_pair( ITEM_NAME_LOCK, ICON::get_icon( ICON::LOCK ) ); append_default_pair( ITEM_NAME_LIVE, ICON::get_icon( ICON::LIVE ) ); append_default_pair( ITEM_NAME_SEPARATOR, ICON::get_icon( ICON::TRANSPARENT ) ); // 文字列を元に行を追加 append_rows( SESSION::get_items_article_toolbar_str() ); set_title( "ツールバー項目設定(スレビュー)" ); } // // OKを押した // void ArticleItemPref::slot_ok_clicked() { SESSION::set_items_article_toolbar_str( get_items() ); CORE::core_set_command( "update_article_toolbar_button" ); } // // デフォルトボタン // void ArticleItemPref::slot_default() { append_rows( SESSION::get_items_article_toolbar_default_str() ); } jd-2.8.7-140104/src/articleitempref.h0000644000076400010400000000105411235056116013707 0ustar // ライセンス: GPL2 // スレビューのツールバーの表示項目設定 #ifndef _ARTICLEITEMPREF_H #define _ARTICLEITEMPREF_H #include "skeleton/selectitempref.h" namespace CORE { class ArticleItemPref : public SKELETON::SelectItemPref { public: ArticleItemPref( Gtk::Window* parent, const std::string& url ); virtual ~ArticleItemPref(){} private: // OKボタン virtual void slot_ok_clicked(); // デフォルトボタン virtual void slot_default(); }; } #endif jd-2.8.7-140104/src/bbslist/0000755000076400010400000000000012261751613012025 5ustar jd-2.8.7-140104/src/bbslist/addetcdialog.cpp0000644000076400010400000000233211357364652015145 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "addetcdialog.h" #include "command.h" #include "session.h" using namespace BBSLIST; AddEtcDialog::AddEtcDialog( const bool move, const std::string& url, const std::string& name, const std::string& id, const std::string& passwd ) : SKELETON::PrefDiag( NULL, url, true ), m_entry_name( true, "板名(_N):", name ), m_entry_url( true, "アドレス(_U):", url ), m_entry_id( true, "ID(_I):", id ), m_entry_pw( true, "パスワード(_P):", passwd ) { resize( 600, 1 ); m_vbox.set_spacing( 8 ); m_vbox.set_border_width( 8 ); m_vbox.add( m_entry_id ); m_vbox.add( m_entry_pw ); set_activate_entry( m_entry_id ); set_activate_entry( m_entry_pw ); m_frame.set_label( "BASIC認証" ); m_frame.add( m_vbox ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_entry_name ); get_vbox()->pack_start( m_entry_url ); get_vbox()->pack_start( m_frame ); set_activate_entry( m_entry_name ); set_activate_entry( m_entry_url ); if( move ){ set_title( "外部板編集" ); } else{ set_title( "外部板追加" ); } show_all_children(); } jd-2.8.7-140104/src/bbslist/addetcdialog.h0000644000076400010400000000165711114236125014603 0ustar // ライセンス: GPL2 // // 外部板追加ダイアログ // #ifndef _ADDETCDIALOG_H #define _ADDETCDIALOG_H #include "skeleton/prefdiag.h" #include "skeleton/label_entry.h" namespace BBSLIST { class AddEtcDialog : public SKELETON::PrefDiag { SKELETON::LabelEntry m_entry_name; SKELETON::LabelEntry m_entry_url; Gtk::Frame m_frame; Gtk::VBox m_vbox; SKELETON::LabelEntry m_entry_id; SKELETON::LabelEntry m_entry_pw; public: AddEtcDialog( const bool move, const std::string& url, const std::string& _name, const std::string& _id, const std::string& _passwd ); const std::string get_name(){ return m_entry_name.get_text(); } const std::string get_url(){ return m_entry_url.get_text(); } const std::string get_id(){ return m_entry_id.get_text(); } const std::string get_passwd(){ return m_entry_pw.get_text(); } }; } #endif jd-2.8.7-140104/src/bbslist/bbslistadmin.cpp0000644000076400010400000002025212175137371015210 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "bbslistadmin.h" #include "bbslistviewbase.h" #include "toolbar.h" #include "skeleton/view.h" #include "skeleton/dragnote.h" #include "skeleton/undobuffer.h" #include "jdlib/miscutil.h" #include "global.h" #include "viewfactory.h" #include "session.h" #include "command.h" // お気に入りの共通UNDOバッファ SKELETON::UNDO_BUFFER *instance_undo_buffer_favorite = NULL; SKELETON::UNDO_BUFFER* BBSLIST::get_undo_buffer_favorite() { if( ! instance_undo_buffer_favorite ) instance_undo_buffer_favorite = new SKELETON::UNDO_BUFFER(); assert( instance_undo_buffer_favorite ); return instance_undo_buffer_favorite; } void BBSLIST::delete_undo_buffer_favorite() { if( instance_undo_buffer_favorite ) delete instance_undo_buffer_favorite; instance_undo_buffer_favorite = NULL; } ////////////////////////////////////////////// BBSLIST::BBSListAdmin *instance_bbslistadmin = NULL; BBSLIST::BBSListAdmin* BBSLIST::get_admin() { if( ! instance_bbslistadmin ) instance_bbslistadmin = new BBSLIST::BBSListAdmin( URL_BBSLISTADMIN ); assert( instance_bbslistadmin ); return instance_bbslistadmin; } void BBSLIST::delete_admin() { if( instance_bbslistadmin ) delete instance_bbslistadmin; instance_bbslistadmin = NULL; } ////////////////////////////////////////////// using namespace BBSLIST; BBSListAdmin::BBSListAdmin( const std::string& url ) : SKELETON::Admin( url ), m_toolbar( NULL ) { get_notebook()->set_dragable( false ); get_notebook()->set_fixtab( true ); } BBSListAdmin::~BBSListAdmin() { #ifdef _DEBUG std::cout << "BBSListAdmin::~BBSListAdmin\n"; #endif if( m_toolbar ) delete m_toolbar; BBSLIST::delete_undo_buffer_favorite(); } void BBSListAdmin::save_session() { Admin::save_session(); // bbslistのページの位置保存 SESSION::set_bbslist_page( get_current_page() ); } // 前回開いていたURLを復元 void BBSListAdmin::restore( const bool only_locked ) { COMMAND_ARGS command_arg; // 板一覧 // 初回起動時は板一覧の読み込みもここで行われる command_arg = url_to_openarg( URL_BBSLISTVIEW, true, false ); open_view( command_arg ); // お気に入り command_arg = url_to_openarg( URL_FAVORITEVIEW, true, false ); open_view( command_arg ); // スレ履歴 command_arg = url_to_openarg( URL_HISTTHREADVIEW, true, false ); open_view( command_arg ); // 板履歴 command_arg = url_to_openarg( URL_HISTBOARDVIEW, true, false ); open_view( command_arg ); // 最近閉じたスレ command_arg = url_to_openarg( URL_HISTCLOSEVIEW, true, false ); open_view( command_arg ); // 最近閉じた板 command_arg = url_to_openarg( URL_HISTCLOSEBOARDVIEW, true, false ); open_view( command_arg ); // 最近閉じた画像 command_arg = url_to_openarg( URL_HISTCLOSEIMGVIEW, true, false ); open_view( command_arg ); set_command( "set_page", std::string(), MISC::itostr( SESSION::bbslist_page() ) ); set_command( "hide_tabs" ); } COMMAND_ARGS BBSListAdmin::url_to_openarg( const std::string& url, const bool tab, const bool lock ) { COMMAND_ARGS command_arg; command_arg.command = "open_view"; command_arg.url = url; if( tab ) command_arg.arg1 = "true"; // タブで開く return command_arg; } void BBSListAdmin::switch_admin() { if( ! has_focus() ) CORE::core_set_command( "switch_sidebar" ); } // // ツールバー表示 // void BBSListAdmin::show_toolbar() { // まだ作成されていない場合は作成する if( ! m_toolbar ){ m_toolbar = new BBSListToolBar(); get_notebook()->append_toolbar( *m_toolbar ); if( SESSION::get_show_bbslist_toolbar() ) m_toolbar->open_buttonbar(); } get_notebook()->show_toolbar(); } // // ツールバー表示/非表示切り替え // void BBSListAdmin::toggle_toolbar() { if( ! m_toolbar ) return; if( SESSION::get_show_bbslist_toolbar() ){ m_toolbar->open_buttonbar(); m_toolbar->show_toolbar(); } else m_toolbar->close_buttonbar(); } SKELETON::View* BBSListAdmin::create_view( const COMMAND_ARGS& command ) { int type = CORE::VIEW_NONE; if( command.url == URL_BBSLISTVIEW ) type = CORE::VIEW_BBSLISTVIEW; if( command.url == URL_FAVORITEVIEW ) type = CORE::VIEW_FAVORITELIST; if( command.url == URL_HISTTHREADVIEW ) type = CORE::VIEW_HISTTHREAD; if( command.url == URL_HISTCLOSEVIEW ) type = CORE::VIEW_HISTCLOSE; if( command.url == URL_HISTBOARDVIEW ) type = CORE::VIEW_HISTBOARD; if( command.url == URL_HISTCLOSEBOARDVIEW ) type = CORE::VIEW_HISTCLOSEBOARD; if( command.url == URL_HISTCLOSEIMGVIEW ) type = CORE::VIEW_HISTCLOSEIMG; CORE::VIEWFACTORY_ARGS view_args; view_args.arg1 = command.arg4; view_args.arg2 = command.arg5; SKELETON::View* view = CORE::ViewFactory( type, command.url, view_args ); return view; } // // ローカルなコマンド // void BBSListAdmin::command_local( const COMMAND_ARGS& command ) { SKELETON::View* view = get_view( command.url ); if( view ){ // アイテム追加 // 共有バッファにコピーデータをセットしておくこと if( command.command == "append_item" ) view->set_command( "append_item" ); // 履歴のセット // 先頭にアイテムを追加する。ツリーにアイテムが含まれている場合は移動する // 共有バッファにコピーデータをセットしておくこと else if( command.command == "append_history" ) view->set_command( "append_history" ); // 項目削除 else if( command.command == "remove_item" ) view->set_command( "remove_item", command.arg1 ); // 先頭項目削除 else if( command.command == "remove_headitem" ) view->set_command( "remove_headitem" ); // 全項目削除 else if( command.command == "remove_allitems" ) view->set_command( "remove_allitems" ); // ツリーの編集 else if( command.command == "edit_tree" ) view->set_command( "edit_tree" ); // お気に入りルート更新チェック else if( command.command == "check_update_root" ) view->set_command( "check_update_root" ); else if( command.command == "check_update_open_root" ) view->set_command( "check_update_open_root" ); else if( command.command == "cancel_check_update" ) view->set_command( "cancel_check_update" ); // お気に入りのスレの url と 名前を変更 else if( command.command == "replace_thread" ) view->set_command( "replace_thread", command.arg1, command.arg2 ); // XML保存 else if( command.command == "save_xml" ) view->set_command( "save_xml" ); // スレのアイコン表示を更新 else if( command.command == "toggle_articleicon" ) view->set_command( "toggle_articleicon", command.arg1 ); // 板のアイコン表示を更新 else if( command.command == "toggle_boardicon" ) view->set_command( "toggle_boardicon", command.arg1 ); // URLを選択 else if( command.command == "select_item" ) view->set_command( "select_item", command.arg1 ); } } // 履歴を DATA_INFO_LIST 型で取得 void BBSListAdmin::get_history( const std::string& url, CORE::DATA_INFO_LIST& info_list ) { info_list.clear(); BBSListViewBase* view = dynamic_cast< BBSListViewBase* >( get_view( url ) ); if( view ) return view->get_history( info_list ); } // サイドバーの指定したidのディレクトリに含まれるスレのアドレスを取得 void BBSListAdmin::get_threads( const std::string& url, const int dirid, std::vector< std::string >& list_url ) { list_url.clear(); BBSListViewBase* view = dynamic_cast< BBSListViewBase* >( get_view( url ) ); if( view ) view->get_threads( dirid, list_url ); } // サイドバーの指定したidのディレクトリの名前を取得 const std::string BBSListAdmin::get_dirname( const std::string& url, const int dirid ) { BBSListViewBase* view = dynamic_cast< BBSListViewBase* >( get_view( url ) ); if( view ) return view->get_dirname( dirid ); return std::string(); } jd-2.8.7-140104/src/bbslist/bbslistadmin.h0000644000076400010400000000410511542415626014653 0ustar // ライセンス: GPL2 // // 板の管理クラス // #ifndef _BBSLISTADMIN_H #define _BBSLISTADMIN_H #include "skeleton/admin.h" #include "type.h" #include "data_info.h" #include #include namespace SKELETON { class UNDO_BUFFER; } namespace BBSLIST { class BBSListToolBar; class BBSListAdmin : public SKELETON::Admin { BBSListToolBar* m_toolbar; public: BBSListAdmin( const std::string& url ); ~BBSListAdmin(); virtual void save_session(); // 履歴を DATA_INFO_LIST 型で取得 void get_history( const std::string& url, CORE::DATA_INFO_LIST& info_list ); // サイドバーの指定したidのディレクトリに含まれるスレのアドレスを取得 void get_threads( const std::string& url, const int dirid, std::vector< std::string >& list_url ); // サイドバーの指定したidのディレクトリの名前を取得 const std::string get_dirname( const std::string& url, const int dirid ); protected: SKELETON::View* create_view( const COMMAND_ARGS& command ); // ツールバー virtual void show_toolbar(); virtual void toggle_toolbar(); virtual void command_local( const COMMAND_ARGS& command ); virtual void restore( const bool only_locked ); virtual COMMAND_ARGS url_to_openarg( const std::string& url, const bool tab, const bool lock ); virtual void switch_admin(); // bbslistはクローズしない virtual void close_view( const std::string& url ){} virtual void close_all_view( const std::string& url ){} // タブの D&D 処理をしない virtual void slot_drag_data_get( Gtk::SelectionData& selection_data, const int page ){} // タブメニュー表示キャンセル virtual void slot_tab_menu( int page, int x, int y ){} }; BBSLIST::BBSListAdmin* get_admin(); void delete_admin(); SKELETON::UNDO_BUFFER* get_undo_buffer_favorite(); void delete_undo_buffer_favorite(); } #endif jd-2.8.7-140104/src/bbslist/bbslistview.cpp0000644000076400010400000001606111506370702015067 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "bbslistview.h" #include "bbslistadmin.h" #include "skeleton/msgdiag.h" #include "dbtree/interface.h" #include "config/globalconf.h" #include "jdlib/misctime.h" #include "cache.h" #include "type.h" #include "command.h" using namespace BBSLIST; // ルート要素名( boards.xml ) #define ROOT_NODE_NAME "boardlist" // メインビュー BBSListViewMain::BBSListViewMain( const std::string& url, const std::string& arg1, const std::string& arg2 ) : BBSListViewBase( url, arg1, arg2 ) { set_label( "板一覧" ); set_open_only_onedir( CONFIG::get_open_one_category() ); } BBSListViewMain::~BBSListViewMain() { #ifdef _DEBUG std::cout << "BBSListViewMain::~BBSListViewMain : " << get_url() << std::endl; #endif } // xml保存 void BBSListViewMain::save_xml() { const std::string file = CACHE::path_xml_listmain(); save_xml_impl( file, ROOT_NODE_NAME, SUBDIR_ETCLIST ); } // // 表示 // void BBSListViewMain::show_view() { #ifdef _DEBUG std::cout << "BBSListViewMain::show_view : " << get_url() << std::endl; #endif // BBSListViewBase::m_document に Root::m_xml_document を代入 set_document( DBTREE::get_xml_document() ); if( get_document().hasChildNodes() ) update_view(); // 板一覧のDomノードが空ならサーバからbbsmenuを取得 // 取得が終わったらBBSListViewMain::update_view()が呼び出される else DBTREE::download_bbsmenu(); } // // 表示更新 // void BBSListViewMain::update_view() { XML::Document document; document = DBTREE::get_xml_document(); // 空なら更新しない if( ! document.hasChildNodes() ) return; // BBSListViewBase::m_document に Root::m_document を代入 set_document( document ); // ルート要素を取得 XML::Dom* root = get_document().get_root_element( std::string( ROOT_NODE_NAME ) ); //---------------------------------- // 外部板追加 // を挿入 // ルート要素の有無で処理を分ける( 旧様式=無, 新様式=有 ) XML::Dom* subdir = 0; if( root ) subdir = root->insertBefore( XML::NODE_TYPE_ELEMENT, "subdir", root->firstChild() ); else subdir = get_document().insertBefore( XML::NODE_TYPE_ELEMENT, "subdir", get_document().firstChild() ); subdir->setAttribute( "name", std::string( SUBDIR_ETCLIST ) ); // 子要素( )を追加 std::list< DBTREE::ETCBOARDINFO > list_etc = DBTREE::get_etcboards(); // 外部板情報( dbtree/etcboardinfo.h ) if( ! list_etc.empty() ) { std::list< DBTREE::ETCBOARDINFO >::iterator it = list_etc.begin(); while( it != list_etc.end() ) { XML::Dom* board = subdir->appendChild( XML::NODE_TYPE_ELEMENT, "board" ); board->setAttribute( "name", (*it).name ); board->setAttribute( "url", (*it).url ); ++it; } } // 外部板追加ここまで //---------------------------------- // BBSListViewBase::xml2tree() m_document -> tree xml2tree( std::string( ROOT_NODE_NAME ) ); set_status( std::string() ); BBSLIST::get_admin()->set_command( "set_status", get_url(), get_status() ); } // // 削除 // // BBSListViewMainの場合は外部板の削除 // void BBSListViewMain::delete_view() { // 選択範囲に通常の板が含まれていないか確認 std::list< Gtk::TreeModel::iterator > list_it = get_treeview().get_selected_iterators(); std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); for( ; it != list_it.end(); ++it ){ if( ! is_etcboard( *it ) ){ SKELETON::MsgDiag mdiag( get_parent_win(), "通常の板は削除出来ません", false, Gtk::MESSAGE_ERROR ); mdiag.run(); return; } } SKELETON::MsgDiag mdiag( get_parent_win(), "削除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; delete_view_impl(); } // BBSListViewMainの場合は外部板の削除 void BBSListViewMain::delete_view_impl() { #ifdef _DEBUG std::cout << "BBSListViewMain::delete_view_impl\n"; #endif // データベースから外部板削除 std::list< Gtk::TreeModel::iterator > list_it = get_treeview().get_selected_iterators(); std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); for( ; it != list_it.end(); ++it ){ if( is_etcboard( *it ) ){ Gtk::TreePath path = get_treestore()->get_path( *it ); std::string url = path2rawurl( path ); std::string name = path2name( path ); #ifdef _DEBUG std::cout << "path = " << path.to_string() << std::endl << "url = " << url << std::endl << "name = " << name << std::endl; #endif DBTREE::remove_etc( url , name ); } } const bool force = true; // 強制的に削除 get_treeview().delete_selected_rows( force ); // etc.txt保存 DBTREE::save_etc(); } void BBSListViewMain::show_preference() { std::string modified = "最終更新日時 :"; if( DBTREE::get_date_modified().empty() ) modified += "未取得"; else modified += MISC::timettostr( DBTREE::get_time_modified(), MISC::TIME_WEEK ) + " ( " + MISC::timettostr( DBTREE::get_time_modified(), MISC::TIME_PASSED ) + " )"; SKELETON::MsgDiag mdiag( get_parent_win(), modified, false ); mdiag.set_title( "板一覧のプロパティ" ); mdiag.run(); } // // ポップアップメニュー取得 // // SKELETON::View::show_popupmenu() を参照すること // Gtk::Menu* BBSListViewMain::get_popupmenu( const std::string& url ) { Gtk::Menu* popupmenu = NULL; if( url.empty() ) return popupmenu; #ifdef _DEBUG std::cout << "BBSListViewMain::get_popupmenu\n"; #endif std::list< Gtk::TreeModel::iterator > list_it = get_treeview().get_selected_iterators(); if( list_it.size() == 1 ){ Gtk::TreePath path = *( get_treeview().get_selection()->get_selected_rows().begin() ); int type = path2type( path ); #ifdef _DEBUG std::cout << "path = " << path.to_string() << " type = " << type << std::endl; #endif if( type == TYPE_DIR ){ if( is_etcdir( path ) ) popupmenu = id2popupmenu( "/popup_menu_etcdir" ); else popupmenu = id2popupmenu( "/popup_menu_dir" ); } else if( type == TYPE_BOARD || type == TYPE_BOARD_UPDATE ){ if( is_etcboard( path ) ) popupmenu = id2popupmenu( "/popup_menu_etc" ); else popupmenu = id2popupmenu( "/popup_menu" ); } } else{ bool have_etc = true; std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); for( ; it != list_it.end(); ++it ){ if( ! is_etcboard( *it ) ){ have_etc = false; break; } } if( have_etc ) popupmenu = id2popupmenu( "/popup_menu_mul_etc" ); else popupmenu = id2popupmenu( "/popup_menu_mul" ); } return popupmenu; } jd-2.8.7-140104/src/bbslist/bbslistview.h0000644000076400010400000000142111506370702014526 0ustar // ライセンス: GPL2 // // メインビュー // #ifndef _BBSLISTVIEW_H #define _BBSLISTVIEW_H #include "bbslistviewbase.h" namespace BBSLIST { // メインビュー class BBSListViewMain : public BBSListViewBase { public: BBSListViewMain( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() ); virtual ~BBSListViewMain(); virtual void show_view(); virtual void update_view(); virtual void delete_view(); virtual void show_preference(); protected: // xml保存 virtual void save_xml(); virtual Gtk::Menu* get_popupmenu( const std::string& url ); private: virtual void delete_view_impl(); }; }; #endif jd-2.8.7-140104/src/bbslist/bbslistviewbase.cpp0000644000076400010400000026326112177057552015742 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _DEBUG_XML #include "jddebug.h" #include "gtkmmversion.h" #include "bbslistviewbase.h" #include "bbslistadmin.h" #include "selectdialog.h" #include "editlistwin.h" #include "addetcdialog.h" #include "skeleton/msgdiag.h" #include "jdlib/miscutil.h" #include "jdlib/miscgtk.h" #include "jdlib/jdregex.h" #include "dbtree/interface.h" #include "dbimg/imginterface.h" #include "icons/iconmanager.h" #include "xml/tools.h" #include "config/globalconf.h" #include "control/controlutil.h" #include "control/controlid.h" #include "cache.h" #include "command.h" #include "global.h" #include "httpcode.h" #include "sharedbuffer.h" #include "viewfactory.h" #include "prefdiagfactory.h" #include "colorid.h" #include "fontid.h" #include "updatemanager.h" #include "session.h" #include "compmanager.h" #include "dndmanager.h" #include "sign.h" enum { REPLACE_NEXT_NO = 0, REPLACE_NEXT_YES, REPLACE_NEXT_ADD }; // row -> path #define GET_PATH( row ) m_treestore->get_path( row ) // ポップアップメニュー表示 #define SHOW_POPUPMENU(slot) do{\ std::string url = path2url( m_path_selected ); \ if( ! m_path_selected.empty() && url.empty() ) url = "dummy_url"; \ show_popupmenu( url, slot ); \ }while(0) #define POPUPMENU_BOARD1 \ "" \ "" \ "" \ "" \ "" \ "" \ "" \ "" #define POPUPMENU_BOARD2 \ "" \ "" \ "" \ "" \ "" \ "" \ #define POPUPMENU_ARRANGE_BASE \ "" \ "" \ "" \ "" #define POPUPMENU_ARRANGE \ "" \ POPUPMENU_ARRANGE_BASE #define POPUPMENU_ARRANGEDIR \ "" \ POPUPMENU_ARRANGE_BASE #define POPUPMENU_DELETE \ "" \ "" \ "" #define POPUPMENU_SELECT \ "" \ "" \ "" \ "" \ "" \ "" \ "" \ POPUPMENU_ARRANGE \ "" \ POPUPMENU_DELETE \ "" \ "" \ "" \ "" \ "" \ "" \ "" \ "" using namespace BBSLIST; BBSListViewBase::BBSListViewBase( const std::string& url,const std::string& arg1, const std::string& arg2 ) : SKELETON::View( url ), m_treeview( url, DNDTARGET_FAVORITE, m_columns, true, CONFIG::get_fontname( FONT_BBS ), COLOR_CHAR_BBS, COLOR_BACK_BBS, COLOR_BACK_BBS_EVEN ), m_ready_tree( false ), m_clicked( false ), m_jump_y( -1 ), m_search_invert( false ), m_open_only_onedir( false ), m_cancel_expand( false ), m_expanding( 0 ), m_editlistwin( NULL ), m_set_bookmark( false ) { m_scrwin.add( m_treeview ); m_scrwin.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); pack_start( m_scrwin ); show_all_children(); m_treestore = Gtk::TreeStore::create( m_columns ); #if !GTKMM_CHECK_VERSION(2,7,0) // gtkmm26以下にはunset_model()が無いのでここでset_model()しておく // それ以上は m_treeview.xml2tree() でセットする m_treeview.set_treestore( m_treestore ); #endif // Gtk::TreeStoreでset_fixed_height_mode()を使うとexpandしたときに // スクロールバーが誤動作するので使わないこと /* #if GTK_CHECK_VERSION(2,6,0) // セルを固定の高さにする // append_column する前に columnに対して set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ) すること m_treeview.set_fixed_height_mode( true ); #ifdef _DEBUG std::cout << "BBSListViewBase::BBSListViewBase : m_treeview.set_fixed_height_mode\n"; #endif #endif */ // 共有UNDOバッファをセット m_treeview.set_undo_buffer( BBSLIST::get_undo_buffer_favorite() ); // 列の登録 m_treeview.create_column( CONFIG::get_tree_ypad() ); m_treeview.set_column_for_height( 0 ); #if GTKMM_CHECK_VERSION(2,12,0) // エクスパンダ表示とレベルインデント m_treeview.set_show_expanders( CONFIG::get_tree_show_expanders() ); m_treeview.set_level_indentation( CONFIG::get_tree_level_indent() ); #endif // treeviewのシグナルにコネクト m_treeview.signal_row_expanded().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_row_exp ) ); m_treeview.signal_row_collapsed().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_row_col ) ); m_treeview.sig_button_press().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_button_press ) ); m_treeview.sig_button_release().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_button_release ) ); m_treeview.sig_motion_notify().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_motion_notify ) ); m_treeview.sig_key_press().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_key_press ) ); m_treeview.sig_key_release().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_key_release ) ); m_treeview.sig_scroll_event().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_scroll_event ) ); m_treeview.sig_dropped_from_other().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_dropped_from_other ) ); /////////////////// // ポップアップメニューの設定 // アクショングループを作ってUIマネージャに登録 action_group() = Gtk::ActionGroup::create(); action_group()->add( Gtk::Action::create( "OpenTab", "タブで開く(_T)"), sigc::mem_fun( *this, &BBSListViewBase::slot_open_tab ) ); action_group()->add( Gtk::Action::create( "OpenBrowser", ITEM_NAME_OPEN_BROWSER "(_W)" ), sigc::mem_fun( *this, &BBSListViewBase::slot_open_browser ) ); action_group()->add( Gtk::Action::create( "OpenCacheBrowser", ITEM_NAME_OPEN_CACHE_BROWSER "(_X)" ), sigc::mem_fun( *this, &BBSListViewBase::slot_open_cache_browser ) ); action_group()->add( Gtk::Action::create( "AppendFavorite", "AppendFavorite"), sigc::mem_fun( *this, &BBSListViewBase::slot_append_favorite ) ); action_group()->add( Gtk::Action::create( "NewDir", "新規ディレクトリ(_N)"), sigc::mem_fun( *this, &BBSListViewBase::slot_newdir ) ); action_group()->add( Gtk::Action::create( "NewCom", "コメント挿入(_I)"), sigc::mem_fun( *this, &BBSListViewBase::slot_newcomment ) ); action_group()->add( Gtk::Action::create( "NewEtc", "外部板追加(_E)..."), sigc::mem_fun( *this, &BBSListViewBase::slot_newetcboard ) ); action_group()->add( Gtk::Action::create( "MoveEtc", "編集(_E)..."), sigc::mem_fun( *this, &BBSListViewBase::slot_moveetcboard ) ); action_group()->add( Gtk::Action::create( "Rename", "名前変更(_R)"), sigc::mem_fun( *this, &BBSListViewBase::slot_rename ) ); action_group()->add( Gtk::Action::create( "Delete_Menu", "Delete" ) ); action_group()->add( Gtk::Action::create( "Delete", "お気に入りから削除する(_D)"), sigc::mem_fun( *this, &BBSListViewBase::delete_view_impl ) ); action_group()->add( Gtk::Action::create( "Delete_etc", "外部板を削除する(_D)"), sigc::mem_fun( *this, &BBSListViewBase::delete_view_impl ) ); action_group()->add( Gtk::Action::create( "Delete_hist", "履歴から削除する(_D)"), sigc::mem_fun( *this, &BBSListViewBase::delete_view_impl ) ); action_group()->add( Gtk::Action::create( "OpenRows", "選択した行を開く(_O)"), sigc::mem_fun( *this, &BBSListViewBase::open_selected_rows ) ); action_group()->add( Gtk::Action::create( "CheckUpdateRows", "更新チェックのみ(_H)"), sigc::mem_fun( *this, &BBSListViewBase::slot_checkupdate_selected_rows ) ); action_group()->add( Gtk::Action::create( "CheckUpdateOpenRows", "更新された行をタブで開く(_E)"), sigc::mem_fun( *this, &BBSListViewBase::slot_checkupdate_open_selected_rows ) ); action_group()->add( Gtk::Action::create( "CopyURL", ITEM_NAME_COPY_URL "(_U)"), sigc::mem_fun( *this, &BBSListViewBase::slot_copy_url ) ); action_group()->add( Gtk::Action::create( "CopyTitleURL", ITEM_NAME_COPY_TITLE_URL "(_L)" ), sigc::mem_fun( *this, &BBSListViewBase::slot_copy_title_url ) ); action_group()->add( Gtk::Action::create( "SelectDir", "全て選択(_A)"), sigc::mem_fun( *this, &BBSListViewBase::slot_select_all_dir ) ); action_group()->add( Gtk::Action::create( "CheckUpdate_Menu", "更新チェック(_M)" ) ); action_group()->add( Gtk::Action::create( "CheckUpdateDir", "更新チェックのみ(_R)"), sigc::mem_fun( *this, &BBSListViewBase::slot_check_update_dir ) ); action_group()->add( Gtk::Action::create( "CheckUpdateOpenDir", "更新された行をタブで開く(_A)"), sigc::mem_fun( *this, &BBSListViewBase::slot_check_update_open_dir ) ); action_group()->add( Gtk::Action::create( "CancelCheckUpdate", "キャンセル(_C)" ), sigc::mem_fun( *this, &BBSListViewBase::stop ) ); action_group()->add( Gtk::Action::create( "Arrange_Menu", "並び替え(_G)" ) ); action_group()->add( Gtk::Action::create( "ArrangeDir_Menu", "ディレクトリ内の並び替え(_G)" ) ); action_group()->add( Gtk::Action::create( "Arrange_Type", "種類順(_T)"), sigc::bind< int >( sigc::mem_fun( *this, &BBSListViewBase::slot_sort ), SKELETON::SORT_BY_TYPE ) ); action_group()->add( Gtk::Action::create( "Arrange_Name", "名前順(_N)"), sigc::bind< int >( sigc::mem_fun( *this, &BBSListViewBase::slot_sort ), SKELETON::SORT_BY_NAME ) ); action_group()->add( Gtk::Action::create( "OpenAsBoard", "ディレクトリをスレ一覧に表示(_B)"), sigc::mem_fun( *this, &BBSListViewBase::slot_opendir_as_board ) ); action_group()->add( Gtk::Action::create( "CreateVBoard", "仮想板作成(_V)"), sigc::mem_fun( *this, &BBSListViewBase::slot_create_vboard ) ); action_group()->add( Gtk::Action::create( "SearchCacheBoard", "キャッシュ内ログ検索(_S)"), sigc::mem_fun( *this, &BBSListViewBase::slot_search_cache_board ) ); action_group()->add( Gtk::Action::create( "ImportDat", "datのインポート(_I)"), sigc::mem_fun( *this, &BBSListViewBase::slot_import_dat ) ); action_group()->add( Gtk::Action::create( "PreferenceArticle", ITEM_NAME_PREF_THREAD "(_P)..." ), sigc::mem_fun( *this, &BBSListViewBase::slot_preferences_article ) ); action_group()->add( Gtk::Action::create( "PreferenceBoard", ITEM_NAME_PREF_BOARD "(_O)..." ), sigc::mem_fun( *this, &BBSListViewBase::slot_preferences_board ) ); action_group()->add( Gtk::Action::create( "PreferenceImage", ITEM_NAME_PREF_IMAGE "(_M)..." ), sigc::mem_fun( *this, &BBSListViewBase::slot_preferences_image ) ); ui_manager() = Gtk::UIManager::create(); ui_manager()->insert_action_group( action_group() ); // ポップアップメニューのレイアウト Glib::ustring str_ui = "" // 板一覧 + 板 "" POPUPMENU_BOARD1 POPUPMENU_BOARD2 // 板一覧 + 外部板 "" POPUPMENU_BOARD1 "" "" "" "" "" "" POPUPMENU_BOARD2 // 板一覧 + 複数選択 "" "" "" "" "" // 板一覧 + 複数選択 + 外部板含む "" "" "" "" "" "" "" "" "" // 板一覧 + ディレクトリ "" "" "" // 板一覧 + 外部板ディレクトリ "" "" "" "" "" ///////////////////////////////////////// // お気に入り "" "" "" "" "" POPUPMENU_SELECT "" // お気に入り + 複数選択 "" "" "" "" "" "" "" "" "" "" POPUPMENU_DELETE "" // お気に入り + 何もないところをクリック "" "" "" "" // お気に入り + ディレクトリ "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" POPUPMENU_ARRANGEDIR "" POPUPMENU_DELETE "" // お気に入り + コメント "" "" "" "" "" POPUPMENU_ARRANGE "" POPUPMENU_DELETE "" // お気に入り + 仮想板 "" "" "" "" "" "" "" POPUPMENU_ARRANGE "" POPUPMENU_DELETE "" ////////////////////////////////////// // 選択(selectlistview) "" POPUPMENU_SELECT "" ///////////////////////////////////////// // 履歴 "" "" "" "" "" \ "" \ "" "" "" \ "" \ "" \ "" \ "" \ "" \ "" \ "" \ "" \ "" \ "" \ "" \ "" // 履歴 + 複数選択 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" // 履歴 + 仮想板 "" "" "" "" "" "" "" ""; ui_manager()->add_ui_from_string( str_ui ); // ポップアップメニューにキーアクセレータを表示 Gtk::Menu* popupmenu = id2popupmenu( "/popup_menu" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_etc" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_mul" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_mul_etc" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_dir" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_favorite" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_favorite_mul" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_favorite_space" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_favorite_dir" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_favorite_com" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_favorite_vboard" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_history" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_history_mul" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_history_vboard" ); CONTROL::set_menu_motion( popupmenu ); popupmenu = id2popupmenu( "/popup_menu_select" ); CONTROL::set_menu_motion( popupmenu ); // マウスジェスチャ可 set_enable_mg( true ); // コントロールモード設定 get_control().add_mode( CONTROL::MODE_BBSLIST ); } BBSListViewBase::~BBSListViewBase() { #ifdef _DEBUG std::cout << "BBSListViewBase::~BBSListViewBase : " << get_url() << std::endl; #endif if( m_editlistwin ) delete m_editlistwin; m_editlistwin = NULL; } void BBSListViewBase::save_session() { save_xml(); } SKELETON::Admin* BBSListViewBase::get_admin() { return BBSLIST::get_admin(); } // // treeviewのD&Dによる編集を可能にする // void BBSListViewBase::set_editable( const bool editable ) { get_treeview().set_editable_view( editable ); } // // 親ウィンドウをセット // void BBSListViewBase::set_parent_win( Gtk::Window* parent_win ) { SKELETON::View::set_parent_win( parent_win ); get_treeview().set_parent_win( parent_win ); } // // コマンド // const bool BBSListViewBase::set_command( const std::string& command, const std::string& arg1, const std::string& arg2 ) { if( command == "append_item" ) append_item(); else if( command == "append_history" ) append_history(); else if( command == "remove_item" ) remove_item( arg1 ); else if( command == "remove_headitem" ) remove_headitem(); else if( command == "remove_allitems" ) remove_allitems(); else if( command == "edit_tree" ) edit_tree(); else if( command == "save_xml" ) save_xml(); else if( command == "toggle_articleicon" ) toggle_articleicon( arg1 ); else if( command == "toggle_boardicon" ) toggle_boardicon( arg1 ); else if( command == "replace_thread" ) replace_thread( arg1, arg2 ); else if( command == "hide_popup" ) m_treeview.hide_popup(); else if( command == "check_update_root" ) check_update_dir( true, false ); else if( command == "check_update_open_root" ) check_update_dir( true, true ); else if( command == "cancel_check_update" ) stop(); else if( command == "select_item" ) select_item( arg1 ); return true; } // // クロック入力 // void BBSListViewBase::clock_in() { View::clock_in(); m_treeview.clock_in(); if( m_editlistwin ) m_editlistwin->clock_in(); // スクロールバー移動 // 初期化直後など、まだスクロールバーが表示されてない時があるので表示されるまでジャンプしない if( m_jump_y != -1 ){ Gtk::Adjustment* adjust = m_treeview.get_vadjustment(); if( adjust && adjust->get_upper() > m_jump_y ){ #ifdef _DEBUG std::cout << "BBSListViewBase::clock_in jump to = " << m_jump_y << " upper = " << (int)adjust->get_upper() << std::endl; #endif // 何故か先頭にジャンプ出来ないので 1 にジャンプする if( m_jump_y == 0 ) m_jump_y = 1; adjust->set_value( m_jump_y ); m_jump_y = -1; } } } // // コメント色変更( 再帰用 ) // void BBSListViewBase::set_fgcolor_of_comment( const Gtk::TreeModel::Children& children ) { Gtk::TreeModel::iterator it = children.begin(); for( ; it != children.end(); ++it ){ Gtk::TreeModel::Row row = *it; const int type = row2type( row ); if( type == TYPE_COMMENT ) row[ m_columns.m_fgcolor ] = Gdk::Color( CONFIG::get_color( COLOR_CHAR_BBS_COMMENT ) ); else if( type == TYPE_DIR ) set_fgcolor_of_comment( row.children() ); } } // // 再描画 // void BBSListViewBase::redraw_view() { // 起動中とシャットダウン中は処理しない if( SESSION::is_booting() ) return; if( SESSION::is_quitting() ) return; #ifdef _DEBUG std::cout << "BBSListViewBase::ViewBase::redraw_view " << get_url() << std::endl; #endif m_treeview.redraw_view(); } // // 色やフォントなどの変更 // void BBSListViewBase::relayout() { m_treeview.init_color( COLOR_CHAR_BBS, COLOR_BACK_BBS, COLOR_BACK_BBS_EVEN ); m_treeview.init_font( CONFIG::get_fontname( FONT_BBS ) ); set_fgcolor_of_comment( m_treestore->children() ); } // // フォーカス // void BBSListViewBase::focus_view() { // 行の名前を編集中なら何もしない if( m_treeview.is_renaming_row() ) return; #ifdef _DEBUG std::cout << "BBSListViewBase::focus_view url = " << get_url() << std::endl; #endif m_treeview.grab_focus(); } // // フォーカスアウト // void BBSListViewBase::focus_out() { SKELETON::View::focus_out(); m_treeview.hide_tooltip(); m_treeview.hide_popup(); } // // 閉じる // void BBSListViewBase::close_view() { #ifdef _DEBUG std::cout << "BBSListViewBase::close_view\n"; #endif CORE::core_set_command( "toggle_sidebar" ); } // // 削除 // // BBSListViewBaseの場合は選択行の削除 // void BBSListViewBase::delete_view() { SKELETON::MsgDiag mdiag( get_parent_win(), "削除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; delete_view_impl(); } // BBSListViewBaseの場合は選択行の削除 void BBSListViewBase::delete_view_impl() { const bool force = true; m_treeview.delete_selected_rows( force ); } // // ツリー内の全ての項目をURLを新しいアドレスに変更 ( id は未使用 ) // void BBSListViewBase::update_item( const std::string& url, const std::string& id ) { #ifdef _DEBUG std::cout << "BBSListViewBase::update_item " << url << " / " << get_url() << std::endl; #endif if( url == get_url() ) update_urls(); } // // viewの操作 // const bool BBSListViewBase::operate_view( const int control ) { if( CONTROL::operate_common( control, get_url(), BBSLIST::get_admin() ) ) return true; Gtk::TreePath path = m_treeview.get_current_path(); Gtk::TreeModel::Row row; bool open_tab = false; #ifdef _DEBUG std::cout << "BBSListViewBase::operate_view = " << control << std::endl; #endif switch( control ){ case CONTROL::Down: row_down(); break; case CONTROL::Up: row_up(); break; case CONTROL::PageUp: page_up(); break; case CONTROL::PageDown: page_down(); break; case CONTROL::PrevDir: prev_dir(); break; case CONTROL::NextDir: next_dir(); break; case CONTROL::Home: goto_top(); break; case CONTROL::End: goto_bottom(); break; // 全て選択 case CONTROL::SelectAll: slot_select_all(); break; // 開く case CONTROL::OpenBoardTabButton: if( ! m_path_selected.empty() ){ open_tab = true; // pathがディレクトリでタブで開くボタンを入れ替えている時はディレクトリ開閉にする if( path2type( path ) == TYPE_DIR && CONTROL::is_toggled_tab_button() ) open_tab = false; open_row( path, open_tab ); } break; case CONTROL::OpenBoardButton: if( ! m_path_selected.empty() ){ open_tab = false; // pathがディレクトリでタブで開くボタンを入れ替えている時は更新チェックにする if( path2type( path ) == TYPE_DIR && CONTROL::is_toggled_tab_button() ) open_tab = true; open_row( path, open_tab ); } break; case CONTROL::OpenBoardTab: open_tab = true; // pathがディレクトリでタブで開くキーを入れ替えている時はディレクトリ開閉にする if( path2type( path ) == TYPE_DIR && CONTROL::is_toggled_tab_key() ) open_tab = false; open_row( path, open_tab ); break; case CONTROL::OpenBoard: open_tab = false; // pathがディレクトリでタブで開くキーを入れ替えている時は更新チェックにする if( path2type( path ) == TYPE_DIR && CONTROL::is_toggled_tab_key() ) open_tab = true; open_row( path, open_tab ); break; case CONTROL::Right: if( m_treeview.get_row( path ) ){ if( ! m_treeview.expand_row( path, false ) ) switch_rightview(); } break; case CONTROL::Left: if( row = m_treeview.get_row( path ) ){ if( ( path2type( path ) != TYPE_DIR || ! m_treeview.row_expanded( path ) ) && row.parent() ){ path = GET_PATH( row.parent() ); m_treeview.set_cursor( path ); } m_treeview.collapse_row( path ); } break; case CONTROL::ToggleArticle: CORE::core_set_command( "toggle_article" ); break; // 終了 case CONTROL::Quit: close_view(); break; case CONTROL::Reload: reload(); break; case CONTROL::Delete: delete_view(); break; // ポップアップメニュー表示 case CONTROL::ShowPopupMenu: { if( m_treeview.get_selection()->get_selected_rows().size() >= 1 ){ m_path_selected = * (m_treeview.get_selection()->get_selected_rows().begin() ); } SHOW_POPUPMENU(true); break; } // 検索 case CONTROL::Search: set_search_invert( false ); BBSLIST::get_admin()->set_command( "focus_toolbar_search" ); break; case CONTROL::SearchInvert: set_search_invert( true ); BBSLIST::get_admin()->set_command( "focus_toolbar_search" ); break; case CONTROL::SearchNext: down_search(); break; case CONTROL::SearchPrev: up_search(); break; case CONTROL::StopLoading: CORE::core_set_command( "cancel_check_update" ); break; case CONTROL::Undo: undo(); break; case CONTROL::Redo: redo(); break; default: return false; } return true; } // // ポップアップメニューを表示する前にメニューのアクティブ状態を切り替える // // SKELETON::View::show_popupmenu() を参照すること // void BBSListViewBase::activate_act_before_popupmenu( const std::string& url ) { Glib::RefPtr< Gtk::Action > act_search, act_import, act_board, act_article, act_image, act_opencache, act_opentab; act_search = action_group()->get_action( "SearchCacheBoard" ); act_import = action_group()->get_action( "ImportDat" ); act_board = action_group()->get_action( "PreferenceBoard" ); act_article = action_group()->get_action( "PreferenceArticle" ); act_image = action_group()->get_action( "PreferenceImage" ); act_opencache = action_group()->get_action( "OpenCacheBrowser" ); act_opentab = action_group()->get_action( "OpenTab" ); if( act_search ) act_search->set_sensitive( false ); if( act_import ) act_import->set_sensitive( false ); if( act_board ) act_board->set_sensitive( false ); if( act_article ) act_article->set_sensitive( false ); if( act_image ) act_image->set_sensitive( false ); if( act_opencache ) act_opencache->set_sensitive( false ); if( act_opentab ) act_opentab->set_sensitive( true ); int type = path2type( m_path_selected ); switch( type ){ case TYPE_BOARD: case TYPE_BOARD_UPDATE: if( act_search ) act_search->set_sensitive( true ); if( act_import ) act_import->set_sensitive( true ); if( act_board ) act_board->set_sensitive( true ); break; case TYPE_THREAD: case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: if( act_article ) act_article->set_sensitive( true ); break; case TYPE_IMAGE: if( act_image && ! DBIMG::get_abone( url ) ) act_image->set_sensitive( true ); if( act_opencache && DBIMG::is_cached( url ) ) act_opencache->set_sensitive( true ); break; case TYPE_DIR: break; case TYPE_LINK: if( act_opentab ) act_opentab->set_sensitive( false ); break; } } // idからポップアップメニュー取得 Gtk::Menu* BBSListViewBase::id2popupmenu( const std::string& id ) { return dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( id ) ); } // // 先頭に戻る // void BBSListViewBase::goto_top() { m_treeview.goto_top(); show_status(); } // // 一番最後へ // void BBSListViewBase::goto_bottom() { m_treeview.goto_bottom(); show_status(); } // // 上へ移動 // void BBSListViewBase::row_up() { m_treeview.row_up(); show_status(); } // // 下へ移動 // void BBSListViewBase::row_down() { m_treeview.row_down(); show_status(); } // // page up // void BBSListViewBase::page_up() { m_treeview.page_up(); } // // page down // void BBSListViewBase::page_down() { m_treeview.page_down(); } // // 前のディレクトリに移動 // void BBSListViewBase::prev_dir() { m_treeview.prev_dir(); } // // 次のディレクトリに移動 // void BBSListViewBase::next_dir() { m_treeview.next_dir(); } // // 他のviewのtreestoreをcopyして表示 // void BBSListViewBase::copy_treestore( Glib::RefPtr< Gtk::TreeStore >& store ) { #ifdef _DEBUG std::cout << "BBSListViewBase::copy_treestore\n"; #endif m_treestore = store; m_treeview.set_treestore( m_treestore ); if( m_treestore->children().begin() ){ Gtk::TreePath path = GET_PATH( *( m_treestore->children().begin() ) ); if( m_treeview.get_row( path ) ){ m_treeview.collapse_all(); m_treeview.scroll_to_row( path, 0 ); m_treeview.get_selection()->unselect_all(); m_treeview.set_cursor( path ); } } } // // マウスボタン押した // bool BBSListViewBase::slot_button_press( GdkEventButton* event ) { m_clicked = true; // マウスジェスチャ get_control().MG_start( event ); // ホイールマウスジェスチャ get_control().MG_wheel_start( event ); // ダブルクリック // button_release_eventでは event->type に必ず GDK_BUTTON_RELEASE が入る m_dblclicked = false; if( event->type == GDK_2BUTTON_PRESS ) m_dblclicked = true; // 親ウィンドウがメインウィンドウならフォーカスを移す if( ! get_parent_win() ) BBSLIST::get_admin()->set_command( "switch_admin" ); return true; } // // マウスボタン離した // bool BBSListViewBase::slot_button_release( GdkEventButton* event ) { if( ! m_clicked ) return true; m_clicked = false; /// マウスジェスチャ int mg = get_control().MG_end( event ); // ホイールマウスジェスチャ // 実行された場合は何もしない if( get_control().MG_wheel_end( event ) ) return true; if( mg != CONTROL::None && enable_mg() ){ operate_view( mg ); return true; } show_status(); m_path_selected = m_treeview.get_path_under_xy( (int)event->x, (int)event->y ); // ダブルクリックの処理のため一時的にtypeを切替える GdkEventType type_copy = event->type; if( m_dblclicked ) event->type = GDK_2BUTTON_PRESS; // 行を開く if( get_control().button_alloted( event, CONTROL::OpenBoardButton ) ) operate_view( CONTROL::OpenBoardButton ); // タブで開く else if( get_control().button_alloted( event, CONTROL::OpenBoardTabButton ) ) operate_view( CONTROL::OpenBoardTabButton ); // ポップアップメニューボタン else if( get_control().button_alloted( event, CONTROL::PopupmenuButton ) ) SHOW_POPUPMENU( false ); // その他の操作 else operate_view( get_control().button_press( event ) ); event->type = type_copy; return true; } // // マウス動かした // bool BBSListViewBase::slot_motion_notify( GdkEventMotion* event ) { /// マウスジェスチャ get_control().MG_motion( event ); int x = (int)event->x; int y = (int)event->y; Gtk::TreeModel::Path path; Gtk::TreeView::Column* column; int cell_x; int cell_y; if( m_treeview.get_path_at_pos( x, y, path, column, cell_x, cell_y ) && m_treeview.get_row( path ) ){ const int mrg = 16; // アイコンの横幅。計算するのが面倒だったのでとりあえず Gtk::TreeModel::Row row = m_treeview.get_row( path ); Glib::ustring subject = row[ m_columns.m_name ]; Glib::ustring url = row[ m_columns.m_url ]; int type = row[ m_columns.m_type ]; m_treeview.reset_pre_popupurl( url ); // 画像ポップアップ if( type == TYPE_IMAGE ){ m_treeview.hide_tooltip(); if( DBIMG::get_type_ext( url ) != DBIMG::T_UNKNOWN && DBIMG::get_code( url ) != HTTP_INIT ){ if( m_treeview.pre_popup_url() != url ){ SKELETON::View* view = CORE::ViewFactory( CORE::VIEW_IMAGEPOPUP, url ); m_treeview.show_popup( url, view ); } } else m_treeview.hide_popup(); } // ツールチップ else{ m_treeview.hide_popup(); Gdk::Rectangle rect; m_treeview.get_cell_area( path, *column, rect ); m_treeview.set_tooltip_min_width( rect.get_width() - mrg ); m_treeview.set_str_tooltip( subject ); } } else{ m_treeview.hide_tooltip(); m_treeview.hide_popup(); } return true; } // // キーを押した // const bool BBSListViewBase::slot_key_press( GdkEventKey* event ) { // 行の名前を編集中なら何もしない if( m_treeview.is_renaming_row() ) return false; const int key = get_control().key_press( event ); // キー入力でboardを開くとkey_pressイベントがboadviewに送られて // 一番上のスレが開くので、open_row() は slot_key_release() で処理する if( key == CONTROL::OpenBoard ) return true; if( key == CONTROL::OpenBoardTab ) return true; if( operate_view( key ) ) return true; return false; } // // キー上げた // bool BBSListViewBase::slot_key_release( GdkEventKey* event ) { #ifdef _DEBUG bool ctrl = ( event->state ) & GDK_CONTROL_MASK; bool shift = ( event->state ) & GDK_SHIFT_MASK; std::cout << "BBSListViewBase::slot_key_release key = " << event->keyval << " ctrl = " << ctrl << " shift = " << shift << std::endl; #endif // 行の名前を編集中なら何もしない if( m_treeview.is_renaming_row() ) return false; // キー入力でboardを開くとkey_pressイベントがboadviewに送られて // 一番上のスレが開くので、open_row() は slot_key_release() で処理する int key = get_control().key_press( event ); if( key == CONTROL::OpenBoard || key == CONTROL::OpenBoardTab ) operate_view( key ); return true; } // // マウスホイールイベント // bool BBSListViewBase::slot_scroll_event( GdkEventScroll* event ) { // ホイールマウスジェスチャ int control = get_control().MG_wheel_scroll( event ); if( enable_mg() && control != CONTROL::None ){ operate_view( control ); return true; } m_treeview.wheelscroll( event ); return true; } // // 他のwidgetからドロップされた // void BBSListViewBase::slot_dropped_from_other( const CORE::DATA_INFO_LIST& list_info ) { #ifdef _DEBUG std::cout << "BBSListViewBase:slot_dropped_from_other\n"; #endif CORE::DATA_INFO_LIST::const_iterator it = list_info.begin(); for( ; it != list_info.end() ; ++it ){ const CORE::DATA_INFO& info = ( *it ); const int type = info.type; switch( type ){ case TYPE_BOARD: case TYPE_BOARD_UPDATE: m_set_board.insert( DBTREE::url_boardbase( info.url ) ); break; case TYPE_VBOARD: m_set_board.insert( info.url ); break; case TYPE_THREAD: case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: if( m_set_bookmark ) DBTREE::set_bookmarked_thread( info.url, true ); m_set_thread.insert( DBTREE::url_dat( info.url ) ); break; case TYPE_IMAGE: if( m_set_bookmark ) DBIMG::set_protect( info.url, true ); m_set_image.insert( info.url ); break; } } } // // popupmenu でタブで開くを選択 // void BBSListViewBase::slot_open_tab() { if( m_path_selected.empty() ) return; open_row( m_path_selected, true ); } // // ブラウザで開く // void BBSListViewBase::slot_open_browser() { if( m_path_selected.empty() ) return; std::string url = path2url( m_path_selected ); CORE::core_set_command( "open_url_browser", url ); } // // 画像キャッシュをブラウザで開く // void BBSListViewBase::slot_open_cache_browser() { if( m_path_selected.empty() ) return; std::string url = path2url( m_path_selected ); if( ! DBIMG::is_cached( url ) ) return; url = "file://" + DBIMG::get_cache_path( url ); CORE::core_set_command( "open_url_browser", url ); } // // 選択行をお気に入りに追加 // void BBSListViewBase::slot_append_favorite() { CORE::DATA_INFO_LIST list_info; const bool dir = true; m_treeview.get_info_in_selection( list_info, dir ); if( list_info.size() ){ CORE::SBUF_set_list( list_info ); CORE::core_set_command( "append_favorite", URL_FAVORITEVIEW ); } } // // メニューでディレクトリを作るを選択 // void BBSListViewBase::slot_newdir() { m_path_selected = m_treeview.create_newdir( m_path_selected ); } // // メニューでコメント挿入を選択 // void BBSListViewBase::slot_newcomment() { m_path_selected = m_treeview.create_newcomment( m_path_selected ); } // // メニューで外部板追加を選択 // void BBSListViewBase::slot_newetcboard() { add_newetcboard( false, "", "", "", "" ); } // // メニューで外部板編集を選択 // void BBSListViewBase::slot_moveetcboard() { add_newetcboard( true, "", "", "", "" ); } // 外部板追加 void BBSListViewBase::add_newetcboard( const bool move, // true なら編集モード const std::string& _url, const std::string& _name, const std::string& _id, const std::string& _passwd ) { if( m_path_selected.empty() ) return; std::string url_old; std::string name_old; std::string url = _url; std::string name = _name; std::string id = _id; std::string passwd = _passwd; std::string basicauth; #ifdef _DEBUG std::cout << "BBSListViewBase::add_newetcboard\n" << "move = " << move << std::endl; #endif if( move ){ url_old = path2url( m_path_selected ); name_old = path2name( m_path_selected ); #ifdef _DEBUG std::cout << "url_old = " << url_old << std::endl << "name_old = " << name_old << std::endl << "board_name = " << DBTREE::board_name( url_old ) << std::endl; #endif if( DBTREE::board_name( url_old ) != name_old ) return; if( url.empty() ) url = url_old; if( name.empty() ) name = name_old; basicauth = DBTREE::board_basicauth( url_old ); size_t i = basicauth.find( ":" ); if( id.empty() && i != std::string::npos ){ id = basicauth.substr( 0, i ); passwd = basicauth.substr( i+1 ); } #ifdef _DEBUG std::cout << "basicauth = " << basicauth << " i = " << i << " id = " << id << "passwd = " << passwd << std::endl; #endif } BBSLIST::AddEtcDialog diag( move, url, name, id, passwd ); if( diag.run() == Gtk::RESPONSE_OK ){ diag.hide(); std::string url_org = MISC::remove_space( diag.get_url() ); name = MISC::remove_space( diag.get_name() ); url = url_org; id = MISC::remove_space( diag.get_id() ); passwd = MISC::remove_space( diag.get_passwd() ); if( ! id.empty() && ! passwd.empty() ) basicauth = id + ":" + passwd; if( name.empty() || url.empty() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "板名またはアドレスが空白です", false, Gtk::MESSAGE_ERROR ); mdiag.run(); mdiag.hide(); add_newetcboard( move, url_org, name, id, passwd ); return; } // http が無ければ付ける if( url.find( "http://" ) != 0 ) url = "http://" + url; // .htmlを取り除く JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "(.*)/[^/]+\\.html?$" , url, offset, icase, newline, usemigemo, wchar ) ) url = regex.str( 1 ); // 末尾の / を取り除く while( url.rfind( "/" ) == url.length() -1 ) url = url.substr( 0, url.length() -1 ); // url の最後に/を付ける url += "/"; // boardid 取得 if( ! regex.exec( "(http://.*)/([^/]*)/$" , url, offset, icase, newline, usemigemo, wchar ) ){ SKELETON::MsgDiag mdiag( get_parent_win(), "アドレスが不正な形式になっています", false, Gtk::MESSAGE_ERROR ); mdiag.run(); mdiag.hide(); add_newetcboard( move, url_org, name, id, passwd ); return; } #ifdef _DEBUG std::cout << "url_old = " << url_old << std::endl << "name_old = " << name_old << std::endl << "url = " << url << std::endl << "name = " << name << std::endl << "basicauth = " << basicauth << std::endl; #endif std::string boardid = regex.str( 2 ); if( boardid.empty() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "板IDを取得出来ません", false, Gtk::MESSAGE_ERROR ); mdiag.run(); mdiag.hide(); add_newetcboard( move, url_org, name, id, passwd ); return; } #ifdef _DEBUG std::cout << "boardid = " << boardid << std::endl; #endif // 既に登録されているか確認 if( ! move && ! DBTREE::board_name( url ).empty() ){ SKELETON::MsgDiag mdiag( get_parent_win(), name + "\n" + url + "\n\nは既に登録されています", false, Gtk::MESSAGE_ERROR ); mdiag.run(); mdiag.hide(); add_newetcboard( move, url_org, name, id, passwd ); return; } // データベースに登録してツリーに表示 if( ! move && DBTREE::add_etc( url, name, basicauth, boardid ) ){ CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; info.type = TYPE_BOARD; info.url = url; info.name = name; info.path = m_path_selected.to_string(); list_info.push_back( info ); const bool before = false; const bool scroll = false; const bool force = true; // 強制的に追加 const bool cancel_undo_commit = false; const int check_dup = 0; // 項目の重複チェックをしない m_treeview.append_info( list_info, m_path_selected, before, scroll, force, cancel_undo_commit, check_dup ); m_path_selected = m_treeview.get_current_path(); // etc.txt保存 DBTREE::save_etc(); } // 編集 else if( move && DBTREE::move_etc( url_old, url, name_old, name, basicauth, boardid ) ){ Gtk::TreeModel::Row row = m_treeview.get_row( m_path_selected ); if( row ){ row[ m_columns.m_url ] = url; row[ m_columns.m_name ] = name; } } else{ SKELETON::MsgDiag mdiag( get_parent_win(), "外部板の登録に失敗しました。アドレスを確認してください", false, Gtk::MESSAGE_ERROR ); mdiag.run(); mdiag.hide(); add_newetcboard( move, url_org, name, id, passwd ); return; } } } // // 名前変更 // void BBSListViewBase::slot_rename() { #ifdef _DEBUG std::cout << "BBSListViewBase::slot_rename\n"; #endif m_treeview.rename_row( m_path_selected ); } // // URLをコピー // void BBSListViewBase::slot_copy_url() { if( m_path_selected.empty() ) return; std::string url = path2url( m_path_selected ); MISC::CopyClipboard( url ); } // 名前とURLをコピー // void BBSListViewBase::slot_copy_title_url() { if( m_path_selected.empty() ) return; const std::string url = path2url( m_path_selected ); const std::string name = path2name( m_path_selected ); MISC::CopyClipboard( name + '\n' + url ); } // // 指定したディレクトリ以下のディレクトリを全て開く // void BBSListViewBase::expand_all_dir( Gtk::TreeModel::Path path ) { if( m_treeview.is_dir( path ) ){ if( ! m_treeview.row_expanded( path ) ){ m_cancel_expand = true; // slot_row_exp()の呼び出しをキャンセル m_treeview.expand_row( path, false ); m_cancel_expand = false; } path.down(); while( m_treeview.get_row( path ) ){ expand_all_dir( path ); path.next(); } } } // // ディレクトリ内を全選択(メニューから呼び出す) // // m_path_selected にパスをセットしておくこと // void BBSListViewBase::slot_select_all_dir() { if( m_path_selected.empty() ) return; m_treeview.select_all_dir( m_path_selected ); } // // 全選択 // void BBSListViewBase::slot_select_all() { SKELETON::MsgDiag mdiag( get_parent_win(), "全ての行を選択しますか?\n\n(注意) ディレクトリは全て展開されます。", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; Gtk::TreeModel::Children child = m_treestore->children(); Gtk::TreeModel::Children::iterator it = child.begin(); for( ; it != child.end() ; ++it ) expand_all_dir( m_treestore->get_path( *it ) ); it = child.begin(); m_treeview.scroll_to_row( m_treestore->get_path( *it ), 0 ); for( ; it != child.end() ; ++it ){ m_treeview.get_selection()->select( *it ); m_treeview.select_all_dir( m_treestore->get_path( *it ) ); } } // // ディレクトリ以下を更新チェック // // root : true ならルートから検索する。falseの場合は m_path_selected にパスをセットしておくこと // open : チェック後に更新していたら開く // void BBSListViewBase::check_update_dir( const bool root, const bool open ) { if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); return; } #ifdef _DEBUG std::cout << "BBSListViewBase::check_update_dir root = " << root << std::endl; #endif Gtk::TreePath path; if( ! root ){ if( m_path_selected.empty() ) return; path = m_path_selected; #ifdef _DEBUG std::cout << "path = " << path.to_string() << std::endl; #endif } SKELETON::EditTreeViewIterator it( m_treeview, m_columns, path ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; const int type = row2type( row ); const std::string url = row2url( row ); #ifdef _DEBUG std::cout << row2name( row ) << std::endl; #endif if( type == TYPE_THREAD || type == TYPE_THREAD_UPDATE ) CORE::get_checkupdate_manager()->push_back( DBTREE::url_dat( url ), open ); else if( CONFIG::get_check_update_board() && ( type == TYPE_BOARD || type == TYPE_BOARD_UPDATE ) ) CORE::get_checkupdate_manager()->push_back( DBTREE::url_subject( url ), open ); } CORE::get_checkupdate_manager()->run(); } void BBSListViewBase::slot_check_update_dir() { check_update_dir( false, false ); } void BBSListViewBase::slot_check_update_open_dir() { check_update_dir( false, true ); } // // ディレクトリをスレ一覧に表示 // void BBSListViewBase::slot_opendir_as_board() { if( m_path_selected.empty() ) return; const size_t dirid = m_treeview.path_to_dirid( m_path_selected ); if( ! dirid ) return; const std::string tab = "true"; const std::string mode = ""; CORE::core_set_command( "open_sidebar_board", get_url(), tab, mode, MISC::itostr( dirid ) ); } // // 仮想板作成 // void BBSListViewBase::slot_create_vboard() { if( m_path_selected.empty() ) return; const size_t dirid = m_treeview.path_to_dirid( m_path_selected ); if( ! dirid ) return; CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; info.type = TYPE_VBOARD; info.parent = BBSLIST::get_admin()->get_win(); info.url = get_url() + SIDEBAR_SIGN + MISC::itostr( dirid ); info.name = path2name( m_path_selected ); info.path = m_path_selected.to_string(); list_info.push_back( info ); CORE::SBUF_set_list( list_info ); CORE::core_set_command( "append_favorite", URL_FAVORITEVIEW ); } // // 更新チェックキャンセル // void BBSListViewBase::stop() { #ifdef _DEBUG std::cout << "BBSListViewBase::stop " << get_url() << std::endl; #endif CORE::get_checkupdate_manager()->stop(); } // // キャッシュ内のログ検索 // void BBSListViewBase::slot_search_cache_board() { if( m_path_selected.empty() ) return; std::string url = path2url( m_path_selected ); CORE::core_set_command( "open_article_searchlog", url, "", "noexec" ); } // // datのインポート // void BBSListViewBase::slot_import_dat() { if( m_path_selected.empty() ) return; std::string url = path2url( m_path_selected ); CORE::core_set_command( "import_dat", url, "show_diag" ); } // // 板プロパティ表示 // void BBSListViewBase::slot_preferences_board() { if( m_path_selected.empty() ) return; std::string url = path2url( m_path_selected ); SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_BOARD, DBTREE::url_subject( url ) ); pref->run(); delete pref; } // // スレプロパティ表示 // void BBSListViewBase::slot_preferences_article() { if( m_path_selected.empty() ) return; std::string url = path2url( m_path_selected ); SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_ARTICLE, DBTREE::url_dat( url ) ); pref->run(); delete pref; } // // 画像プロパティ表示 // void BBSListViewBase::slot_preferences_image() { if( m_path_selected.empty() ) return; std::string url = path2url( m_path_selected ); SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_IMAGE, url ); pref->run(); delete pref; } // // フォルダを開いた時に呼ばれる // void BBSListViewBase::slot_row_exp( const Gtk::TreeModel::iterator&, const Gtk::TreeModel::Path& path ) { if( m_cancel_expand ) return; if( m_expanding ) return; // 他のフォルダを全て閉じる if( m_open_only_onedir && path.get_depth() == 1 // 子フォルダの時は閉じない ){ m_expanding = true; m_treeview.collapse_all(); m_treeview.expand_row( path, false ); m_expanding = false; } m_treeview.set_cursor( path ); if( CONFIG::get_scroll_tree() ) m_treeview.scroll_to_row( path, 0.1 ); show_status(); } // // フォルダを閉じた時に呼ばれる // void BBSListViewBase::slot_row_col( const Gtk::TreeModel::iterator&, const Gtk::TreeModel::Path& path ) { if( m_expanding ) return; m_treeview.set_cursor( path ); show_status(); } // // 選択した行を開く // const bool BBSListViewBase::open_row( Gtk::TreePath& path, const bool tab ) { if( ! m_treeview.get_row( path ) ) return false; std::string str_tab = "false"; if( tab ) str_tab = "true"; const std::string str_mode = ""; const Glib::ustring url = path2url( path ); const int type = path2type( path ); if( type != TYPE_DIR && url.empty() ) return false; switch( type ){ case TYPE_BOARD: case TYPE_BOARD_UPDATE: CORE::core_set_command( "open_board", DBTREE::url_subject( url ), str_tab, str_mode ); break; case TYPE_THREAD_OLD: toggle_articleicon( url ); // break;しない case TYPE_THREAD: case TYPE_THREAD_UPDATE: CORE::core_set_command( "open_article", DBTREE::url_dat( url ), str_tab, str_mode ); break; case TYPE_IMAGE: if( DBIMG::get_abone( url )){ SKELETON::MsgDiag mdiag( get_parent_win(), "あぼ〜んされています" ); mdiag.run(); } else{ CORE::core_set_command( "open_image", url ); CORE::core_set_command( "switch_image" ); } break; case TYPE_LINK: CORE::core_set_command( "open_url_browser", url ); break; case TYPE_DIR: if( tab ) slot_check_update_open_dir(); else if( ! m_treeview.row_expanded( path ) ) m_treeview.expand_row( path, false ); else m_treeview.collapse_row( path ); break; case TYPE_VBOARD: CORE::core_set_command( "open_sidebar_board", url, str_tab, str_mode, "", "set_history" ); break; } #ifdef _DEBUG std::cout << "BBSListViewBase::open_row : path = " << path.to_string() << " tab = " << tab << std::endl; #endif // treeviewが編集されていたらxml保存 if( type != TYPE_DIR && m_treeview.is_updated() ){ save_xml(); m_treeview.set_updated( false ); } return true; } // // 右のビュー(board)に切り替え // void BBSListViewBase::switch_rightview() { CORE::core_set_command( "switch_rightview" ); } // // 選択した行をまとめて開く // void BBSListViewBase::open_selected_rows() { std::string list_url_board; std::string list_url_article; std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); for( ; it != list_it.end(); ++it ){ Gtk::TreeModel::Row row = *( *it ); Gtk::TreePath path = GET_PATH( row ); int type = path2type( path ); std::string url = path2url( path ); switch( type ){ case TYPE_BOARD: case TYPE_BOARD_UPDATE: url = DBTREE::url_subject( url ); if( !list_url_board.empty() ) list_url_board += " "; list_url_board += url; break; case TYPE_THREAD: case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: url = DBTREE::url_dat( url ); if( !list_url_article.empty() ) list_url_article += " "; list_url_article += url; break; case TYPE_IMAGE: if( ! DBIMG::get_abone( url ) ) CORE::core_set_command( "open_image", url ); break; } } if( !list_url_board.empty() ) CORE::core_set_command( "open_board_list", std::string(), list_url_board ); if( !list_url_article.empty() ) CORE::core_set_command( "open_article_list", std::string(), list_url_article ); } // // 選択したスレを更新チェック // // このあとで CORE::get_checkupdate_manager()->run() を実行すること // void BBSListViewBase::checkupdate_selected_rows( const bool open ) { std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); for( ; it != list_it.end(); ++it ){ Gtk::TreeModel::Row row = *( *it ); Gtk::TreePath path = GET_PATH( row ); int type = path2type( path ); std::string url = path2url( path ); if( type == TYPE_THREAD || type == TYPE_THREAD_UPDATE ) CORE::get_checkupdate_manager()->push_back( DBTREE::url_dat( url ), open ); else if( CONFIG::get_check_update_board() && ( type == TYPE_BOARD || type == TYPE_BOARD_UPDATE ) ) CORE::get_checkupdate_manager()->push_back( DBTREE::url_subject( url ), open ); } } void BBSListViewBase::slot_checkupdate_selected_rows() { checkupdate_selected_rows( false ); CORE::get_checkupdate_manager()->run(); } void BBSListViewBase::slot_checkupdate_open_selected_rows() { checkupdate_selected_rows( true ); CORE::get_checkupdate_manager()->run(); } void BBSListViewBase::slot_sort( const int mode ) { m_treeview.sort( m_path_selected, mode ); } // // path -> url 変換 // const Glib::ustring BBSListViewBase::path2rawurl( const Gtk::TreePath& path ) { Gtk::TreeModel::Row row = m_treeview.get_row( path ); if( !row ) return Glib::ustring(); Glib::ustring url = row[ m_columns.m_url ]; return url; } // 移転をチェックするバージョン const Glib::ustring BBSListViewBase::path2url( const Gtk::TreePath& path ) { Gtk::TreeModel::Row row = m_treeview.get_row( path ); if( !row ) return Glib::ustring(); Glib::ustring url = row[ m_columns.m_url ]; if( url.empty() ) return url; // 移転があったら url を最新のものに変換しておく int type = path2type( path ); switch( type ){ case TYPE_BOARD: case TYPE_BOARD_UPDATE: url = DBTREE::url_boardbase( url ); break; case TYPE_THREAD: case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: url = DBTREE::url_readcgi( url, 0, 0 ); break; } return url; } // // row -> url 変換 // // 板の場合は boardbase // スレの場合は dat 型のアドレスを返す // const Glib::ustring BBSListViewBase::row2url( const Gtk::TreeModel::Row& row ) { if( ! row ) return Glib::ustring(); Glib::ustring url = row[ m_columns.m_url ]; if( url.empty() ) return url; // 移転があったら url を最新のものに変換しておく int type = row2type( row ); switch( type ){ case TYPE_BOARD: case TYPE_BOARD_UPDATE: url = DBTREE::url_boardbase( url ); break; case TYPE_THREAD: case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: url = DBTREE::url_dat( url ); break; } return url; } // // path -> name 変換 // const Glib::ustring BBSListViewBase::path2name( const Gtk::TreePath& path ) { Gtk::TreeModel::Row row = m_treeview.get_row( path ); if( !row ) return Glib::ustring(); return row[ m_columns.m_name ]; } // // path -> type 変換 // const int BBSListViewBase::path2type( const Gtk::TreePath& path ) { Gtk::TreeModel::Row row = m_treeview.get_row( path ); if( !row ) return TYPE_UNKNOWN; return row[ m_columns.m_type ]; } // // row -> type 変換 // const int BBSListViewBase::row2type( const Gtk::TreeModel::Row& row ) { if( ! row ) return TYPE_UNKNOWN; return row[ m_columns.m_type ]; } // // row -> name 変換 // const Glib::ustring BBSListViewBase::row2name( const Gtk::TreeModel::Row& row ) { if( !row ) return Glib::ustring(); return row[ m_columns.m_name ]; } // // row -> dirid 変換 // const size_t BBSListViewBase::row2dirid( const Gtk::TreeModel::Row& row ) { if( !row ) return 0; return row[ m_columns.m_dirid ]; } // // 外部板のディレクトリか // bool BBSListViewBase::is_etcdir( Gtk::TreePath path ) { std::string name = path2name( path ); #ifdef _DEBUG std::cout << "BBSListViewBase:is_etcdir path = " << path.to_string() << " name = " << name << std::endl; #endif if( name == SUBDIR_ETCLIST ) return true; return false; } // // 外部板か // bool BBSListViewBase::is_etcboard( Gtk::TreeModel::iterator& it ) { Gtk::TreePath path = get_treestore()->get_path( *it ); return is_etcboard( path ); } bool BBSListViewBase::is_etcboard( Gtk::TreePath path ) { path.up(); return is_etcdir( path ); } // // ステータス表示 // void BBSListViewBase::show_status() { set_status( path2url( m_treeview.get_current_path() ) ); BBSLIST::get_admin()->set_command( "set_status", get_url(), get_status() ); } // // tree -> XML 変換 // // void BBSListViewBase::tree2xml( const std::string& root_name ) { if( ! m_ready_tree ) return; #ifdef _DEBUG std::cout << "BBSListViewBase::tree2xml\n"; #endif m_treeview.tree2xml( m_document, root_name ); // 座標 int y = 0; Gtk::Adjustment* adjust = m_treeview.get_vadjustment(); if( adjust ) { if( m_jump_y != -1 && adjust->get_upper() > m_jump_y ) y = m_jump_y; else y = ( int ) adjust->get_value(); } else if( m_jump_y != -1 ) y = m_jump_y; // 選択中のパス std::string path; Gtk::TreeModel::Path focused_path = m_treeview.get_current_path(); if( ! focused_path.empty() ) path = focused_path.to_string(); // ルート要素に属性( path, y )の値を設定 XML::Dom* root = m_document.get_root_element( root_name ); if( root ){ if( ! m_date_modified.empty() ) root->setAttribute( "date_modified", m_date_modified ); root->setAttribute( "y", y ); root->setAttribute( "path", path ); } } // // XML -> tree 変換 // void BBSListViewBase::xml2tree( const std::string& root_name, const std::string& xml ) { #ifdef _DEBUG std::cout << "BBSListViewBase::xml2tree\n"; #endif m_ready_tree = false; m_jump_y = 0; // 新規に文字列からDOMノードツリーを作成する場合 if( ! xml.empty() ) m_document.init( xml ); #ifdef _DEBUG std::cout << " ルートノード名=" << root_name; std::cout << " 子ノード数=" << m_document.childNodes().size() << std::endl; #endif m_treeview.xml2tree( m_document, m_treestore, root_name ); // ルート要素を取り出す XML::Dom* root = m_document.get_root_element( root_name ); if( root ){ // ルート要素から属性( date_modified, path, y )の値を取得 m_date_modified = root->getAttribute( "date_modified" ); std::string focused_path = root->getAttribute( "path" ); int y = atoi( root->getAttribute( "y" ).c_str() ); // 前回閉じた位置まで移動 if( focused_path.empty() ) { focused_path = "0"; y = 0; } Gtk::TreePath path = Gtk::TreePath( focused_path ); if( m_treeview.get_row( path ) ) m_treeview.set_cursor( path ); else { m_treeview.get_selection()->unselect_all(); y = 0; } // この段階ではまだスクロールバーが表示されてない時があるのでclock_in()で移動する m_jump_y = y; } m_ready_tree = true; } // // 起動時や移転があったときなどに行に含まれるURlを変更する // void BBSListViewBase::update_urls() { if( ! m_ready_tree ) return; if( m_treestore->children().empty() ) return; #ifdef _DEBUG std::cout << "BBSListViewBase::update_urls " << get_url() << std::endl; #endif bool updated = false; // 移転情報の保存( Root::save_movetable() )を無効にする。 // 無効にしないと DBTREE::url_boardbase() -> Root::get_board() 経由で // 繰り返し Root::save_movetable() が実行されてJDが固まったようになる DBTREE::set_enable_save_movetable( false ); m_set_board.clear(); m_set_thread.clear(); m_set_image.clear(); SKELETON::EditTreeViewIterator it( m_treeview, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; const Glib::ustring url = row[ m_columns.m_url ]; const int type = row[ m_columns.m_type ]; #ifdef _DEBUG std::cout << row2name( row ) << std::endl; #endif std::string url_new; switch( type ){ case TYPE_BOARD: // 板 case TYPE_BOARD_UPDATE: url_new = DBTREE::url_boardbase( url ); if( url != url_new ){ updated = true; row[ m_columns.m_url ] = url_new; #ifdef _DEBUG std::cout << url << " -> " << url_new << std::endl; #endif } m_set_board.insert( url_new ); break; case TYPE_VBOARD: m_set_board.insert( url ); break; case TYPE_THREAD: // スレ case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: url_new = DBTREE::url_dat( url ); if( url != url_new ){ updated = true; row[ m_columns.m_url ] = url_new; #ifdef _DEBUG std::cout << url << " -> " << url_new << std::endl; #endif } m_set_thread.insert( url_new ); break; case TYPE_IMAGE: m_set_image.insert( url ); break; } } DBTREE::set_enable_save_movetable( true ); if( updated ){ save_xml(); DBTREE::save_movetable(); } } // // アイコン表示(スレ)の切り替え // void BBSListViewBase::toggle_articleicon( const std::string& url ) { if( ! m_ready_tree ) return; if( m_treestore->children().empty() ) return; // ツリーの中に無い場合は処理しない if( ! m_set_thread.find_if( url ) ) return; bool erase = true; int type = TYPE_THREAD; const int status = DBTREE::article_status( url ); if( status & STATUS_OLD ) type = TYPE_THREAD_OLD; else if( status & STATUS_UPDATE ) type = TYPE_THREAD_UPDATE; #ifdef _DEBUG std::cout << "BBSListViewBase::toggle_articleicon url = " << url << " type = " << type << std::endl; #endif SKELETON::EditTreeViewIterator it( m_treeview, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; const Glib::ustring url_row = row[ m_columns.m_url ]; const int type_row = row[ m_columns.m_type ]; if( type_row == TYPE_THREAD || type_row == TYPE_THREAD_UPDATE || type_row == TYPE_THREAD_OLD ){ if( url == url_row ){ #ifdef _DEBUG std::cout << "hit " << url << " == " << url_row << std::endl; std::cout << row2name( row ) << std::endl; #endif row[ m_columns.m_type ] = type; row[ m_columns.m_image ] = XML::get_icon( type ); erase = false; } } } if( erase ) m_set_thread.erase( url ); } // // アイコン表示(板)の切り替え // void BBSListViewBase::toggle_boardicon( const std::string& url ) { if( ! m_ready_tree ) return; if( m_treestore->children().empty() ) return; const std::string url_boardbase = DBTREE::url_boardbase( url ); // ツリーの中に無い場合は処理しない if( m_set_board.find( url_boardbase ) == m_set_board.end() ) return; bool erase = true; int type = TYPE_BOARD; const int status = DBTREE::board_status( url ); if( status & STATUS_UPDATE ) type = TYPE_BOARD_UPDATE; #ifdef _DEBUG std::cout << "BBSListViewBase::toggle_boardicon url = " << url_boardbase << " type = " << type << std::endl; #endif SKELETON::EditTreeViewIterator it( m_treeview, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; const Glib::ustring url_row = row[ m_columns.m_url ]; const int type_row = row[ m_columns.m_type ]; if( type_row == TYPE_BOARD || type_row == TYPE_BOARD_UPDATE ){ if( url_boardbase == url_row ){ #ifdef _DEBUG std::cout << "hit " << url_boardbase << " == " << url_row << std::endl; std::cout << row2name( row ) << std::endl; #endif row[ m_columns.m_type ] = type; row[ m_columns.m_image ] = XML::get_icon( type ); erase = false; } } } if( erase ) m_set_board.erase( url_boardbase ); } // // URLを選択 // void BBSListViewBase::select_item( const std::string& url ) { if( ! m_ready_tree ) return; if( m_treestore->children().empty() ) return; std::string url_item( url ); if( m_set_thread.find_if( url_item ) || m_set_image.find( url_item ) != m_set_image.end()){ // スレまたは画像の場合 } else { // 板の場合 url_item = DBTREE::url_boardbase( url ); // 未登録の画像などで、板が見つからない場合は処理しない if( url_item.empty() ) return; } Gtk::TreePath closed_path; int closed_found = false; SKELETON::EditTreeViewIterator it( m_treeview, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; const Glib::ustring url_row = row[ m_columns.m_url ]; if( url_item == url_row ){ // 最初に見つかったものにフォーカスする Gtk::TreePath path = GET_PATH( row ); if( m_treeview.is_expand( path ) ){ // 開いているエントリ m_treeview.get_selection()->unselect_all(); m_treeview.set_cursor( path ); return; } // 最初の閉じたエントリを覚えておく if( ! closed_found ){ closed_found = true; closed_path = path; } } } // 開いたエントリが見つからない if( closed_found && CONFIG::get_select_item_sync() == 2 ){ // 閉じたエントリの上位フォルダを開いてフォーカスする m_treeview.get_selection()->unselect_all(); m_treeview.expand_parents( closed_path ); m_treeview.set_cursor( closed_path ); } } // // 新スレ移行時などにスレの url と 名前を変更 // void BBSListViewBase::replace_thread( const std::string& url, const std::string& url_new ) { #ifdef _DEBUG std::cout << "BBSListViewBase::replace_thread url = " << url << " url_new = " << url_new << std::endl; #endif if( ! m_ready_tree ) return; if( m_treestore->children().empty() ) return; const std::string urldat_new = DBTREE::url_dat( url_new ); if( urldat_new.empty() ) return; const std::string name_new = DBTREE::article_subject( urldat_new ); if( name_new.empty() ) return; bool show_diag = CONFIG::show_diag_replace_favorite(); int mode = CONFIG::get_replace_favorite_next(); if( ! show_diag && mode == REPLACE_NEXT_NO ) return; const std::string urldat = DBTREE::url_dat( url ); const std::string urlcgi = DBTREE::url_readcgi( url, 0, 0 ); const std::string name_old = MISC::remove_space( DBTREE::article_subject( urldat ) ); int type = TYPE_THREAD; const int status = DBTREE::article_status( urldat_new ); if( status & STATUS_OLD ) type = TYPE_THREAD_OLD; if( status & STATUS_UPDATE ) type = TYPE_THREAD_UPDATE; #ifdef _DEBUG std::cout << "name_new = " << name_new << std::endl << "name_old = " << name_old << std::endl << "type = " << type << std::endl; #endif SKELETON::EditTreeViewIterator it( m_treeview, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; const Glib::ustring url_row = row[ m_columns.m_url ]; switch( row[ m_columns.m_type ] ){ case TYPE_THREAD: case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: if( urldat == url_row || urlcgi == url_row ){ if( show_diag ){ show_diag = false; SKELETON::MsgCheckDiag mdiag( get_parent_win(), "お気に入りに前スレが登録されています。\n\n名前とアドレスを新スレの物に置き換えますか?" , "今後表示しない(_D)", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE ); mdiag.add_default_button( Gtk::Stock::NO, Gtk::RESPONSE_NO ); mdiag.add_button( Gtk::Stock::YES, Gtk::RESPONSE_YES ); mdiag.add_button( "新スレをお気に入りに追加(_F)", Gtk::RESPONSE_CANCEL ); mdiag.set_title( "お気に入り更新" ); const int ret = mdiag.run(); switch( ret ){ case Gtk::RESPONSE_YES: mode = REPLACE_NEXT_YES; break; case Gtk::RESPONSE_NO: mode = REPLACE_NEXT_NO; break; case Gtk::RESPONSE_CANCEL: mode = REPLACE_NEXT_ADD; break; } if( mdiag.get_chkbutton().get_active() ){ CONFIG::set_show_diag_replace_favorite( false ); CONFIG::set_replace_favorite_next( mode ); } if( mode == REPLACE_NEXT_NO ) return; } // 行を開いた時にxmlを保存 m_treeview.set_updated( true ); // 置き換え if( mode == REPLACE_NEXT_YES ){ row[ m_columns.m_url ] = urldat_new; // 名前が古いものであったら更新 // 手動で変更されていたらそのまま const Glib::ustring name_row = row[ m_columns.m_name ]; #ifdef _DEBUG std::cout << "name_row = " << name_row << std::endl; #endif if( MISC::remove_space( name_row ) == name_old ){ #ifdef _DEBUG std::cout << "replace name\n"; #endif row[ m_columns.m_name ] = name_new; } row[ m_columns.m_type ] = type; row[ m_columns.m_image ] = XML::get_icon( type ); } // 追加 else if( mode == REPLACE_NEXT_ADD ){ CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; info.type = type; info.parent = BBSLIST::get_admin()->get_win(); info.url = urldat_new; info.name = name_new; info.path = Gtk::TreePath( "0" ).to_string(); list_info.push_back( info ); CORE::SBUF_set_list( list_info ); CORE::core_set_command( "append_favorite", URL_FAVORITEVIEW ); return; } } } } } // // 検索 // // m_search_invert = true なら前方検索 // void BBSListViewBase::exec_search() { JDLIB::Regex regex_name; JDLIB::Regex regex_url; CORE::core_set_command( "set_info", "", "" ); std::string query = get_search_query(); if( query.empty() ){ focus_view(); return; } Gtk::TreePath path = m_treeview.get_current_path(); if( !m_treeview.get_row( path ) ){ goto_top(); path = m_treeview.get_current_path(); } // queryが新しいのに更新されたらひとつ前か後から検索をかける if( query != m_pre_query ){ if( !m_search_invert ) path = m_treeview.prev_path( path, false ); else path = m_treeview.next_path( path, false ); m_pre_query = query; CORE::get_completion_manager()->set_query( CORE::COMP_SEARCH_BBSLIST, query ); } Gtk::TreePath path_start = path; #ifdef _DEBUG std::cout << "BBSListViewBase::exec_search() path = " << path.to_string() << " query = " << query << std::endl; #endif const bool icase_name = true; // 大文字小文字区別しない const bool newline_name = true; // . に改行をマッチさせない const bool usemigemo_name = true; // migemo使用 const bool wchar_name = true; // 全角半角の区別をしない regex_name.compile( query, icase_name, newline_name, usemigemo_name, wchar_name ); const bool icase_url = true; // 大文字小文字区別しない const bool newline_url = true; const bool usemigemo_url = false; const bool wchar_url = false; regex_url.compile( query, icase_url, newline_url, usemigemo_url, wchar_url ); bool hit = false; for(;;){ // 後方 if( !m_search_invert ){ path = m_treeview.next_path( path, false ); // 一番最後を過ぎたら先頭に戻る if( ! m_treeview.get_row( path ) ) path = GET_PATH( *( m_treestore->children().begin() ) ); } // 前方 else{ // 先頭にいるときは最後に戻る if( path == GET_PATH( *( m_treestore->children().begin() ) ) ){ path = GET_PATH( *( m_treestore->children().rbegin() ) ); Gtk::TreePath path_tmp = path; while( m_treeview.get_row( path_tmp ) ){ path = path_tmp; path_tmp = m_treeview.next_path( path_tmp, false ); } } else path = m_treeview.prev_path( path, false ); } Glib::ustring name = path2name( path ); Glib::ustring url = path2url( path ); const size_t offset = 0; if( regex_name.exec( name, offset ) || regex_url.exec( url, offset ) ) hit = true; // 一周したら終わり if( path == path_start ) break; // カーソル移動 if( hit ){ m_treeview.expand_parents( path ); m_treeview.scroll_to_row( path, 0.1 ); m_treeview.set_cursor( path ); show_status(); break; } } if( hit ) focus_view(); else CORE::core_set_command( "set_info", "", "検索結果: ヒット無し" ); } // 前検索 void BBSListViewBase::up_search() { set_search_invert( true ); exec_search(); } // 後検索 void BBSListViewBase::down_search() { set_search_invert( false ); exec_search(); } // // 検索entryの操作 // void BBSListViewBase::operate_search( const std::string& controlid ) { int id = atoi( controlid.c_str() ); if( id == CONTROL::Cancel ) focus_view(); } // // 挿入先ダイアログを表示してアイテム追加 // // あらかじめ共有バッファにデータを入れておくこと // void BBSListViewBase::append_item() { if( m_editlistwin ){ m_editlistwin->append_item(); return; } if( CORE::SBUF_size() == 0 ) return; // 挿入先ダイアログ内で編集を行うとバッファがクリアされてしまうので // バックアップを取っておく CORE::DATA_INFO_LIST list_info_bkup = CORE::SBUF_list_info(); std::string path_str; const int show_diag = CONFIG::get_show_favorite_select_diag(); if( show_diag == 1 ) path_str = "-1"; else if( show_diag == 2 ) path_str = ""; else{ // 挿入先ダイアログ表示 Gtk::Window* parent = ( *list_info_bkup.begin() ).parent; SelectListDialog diag( parent, get_url(), get_treestore() ); if( diag.run() != Gtk::RESPONSE_OK ) return; path_str = diag.get_path(); if( list_info_bkup.size() == 1 && ! diag.get_name().empty() ) ( *list_info_bkup.begin() ).name = diag.get_name(); } bool before = false; Gtk::TreePath path; // 先頭 if( path_str == "-1" ){ path = Gtk::TreePath( "0" ); before = true; } // 最後 else if( path_str.empty() ) path = Gtk::TreePath(); else path = Gtk::TreePath( path_str ); const bool scroll = true; const bool force = false; const bool cancel_undo_commit = false; const int check_dup = CONFIG::get_check_favorite_dup(); // 重複チェックするか const CORE::DATA_INFO_LIST list_info = m_treeview.append_info( list_info_bkup, path, before, scroll, force, cancel_undo_commit, check_dup ); CORE::SBUF_clear_info(); slot_dropped_from_other( list_info ); // 行を開いた時にxmlを保存 m_treeview.set_updated( true ); } // // 履歴のセット // // 先頭にアイテムを追加する。ツリーにアイテムが含まれている場合は移動する // あらかじめ共有バッファにデータを入れておくこと // void BBSListViewBase::append_history() { if( CORE::SBUF_size() == 0 ) return; CORE::DATA_INFO_LIST list_info = CORE::SBUF_list_info(); CORE::DATA_INFO_LIST::iterator it_info = list_info.begin(); ( *it_info ).path = Gtk::TreePath( "0" ).to_string(); #ifdef _DEBUG std::cout << "BBSListViewBase::append_history url = " << ( *it_info ).url << std::endl; #endif // ツリーにアイテムが含まれている場合は削除 // 履歴はサブディレクトリが無いと仮定してサブディレクトリの探査はしない if( ( ( *it_info ).type == TYPE_THREAD && m_set_thread.find_if( ( *it_info ).url ) ) || ( ( ( *it_info ).type == TYPE_BOARD || ( *it_info ).type == TYPE_VBOARD ) && m_set_board.find( ( *it_info ).url ) != m_set_board.end() ) || ( ( *it_info ).type == TYPE_IMAGE && m_set_image.find( ( *it_info ).url ) != m_set_image.end() ) ){ std::vector< Gtk::TreePath > del_path; Gtk::TreeModel::iterator it = m_treestore->children().begin(); for( ; it != m_treestore->children().end(); ++it ){ Gtk::TreeModel::Row row = *it; if( row2url( row ) == ( *it_info ).url ) del_path.push_back( GET_PATH( row ) ); } for( int i = del_path.size() -1; i >= 0 ; --i ){ #ifdef _DEBUG std::cout << "erase " << del_path[ i ].to_string() << std::endl; #endif m_treestore->erase( m_treeview.get_row( del_path[ i ] ) ); } } // 先頭にアイテム追加 Gtk::TreePath path; if( ! m_treestore->children().empty() ) path = Gtk::TreePath( "0" ); const bool before = true; const bool subdir = false; m_treeview.append_one_row( ( *it_info ).url, ( *it_info ).name, ( *it_info ).type, ( *it_info ).dirid, ( *it_info ).data, path, before, subdir ); // サイズが越えていたら最後を削除 while( ( int )m_treestore->children().size() > CONFIG::get_historyview_size() ){ Gtk::TreeModel::Row row = *( m_treestore->children().rbegin() ); m_treestore->erase( row ); #ifdef _DEBUG std::cout << "erase bottom\n"; #endif } goto_top(); CORE::SBUF_clear_info(); slot_dropped_from_other( list_info ); } // // 履歴を DATA_INFO_LIST 型で取得 // void BBSListViewBase::get_history( CORE::DATA_INFO_LIST& info_list ) { info_list.clear(); CORE::DATA_INFO info; // 履歴はサブディレクトリが無いと仮定してサブディレクトリの探査はしない Gtk::TreeModel::iterator it = get_treestore()->children().begin(); for( ; it != get_treestore()->children().end(); ++it ){ Gtk::TreeModel::Row row = *it; info.type = row2type( row ); info.url = row2url( row ); info.name = row2name( row ); info.dirid = row2dirid( row ); info_list.push_back( info ); } } // // 指定したidのディレクトリに含まれるスレのアドレスを取得 // void BBSListViewBase::get_threads( const size_t dirid, std::vector< std::string >& list_url ) { list_url.clear(); #ifdef _DEBUG std::cout << "BBSListViewBase::get_threads " << dirid << std::endl; #endif std::list< Gtk::TreePath > list_path; Gtk::TreePath path = m_treeview.dirid_to_path( dirid ); if( dirid && path.empty() ) return; SKELETON::EditTreeViewIterator it( m_treeview, m_columns, path ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; const int type = row2type( row ); if( type == TYPE_THREAD || type == TYPE_THREAD_UPDATE || type == TYPE_THREAD_OLD ){ #ifdef _DEBUG std::cout << row2name( row ) << std::endl; #endif list_url.push_back( row2url( row ) ); } } } // 指定したidのディレクトリの名前を取得 const std::string BBSListViewBase::get_dirname( const int dirid ) { if( ! dirid ) return get_label(); return path2name( m_treeview.dirid_to_path( dirid ) ); } // // url で指定した項目を削除 // void BBSListViewBase::remove_item( const std::string& url ) { std::string url_target = DBTREE::url_dat( url ); if( url_target.empty() ) url_target = DBTREE::url_boardbase( url ); if( url_target.empty() && DBIMG::get_type_ext( url ) != DBIMG::T_UNKNOWN ) url_target = url; if( url_target.empty() ) return; #ifdef _DEBUG std::cout << "BBSListViewBase::remove_item url = " << url_target << std::endl; #endif std::list< Gtk::TreePath > list_path; SKELETON::EditTreeViewIterator it( m_treeview, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; const Glib::ustring url = row[ m_columns.m_url ]; const int type = row[ m_columns.m_type ]; switch( type ){ case TYPE_BOARD: // 板 case TYPE_BOARD_UPDATE: case TYPE_THREAD: // スレ case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: case TYPE_IMAGE: // 画像 if( url == url_target ){ #ifdef _DEBUG std::cout << "hit " << url << " == " << url_target << std::endl; std::cout << row2name( row ) << std::endl; #endif list_path.push_back( it.get_path() ); } break; } } const bool force = true; m_treeview.delete_path( list_path, force ); } // // 先頭項目を削除 // void BBSListViewBase::remove_headitem() { if( ! m_ready_tree ) return; if( m_treestore->children().empty() ) return; #ifdef _DEBUG std::cout << "BBSListViewBase::remove_headitem\n"; #endif std::list< Gtk::TreePath > list_path; SKELETON::EditTreeViewIterator it( m_treeview, m_columns, Gtk::TreePath() ); list_path.push_back( it.get_path() ); const bool force = true; m_treeview.delete_path( list_path, force ); } // // 全項目を削除 // void BBSListViewBase::remove_allitems() { #ifdef _DEBUG std::cout << "BBSListViewBase::remove_allitems\n"; #endif m_treestore->clear(); m_set_board.clear(); m_set_thread.clear(); m_set_image.clear(); } // // ツリーの編集ウィンドウを開く // void BBSListViewBase::edit_tree() { if( m_editlistwin ) m_editlistwin->present(); else{ m_editlistwin = new EditListWin( get_url(), get_treestore() ); m_editlistwin->signal_hide().connect( sigc::mem_fun(*this, &BBSListViewBase::slot_hide_editlistwin ) ); m_editlistwin->show(); } } // // ツリーの編集ウィンドウが閉じた // void BBSListViewBase::slot_hide_editlistwin() { #ifdef _DEBUG std::cout << "BBSListViewBase::slot_hide_editlistwin\n"; #endif if( m_editlistwin ) delete m_editlistwin; m_editlistwin = NULL; } // // XML保存 // // remove_dir != empty()の時はその名前のディレクトリを削除する // void BBSListViewBase::save_xml_impl( const std::string& file, const std::string& root, const std::string& remove_dir ) { if( file.empty() ) return; if( root.empty() ) return; if( ! get_ready_tree() ) return; #ifdef _DEBUG std::cout << "BBSListViewBase::save_xml file = " << file << " root = " << root << " remove_dir = " << remove_dir << std::endl; #endif tree2xml( root ); // 指定したディレクトリを取り除く if( ! remove_dir.empty() ) { XML::Dom* domroot = m_document.get_root_element( root ); XML::DomList domlist = domroot->childNodes(); std::list< XML::Dom* >::iterator it = domlist.begin(); while( it != domlist.end() ) { if( (*it)->nodeName() == "subdir" && (*it)->getAttribute( "name" ) == remove_dir ) { domroot->removeChild( *it ); break; } ++it; } } CACHE::save_rawdata( file, m_document.get_xml() ); } // undo, redo void BBSListViewBase::undo() { m_treeview.undo(); } void BBSListViewBase::redo() { m_treeview.redo(); } jd-2.8.7-140104/src/bbslist/bbslistviewbase.h0000644000076400010400000002626512175137371015404 0ustar // ライセンス: GPL2 // // 板ビュークラスのベースクラス // #ifndef _BBSLISTVIEWBASE_H #define _BBSLISTVIEWBASE_H #include "skeleton/view.h" #include "skeleton/edittreeview.h" #include "xml/document.h" #include "jdlib/hash_set.h" #include "columns.h" #include namespace SKELETON { class Admin; }; #define SUBDIR_ETCLIST "外部板" namespace BBSLIST { class EditListWin; class BBSListViewBase : public SKELETON::View { Glib::RefPtr< Gtk::TreeStore > m_treestore; SKELETON::EditTreeView m_treeview; // DOM共有オブジェクト XML::Document m_document; std::string m_date_modified; bool m_ready_tree; // ツリーがセットされているならtrue BBSLIST::TreeColumns m_columns; Gtk::ScrolledWindow m_scrwin; // クリック状態 bool m_clicked; // ダブルクリック状態 bool m_dblclicked; // ポップアップメニュー用 Gtk::TreeModel::Path m_path_selected; // クロック入力されたときにtreeview のスクロールバーを指定した位置に移動する // clock_in()の説明を参照 int m_jump_y; // サーチで使う変数 bool m_search_invert; std::string m_pre_query; bool m_open_only_onedir; // あるフォルダを開いたときに他のフォルダを閉じる bool m_cancel_expand; // signal_row_expanded() をキャンセルする bool m_expanding; // 行を開いている最中にtrueにしてsignal_row_collapsed()をキャンセルする // ツリーに含まれているスレのURLを入れる hash_set // toggle_articleicon() で使用する JDLIB::hash_set_thread m_set_thread; // ツリーに含まれている板のURLを入れる set // toggle_boardicon() で使用する std::set< std::string > m_set_board; // ツリーに含まれている画像のURLを入れる hash_set std::set< std::string > m_set_image; EditListWin* m_editlistwin; // スレを追加したときにそのスレにしおりを付ける bool m_set_bookmark; protected: // Viewが所属するAdminクラス virtual SKELETON::Admin* get_admin(); // treeviewのD&Dによる編集を可能にする void set_editable( const bool editable ); void set_search_invert( const bool invert ){ m_search_invert = invert; } // スレを追加したときにそのスレにしおりを付ける void set_bookmark( const bool set ){ m_set_bookmark = set; } // DOM共有オブジェクト XML::Document& get_document(){ return m_document;} void set_document( const XML::Document& document){ m_document = document;} Glib::RefPtr< Gtk::TreeStore >& get_treestore() { return m_treestore; } SKELETON::EditTreeView& get_treeview() { return m_treeview; } const bool& get_ready_tree() const{ return m_ready_tree; } void set_open_only_onedir( const bool set ){ m_open_only_onedir = set; } virtual void activate_act_before_popupmenu( const std::string& url ); // tree <-> XML( DOM )変換 void tree2xml( const std::string& root_name ); void xml2tree( const std::string& root_name, const std::string& xml = std::string() ); // 外部板のディレクトリか bool is_etcdir( Gtk::TreePath path ); // 外部板か bool is_etcboard( Gtk::TreeModel::iterator& it ); bool is_etcboard( Gtk::TreePath path ); // 起動時や移転があったときなどに行に含まれるURlを変更する void update_urls(); // アイコン表示(スレ)の切り替え void toggle_articleicon( const std::string& url ); // アイコン表示(板)の切り替え void toggle_boardicon( const std::string& url ); // URLを選択 void select_item( const std::string& url ); // スレの url と 名前を変更 void replace_thread( const std::string& url, const std::string& url_new ); // path からその行のタイプを取得 const int path2type( const Gtk::TreePath& path ); // row からタイプを取得 const int row2type( const Gtk::TreeModel::Row& row ); // row -> name 変換 const Glib::ustring row2name( const Gtk::TreeModel::Row& row ); // row -> url 変換 // 板の場合は boardbase // スレの場合は dat 型のアドレスを返す const Glib::ustring row2url( const Gtk::TreeModel::Row& row ); // row -> dirid 変換 const size_t row2dirid( const Gtk::TreeModel::Row& row ); // path からその行の名前を取得 const Glib::ustring path2name( const Gtk::TreePath& path ); // path からその行のURLを取得 const Glib::ustring path2rawurl( const Gtk::TreePath& path ); const Glib::ustring path2url( const Gtk::TreePath& path ); // 移転をチェックするバージョン // url で指定した項目を削除 void remove_item( const std::string& url ); // 先頭項目を削除 void remove_headitem(); // 全項目を削除 void remove_allitems(); // ツリーの編集ウィンドウを開く void edit_tree(); // xml保存 virtual void save_xml() = 0; // remove_dir != empty()の時はその名前のディレクトリを削除する void save_xml_impl( const std::string& file, const std::string& root, const std::string& remove_dir ); // idからポップアップメニュー取得 Gtk::Menu* id2popupmenu( const std::string& id ); public: BBSListViewBase( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() ); virtual ~BBSListViewBase(); // // SKELETON::View の関数のオーバロード // virtual void save_session(); // 親ウィンドウをセット virtual void set_parent_win( Gtk::Window* parent_win ); virtual const std::string url_for_copy(){ return std::string(); } virtual const bool set_command( const std::string& command, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() ); virtual void clock_in(); // キーを押した virtual const bool slot_key_press( GdkEventKey* event ); virtual void stop(); virtual void redraw_view(); virtual void relayout(); // 色やフォントなどの変更 virtual void focus_view(); virtual void focus_out(); virtual void close_view(); virtual void delete_view(); // ツリー内の全ての項目をURLを新しいアドレスに変更 ( id は未使用 ) virtual void update_item( const std::string& url, const std::string& id ); virtual const bool operate_view( const int control ); virtual void goto_top(); virtual void goto_bottom(); // 検索 virtual void exec_search(); virtual void up_search(); virtual void down_search(); virtual void operate_search( const std::string& controlid ); // 挿入先ダイアログを表示してアイテム追加 // あらかじめ共有バッファに追加するデータをセットしておくこと void append_item(); // 履歴のセット // 先頭にアイテムを追加する。ツリーにアイテムが含まれている場合は移動する // あらかじめ共有バッファに追加するデータをセットしておくこと void append_history(); // 履歴を DATA_INFO_LIST 型で取得 void get_history( CORE::DATA_INFO_LIST& info_list ); // 指定したidのディレクトリに含まれるスレのアドレスを取得 void get_threads( const size_t dirid, std::vector< std::string >& list_url ); // 指定したidのディレクトリの名前を取得 const std::string get_dirname( const int dirid ); // selectdialogで使う Gtk::TreePath get_current_path() { return m_treeview.get_current_path(); } void copy_treestore( Glib::RefPtr< Gtk::TreeStore >& store ); // undo, redo void undo(); void redo(); private: void set_fgcolor_of_comment( const Gtk::TreeModel::Children& children ); void row_up(); void row_down(); void page_up(); void page_down(); void prev_dir(); void next_dir(); void expand_all_dir( Gtk::TreeModel::Path path ); // ディレクトリ以下を更新チェック // root : true ならルートから検索する。falseの場合は m_path_selected にパスをセットしておくこと // open : チェック後に更新していたら開く void check_update_dir( const bool root, const bool open ); bool slot_button_press( GdkEventButton* event ); bool slot_button_release( GdkEventButton* event ); bool slot_motion_notify( GdkEventMotion* event ); bool slot_key_release( GdkEventKey* event ); bool slot_scroll_event( GdkEventScroll* event ); void slot_dropped_from_other( const CORE::DATA_INFO_LIST& list_info ); void slot_open_tab(); void slot_open_browser(); void slot_open_cache_browser(); void slot_append_favorite(); void slot_newdir(); void slot_newcomment(); void slot_newetcboard(); void slot_moveetcboard(); void slot_rename(); void slot_copy_url(); void slot_copy_title_url(); void slot_select_all_dir(); void slot_select_all(); void slot_check_update_dir(); void slot_check_update_open_dir(); void slot_opendir_as_board(); void slot_create_vboard(); void slot_search_cache_board(); void slot_import_dat(); void slot_preferences_board(); void slot_preferences_article(); void slot_preferences_image(); void slot_row_exp( const Gtk::TreeModel::iterator& it, const Gtk::TreeModel::Path& path ); void slot_row_col( const Gtk::TreeModel::iterator& it, const Gtk::TreeModel::Path& path ); void slot_checkupdate_selected_rows(); void slot_checkupdate_open_selected_rows(); void slot_sort( const int mode ); virtual void delete_view_impl(); // 外部板追加/編集 void add_newetcboard( const bool move, const std::string& _url, const std::string& _name, const std::string& _id, const std::string& _passwd ); // D&D 関係 void slot_drag_drop( Gtk::TreeModel::Path path, const bool after ); virtual const bool open_row( Gtk::TreePath& path, const bool tab ); virtual void switch_rightview(); void open_selected_rows(); void checkupdate_selected_rows( const bool open ); void show_status(); // ツリーの編集ウィンドウが閉じた void slot_hide_editlistwin(); }; }; #endif jd-2.8.7-140104/src/bbslist/columns.cpp0000644000076400010400000000126211350440352014203 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "columns.h" #include "config/globalconf.h" #include "xml/tools.h" #include "colorid.h" #include "type.h" using namespace BBSLIST; TreeColumns::TreeColumns() : SKELETON::EditColumns() {} TreeColumns::~TreeColumns() {} void TreeColumns::setup_row( Gtk::TreeModel::Row& row, const Glib::ustring url, const Glib::ustring name, const Glib::ustring data, const int type, const size_t dirid ) { SKELETON::EditColumns::setup_row( row, url, name, data, type, dirid ); if( type == TYPE_COMMENT ) row[ m_fgcolor ] = Gdk::Color( CONFIG::get_color( COLOR_CHAR_BBS_COMMENT ) ); } jd-2.8.7-140104/src/bbslist/columns.h0000644000076400010400000000100111350440352013637 0ustar // ライセンス: GPL2 // // コラム // #ifndef _BBSLISTCOLUMNS_H #define _BBSLISTCOLUMNS_H #include "skeleton/editcolumns.h" namespace BBSLIST { class TreeColumns : public SKELETON::EditColumns { public: TreeColumns(); virtual ~TreeColumns(); virtual void setup_row( Gtk::TreeModel::Row& row, const Glib::ustring url, const Glib::ustring name, const Glib::ustring data, const int type, const size_t dirid ); }; } #endif jd-2.8.7-140104/src/bbslist/editlistwin.cpp0000644000076400010400000001216611177206361015076 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "editlistwin.h" #include "selectlistview.h" #include "toolbar.h" #include "bbslistadmin.h" #include "skeleton/compentry.h" #include "skeleton/undobuffer.h" #include "jdlib/miscutil.h" #include "viewfactory.h" using namespace BBSLIST; enum { EDITWIN_WIDTH = 800, EDITWIN_HEIGHT = 500 }; EditListWin::EditListWin( const std::string& url, Glib::RefPtr< Gtk::TreeStore >& treestore ) : Gtk::Window( Gtk::WINDOW_TOPLEVEL ), m_label( "マウスの中ボタンドラッグで行の複数選択が可能です。" ) { // ツールバー m_toolbar = Gtk::manage( new EditListToolBar() ); m_toolbar->open_buttonbar(); m_vbox.pack_start( *m_toolbar, Gtk::PACK_SHRINK ); m_toolbar->show_toolbar(); // Adminクラスが無いのでツールバーのボタン等のシグナルを直接つなぐ m_toolbar->get_button_close()->signal_clicked().connect( sigc::mem_fun( this, &EditListWin::slot_close ) ); m_toolbar->get_entry_search()->signal_changed().connect( sigc::mem_fun( *this, &EditListWin::slot_changed_search ) ); m_toolbar->get_entry_search()->signal_activate().connect( sigc::mem_fun( *this, &EditListWin::slot_active_search ) ); m_toolbar->get_entry_search()->signal_operate().connect( sigc::mem_fun( *this, &EditListWin::slot_operate_search ) ); m_toolbar->get_button_up_search()->signal_clicked().connect( sigc::mem_fun( this, &EditListWin::slot_up_search ) ); m_toolbar->get_button_down_search()->signal_clicked().connect( sigc::mem_fun( this, &EditListWin::slot_down_search ) ); m_toolbar->get_button_undo()->signal_clicked().connect( sigc::mem_fun( this, &EditListWin::slot_undo ) ); m_toolbar->get_button_redo()->signal_clicked().connect( sigc::mem_fun( this, &EditListWin::slot_redo ) ); // ラベル m_vbox.pack_start( m_label, Gtk::PACK_SHRINK ); // ビュー m_selectview = dynamic_cast< SelectListView* > ( Gtk::manage( CORE::ViewFactory( CORE::VIEW_SELECTLIST, url ) ) ); if( m_selectview ){ m_selectview->set_parent_win( this ); m_selectview->copy_treestore( treestore ); m_selectview->sig_close_dialog().connect( sigc::mem_fun(*this, &EditListWin::hide ) ); m_selectview->sig_focus_entry_search().connect( sigc::mem_fun(*this, &EditListWin::slot_focus_entry_search ) ); m_vbox.pack_start( *m_selectview ); m_selectview->focus_view(); } // UNDOバッファの監視 BBSLIST::get_undo_buffer_favorite()->sig_undo().connect( sigc::mem_fun(*this, &EditListWin::slot_undo_buffer_changed ) ); BBSLIST::get_undo_buffer_favorite()->sig_redo().connect( sigc::mem_fun(*this, &EditListWin::slot_undo_buffer_changed ) ); BBSLIST::get_undo_buffer_favorite()->sig_commit().connect( sigc::mem_fun(*this, &EditListWin::slot_undo_buffer_changed ) ); add( m_vbox ); set_title( "お気に入りの編集" ); resize( EDITWIN_WIDTH, EDITWIN_HEIGHT ); show_all_children(); } void EditListWin::clock_in() { if( m_selectview ) m_selectview->clock_in(); } void EditListWin::append_item() { if( m_selectview ) m_selectview->append_item(); } // // 閉じる // void EditListWin::slot_close() { #ifdef _DEBUG std::cout << "EditListWin::slot_close\n"; #endif hide(); } // // 検索関係 // void EditListWin::slot_focus_entry_search() { #ifdef _DEBUG std::cout << "EditListWin::slot_focus_search\n"; #endif if( m_toolbar ) m_toolbar->focus_entry_search(); } void EditListWin::slot_changed_search() { #ifdef _DEBUG std::cout << "EditListWin::slot_changed_search\n"; #endif if( m_selectview && m_toolbar ) m_selectview->set_search_query( m_toolbar->get_search_text() ); } void EditListWin::slot_active_search() { #ifdef _DEBUG std::cout << "EditListWin::slot_active_search\n"; #endif if( m_selectview ) m_selectview->exec_search(); } void EditListWin::slot_operate_search( const int controlid ) { #ifdef _DEBUG std::cout << "EditListWin::slot_operate_search id = " << controlid << std::endl; #endif if( m_selectview ) m_selectview->operate_search( MISC::itostr( controlid ) ); } void EditListWin::slot_up_search() { #ifdef _DEBUG std::cout << "EditListWin::slot_up_search\n"; #endif if( m_selectview ) m_selectview->up_search(); } void EditListWin::slot_down_search() { #ifdef _DEBUG std::cout << "EditListWin::slot_down_search\n"; #endif if( m_selectview ) m_selectview->down_search(); } void EditListWin::slot_undo() { #ifdef _DEBUG std::cout << "EditListWin::slot_undo\n"; #endif if( m_selectview ) m_selectview->undo(); } void EditListWin::slot_redo() { #ifdef _DEBUG std::cout << "EditListWin::slot_redo\n"; #endif if( m_selectview ) m_selectview->redo(); } // // UNDOバッファを監視してボタン状態を更新する // void EditListWin::slot_undo_buffer_changed() { #ifdef _DEBUG std::cout << "EditListWin::slot_undo_buffer_changed\n"; #endif m_toolbar->get_button_undo()->set_sensitive( BBSLIST::get_undo_buffer_favorite()->get_enable_undo() ); m_toolbar->get_button_redo()->set_sensitive( BBSLIST::get_undo_buffer_favorite()->get_enable_redo() ); } jd-2.8.7-140104/src/bbslist/editlistwin.h0000644000076400010400000000173411125705250014534 0ustar // ライセンス: GPL2 // // お気に入り編集ウィンドウ // #ifndef _EDITLISTWIN_H #define _EDITLISTWIN_H #include namespace BBSLIST { class EditListToolBar; class SelectListView; class EditListWin : public Gtk::Window { SelectListView* m_selectview; Gtk::VBox m_vbox; Gtk::Label m_label; EditListToolBar* m_toolbar; public: EditListWin( const std::string& url, Glib::RefPtr< Gtk::TreeStore >& treestore ); void clock_in(); void append_item(); private: // 閉じる void slot_close(); // 検索関係 void slot_focus_entry_search(); void slot_changed_search(); void slot_active_search(); void slot_operate_search( const int controlid ); void slot_up_search(); void slot_down_search(); void slot_undo(); void slot_redo(); void slot_undo_buffer_changed(); }; }; #endif jd-2.8.7-140104/src/bbslist/favoriteview.cpp0000644000076400010400000000474711466523774015272 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "favoriteview.h" #include "toolbar.h" #include "config/globalconf.h" #include "cache.h" #include "type.h" // ルート要素名( bookmark.xml ) #define ROOT_NODE_NAME "favorite" using namespace BBSLIST; FavoriteListView::FavoriteListView( const std::string& url, const std::string& arg1, const std::string& arg2 ) : BBSListViewBase( url, arg1, arg2 ) { set_label( "お気に入り" ); // D&Dで編集可能 set_editable( true ); // スレをお気に入りに追加したらしおりをつけるかどうか set_bookmark( CONFIG::get_bookmark_drop() ); set_open_only_onedir( CONFIG::get_open_one_favorite() ); } FavoriteListView::~FavoriteListView() { #ifdef _DEBUG std::cout << "FavoriteList::~FavoriteList : " << get_url() << std::endl; #endif } // xml保存 void FavoriteListView::save_xml() { const std::string file = CACHE::path_xml_favorite(); save_xml_impl( file, ROOT_NODE_NAME, "" ); } // // 表示 // void FavoriteListView::show_view() { std::string xml; // ファイルが存在しなければ入力を旧ファイル名にする std::string file_in = CACHE::path_xml_favorite(); if( CACHE::file_exists( file_in ) != CACHE::EXIST_FILE ) { file_in = CACHE::path_xml_favorite_old(); } CACHE::load_rawdata( file_in, xml ); xml2tree( std::string( ROOT_NODE_NAME ), xml ); update_urls(); } // // ポップアップメニュー取得 // // SKELETON::View::show_popupmenu() を参照すること // Gtk::Menu* FavoriteListView::get_popupmenu( const std::string& url ) { Gtk::Menu* popupmenu = NULL; if( url.empty() ) popupmenu = id2popupmenu( "/popup_menu_favorite_space" ); else{ std::list< Gtk::TreeModel::iterator > list_it = get_treeview().get_selected_iterators(); if( list_it.size() == 1 ){ const int type = path2type( *( get_treeview().get_selection()->get_selected_rows().begin() ) ); if( type == TYPE_DIR ) popupmenu = id2popupmenu( "/popup_menu_favorite_dir" ); else if( type == TYPE_COMMENT ) popupmenu = id2popupmenu( "/popup_menu_favorite_com" ); else if( type == TYPE_VBOARD ) popupmenu = id2popupmenu( "/popup_menu_favorite_vboard" ); else popupmenu = id2popupmenu( "/popup_menu_favorite" ); } else popupmenu = id2popupmenu( "/popup_menu_favorite_mul" ); } return popupmenu; } jd-2.8.7-140104/src/bbslist/favoriteview.h0000644000076400010400000000116111466523774014722 0ustar // ライセンス: GPL2 // お気に入りビュー #ifndef _FAVORITEVIEW_H #define _FAVORITEVIEW_H #include "bbslistviewbase.h" namespace BBSLIST { // お気に入りビュー class FavoriteListView : public BBSListViewBase { public: FavoriteListView( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() ); virtual ~FavoriteListView(); virtual void show_view(); protected: // xml保存 virtual void save_xml(); virtual Gtk::Menu* get_popupmenu( const std::string& url ); }; } #endif jd-2.8.7-140104/src/bbslist/historyview.cpp0000644000076400010400000000560311577662613015143 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "historyview.h" #include "toolbar.h" #include "config/globalconf.h" #include "cache.h" #include "type.h" #include "global.h" // ルート要素名 #define ROOT_NODE_NAME "history" using namespace BBSLIST; HistoryViewBase::HistoryViewBase( const std::string& url, const std::string& file_xml, const std::string& arg1, const std::string& arg2 ) : BBSListViewBase( url, arg1, arg2 ), m_file_xml( file_xml ) {} HistoryViewBase::~HistoryViewBase() { #ifdef _DEBUG std::cout << "HistoryViewBase::~HistoryViewBase : " << get_url() << std::endl; #endif } // // 表示 // void HistoryViewBase::show_view() { std::string xml; CACHE::load_rawdata( m_file_xml, xml ); xml2tree( std::string( ROOT_NODE_NAME ), xml ); update_urls(); } // xml保存 void HistoryViewBase::save_xml() { save_xml_impl( m_file_xml, ROOT_NODE_NAME, "" ); } // // ポップアップメニュー取得 // // SKELETON::View::show_popupmenu() を参照すること // Gtk::Menu* HistoryViewBase::get_popupmenu( const std::string& url ) { Gtk::Menu* popupmenu = NULL; if( ! url.empty() ){ std::list< Gtk::TreeModel::iterator > list_it = get_treeview().get_selected_iterators(); if( list_it.size() == 1 ){ const int type = path2type( *( get_treeview().get_selection()->get_selected_rows().begin() ) ); if( type == TYPE_VBOARD ) popupmenu = id2popupmenu( "/popup_menu_history_vboard" ); else popupmenu = id2popupmenu( "/popup_menu_history" ); } else popupmenu = id2popupmenu( "/popup_menu_history_mul" ); } return popupmenu; } ////////////////////////////////// HistoryThreadView::HistoryThreadView( const std::string& url, const std::string& arg1, const std::string& arg2 ) : HistoryViewBase( url, CACHE::path_xml_history(), arg1, arg2 ) { set_label( ITEM_NAME_HISTVIEW ); } HistoryCloseView::HistoryCloseView( const std::string& url, const std::string& arg1, const std::string& arg2 ) : HistoryViewBase( url, CACHE::path_xml_history_close(), arg1, arg2 ) { set_label( ITEM_NAME_HIST_CLOSEVIEW ); } HistoryBoardView::HistoryBoardView( const std::string& url, const std::string& arg1, const std::string& arg2 ) : HistoryViewBase( url, CACHE::path_xml_history_board(), arg1, arg2 ) { set_label( ITEM_NAME_HIST_BOARDVIEW ); } HistoryCloseBoardView::HistoryCloseBoardView( const std::string& url, const std::string& arg1, const std::string& arg2 ) : HistoryViewBase( url, CACHE::path_xml_history_closeboard(), arg1, arg2 ) { set_label( ITEM_NAME_HIST_CLOSEBOARDVIEW ); } HistoryCloseImgView::HistoryCloseImgView( const std::string& url, const std::string& arg1, const std::string& arg2 ) : HistoryViewBase( url, CACHE::path_xml_history_closeimg(), arg1, arg2 ) { set_label( ITEM_NAME_HIST_CLOSEIMGVIEW ); } jd-2.8.7-140104/src/bbslist/historyview.h0000644000076400010400000000336011577662613014606 0ustar // ライセンス: GPL2 // 履歴ビュー #ifndef _HISTORYVIEW_H #define _HISTORYVIEW_H #include "bbslistviewbase.h" namespace BBSLIST { class HistoryViewBase : public BBSListViewBase { std::string m_file_xml; public: HistoryViewBase( const std::string& url, const std::string& file_xml, const std::string& arg1, const std::string& arg2 ); virtual ~HistoryViewBase(); virtual void show_view(); protected: // xml保存 virtual void save_xml(); virtual Gtk::Menu* get_popupmenu( const std::string& url ); }; /////////////////////////////////////// class HistoryThreadView : public HistoryViewBase { public: HistoryThreadView( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() ); }; class HistoryCloseView : public HistoryViewBase { public: HistoryCloseView( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() ); }; class HistoryBoardView : public HistoryViewBase { public: HistoryBoardView( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() ); }; class HistoryCloseBoardView : public HistoryViewBase { public: HistoryCloseBoardView( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() ); }; class HistoryCloseImgView : public HistoryViewBase { public: HistoryCloseImgView( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() ); }; } #endif jd-2.8.7-140104/src/bbslist/Makefile.am0000644000076400010400000000103212072045132014045 0ustar noinst_LIBRARIES = libbbslist.a libbbslist_a_SOURCES = \ bbslistadmin.cpp \ bbslistviewbase.cpp \ bbslistview.cpp \ favoriteview.cpp \ selectlistview.cpp \ historyview.cpp \ selectdialog.cpp \ editlistwin.cpp \ addetcdialog.cpp \ columns.cpp \ toolbar.cpp noinst_HEADERS = \ bbslistadmin.h \ bbslistviewbase.h bbslistview.h \ favoriteview.h \ selectlistview.h \ historyview.h \ selectdialog.h \ editlistwin.h \ addetcdialog.h \ columns.h \ toolbar.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/bbslist/selectdialog.cpp0000644000076400010400000001111111331063026015152 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "selectdialog.h" #include "selectlistview.h" #include "columns.h" #include "viewfactory.h" #include "command.h" #include "session.h" #include "type.h" #include "sharedbuffer.h" using namespace BBSLIST; enum { SELECTDIAG_WIDTH = 600, SELECTDIAG_TREEHEIGHT = 300 }; SelectListDialog::SelectListDialog( Gtk::Window* parent, const std::string& url, Glib::RefPtr< Gtk::TreeStore >& treestore ) : SKELETON::PrefDiag( parent, url, true ), m_treestore( treestore ), m_label_name( CORE::SBUF_size() == 1, "名前 :" ), m_label_dirs( "ディレクトリ :" ), m_bt_show_tree( "詳細" ), m_selectview( NULL ) { const int mrg = 8; if( CORE::SBUF_size() ) m_label_name.set_text( ( *CORE::SBUF_list_info().begin() ).name ); set_activate_entry( m_label_name ); m_hbox_dirs.set_spacing( mrg ); m_hbox_dirs.pack_start( m_label_dirs, Gtk::PACK_SHRINK ); m_hbox_dirs.pack_start( m_combo_dirs, Gtk::PACK_EXPAND_WIDGET ); m_hbox_dirs.pack_start( m_bt_show_tree, Gtk::PACK_SHRINK ); // コンボボックスにディレクトリをセット int active_row = 0; Glib::ustring name; name = "お気に入りの先頭に追加"; m_combo_dirs.append_text( name ); if( ! active_row && name == SESSION::get_dir_select_favorite() ) active_row = m_vec_path.size(); m_vec_path.push_back( "-1" ); name = "お気に入りの最後に追加"; m_combo_dirs.append_text( name ); if( ! active_row && name == SESSION::get_dir_select_favorite() ) active_row = m_vec_path.size(); m_vec_path.push_back( "" ); BBSLIST::TreeColumns columns; Gtk::TreeModel::Children child = m_treestore->children(); Gtk::TreeModel::Children::iterator it = child.begin(); for( ; it != child.end() ; ++it ){ Gtk::TreeModel::Row row = ( *it ); const int type = row[ columns.m_type ]; if( type == TYPE_DIR ){ name = row[ columns.m_name ]; m_combo_dirs.append_text( name ); if( ! active_row && name == SESSION::get_dir_select_favorite() ) active_row = m_vec_path.size(); Gtk::TreePath path = m_treestore->get_path( row ); m_vec_path.push_back( path.to_string() ); #ifdef _DEBUG std::cout << row[ columns.m_name ] << " path = " << path.to_string() << std::endl; #endif } } #ifdef _DEBUG std::cout << "active_row = " << active_row << std::endl; #endif m_combo_dirs.set_active( active_row ); get_vbox()->pack_start( m_label_name, Gtk::PACK_SHRINK ); get_vbox()->pack_start( m_hbox_dirs, Gtk::PACK_SHRINK ); m_bt_show_tree.signal_clicked().connect( sigc::mem_fun( this, &SelectListDialog::slot_show_tree ) ); set_title( "お気に入り追加先選択" ); resize( SELECTDIAG_WIDTH, 1 ); set_default_response( Gtk::RESPONSE_OK ); grab_ok(); show_all_children(); } SelectListDialog::~SelectListDialog() { if( m_selectview ) delete m_selectview; } // // OKを押した // void SelectListDialog::slot_ok_clicked() { if( ! m_selectview ) SESSION::set_dir_select_favorite( m_combo_dirs.get_active_text() ); } const std::string SelectListDialog::get_name() { return m_label_name.get_text(); } const std::string SelectListDialog::get_path() { std::string path; if( m_selectview ) path = m_selectview->get_current_path().to_string(); else path = m_vec_path[ m_combo_dirs.get_active_row_number() ]; #ifdef _DEBUG std::cout << "SelectListDialog::get_path path = " << path << std::endl; #endif return path; } void SelectListDialog::slot_show_tree() { #ifdef _DEBUG std::cout << "SelectListDialog::slot_show_tree\n"; #endif if( m_bt_show_tree.get_active() ){ if( ! m_selectview ) m_selectview = dynamic_cast< SelectListView* > ( Gtk::manage( CORE::ViewFactory( CORE::VIEW_SELECTLIST, get_url() ) ) ); if( m_selectview ){ m_selectview->set_parent_win( this ); m_selectview->copy_treestore( m_treestore ); m_selectview->sig_close_dialog().connect( sigc::mem_fun(*this, &SelectListDialog::hide ) ); get_vbox()->pack_start(* m_selectview ); m_selectview->set_size_request( -1, SELECTDIAG_TREEHEIGHT ); m_selectview->focus_view(); show_all_children(); } } else if( m_selectview ){ get_vbox()->remove( *m_selectview ); resize( get_width(), 1 ); delete m_selectview; m_selectview = NULL; } } void SelectListDialog::timeout() { if( m_selectview ) m_selectview->clock_in(); } jd-2.8.7-140104/src/bbslist/selectdialog.h0000644000076400010400000000203611331063026014625 0ustar // ライセンス: GPL2 // // お気に入り挿入ダイアログ // #ifndef _SELECTDIALOG_H #define _SELECTDIALOG_H #include "skeleton/prefdiag.h" #include "skeleton/label_entry.h" #include namespace BBSLIST { class SelectListView; class SelectListDialog : public SKELETON::PrefDiag { Glib::RefPtr< Gtk::TreeStore >& m_treestore; std::vector< std::string > m_vec_path; SKELETON::LabelEntry m_label_name; Gtk::HBox m_hbox_dirs; Gtk::Label m_label_dirs; Gtk::ComboBoxText m_combo_dirs; Gtk::ToggleButton m_bt_show_tree; SelectListView* m_selectview; public: SelectListDialog( Gtk::Window* parent, const std::string& url, Glib::RefPtr< Gtk::TreeStore >& treestore ); virtual ~SelectListDialog(); const std::string get_name(); const std::string get_path(); protected: virtual void slot_ok_clicked(); private: void slot_show_tree(); virtual void timeout(); }; }; #endif jd-2.8.7-140104/src/bbslist/selectlistview.cpp0000644000076400010400000000457411125705250015603 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "selectlistview.h" #include "toolbar.h" #include "control/controlid.h" #include "type.h" using namespace BBSLIST; SelectListView::SelectListView( const std::string& url, const std::string& arg1, const std::string& arg2) : BBSListViewBase( url, arg1, arg2 ) { // D&Dで編集可能 set_editable( true ); } void SelectListView::close_view() { #ifdef _DEBUG std::cout << "SelectListView::close_view\n"; #endif // ダイアログを閉じる m_sig_close_dialog.emit(); } const bool SelectListView::operate_view( const int control ) { bool ret = true; // ESCでダイアログを閉じる if( control == CONTROL::Cancel ){ close_view(); } else if( control == CONTROL::Search ){ set_search_invert( false ); m_sig_focus_entry_search.emit(); } else if( control == CONTROL::SearchInvert ){ set_search_invert( true ); m_sig_focus_entry_search.emit(); } else ret = BBSListViewBase::operate_view( control ); return ret; } // // ポップアップメニュー取得 // // SKELETON::View::show_popupmenu() を参照すること // Gtk::Menu* SelectListView::get_popupmenu( const std::string& url ) { Gtk::Menu* popupmenu; if( url.empty() ) popupmenu = id2popupmenu( "/popup_menu_favorite_space" ); else{ std::list< Gtk::TreeModel::iterator > list_it = get_treeview().get_selected_iterators(); if( list_it.size() == 1 ){ int type = path2type( *( get_treeview().get_selection()->get_selected_rows().begin() ) ); if( type == TYPE_DIR ) popupmenu = id2popupmenu( "/popup_menu_favorite_dir" ); else if( type == TYPE_COMMENT ) popupmenu = id2popupmenu( "/popup_menu_favorite_com" ); else popupmenu = id2popupmenu( "/popup_menu_select" ); } else popupmenu = id2popupmenu( "/popup_menu_favorite_mul" ); } return popupmenu; } // // 選択した行を開く // const bool SelectListView::open_row( Gtk::TreePath& path, const bool tab ) { if( ! get_treeview().get_row( path ) ) return false; // ディレクトリの開け閉め if( path2type( path ) == TYPE_DIR ){ if( ! get_treeview().row_expanded( path ) ) get_treeview().expand_row( path, false ); else get_treeview().collapse_row( path ); } return true; } jd-2.8.7-140104/src/bbslist/selectlistview.h0000644000076400010400000000237411466523774015265 0ustar // ライセンス: GPL2 // // お気に入り追加の時の選択ビュー // #ifndef _SELECTLISTVIEW_H #define _SELECTLISTVIEW_H #include "bbslistviewbase.h" namespace BBSLIST { // 親の SelectListDialog や EditListWin に送る信号 typedef sigc::signal< void > SIG_CLOSE_DIALOG; typedef sigc::signal< void > SIG_FOCUS_ENTRY_SEARCH; class SelectListView : public BBSListViewBase { SIG_CLOSE_DIALOG m_sig_close_dialog; SIG_FOCUS_ENTRY_SEARCH m_sig_focus_entry_search; public: SelectListView( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() ); virtual ~SelectListView(){} SIG_CLOSE_DIALOG sig_close_dialog() { return m_sig_close_dialog; } SIG_FOCUS_ENTRY_SEARCH sig_focus_entry_search() { return m_sig_focus_entry_search; } virtual void save_xml(){} virtual void close_view(); virtual const bool operate_view( const int control ); private: virtual const bool open_row( Gtk::TreePath& path, const bool tab ); virtual void switch_rightview(){} // boardに移動しないようにキャンセル virtual Gtk::Menu* get_popupmenu( const std::string& url ); }; }; #endif jd-2.8.7-140104/src/bbslist/toolbar.cpp0000644000076400010400000001762712006761301014200 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "gtkmmversion.h" #include "toolbar.h" #include "bbslistadmin.h" #include "skeleton/view.h" #include "skeleton/menubutton.h" #include "skeleton/imgtoolbutton.h" #include "control/controlutil.h" #include "control/controlid.h" #include "icons/iconmanager.h" #include "config/globalconf.h" #include "command.h" #include "session.h" #include "compmanager.h" #include "global.h" using namespace BBSLIST; BBSListToolBar::BBSListToolBar() : SKELETON::ToolBar( BBSLIST::get_admin() ), m_button_toggle( "ページ切り替え", true, true, m_label ), m_button_check_update_root( NULL ), m_button_check_update_open_root( NULL ), m_button_stop_check_update( NULL ) { m_button_toggle.get_button()->set_tooltip_arrow( "ページ切り替え\n\nマウスホイール回転でも切り替え可能" ); m_label.set_alignment( Gtk::ALIGN_LEFT ); std::vector< std::string > menu; menu.push_back( ITEM_NAME_BBSLISTVIEW ); menu.push_back( ITEM_NAME_FAVORITEVIEW ); menu.push_back( ITEM_NAME_HISTVIEW ); menu.push_back( ITEM_NAME_HIST_BOARDVIEW ); menu.push_back( ITEM_NAME_HIST_CLOSEVIEW ); menu.push_back( ITEM_NAME_HIST_CLOSEBOARDVIEW ); menu.push_back( ITEM_NAME_HIST_CLOSEIMGVIEW ); m_button_toggle.get_button()->append_menu( menu ); m_button_toggle.get_button()->signal_selected().connect( sigc::mem_fun(*this, &BBSListToolBar::slot_toggle ) ); m_button_toggle.get_button()->signal_scroll_event().connect( sigc::mem_fun( *this, &BBSListToolBar::slot_scroll_event )); m_button_toggle.get_button()->set_enable_sig_clicked( false ); #if GTKMM_CHECK_VERSION(2,12,0) m_tool_label.set_icon_size( Gtk::ICON_SIZE_MENU ); #endif m_tool_label.set_toolbar_style( Gtk::TOOLBAR_ICONS ); m_tool_label.append( m_button_toggle ); m_tool_label.append( *get_button_close() ); pack_start( m_tool_label, Gtk::PACK_SHRINK ); pack_buttons(); add_search_control_mode( CONTROL::MODE_BBSLIST ); } // // ボタンのパッキング // // virtual void BBSListToolBar::pack_buttons() { int num = 0; for(;;){ int item = SESSION::get_item_sidebar_toolbar( num ); if( item == ITEM_END ) break; switch( item ){ case ITEM_SEARCHBOX: get_buttonbar().append( *get_tool_search( CORE::COMP_SEARCH_BBSLIST ) ); break; case ITEM_CHECK_UPDATE_ROOT: if( ! m_button_check_update_root ){ m_button_check_update_root = Gtk::manage( new SKELETON::ImgToolButton( ICON::CHECK_UPDATE_ROOT ) ); m_button_check_update_root->signal_clicked().connect( sigc::mem_fun(*this, &BBSListToolBar::slot_check_update_root ) ); set_tooltip( *m_button_check_update_root, CONTROL::get_label_motions( CONTROL::CheckUpdateRoot ) ); } get_buttonbar().append( *m_button_check_update_root ); break; case ITEM_CHECK_UPDATE_OPEN_ROOT: if( ! m_button_check_update_open_root ){ m_button_check_update_open_root = Gtk::manage( new SKELETON::ImgToolButton( ICON::CHECK_UPDATE_OPEN_ROOT ) ); m_button_check_update_open_root->signal_clicked().connect( sigc::mem_fun(*this, &BBSListToolBar::slot_check_update_open_root ) ); set_tooltip( *m_button_check_update_open_root, CONTROL::get_label_motions( CONTROL::CheckUpdateOpenRoot ) ); } get_buttonbar().append( *m_button_check_update_open_root ); break; case ITEM_STOPLOADING: if( ! m_button_stop_check_update ) m_button_stop_check_update = get_button_stop(); get_buttonbar().append( *m_button_stop_check_update ); break; case ITEM_SEARCH_NEXT: get_buttonbar().append( *get_button_down_search() ); break; case ITEM_SEARCH_PREV: get_buttonbar().append( *get_button_up_search() ); break; case ITEM_SEPARATOR: pack_separator(); break; } ++num; } set_relief(); show_all_children(); } // タブが切り替わった時にDragableNoteBook::set_current_toolbar()から呼び出される( Viewの情報を取得する ) // virtual void BBSListToolBar::set_view( SKELETON::View* view ) { ToolBar::set_view( view ); if( view ){ m_label.set_text( view->get_label() ); if( view->get_url() == URL_BBSLISTVIEW || ( ! CONFIG::get_check_update_board() && view->get_url() == URL_HISTBOARDVIEW ) ) { if( m_button_check_update_root ) m_button_check_update_root->set_sensitive( false ); if( m_button_check_update_open_root ) m_button_check_update_open_root->set_sensitive( false ); if( m_button_stop_check_update ) m_button_stop_check_update->set_sensitive( false ); } else{ if( m_button_check_update_root ) m_button_check_update_root->set_sensitive( true ); if( m_button_check_update_open_root ) m_button_check_update_open_root->set_sensitive( true ); if( m_button_stop_check_update ) m_button_stop_check_update->set_sensitive( true ); } } } void BBSListToolBar::slot_toggle( const int i ) { #ifdef _DEBUG std::cout << "BBSListToolBar::slot_toggle = " << get_url() << " i = " << i << std::endl; #endif switch( i ){ case 0: if( get_url() != URL_BBSLISTVIEW ) CORE::core_set_command( "switch_sidebar", URL_BBSLISTVIEW ); break; case 1: if( get_url() != URL_FAVORITEVIEW ) CORE::core_set_command( "switch_sidebar", URL_FAVORITEVIEW ); break; case 2: if( get_url() != URL_HISTTHREADVIEW ) CORE::core_set_command( "switch_sidebar", URL_HISTTHREADVIEW ); break; case 3: if( get_url() != URL_HISTBOARDVIEW ) CORE::core_set_command( "switch_sidebar", URL_HISTBOARDVIEW ); break; case 4: if( get_url() != URL_HISTCLOSEVIEW ) CORE::core_set_command( "switch_sidebar", URL_HISTCLOSEVIEW ); break; case 5: if( get_url() != URL_HISTCLOSEBOARDVIEW ) CORE::core_set_command( "switch_sidebar", URL_HISTCLOSEBOARDVIEW ); break; case 6: if( get_url() != URL_HISTCLOSEIMGVIEW ) CORE::core_set_command( "switch_sidebar", URL_HISTCLOSEIMGVIEW ); break; } } bool BBSListToolBar::slot_scroll_event( GdkEventScroll* event ) { guint direction = event->direction; #ifdef _DEBUG std::cout << "BBSListToolBar::slot_scroll_event dir = " << direction << std::endl; #endif int page = get_admin()->get_current_page(); const int tab_nums = get_admin()->get_tab_nums(); if( direction == GDK_SCROLL_UP ) --page; if( direction == GDK_SCROLL_DOWN ) ++page; if( page < 0 ) page = tab_nums-1; else if( page >= tab_nums ) page = 0; slot_toggle( page ); return true; } void BBSListToolBar::slot_check_update_root() { CORE::core_set_command( "check_update_root", "" ); } void BBSListToolBar::slot_check_update_open_root() { CORE::core_set_command( "check_update_open_root", "" ); } //////////////////////////////////////// EditListToolBar::EditListToolBar() : SKELETON::ToolBar( NULL ) { pack_buttons(); } // // ボタンのパッキング // // virtual void EditListToolBar::pack_buttons() { get_buttonbar().append( *get_tool_search( CORE::COMP_SEARCH_BBSLIST ) ); get_buttonbar().append( *get_button_down_search() ); get_buttonbar().append( *get_button_up_search() ); add_search_control_mode( CONTROL::MODE_BBSLIST ); get_buttonbar().append( *get_button_undo() ); get_buttonbar().append( *get_button_redo() ); get_buttonbar().append( *get_button_close() ); set_relief(); show_all_children(); } jd-2.8.7-140104/src/bbslist/toolbar.h0000644000076400010400000000303011506370702013631 0ustar // ライセンス: GPL2 // ツールバーのクラス #ifndef _BBSLIST_TOOLBAR_H #define _BBSLIST_TOOLBAR_H #include #include "skeleton/toolbar.h" #include "skeleton/jdtoolbar.h" #include "skeleton/toolmenubutton.h" namespace BBSLIST { class BBSListToolBar : public SKELETON::ToolBar { // ラベルバー SKELETON::JDToolbar m_tool_label; Gtk::Label m_label; SKELETON::ToolMenuButton m_button_toggle; SKELETON::ImgToolButton* m_button_check_update_root; SKELETON::ImgToolButton* m_button_check_update_open_root; Gtk::ToolItem* m_button_stop_check_update; public: BBSListToolBar(); virtual ~BBSListToolBar(){} // タブが切り替わった時にDragableNoteBookから呼び出される( Viewの情報を取得する ) virtual void set_view( SKELETON::View * view ); protected: virtual void pack_buttons(); private: void slot_toggle( const int i ); bool slot_scroll_event( GdkEventScroll* event ); void slot_check_update_root(); void slot_check_update_open_root(); }; /////////////////////////////////////// // 編集ウィンドウのツールバー class EditListToolBar : public SKELETON::ToolBar { // ボタン等のシグナルに直接コネクトする friend class EditListWin; public: EditListToolBar(); virtual ~EditListToolBar(){} protected: virtual void pack_buttons(); }; } #endif jd-2.8.7-140104/src/board/0000755000076400010400000000000012261751612011451 5ustar jd-2.8.7-140104/src/board/boardadmin.cpp0000644000076400010400000002746612175137371014300 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boardadmin.h" #include "boardviewnext.h" #include "toolbar.h" #include "dbtree/interface.h" #include "skeleton/admin.h" #include "skeleton/view.h" #include "skeleton/dragnote.h" #include "icons/iconmanager.h" #include "jdlib/miscutil.h" #include "jdlib/jdregex.h" #include "jdlib/miscmsg.h" #include "history/historymanager.h" #include "global.h" #include "type.h" #include "viewfactory.h" #include "sharedbuffer.h" #include "session.h" #include "command.h" #include "dndmanager.h" BOARD::BoardAdmin *instance_boardadmin = NULL; BOARD::BoardAdmin* BOARD::get_admin() { if( ! instance_boardadmin ) instance_boardadmin = new BOARD::BoardAdmin( URL_BOARDADMIN ); assert( instance_boardadmin ); return instance_boardadmin; } void BOARD::delete_admin() { if( instance_boardadmin ) delete instance_boardadmin; instance_boardadmin = NULL; } using namespace BOARD; BoardAdmin::BoardAdmin( const std::string& url ) : SKELETON::Admin( url ) , m_toolbar( NULL ) { set_use_viewhistory( true ); set_use_switchhistory( true ); get_notebook()->set_dragable( true ); get_notebook()->set_fixtab( false ); if( ! SESSION::get_show_board_tab() ) get_notebook()->set_show_tabs( false ); setup_menu(); } BoardAdmin::~BoardAdmin() { #ifdef _DEBUG std::cout << "BoardAdmin::~BoardAdmin\n"; #endif if( m_toolbar ) delete m_toolbar; } void BoardAdmin::save_session() { Admin::save_session(); // 開いているURLを保存 SESSION::set_board_URLs( get_URLs() ); SESSION::set_board_locked( get_locked() ); SESSION::set_board_switchhistory( get_switchhistory() ); SESSION::set_board_page( get_current_page() ); } // 前回開いていたURLを復元 void BoardAdmin::restore( const bool only_locked ) { int set_page_num = 0; const bool online = SESSION::is_online(); SESSION::set_online( false ); const std::list< std::string >& list_url = SESSION::get_board_URLs(); std::list< std::string >::const_iterator it_url = list_url.begin(); std::list< std::string > list_switchhistory = SESSION::get_board_switchhistory(); std::list< bool > list_locked = SESSION::get_board_locked(); std::list< bool >::iterator it_locked = list_locked.begin(); for( int page = 0; it_url != list_url.end(); ++it_url, ++page ){ // タブのロック状態 bool lock = false; if( it_locked != list_locked.end() ){ if( (*it_locked ) ) lock = true; ++it_locked; } // ロックされているものだけ表示 if( only_locked && ! lock ){ list_switchhistory.remove( *it_url ); continue; } if( page == SESSION::board_page() ) set_page_num = get_tab_nums(); COMMAND_ARGS command_arg = url_to_openarg( *it_url, true, lock ); // 板がDBに登録されていない場合は表示しない if( command_arg.url != URL_ALLLOG && command_arg.arg4 != "SIDEBAR" && DBTREE::url_boardbase( command_arg.url ).empty() ){ MISC::ERRMSG( *it_url + " is not registered" ); list_switchhistory.remove( *it_url ); continue; } open_view( command_arg ); } set_switchhistory( list_switchhistory ); SESSION::set_online( online ); if( get_tab_nums() ) set_command( "set_page", std::string(), MISC::itostr( set_page_num ) ); } COMMAND_ARGS BoardAdmin::url_to_openarg( const std::string& url, const bool tab, const bool lock ) { JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; COMMAND_ARGS command_arg; command_arg.command = "open_view"; command_arg.url = std::string(); if( tab ) command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // 既に開いているかチェック if( lock ) command_arg.arg3 = "lock"; // 開き方のモード ( Admin::open_view 参照 ) #ifdef _DEBUG std::cout << "BoardAdmin::url_to_openarg url = " << url << std::endl; #endif // 次スレ検索 if( regex.exec( std::string( "(.*)" ) + NEXT_SIGN + ARTICLE_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); command_arg.arg4 = "NEXT"; command_arg.arg5 = regex.str( 2 ); // 前スレのアドレス } // 全ログ一覧 else if( url == URL_ALLLOG ){ command_arg.url = URL_ALLLOG; command_arg.arg4 = "LOG"; } // ログ一覧 else if( regex.exec( std::string( "(.*)" ) + LOG_SIGN, url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); command_arg.arg4 = "LOG"; } // サイドバー else if( regex.exec( std::string( "(.*)" ) + SIDEBAR_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){ command_arg.url = regex.str( 1 ); command_arg.arg4 = "SIDEBAR"; command_arg.arg5 = regex.str( 2 ); // ディレクトリID } // スレビュー else{ command_arg.url = url; command_arg.arg4 = "MAIN"; } #ifdef _DEBUG std::cout << "open " << command_arg.arg4 << std::endl; #endif return command_arg; } const std::string BoardAdmin::command_to_url( const COMMAND_ARGS& command ) { if( command.arg4 == "NEXT" ) return command.url + NEXT_SIGN + ARTICLE_SIGN + command.arg5; else if( command.arg4 == "LOG" ){ if( command.url == URL_ALLLOG ) return URL_ALLLOG; else return command.url + LOG_SIGN; } else if( command.arg4 == "SIDEBAR" ){ if( command.arg5.empty() ) return command.url; return command.url + SIDEBAR_SIGN + command.arg5; } return command.url; } void BoardAdmin::switch_admin() { if( ! has_focus() ) CORE::core_set_command( "switch_board" ); } void BoardAdmin::restore_lasttab() { HISTORY::restore_history( URL_HISTCLOSEBOARDVIEW ); } // // リストで与えられたページをタブで連続して開くとき(Admin::open_list())の引数セット // COMMAND_ARGS BoardAdmin::get_open_list_args( const std::string& url, const COMMAND_ARGS& command_list ) { COMMAND_ARGS command_arg; command_arg.arg4 = "MAIN"; return command_arg; } // // view_modeに該当するページを探す // int BoardAdmin::find_view( const std::string& view_mode ) { if( view_mode.empty() ) return -1; // 検索の基準を、アクティブなタブに仮定 const int page = m_notebook->get_current_page(); const int pages = m_notebook->get_n_pages(); // "boardnext" なら次スレ検索のタブで開く if( view_mode.find( "boardnext" ) != std::string::npos ){ // アクティブな開始タブの右側から順に、すべてのタブをループ int i = page; while( i >= 0 ){ // BoardViewNextクラスのタブを探す BOARD::BoardViewNext* view = dynamic_cast< BOARD::BoardViewNext* >( m_notebook->get_nth_page( i ) ); if( view ){ if( ! view->is_locked() ){ // ページが見つかった return i; } // ロックされていれば次に該当するタブを探す } // 次のタブへインクリメント i++; if( i >= pages ) i = 0; // 右端まで探したら左端から if( i == page ) break; // 一巡しても見つからなかった } } // 該当するタブが見つからない場合 return -1; } // // ツールバー表示 // void BoardAdmin::show_toolbar() { // まだ作成されていない場合は作成する if( ! m_toolbar ){ m_toolbar = new BoardToolBar(); get_notebook()->append_toolbar( *m_toolbar ); if( SESSION::get_show_board_toolbar() ) m_toolbar->open_buttonbar(); } get_notebook()->show_toolbar(); } // // ツールバー表示/非表示切り替え // void BoardAdmin::toggle_toolbar() { if( ! m_toolbar ) return; #ifdef _DEBUG std::cout << "BoardAdmin::toggle_toolbar\n"; #endif // 検索関係の wiget の位置を変更 m_toolbar->unpack_pack(); if( SESSION::get_show_board_toolbar() ) m_toolbar->open_buttonbar(); else m_toolbar->close_buttonbar(); m_toolbar->close_searchbar(); m_toolbar->show_toolbar(); } // // 検索バー表示 // void BoardAdmin::open_searchbar() { if( ! m_toolbar ) return; // ツールバー表示時は検索関係の wiget はツールバーに表示されている if( ! SESSION::get_show_board_toolbar() ){ m_toolbar->open_searchbar(); m_toolbar->show_toolbar(); } m_toolbar->focus_entry_search(); } // // 検索バー非表示 // void BoardAdmin::close_searchbar() { if( ! m_toolbar ) return; if( ! SESSION::get_show_board_toolbar() ) m_toolbar->close_searchbar(); } SKELETON::View* BoardAdmin::create_view( const COMMAND_ARGS& command ) { int type = CORE::VIEW_NONE; CORE::VIEWFACTORY_ARGS view_args; // メインビュー if( command.arg4 == "MAIN" ){ type = CORE::VIEW_BOARDVIEW; } // 次スレ検索 else if( command.arg4 == "NEXT" ){ type = CORE::VIEW_BOARDNEXT; view_args.arg1 = command.arg5; // 前スレのアドレス } // ログ else if( command.arg4 == "LOG" ){ type = CORE::VIEW_BOARDLOG; } // サイドバー else if( command.arg4 == "SIDEBAR" ){ type = CORE::VIEW_BOARDSIDEBAR; view_args.arg1 = command.arg6; // "set_history" の時は板の履歴に登録する } else return NULL; SKELETON::View* view = CORE::ViewFactory( type, command_to_url( command ), view_args ); assert( view != NULL ); return view; } // // ローカルなコマンド // void BoardAdmin::command_local( const COMMAND_ARGS& command ) { // 列項目の更新 if( command.command == "update_columns" ){ std::list< SKELETON::View* > list_view = get_list_view( command.url ); std::list< SKELETON::View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); if( view ) view->set_command( "update_columns" ); } } // 指定したスレを強調して表示 else if( command.command == "draw_bg_articles" ){ SKELETON::View* view = get_view( command.url ); if( view ) view->set_command( "draw_bg_articles" ); } // ハイライト解除 else if( command.command == "clear_highlight" ){ SKELETON::View* view = get_view( command.url ); if( view ) view->set_command( "clear_highlight" ); } // URLを選択 else if( command.command == "select_item" ){ SKELETON::View* view = get_current_view(); if( view ) view->set_command( "select_item", command.url ); } } // // タブをサイドバーにドロップした時にお気に入りがデータ送信を要求してきた // void BoardAdmin::slot_drag_data_get( Gtk::SelectionData& selection_data, const int page ) { #ifdef _DEBUG std::cout << "BoardAdmin::slot_drag_data_get page = " << page << std::endl; #endif SKELETON::View* view = ( SKELETON::View* )get_notebook()->get_nth_page( page ); if( ! view ) return; const std::string url = view->get_url(); CORE::DATA_INFO info; info.type = TYPE_BOARD; info.url = DBTREE::url_boardbase( url ); info.name = DBTREE::board_name( info.url ); info.path = Gtk::TreePath( "0" ).to_string(); if( info.url.empty() ) return; #ifdef _DEBUG std::cout << "name = " << info.name << std::endl; #endif CORE::DATA_INFO_LIST list_info; list_info.push_back( info ); CORE::SBUF_set_list( list_info ); selection_data.set( DNDTARGET_FAVORITE, get_url() ); } jd-2.8.7-140104/src/board/boardadmin.h0000644000076400010400000000313312056423430013716 0ustar // ライセンス: GPL2 // // 個別の板の管理クラス // #ifndef _BOARDADMIN_H #define _BOARDADMIN_H #include "skeleton/admin.h" #include "sign.h" #include namespace BOARD { class BoardToolBar; class BoardAdmin : public SKELETON::Admin { BoardToolBar* m_toolbar; public: BoardAdmin( const std::string& url ); ~BoardAdmin(); virtual void save_session(); protected: virtual COMMAND_ARGS get_open_list_args( const std::string& url, const COMMAND_ARGS& command_list ); virtual SKELETON::View* create_view( const COMMAND_ARGS& command ); // view_modeに該当するページを探す virtual int find_view( const std::string& view_mode ); // ツールバー virtual void show_toolbar(); virtual void toggle_toolbar(); virtual void open_searchbar(); virtual void close_searchbar(); virtual void command_local( const COMMAND_ARGS& command ); virtual void restore( const bool only_locked ); virtual COMMAND_ARGS url_to_openarg( const std::string& url, const bool tab, const bool lock ); virtual const std::string command_to_url( const COMMAND_ARGS& command ); virtual void switch_admin(); virtual void restore_lasttab(); private: // タブをお気に入りにドロップした時にお気に入りがデータ送信を要求してきた virtual void slot_drag_data_get( Gtk::SelectionData& selection_data, const int page ); }; BoardAdmin* get_admin(); void delete_admin(); } #endif jd-2.8.7-140104/src/board/boardview.cpp0000644000076400010400000001037411577662613014157 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boardadmin.h" #include "boardview.h" #include "dbtree/interface.h" #include "skeleton/msgdiag.h" #include "sound/soundmanager.h" #include "history/historymanager.h" #include "config/globalconf.h" #include "session.h" #include "command.h" #include "httpcode.h" #include "global.h" using namespace BOARD; BoardView::BoardView( const std::string& url ) : BoardViewBase( url, false ) { #ifdef _DEBUG std::cout << "BoardView::BoardView : url = " << get_url() << std::endl; #endif // オートリロード可 set_enable_autoreload( true ); // text/url-list のドロップ可 get_treeview().set_enable_drop_uri_list(); } BoardView::~BoardView() { #ifdef _DEBUG std::cout << "BoardView::~BoardView : url = " << get_url() << std::endl; #endif // 閉じたタブ履歴更新 HISTORY::append_history( URL_HISTCLOSEBOARDVIEW, DBTREE::url_boardbase( get_url() ), DBTREE::board_name( get_url() ), TYPE_BOARD ); if( ! SESSION::is_quitting() ) save_session(); } void BoardView::save_session() { DBTREE::board_save_info( get_url_board() ); } // 更新した const bool BoardView::is_updated() { const int status = DBTREE::board_status( get_url_board() ); #ifdef _DEBUG std::cout << "BoardView::is_updated " << ( status & STATUS_UPDATED ) << std::endl; #endif return ( status & STATUS_UPDATED ); } // 更新チェックして更新可能か const bool BoardView::is_check_update() { const int status = DBTREE::board_status( get_url_board() ); #ifdef _DEBUG std::cout << "BoardView::is_check_update status = " << ( status & STATUS_UPDATE ) << std::endl; #endif return ( status & STATUS_UPDATE ); } // // リロード // void BoardView::reload() { // オフライン if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); return; } show_view(); } // // ビュー表示 // void BoardView::show_view() { #ifdef _DEBUG std::cout << "BoardView::show_view " << get_url() << std::endl; #endif BoardViewBase::show_view(); // ロード中にキャッシュにあるスレ一覧を表示する if( CONFIG::get_show_cached_board() && SESSION::is_online() && ! get_row_size() ){ const std::vector< DBTREE::ArticleBase* >& list_article = DBTREE::board_list_subject( get_url_board() ); if( list_article.size() ){ #ifdef _DEBUG std::cout << "append rows\n"; #endif const bool loading_fin = false; update_view_impl( list_article, loading_fin ); } } } // // view更新 // // subject.txtのロードが終わったら呼ばれる // void BoardView::update_view() { const int code = DBTREE::board_code( get_url_board() ); #ifdef _DEBUG std::cout << "BoardView::update_view " << get_url() << " code = " << code << std::endl; #endif // 音を鳴らす if( SESSION::is_online() && code != HTTP_INIT ){ if( code == HTTP_OK ) SOUND::play( SOUND::SOUND_RES ); else if( code == HTTP_NOT_MODIFIED ) SOUND::play( SOUND::SOUND_NO ); else SOUND::play( SOUND::SOUND_ERR ); } // 高速化のためデータベースに直接アクセス const std::vector< DBTREE::ArticleBase* >& list_article = DBTREE::board_list_subject( get_url_board() ); const bool loading_fin = true; update_view_impl( list_article, loading_fin ); // dat落ちしたスレッドをスレあぼーんのリストから取り除く if( code == HTTP_OK ) DBTREE::remove_old_abone_thread( get_url_board() ); // 板の履歴に登録 HISTORY::append_history( URL_HISTBOARDVIEW, DBTREE::url_boardbase( get_url_board() ), DBTREE::board_name( get_url_board() ), TYPE_BOARD ); } // // 板名更新 // void BoardView::update_boardname() { // ウィンドウタイトル表示 set_title( DBTREE::board_name( get_url_board() ) ); BOARD::get_admin()->set_command( "set_title", get_url(), get_title() ); // タブに名前をセット BOARD::get_admin()->set_command( "set_tablabel", get_url(), DBTREE::board_name( get_url_board() ) ); } jd-2.8.7-140104/src/board/boardview.h0000644000076400010400000000120211437471144013602 0ustar // ライセンス: GPL2 // スレ一覧 メインビュー #ifndef _BOARDVIEW_H #define _BOARDVIEW_H #include "boardviewbase.h" namespace BOARD { class BoardView : public BOARD::BoardViewBase { public: BoardView( const std::string& url ); virtual ~BoardView(); // SKELETON::View の関数のオーバロード virtual void save_session(); virtual const bool is_updated(); virtual const bool is_check_update(); virtual void reload(); virtual void show_view(); virtual void update_view(); virtual void update_boardname(); }; }; #endif jd-2.8.7-140104/src/board/boardviewbase.cpp0000644000076400010400000025633512175137371015014 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "gtkmmversion.h" #include "boardadmin.h" #include "boardview.h" #include "skeleton/msgdiag.h" #include "skeleton/filediag.h" #include "jdlib/miscutil.h" #include "jdlib/miscgtk.h" #include "jdlib/jdregex.h" #include "dbtree/interface.h" #include "dbtree/articlebase.h" #include "config/globalconf.h" #include "control/controlid.h" #include "control/controlutil.h" #include "command.h" #include "cache.h" #include "session.h" #include "sharedbuffer.h" #include "global.h" #include "type.h" #include "prefdiagfactory.h" #include "httpcode.h" #include "colorid.h" #include "fontid.h" #include "compmanager.h" #include "dndmanager.h" #include "icons/iconmanager.h" #include // m_liststore->gobj()->sort_column_id = -2 #include using namespace BOARD; // row -> path #define GET_PATH( row ) m_liststore->get_path( row ) enum{ CANCEL_OPENROW = 500, // msec 連続クリック防止用カウンタ DEFAULT_COLMUN_WIDTH = 50 }; enum{ COL_MARKVAL_OLD = -2, // dat 落ち COL_MARKVAL_FINISHED = -1, // キャッシュあり、新着無し、規定スレ数を越えている COL_MARKVAL_NORMAL = 0, // 通常状態、キャッシュ無し、 COL_MARKVAL_924, // スレッド924、キャッシュ無し COL_MARKVAL_NEWTHREAD_HOUR, // 新スレ( CONFIG::get_newthread_hour 時間以内 )、キャッシュ無し COL_MARKVAL_NEWTHREAD, // 前回の板一覧読み込み時から新しく出来たスレ、キャッシュ無し COL_MARKVAL_CACHED, // キャッシュあり、新着無し COL_MARKVAL_BROKEN_SUBJECT, // キャッシュあり、新着無しだが subject.txt が壊れている可能性がある COL_MARKVAL_UPDATED, // キャッシュあり、新着有り COL_MARKVAL_BKMARKED, // ブックマークされている、新着無し COL_MARKVAL_BKMARKED_BROKEN_SUBJECT, // ブックマークされている、新着無しだが subject.txt が壊れている可能性がある COL_MARKVAL_BKMARKED_UPDATED // ブックマークされている、新着有り }; // 昇順で上か下か enum{ COL_A_UP = -1, COL_B_UP = 1, }; enum { BOOKMARK_AUTO = -1, BOOKMARK_UNSET = 0, BOOKMARK_SET = 1 }; #define DELETE_COLUMN(col) do{ if( ! col ) { delete col; col = NULL; } }while(0) // set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ) を指定して append_columnする #define APPEND_COLUMN(col,title,model) do{ \ col = Gtk::manage( new Gtk::TreeViewColumn( title, model ) ); \ col->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ); \ m_treeview.append_column( *col ); \ }while(0) BoardViewBase::BoardViewBase( const std::string& url, const bool show_col_board ) : SKELETON::View( url ), m_treeview( url, DNDTARGET_FAVORITE, true, CONFIG::get_fontname( FONT_BOARD ), COLOR_CHAR_BOARD, COLOR_BACK_BOARD, COLOR_BACK_BOARD_EVEN ), m_col_mark( NULL ), m_col_id( NULL ), m_col_board( NULL ), m_col_subject( NULL ), m_col_res( NULL ), m_col_str_load( NULL ), m_col_str_new( NULL ), m_col_since( NULL ), m_col_write( NULL ), m_col_access( NULL ), m_col_speed( NULL ), m_col_diff( NULL ), m_clicked( false ), m_col( COL_NUM_COL ), m_previous_col( COL_NUM_COL ), m_sortmode( SORTMODE_ASCEND ), m_previous_sortmode( false ), m_loading( false ), m_enable_menuslot( true ), m_load_subject_txt( true ), m_show_col_board( show_col_board ), m_col_diff_is_shown( false ), m_cancel_openrow_counter( 0 ) { // 次スレ検索ビューのようにURLの途中に http が入っている場合は取り除く const size_t pos = url.rfind( "http://" ); if( pos != std::string::npos && pos != 0 ) m_url_board = DBTREE::url_subject( url.substr( 0, pos ) ); else m_url_board = DBTREE::url_subject( url ); m_scrwin.add( m_treeview ); m_scrwin.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS ); pack_start( m_scrwin ); show_all_children(); // ツリービュー設定 m_liststore = Gtk::ListStore::create( m_columns ); #if !GTKMM_CHECK_VERSION(2,7,0) // gtkmm26以下にはunset_model()が無いのでここでset_model()しておく m_treeview.set_model( m_liststore ); #endif #if GTKMM_CHECK_VERSION(2,6,0) // セルを固定の高さにする // append_column する前に columnに対して set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ) すること m_treeview.set_fixed_height_mode( true ); #ifdef _DEBUG std::cout << "BoardViewBase::BoardViewBase : m_treeview.set_fixed_height_mode\n"; #endif #endif // 列のappend update_columns(); // ソート関数セット m_liststore->set_sort_func( COL_MARK, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_ID, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_BOARD, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_SUBJECT, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_RES, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_STR_LOAD, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_STR_NEW, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_SINCE, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_WRITE, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_ACCESS, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_SPEED, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_liststore->set_sort_func( COL_DIFF, sigc::mem_fun( *this, &BoardViewBase::slot_compare_row ) ); m_treeview.sig_button_press().connect( sigc::mem_fun(*this, &BoardViewBase::slot_button_press ) ); m_treeview.sig_button_release().connect( sigc::mem_fun(*this, &BoardViewBase::slot_button_release ) ); m_treeview.sig_motion_notify().connect( sigc::mem_fun(*this, &BoardViewBase::slot_motion_notify ) ); m_treeview.sig_key_press().connect( sigc::mem_fun(*this, &BoardViewBase::slot_key_press ) ); m_treeview.sig_key_release().connect( sigc::mem_fun(*this, &BoardViewBase::slot_key_release ) ); m_treeview.sig_scroll_event().connect( sigc::mem_fun(*this, &BoardViewBase::slot_scroll_event ) ); m_treeview.signal_drag_data_get().connect( sigc::mem_fun(*this, &BoardViewBase::slot_drag_data_get ) ); m_treeview.sig_dropped_uri_list().connect( sigc::mem_fun(*this, &BoardViewBase::slot_dropped_url_list ) ); // アクション初期化 setup_action(); // マウスジェスチャ可能 set_enable_mg( true ); // コントロールモード設定 get_control().add_mode( CONTROL::MODE_BOARD ); } BoardViewBase::~BoardViewBase() { #ifdef _DEBUG std::cout << "BoardViewBase::~BoardViewBase : " << get_url() << std::endl; #endif } SKELETON::Admin* BoardViewBase::get_admin() { return BOARD::get_admin(); } // // url 更新 // // 移転があったときなどにadminから呼び出される // void BoardViewBase::update_url( const std::string& url_old, const std::string& url_new ) { if( m_url_board.find( url_old ) == 0 ) m_url_board = url_new + m_url_board.substr( url_old.length() ); SKELETON::View::update_url( url_old, url_new ); } // アイコンのID取得 const int BoardViewBase::get_icon( const std::string& iconname ) { int id = ICON::NONE; if( iconname == "default" ) id = ICON::BOARD; if( iconname == "loading" ) id = ICON::LOADING; if( iconname == "loading_stop" ) id = ICON::LOADING_STOP; if( iconname == "update" ) id = ICON::BOARD_UPDATE; // 更新チェックして更新があった場合 if( iconname == "updated" ) id = ICON::BOARD_UPDATED; #ifdef _DEBUG std::cout << "BoardViewBase::get_icon : " << iconname << " url = " << get_url() << std::endl; #endif return id; } // // コピー用URL(メインウィンドウのURLバーなどに表示する) // const std::string BoardViewBase::url_for_copy() { return DBTREE::url_boardbase( get_url_board() ); } // // アクション初期化 // void BoardViewBase::setup_action() { #ifdef _DEBUG std::cout << "BoardViewBase::setup_action\n"; #endif // アクショングループを作ってUIマネージャに登録 action_group() = Gtk::ActionGroup::create(); action_group()->add( Gtk::Action::create( "BookMark", ITEM_NAME_BOOKMARK "(_B)" ), sigc::bind< int >( sigc::mem_fun( *this, &BoardViewBase::slot_bookmark ), BOOKMARK_AUTO ) ); action_group()->add( Gtk::Action::create( "SetBookMark", "しおりを設定(_S)" ), // 未使用 sigc::bind< int >( sigc::mem_fun( *this, &BoardViewBase::slot_bookmark ), BOOKMARK_SET ) ); action_group()->add( Gtk::Action::create( "UnsetBookMark", "しおりを解除(_U)" ), // 未使用 sigc::bind< int >( sigc::mem_fun( *this, &BoardViewBase::slot_bookmark ), BOOKMARK_UNSET ) ); action_group()->add( Gtk::Action::create( "OpenTab", "OpenArticleTab" ), sigc::mem_fun( *this, &BoardViewBase::slot_open_tab ) ); action_group()->add( Gtk::Action::create( "RegetArticle", ITEM_NAME_REGETARTICLE "(_R)" ), sigc::mem_fun( *this, &BoardViewBase::slot_reget_article ) ); action_group()->add( Gtk::Action::create( "Favorite_Article", ITEM_NAME_FAVORITE_ARTICLE "(_F)..." ), sigc::mem_fun( *this, &BoardViewBase::slot_favorite_thread ) ); action_group()->add( Gtk::Action::create( "Favorite_Board", "板をお気に入りに追加(_A)" ), sigc::mem_fun( *this, &BoardViewBase::slot_favorite_board ) ); action_group()->add( Gtk::Action::create( "GotoTop", "一番上に移動(_T)" ), sigc::mem_fun( *this, &BoardViewBase::goto_top ) ); action_group()->add( Gtk::Action::create( "GotoBottom", "一番下に移動(_M)" ), sigc::mem_fun( *this, &BoardViewBase::goto_bottom ) ); action_group()->add( Gtk::Action::create( "Delete_Menu", "Delete" ) ); action_group()->add( Gtk::Action::create( "Delete", "選択した行のログを削除する(_D)" ), sigc::mem_fun( *this, &BoardViewBase::slot_delete_logs ) ); action_group()->add( Gtk::Action::create( "OpenRows", "選択したスレを開く(_O)" ), sigc::bind< bool >( sigc::mem_fun( *this, &BoardViewBase::open_selected_rows ), false ) ); action_group()->add( Gtk::Action::create( "RegetRows", "スレ情報を消さずにスレを再取得(_R)" ), sigc::bind< bool >( sigc::mem_fun( *this, &BoardViewBase::open_selected_rows ), true ) ); action_group()->add( Gtk::Action::create( "CopyURL", ITEM_NAME_COPY_URL "(_U)" ), sigc::mem_fun( *this, &BoardViewBase::slot_copy_url ) ); action_group()->add( Gtk::Action::create( "CopyTitleURL", ITEM_NAME_COPY_TITLE_URL "(_L)" ), sigc::mem_fun( *this, &BoardViewBase::slot_copy_title_url ) ); action_group()->add( Gtk::Action::create( "OpenBrowser", ITEM_NAME_OPEN_BROWSER "(_W)" ), sigc::mem_fun( *this, &BoardViewBase::slot_open_browser ) ); action_group()->add( Gtk::Action::create( "AboneThread", ITEM_NAME_ABONE_ARTICLE "(_N)" ), sigc::mem_fun( *this, &BoardViewBase::slot_abone_thread ) ); action_group()->add( Gtk::Action::create( "PreferenceArticle", ITEM_NAME_PREF_THREAD "(_P)..." ), sigc::mem_fun( *this, &BoardViewBase::slot_preferences_article ) ); action_group()->add( Gtk::Action::create( "PreferenceBoard", "PreferenceBoard" ), sigc::mem_fun( *this, &BoardViewBase::show_preference ) ); action_group()->add( Gtk::Action::create( "SaveDat", "SaveDat" ), sigc::mem_fun( *this, &BoardViewBase::slot_save_dat ) ); action_group()->add( Gtk::Action::create( "SearchNextArticle", ITEM_NAME_NEXTARTICLE ), sigc::mem_fun( *this, &BoardViewBase::slot_search_next ) ); // その他 action_group()->add( Gtk::Action::create( "Etc_Menu", ITEM_NAME_ETC "(_O)" ) ); ui_manager().clear(); ui_manager() = Gtk::UIManager::create(); ui_manager()->insert_action_group( action_group() ); // 通常 + 複数 const std::string menu_mul = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; // お気に入りボタン押した時のメニュー const std::string menu_favorite = "" "" "" ""; // お気に入りボタン押した時のメニュー( スレのみ ) const std::string menu_favorite_article = "" "" ""; // 削除ボタン押した時のメニュー const std::string menu_delete = "" "" ""; ui_manager()->add_ui_from_string( "" + menu_mul + menu_favorite + menu_favorite_article + menu_delete + create_context_menu() + "" ); // ポップアップメニューにキーアクセレータを表示 Gtk::Menu* popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu" ) ); CONTROL::set_menu_motion( popupmenu ); popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_mul" ) ); CONTROL::set_menu_motion( popupmenu ); } // // 通常の右クリックメニューの作成 // const std::string BoardViewBase::create_context_menu() { std::list< int > list_menu; list_menu.push_back( ITEM_BOOKMARK ); list_menu.push_back( ITEM_OPENARTICLETAB ); list_menu.push_back( ITEM_REGETARTICLE ); list_menu.push_back( ITEM_OPEN_BROWSER ); list_menu.push_back( ITEM_COPY_URL ); list_menu.push_back( ITEM_COPY_TITLE_URL_THREAD ); list_menu.push_back( ITEM_SAVE_DAT ); list_menu.push_back( ITEM_FAVORITE_ARTICLE ); list_menu.push_back( ITEM_NEXTARTICLE ); list_menu.push_back( ITEM_ABONE_ARTICLE ); list_menu.push_back( ITEM_DELETE ); list_menu.push_back( ITEM_PREF_THREAD ); list_menu.push_back( ITEM_PREF_BOARD ); // メニューに含まれていない項目を抜き出して「その他」に含める int num = 0; for(;;){ const int item = SESSION::get_item_board_menu( num ); if( item == ITEM_END ) break; list_menu.remove( item ); ++num; } std::string menu; num = 0; for(;;){ const int item = SESSION::get_item_board_menu( num ); if( item == ITEM_END ) break; else if( item == ITEM_ETC && list_menu.size() ){ menu += std::string( "" ); std::list< int >::iterator it = list_menu.begin(); for( ; it != list_menu.end(); ++it ) menu += get_menu_item( *it ); menu += std::string( "" ); } else menu += get_menu_item( item ); ++num; } #ifdef _DEBUG std::cout << "menu = " << menu << std::endl; #endif return "" + menu + ""; } const char* BoardViewBase::get_menu_item( const int item ) { switch( item ){ // しおりを設定/解除 case ITEM_BOOKMARK: return ""; // タブでスレを開く case ITEM_OPENARTICLETAB: return ""; // スレ情報を消さずに再取得" case ITEM_REGETARTICLE: return ""; // リンクをブラウザで開く case ITEM_OPEN_BROWSER: return ""; // リンクのURLをコピー case ITEM_COPY_URL: return ""; // スレのタイトルとURLをコピー case ITEM_COPY_TITLE_URL_THREAD: return ""; // dat 保存 case ITEM_SAVE_DAT: return ""; // スレをお気に入りに追加 case ITEM_FAVORITE_ARTICLE: return ""; // 次スレ検索 case ITEM_NEXTARTICLE: return ""; // スレをあぼ〜んする" case ITEM_ABONE_ARTICLE: return ""; // 削除 case ITEM_DELETE: return "" "" ""; // スレのプロパティ case ITEM_PREF_THREAD: return ""; // 板のプロパティ case ITEM_PREF_BOARD: return ""; // 区切り case ITEM_SEPARATOR: return ""; } return ""; } // // 行数 // const int BoardViewBase::get_row_size() { return m_treeview.get_row_size(); } // // 自動ソート抑制 // -2 = DEFAULT_UNSORTED_COLUMN_ID // // 追加や更新などで列に値をセットする前に実行してしておかないと // いちいちソートをかけるので極端に遅くなる // void BoardViewBase::unsorted_column() { m_liststore->gobj()->sort_column_id = -2; } // // url から row を取得 // Gtk::TreeModel::Row BoardViewBase::get_row_from_url( const std::string& url ) { Gtk::TreeModel::Children child = m_liststore->children(); Gtk::TreeModel::Children::iterator it; for( it = child.begin() ; it != child.end() ; ++it ){ Gtk::TreeModel::Row row = *( it ); DBTREE::ArticleBase *art = row[ m_columns.m_col_article ]; if( url == art->get_url() ) return row; } return Gtk::TreeModel::Row(); } // // 列項目の更新 // void BoardViewBase::update_columns() { m_treeview.remove_all_columns(); DELETE_COLUMN( m_col_id ); DELETE_COLUMN( m_col_board ); DELETE_COLUMN( m_col_subject ); DELETE_COLUMN( m_col_res ); DELETE_COLUMN( m_col_str_load ); DELETE_COLUMN( m_col_str_new ); DELETE_COLUMN( m_col_since ); DELETE_COLUMN( m_col_write ); DELETE_COLUMN( m_col_speed ); DELETE_COLUMN( m_col_diff ); DELETE_COLUMN( m_col_access ); int num = 0; // 先頭に「板」列を追加 if( m_show_col_board ){ bool append_board = true; for(;;){ const int item = SESSION::get_item_board_col( num ); if( item == ITEM_BOARD ) append_board = false; if( item == ITEM_END ) break; num++; } if( append_board ) APPEND_COLUMN( m_col_board, ITEM_NAME_BOARD, m_columns.m_col_board ); } m_col_diff_is_shown = false; num = 0; for(;;){ const int item = SESSION::get_item_board_col( num ); if( item == ITEM_END ) break; switch( item ){ case ITEM_MARK: APPEND_COLUMN( m_col_mark, ITEM_NAME_MARK, m_columns.m_col_mark ); break; case ITEM_ID: APPEND_COLUMN( m_col_id, ITEM_NAME_ID, m_columns.m_col_id ); break; case ITEM_BOARD: APPEND_COLUMN( m_col_board, ITEM_NAME_BOARD, m_columns.m_col_board ); break; case ITEM_NAME: APPEND_COLUMN( m_col_subject, ITEM_NAME_NAME, m_columns.m_col_subject ); break; case ITEM_RES: APPEND_COLUMN( m_col_res, ITEM_NAME_RES, m_columns.m_col_res ); break; case ITEM_LOAD: APPEND_COLUMN( m_col_str_load, ITEM_NAME_LOAD, m_columns.m_col_str_load ); break; case ITEM_NEW: APPEND_COLUMN( m_col_str_new, ITEM_NAME_NEW, m_columns.m_col_str_new ); break; case ITEM_SINCE: APPEND_COLUMN( m_col_since, ITEM_NAME_SINCE, m_columns.m_col_since ); break; case ITEM_LASTWRITE: APPEND_COLUMN( m_col_write, ITEM_NAME_LASTWRITE, m_columns.m_col_write ); break; case ITEM_ACCESS: APPEND_COLUMN( m_col_access, ITEM_NAME_ACCESS, m_columns.m_col_access); break; case ITEM_SPEED: APPEND_COLUMN( m_col_speed, ITEM_NAME_SPEED, m_columns.m_col_speed ); break; case ITEM_DIFF: APPEND_COLUMN( m_col_diff, ITEM_NAME_DIFF, m_columns.m_col_diff); m_col_diff_is_shown = true; break; } ++num; } // サイズを調整しつつソートの設定 for( guint i = 0; i < COL_VISIBLE_END; i++ ){ const int id = get_title_id( i ); if( id < 0 ) continue; Gtk::TreeView::Column* column = m_treeview.get_column( i ); if( ! column ) continue; int width = 0; switch( id ){ case COL_MARK: width = SESSION::col_mark(); break; case COL_ID: width = SESSION::col_id(); break; case COL_BOARD: width = SESSION::col_board(); break; case COL_SUBJECT: width = SESSION::col_subject(); m_treeview.set_column_for_height( id ); break; case COL_RES: width = SESSION::col_number(); break; case COL_STR_LOAD: width = SESSION::col_load(); break; case COL_STR_NEW: width = SESSION::col_new(); break; case COL_SINCE: width = SESSION::col_since(); break; case COL_WRITE: width = SESSION::col_write(); break; case COL_ACCESS: width = SESSION::col_access(); break; case COL_SPEED: width = SESSION::col_speed(); break; case COL_DIFF: width = SESSION::col_diff(); break; } if( ! width ) width = DEFAULT_COLMUN_WIDTH; column->set_fixed_width( width ); column->set_resizable( true ); column->set_clickable( true ); // ヘッダをクリックしたときに呼ぶslot column->signal_clicked().connect( sigc::bind< int >( sigc::mem_fun( *this, &BoardViewBase::slot_col_clicked ), id ) ); // ヘッダの位置 switch( id ){ case COL_MARK: column->set_alignment( 0.5 ); break; case COL_ID: case COL_RES: case COL_STR_LOAD: case COL_STR_NEW: case COL_SPEED: case COL_DIFF: column->set_alignment( 1.0 ); break; default: column->set_alignment( 0.0 ); break; } Gtk::CellRenderer *cell = column->get_first_cell_renderer(); // 実際の描画の際に cellrendere のプロパティをセットするスロット関数 if( cell ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &BoardViewBase::slot_cell_data ) ); Gtk::CellRendererText* rentext = dynamic_cast< Gtk::CellRendererText* >( cell ); if( rentext ){ // 列間スペース rentext->property_xpad() = 4; // 行間スペース rentext->property_ypad() = CONFIG::get_tree_ypad();; // 文字位置 switch( id ){ case COL_ID: case COL_RES: case COL_STR_LOAD: case COL_STR_NEW: case COL_SPEED: case COL_DIFF: rentext->property_xalign() = 1.0; break; default: rentext->property_xalign() = 0.0; } } } } // // i列目のIDを取得 // // 失敗の時は-1を変えす // const int BoardViewBase::get_title_id( const int col ) { Gtk::TreeView::Column* column = m_treeview.get_column( col ); if( ! column ) return -1; const std::string title = column->get_title(); int id = -1; if( title == ITEM_NAME_MARK ) id = COL_MARK; else if( title == ITEM_NAME_ID ) id = COL_ID; else if( title == ITEM_NAME_BOARD ) id = COL_BOARD; else if( title == ITEM_NAME_NAME ) id = COL_SUBJECT; else if( title == ITEM_NAME_RES ) id = COL_RES; else if( title == ITEM_NAME_LOAD ) id = COL_STR_LOAD; else if( title == ITEM_NAME_NEW ) id = COL_STR_NEW; else if( title == ITEM_NAME_SINCE ) id = COL_SINCE; else if( title == ITEM_NAME_LASTWRITE ) id = COL_WRITE; else if( title == ITEM_NAME_ACCESS ) id = COL_ACCESS; else if( title == ITEM_NAME_SPEED ) id = COL_SPEED; else if( title == ITEM_NAME_DIFF ) id = COL_DIFF; return id; } // // ソート列やソートモードの保存 // void BoardViewBase::save_sort_columns() { #ifdef _DEBUG std::cout << "BoardViewBase::save_sort_columns : url = " << get_url() << std::endl; #endif DBTREE::board_set_view_sort_column( get_url_board(), m_col ); DBTREE::board_set_view_sort_mode( get_url_board(), m_sortmode ); DBTREE::board_set_view_sort_pre_column( get_url_board(), m_previous_col ); DBTREE::board_set_view_sort_pre_mode( get_url_board(), m_previous_sortmode ); } // // 列の幅の保存 // void BoardViewBase::save_column_width() { #ifdef _DEBUG std::cout << "save_column_width " << get_url() << std::endl; #endif for( guint i = 0; i < COL_VISIBLE_END; i++ ){ const int id = get_title_id( i ); if( id < 0 ) continue; Gtk::TreeView::Column* column = m_treeview.get_column( i ); int width = 0; if( column ) width = column->get_width(); if( ! width ) continue; switch( id ){ case COL_MARK: SESSION::set_col_mark( width ); break; case COL_ID: SESSION::set_col_id( width ); break; case COL_BOARD: SESSION::set_col_board( width ); break; case COL_SUBJECT: SESSION::set_col_subject( width ); break; case COL_RES: SESSION::set_col_number( width ); break; case COL_STR_LOAD: SESSION::set_col_load( width ); break; case COL_STR_NEW: SESSION::set_col_new( width ); break; case COL_SINCE: SESSION::set_col_since( width ); break; case COL_WRITE: SESSION::set_col_write( width ); break; case COL_ACCESS: SESSION::set_col_access( width ); break; case COL_SPEED: SESSION::set_col_speed( width ); break; case COL_DIFF: SESSION::set_col_diff( width ); break; } } } // // 実際の描画の際に cellrendere のプロパティをセットするスロット関数 // void BoardViewBase::slot_cell_data( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ) { Gtk::TreeModel::Row row = *it; Gtk::TreePath path = GET_PATH( row ); #ifdef _DEBUG // std::cout << "BoardViewBase::slot_cell_data path = " << path.to_string() << std::endl; #endif // ハイライト色 ( 抽出状態 ) if( row[ m_columns.m_col_drawbg ] ){ cell->property_cell_background() = CONFIG::get_color( COLOR_BACK_HIGHLIGHT_TREE ); cell->property_cell_background_set() = true; } else m_treeview.slot_cell_data( cell, it ); } // // ソート実行 // void BoardViewBase::exec_sort() { #ifdef _DEBUG std::cout << "BoardViewBase::exec_sort url = " << get_url() << std::endl; #endif if( m_col < 0 || m_col >= COL_VISIBLE_END ){ m_col = COL_ID; m_sortmode = SORTMODE_ASCEND; } m_liststore->set_sort_column( -2, Gtk::SORT_ASCENDING ); m_liststore->set_sort_column( m_col, Gtk::SORT_ASCENDING ); } // // ソート状態回復 // void BoardViewBase::restore_sort() { m_search_invert = false; m_col = get_default_sort_column(); m_sortmode = get_default_view_sort_mode(); m_previous_col = get_default_view_sort_pre_column(); m_previous_sortmode = get_default_view_sort_pre_mode(); if( get_row_size() ){ exec_sort(); goto_top(); } } // // デフォルトのソート状態 // const int BoardViewBase::get_default_sort_column() { return DBTREE::board_view_sort_column( get_url_board() ); } const int BoardViewBase::get_default_view_sort_mode() { return DBTREE::board_view_sort_mode( get_url_board() ); } const int BoardViewBase::get_default_view_sort_pre_column() { return DBTREE::board_view_sort_pre_column( get_url_board() ); } const int BoardViewBase::get_default_view_sort_pre_mode() { return DBTREE::board_view_sort_pre_mode( get_url_board() ); } // // ヘッダをクリックしたときのslot関数 // void BoardViewBase::slot_col_clicked( const int col ) { #ifdef _DEBUG std::cout << "BoardViewBase::slot_col_clicked col = " << col << std::endl; #endif if( m_col != col ){ // 前回クリックした列と違う列をクリックした m_previous_col = m_col; m_previous_sortmode = m_sortmode; m_col = col; if( m_col == COL_MARK ) m_sortmode = SORTMODE_MARK1; else if( m_col == COL_ID ) m_sortmode = SORTMODE_ASCEND; else if( m_col == COL_SUBJECT ) m_sortmode = SORTMODE_ASCEND; else m_sortmode = SORTMODE_DESCEND; } else if( m_sortmode == SORTMODE_DESCEND ) m_sortmode = SORTMODE_ASCEND; else if( m_sortmode == SORTMODE_ASCEND ) m_sortmode = SORTMODE_DESCEND; else if( m_sortmode == SORTMODE_MARK1 ) m_sortmode = SORTMODE_MARK2; else if( m_sortmode == SORTMODE_MARK2 ) m_sortmode = SORTMODE_MARK3; else if( m_sortmode == SORTMODE_MARK3 ) m_sortmode = SORTMODE_MARK4; else if( m_sortmode == SORTMODE_MARK4 ) m_sortmode = SORTMODE_MARK1; if( m_col == COL_MARK ){ std::string info; if( m_sortmode == SORTMODE_MARK1 ) info = "モード 1"; if( m_sortmode == SORTMODE_MARK2 ) info = "モード 2"; if( m_sortmode == SORTMODE_MARK3 ) info = "モード 3"; if( m_sortmode == SORTMODE_MARK4 ) info = "モード 4"; CORE::core_set_command( "set_info", "", info ); } /* そろそろ消しても良い? 問題があれば戻す // 旧バージョンとの互換性のため if( m_col == COL_MARK ){ if( m_sortmode == SORTMODE_DESCEND || m_sortmode == SORTMODE_ASCEND ) m_sortmode = SORTMODE_MARK1; } */ save_sort_columns(); exec_sort(); focus_view(); } // // 抽出状態で比較 // // row_a が上か row_b が上かを返す。同じ状態なら 0 // const int BoardViewBase::compare_drawbg( Gtk::TreeModel::Row& row_a, Gtk::TreeModel::Row& row_b ) { const bool draw_a = row_a[ m_columns.m_col_drawbg ]; const bool draw_b = row_b[ m_columns.m_col_drawbg ]; if( draw_a && ! draw_b ) return COL_A_UP; else if( draw_b && ! draw_a ) return COL_B_UP; return 0; } // // 列の値によるソート // // row_a が上か row_b が上かを返す。同じなら 0 // const int BoardViewBase::compare_col( const int col, const int sortmode, Gtk::TreeModel::Row& row_a, Gtk::TreeModel::Row& row_b ) { int num_a = 0, num_b = 0; int ret = 0; DBTREE::ArticleBase *arta, *artb; const int UP = 1; const int DOWN = 2; switch( col ){ case COL_MARK: { num_a = row_a[ m_columns.m_col_mark_val ]; num_b = row_b[ m_columns.m_col_mark_val ]; if( sortmode == SORTMODE_MARK2 ){ // 新着をキャッシュの上に if( num_a == COL_MARKVAL_NEWTHREAD && ( num_b != COL_MARKVAL_NEWTHREAD && num_b <= COL_MARKVAL_UPDATED ) ){ num_a = DOWN; // 下で ret *= -1 しているので UP と DOWNを逆にする num_b = UP; } else if( num_b == COL_MARKVAL_NEWTHREAD && ( num_a != COL_MARKVAL_NEWTHREAD && num_a <= COL_MARKVAL_UPDATED ) ){ num_a = UP; // 下で ret *= -1 しているので UP と DOWNを逆にする num_b = DOWN; } } else if( sortmode == SORTMODE_MARK3 ){ // 新着を一番上に if( num_a == COL_MARKVAL_NEWTHREAD && num_b != COL_MARKVAL_NEWTHREAD ){ num_a = DOWN; // 下で ret *= -1 しているので UP と DOWNを逆にする num_b = UP; } else if( num_b == COL_MARKVAL_NEWTHREAD && num_a != COL_MARKVAL_NEWTHREAD ){ num_a = UP; // 下で ret *= -1 しているので UP と DOWNを逆にする num_b = DOWN; } else if( num_a == COL_MARKVAL_NEWTHREAD_HOUR && num_b != COL_MARKVAL_NEWTHREAD_HOUR ){ num_a = DOWN; // 下で ret *= -1 しているので UP と DOWNを逆にする num_b = UP; } else if( num_b == COL_MARKVAL_NEWTHREAD_HOUR && num_a != COL_MARKVAL_NEWTHREAD_HOUR ){ num_a = UP; // 下で ret *= -1 しているので UP と DOWNを逆にする num_b = DOWN; } } break; } case COL_ID: num_a = row_a[ m_columns.m_col_id ]; num_b = row_b[ m_columns.m_col_id ]; break; case COL_SUBJECT: { // 文字列の大小を数字に変換 const Glib::ustring name_a = row_a[ m_columns.m_col_subject ]; const Glib::ustring name_b = row_b[ m_columns.m_col_subject ]; if( name_a < name_b ) { num_a = UP; num_b = DOWN; } else if( name_a > name_b ) { num_a = DOWN; num_b = UP; } break; } case COL_RES: num_a = row_a[ m_columns.m_col_res ]; num_b = row_b[ m_columns.m_col_res ]; break; case COL_STR_LOAD: arta = row_a[ m_columns.m_col_article ]; artb = row_b[ m_columns.m_col_article ]; num_a = arta->get_number_load(); num_b = artb->get_number_load(); break; case COL_STR_NEW: num_a = row_a[ m_columns.m_col_new ]; num_b = row_b[ m_columns.m_col_new ]; break; case COL_SINCE: arta = row_a[ m_columns.m_col_article ]; artb = row_b[ m_columns.m_col_article ]; num_a = arta->get_since_time(); num_b = artb->get_since_time(); break; case COL_WRITE: num_a = row_a[ m_columns.m_col_write_t ]; num_b = row_b[ m_columns.m_col_write_t ]; break; case COL_ACCESS: num_a = row_a[ m_columns.m_col_access_t ]; num_b = row_b[ m_columns.m_col_access_t ]; break; case COL_SPEED: num_a = row_a[ m_columns.m_col_speed ]; num_b = row_b[ m_columns.m_col_speed ]; break; case COL_DIFF: num_a = row_a[ m_columns.m_col_diff ]; num_b = row_b[ m_columns.m_col_diff ]; break; case COL_BOARD: { // 文字列の大小を数字に変換 Glib::ustring name_a = row_a[ m_columns.m_col_board ]; Glib::ustring name_b = row_b[ m_columns.m_col_board ]; if( name_a < name_b ) { num_a = UP; num_b = DOWN; } else if( name_a > name_b ) { num_a = DOWN; num_b = UP; } break; } } // 両方とも 0 より大きいか 0 より小さい場合は普通に比較 if( ( num_a > 0 && num_b > 0 ) || ( num_a < 0 && num_b < 0 ) ){ if( num_a < num_b ) ret = COL_A_UP; else if( num_a > num_b ) ret = COL_B_UP; if( sortmode == SORTMODE_DESCEND ) ret *= -1; if( sortmode == SORTMODE_MARK1 || sortmode == SORTMODE_MARK2 || sortmode == SORTMODE_MARK3 ) ret *= -1; } // 0より大きい方を優先 else if( num_a > 0 && num_b <= 0 ) ret = COL_A_UP; else if( num_b > 0 && num_a <= 0 ) ret = COL_B_UP; // 0を優先 else if( num_a == 0 && num_b < 0 ) ret = COL_A_UP; else if( num_b == 0 && num_a < 0 ) ret = COL_B_UP; return ret; } // // ソート関数 // const int BoardViewBase::slot_compare_row( const Gtk::TreeModel::iterator& a, const Gtk::TreeModel::iterator& b ) { Gtk::TreeModel::Row row_a = *( a ); Gtk::TreeModel::Row row_b = *( b ); // 抽出状態を最優先 int ret = compare_drawbg( row_a, row_b ); if( ! ret ) ret = compare_col( m_col, m_sortmode, row_a, row_b ); // マルチキーソート if( ! ret ) ret = compare_col( m_previous_col, m_previous_sortmode, row_a, row_b ); if( ! ret ) ret = compare_col( COL_MARK, SORTMODE_ASCEND, row_a, row_b ); if( ! ret ) ret = compare_col( COL_ID, SORTMODE_ASCEND, row_a, row_b ); return ret; } // // コマンド // const bool BoardViewBase::set_command( const std::string& command, const std::string& arg1, const std::string& arg2 ) { if( command == "update_columns" ) update_columns(); else if( command == "draw_bg_articles" ) draw_bg_articles(); else if( command == "clear_highlight" ) clear_highlight(); else if( command == "select_item" ) select_item( arg1 ); return true; } // // クロック入力 // void BoardViewBase::clock_in() { View::clock_in(); m_treeview.clock_in(); if( m_cancel_openrow_counter ) --m_cancel_openrow_counter; } // // ロード停止 // void BoardViewBase::stop() { DBTREE::board_stop_load( get_url_board() ); } // // ビュー表示 // void BoardViewBase::show_view() { #ifdef _DEBUG std::cout << "BoardViewBase::show_view " << get_url() << std::endl; #endif if( is_loading() ) return; update_boardname(); m_pre_query = std::string(); m_last_access_time = DBTREE::board_last_access_time( get_url_board() ); // オートリロードのカウンタを0にする reset_autoreload_counter(); if( ! m_load_subject_txt ){ update_view(); return; } if( m_col_diff_is_shown ) DBTREE::board_read_subject_from_cache( get_url_board() ); // download 開始 // 終わったら update_view() が呼ばれる // DBに登録されてない時はロードしない if( get_url_board().empty() ){ set_status( "invalid URL" ); BOARD::get_admin()->set_command( "set_status", get_url(), get_status() ); return; } m_loading = true; DBTREE::board_download_subject( get_url_board(), get_url() ); set_status( "loading..." ); BOARD::get_admin()->set_command( "set_status", get_url(), get_status() ); // タブにアイコンを表示 BOARD::get_admin()->set_command( "toggle_icon", get_url() ); } // // スクロールバー再描画 // void BoardViewBase::redraw_scrollbar() { #ifdef _DEBUG std::cout << "BoardViewBase::redraw_scrollbar\n"; #endif m_scrwin.queue_draw(); } // // 色、フォント、表示内容の更新 // void BoardViewBase::relayout() { m_treeview.init_color( COLOR_CHAR_BOARD, COLOR_BACK_BOARD, COLOR_BACK_BOARD_EVEN ); m_treeview.init_font( CONFIG::get_fontname( FONT_BOARD ) ); update_item_all(); } // // view更新 // // loading_fin : ロードが完了したら true をセットして呼び出す // void BoardViewBase::update_view_impl( const std::vector< DBTREE::ArticleBase* >& list_article, const bool loading_fin ) { #ifdef _DEBUG const int code = DBTREE::board_code( get_url_board() ); std::cout << "BoardViewBase::update_view_impl " << get_url() << " code = " << code << " size = " << list_article.size() << std::endl; #endif // 画面消去 #if GTKMM_CHECK_VERSION(2,8,0) m_treeview.unset_model(); #endif if( list_article.size() ){ m_liststore->clear(); unsorted_column(); // 行の追加 for( int i = list_article.size()-1; i >= 0; --i ){ DBTREE::ArticleBase* art = list_article[ i ]; prepend_row( art, i + 1 ); } #if GTKMM_CHECK_VERSION(2,8,0) m_treeview.set_model( m_liststore ); #endif if( loading_fin ){ if( m_list_draw_bg_articles.size() ) draw_bg_articles(); else restore_sort(); } } if( loading_fin ){ m_loading = false; update_status(); // タブのアイコン状態を更新 BOARD::get_admin()->set_command( "toggle_icon", get_url() ); } } // // ステータスバー更新 // void BoardViewBase::update_status() { std::ostringstream ss_tmp; if( m_load_subject_txt ) ss_tmp << DBTREE::board_str_code( get_url_board() ) << " "; ss_tmp << "[ 全 " << get_row_size() << " ] "; set_status( ss_tmp.str() ); BOARD::get_admin()->set_command( "set_status", get_url(), get_status() ); } // // URLを選択 // void BoardViewBase::select_item( const std::string& url ) { const Gtk::TreeModel::Row row = get_row_from_url( url ); if( row ){ Gtk::TreePath path = GET_PATH( row ); m_treeview.get_selection()->unselect_all(); m_treeview.set_cursor( path ); } } void BoardViewBase::focus_view() { #ifdef _DEBUG std::cout << "BoardViewBase::focus_view\n"; #endif m_treeview.grab_focus(); } void BoardViewBase::focus_out() { SKELETON::View::focus_out(); m_treeview.hide_tooltip(); } // // 閉じる // void BoardViewBase::close_view() { BOARD::get_admin()->set_command( "close_currentview" ); } // // 選択した行のログをまとめて削除 // void BoardViewBase::slot_delete_logs() { std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); for( ; it != list_it.end(); ++it ){ Gtk::TreeModel::Row row = *( *it ); DBTREE::ArticleBase *art = row[ m_columns.m_col_article ]; CORE::core_set_command( "delete_article", art->get_url() ); } } // // viewの操作 // const bool BoardViewBase::operate_view( const int control ) { if( CONTROL::operate_common( control, get_url(), BOARD::get_admin() ) ) return true; bool open_tab = false; Gtk::TreePath path = m_treeview.get_current_path();; switch( control ){ case CONTROL::Down: row_down(); break; case CONTROL::Up: row_up(); break; case CONTROL::PageUp: page_up(); break; case CONTROL::PageDown: page_down(); break; case CONTROL::Home: goto_top(); break; case CONTROL::End: goto_bottom(); break; // 全て選択 case CONTROL::SelectAll: slot_select_all(); break; // お気に入りに追加 case CONTROL::AppendFavorite: { SKELETON::MsgDiag mdiag( get_parent_win(), "板と選択中のスレのどちらを登録しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE ); mdiag.add_button( "板を登録", Gtk::RESPONSE_NO ); mdiag.add_button( "スレを登録", Gtk::RESPONSE_YES ); mdiag.set_default_response( Gtk::RESPONSE_YES ); int ret = mdiag.run(); if( ret == Gtk::RESPONSE_YES ) slot_favorite_thread(); else slot_favorite_board(); } break; // スレを開く case CONTROL::OpenArticleTab: open_tab = true; case CONTROL::OpenArticle: if( ! path.empty() ) open_row( path, open_tab, false ); break; // Listに戻る case CONTROL::Left: CORE::core_set_command( "switch_leftview" ); break; // 現在の記事を表示 case CONTROL::Right: CORE::core_set_command( "switch_rightview" ); break; case CONTROL::ScrollLeftBoard: scroll_left(); break; case CONTROL::ScrollRightBoard: scroll_right(); break; case CONTROL::ToggleArticle: CORE::core_set_command( "toggle_article" ); break; // 戻る、進む case CONTROL::PrevView: back_viewhistory( 1 ); break; case CONTROL::NextView: forward_viewhistory( 1 ); break; // datを保存 case CONTROL::Save: slot_save_dat(); break; // 閉じる case CONTROL::Quit: close_view(); break; case CONTROL::Reload: reload(); break; case CONTROL::StopLoading: stop(); break; case CONTROL::NewArticle: write(); break; case CONTROL::Delete: { if( CONFIG::get_show_deldiag() ){ SKELETON::MsgCheckDiag mdiag( get_parent_win(), "選択した行のログを削除しますか?", "今後表示しない(常に削除)(_D)", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_title( "削除確認" ); const int ret = mdiag.run(); if( ret != Gtk::RESPONSE_YES ) return true; if( mdiag.get_chkbutton().get_active() ) CONFIG::set_show_deldiag( false ); } slot_delete_logs(); break; } // ポップアップメニュー表示 case CONTROL::ShowPopupMenu: show_popupmenu( "", true ); break; // 検索 case CONTROL::Search: m_search_invert = false; BOARD::get_admin()->set_command( "open_searchbar", get_url() ); break; case CONTROL::SearchInvert: m_search_invert = true; BOARD::get_admin()->set_command( "open_searchbar", get_url() ); break; case CONTROL::SearchNext: down_search(); break; case CONTROL::SearchPrev: up_search(); break; // 板のプロパティ case CONTROL::PreferenceView: show_preference(); break; default: return false; } return true; } // // 先頭に戻る // void BoardViewBase::goto_top() { m_treeview.goto_top(); } // // 一番最後へ // void BoardViewBase::goto_bottom() { m_treeview.goto_bottom(); } // // 指定したIDのスレに移動 // void BoardViewBase::goto_num( const int num, const int ) { if( ! num ) return; focus_view(); Gtk::TreeModel::Children child = m_liststore->children(); Gtk::TreeModel::Children::iterator it = child.begin(); for( ; it != child.end() ; ++it ){ Gtk::TreeModel::Row row = *( it ); if( row[ m_columns.m_col_id ] == num ){ Gtk::TreePath path = GET_PATH( row ); m_treeview.scroll_to_row( path ); m_treeview.set_cursor( path ); return; } } } // // 左スクロール // void BoardViewBase::scroll_left() { Gtk::Adjustment* hadjust = m_scrwin.get_hadjustment(); if( !hadjust ) return; hadjust->set_value( MAX( 0, hadjust->get_value() - hadjust->get_step_increment() ) ); } // // 右スクロール // void BoardViewBase::scroll_right() { Gtk::Adjustment* hadjust = m_scrwin.get_hadjustment(); if( !hadjust ) return; hadjust->set_value( MIN( hadjust->get_upper() - hadjust->get_page_size(), hadjust->get_value() + hadjust->get_step_increment() ) ); } // // 上へ移動 // void BoardViewBase::row_up() { m_treeview.row_up(); } // // 下へ移動 // void BoardViewBase::row_down() { m_treeview.row_down(); } // // page up // void BoardViewBase::page_up() { m_treeview.page_up(); } // // page down // void BoardViewBase::page_down() { m_treeview.page_down(); } // // ポップアップメニューを表示する前にメニューのアクティブ状態を切り替える // // SKELETON::View::show_popupmenu() を参照すること // void BoardViewBase::activate_act_before_popupmenu( const std::string& url ) { // toggle アクションを activeにするとスロット関数が呼ばれるので処理しないようにする m_enable_menuslot = false; Glib::RefPtr< Gtk::Action > act; // dat 保存 act = action_group()->get_action( "SaveDat" ); if( act ){ act->set_sensitive( false ); std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); if( list_it.size() ){ std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); for( ; it != list_it.end(); ++it ){ Gtk::TreeModel::Row row = *( *it ); DBTREE::ArticleBase *art = row[ m_columns.m_col_article ]; if( art->is_cached() ) { act->set_sensitive( true ); break; } } } } m_enable_menuslot = true; } // // ポップアップメニュー取得 // // SKELETON::View::show_popupmenu() を参照すること // Gtk::Menu* BoardViewBase::get_popupmenu( const std::string& url ) { Gtk::Menu* popupmenu = NULL; // 削除サブメニュー if( url == "popup_menu_delete" ){ popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_delete" ) ); } // お気に入りサブメニュー else if( url == "popup_menu_favorite" ){ const std::string url_board = path2url_board( m_path_selected ); if( url_board.empty() ) popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_favorite_article" ) ); else popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_favorite" ) ); } // 通常メニュー else if( m_treeview.get_selection()->get_selected_rows().size() == 1 ){ m_path_selected = * (m_treeview.get_selection()->get_selected_rows().begin() ); popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu" ) ); } // 複数選択メニュー else{ m_path_selected = Gtk::TreeModel::Path(); popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_mul" ) ); } return popupmenu; } // // 特定の行だけの表示内容更新 // // url : subject.txt のアドレス // id : DAT の ID(拡張子付き), empty なら全ての行の表示内容を更新する // void BoardViewBase::update_item( const std::string& url, const std::string& id ) { if( is_loading() ) return; if( ! get_row_size() ) return; if( ! get_url_board().empty() && get_url_board() != url ) return; if( id.empty() ){ update_item_all(); return; } const std::string url_dat = DBTREE::url_datbase( url ) + id; #ifdef _DEBUG std::cout << "BoardViewBase::update_item " << get_url() << std::endl << "url = " << url << " id = " << id << " url_dat = " << url_dat << std::endl; #endif unsorted_column(); const Gtk::TreeModel::Row row = get_row_from_url( url_dat ); if( row ) update_row_common( row ); } // // 全ての行の表示内容更新 // void BoardViewBase::update_item_all() { #ifdef _DEBUG std::cout << "BoardViewBase::update_item_all " << get_url() << std::endl; #endif unsorted_column(); Gtk::TreeModel::Children child = m_liststore->children(); Gtk::TreeModel::Children::iterator it; for( it = child.begin() ; it != child.end() ; ++it ){ Gtk::TreeModel::Row row = *( it ); if( ! row ) continue; DBTREE::ArticleBase* art = row[ m_columns.m_col_article ]; if( ! art ) continue; update_row_common( row ); } } // // 行を作って内容をセット // const Gtk::TreeModel::Row BoardViewBase::prepend_row( DBTREE::ArticleBase* art, const int id ) { Gtk::TreeModel::Row row = *( m_liststore->prepend() ); // append より prepend の方が速いらしい row[ m_columns.m_col_id ] = id; if( ( art->get_status() & STATUS_NORMAL ) && ! art->is_924() ) row[ m_columns.m_col_speed ] = art->get_speed(); row[ m_columns.m_col_diff ] = art->get_number_diff(); if( m_col_board ) row[ m_columns.m_col_board ] = DBTREE::board_name( art->get_url() ); row[ m_columns.m_col_article ] = art; row[ m_columns.m_col_drawbg ] = false; update_row_common( row ); return row; } // // prepend_row() と update_item() で共通に更新する列 // void BoardViewBase::update_row_common( const Gtk::TreeModel::Row& row ) { DBTREE::ArticleBase* art = row[ m_columns.m_col_article ]; if( art->empty() ) return; const int load = art->get_number_load(); const int res = art->get_number(); // タイトル、レス数、抽出 row[ m_columns.m_col_subject ] = art->get_subject(); row[ m_columns.m_col_res ] = res; // 読み込み数 if( load ){ const int tmpsize = 32; char tmp[ tmpsize ]; snprintf( tmp, tmpsize, "%d", load ); row[ m_columns.m_col_str_load ] = tmp; snprintf( tmp, tmpsize, "%d", res - load ); row[ m_columns.m_col_str_new ] = tmp; row[ m_columns.m_col_new ] = res - load; } else{ row[ m_columns.m_col_str_load ] = ""; row[ m_columns.m_col_str_new ] = ""; // キャッシュが無い場合はソートの優先度を // キャッシュがあって新着0の物より下げる row[ m_columns.m_col_new ] = -1; } // // マーク int mark_val; int icon; // ブックマーク if( art->is_bookmarked_thread() ){ // 新着あり if( art->enable_load() ){ mark_val = COL_MARKVAL_BKMARKED_UPDATED; icon = ICON::BKMARK_UPDATE; } // subject.txt が壊れている( subject.txt に示されたレス数よりも実際の取得数の方が多い ) else if( art->is_cached() && ( art->get_status() & STATUS_BROKEN_SUBJECT ) ){ mark_val = COL_MARKVAL_BKMARKED_BROKEN_SUBJECT; icon = ICON::BKMARK_BROKEN_SUBJECT; } else{ mark_val = COL_MARKVAL_BKMARKED; icon = ICON::BKMARK; } } // dat落ち else if( art->get_status() & STATUS_OLD ){ mark_val = COL_MARKVAL_OLD; icon = ICON::OLD; } // キャッシュはあるが規定のレス数を越えていて全てのレスが既読 else if( art->is_finished() ){ mark_val = COL_MARKVAL_FINISHED; // subject.txt が壊れている( subject.txt に示されたレス数よりも実際の取得数の方が多い ) if( art->get_status() & STATUS_BROKEN_SUBJECT ) icon = ICON::BROKEN_SUBJECT; else icon = ICON::CHECK; } // 新着あり else if( art->enable_load() ){ mark_val = COL_MARKVAL_UPDATED; icon = ICON::UPDATE; } // キャッシュあり else if( art->is_cached() ){ // subject.txt が壊れている( subject.txt に示されたレス数よりも実際の取得数の方が多い ) if( art->get_status() & STATUS_BROKEN_SUBJECT ){ mark_val = COL_MARKVAL_BROKEN_SUBJECT; icon = ICON::BROKEN_SUBJECT; } // 新着無し else{ mark_val = COL_MARKVAL_CACHED; icon = ICON::CHECK; } } // スレッド924 else if( art->is_924() ){ if( CONFIG::get_show_924() ){ mark_val = COL_MARKVAL_924; icon = ICON::INFO; } else{ mark_val = COL_MARKVAL_NORMAL; icon = ICON::TRANSPARENT; } } // キャッシュ無し、新着 else if( ! get_url_board().empty() && art->get_since_time() > m_last_access_time ){ mark_val = COL_MARKVAL_NEWTHREAD; icon = ICON::NEWTHREAD; } // キャッシュ無し、新着( CONFIG::get_newthread_hour() 時間以内 ) else if( art->get_hour() < CONFIG::get_newthread_hour() ){ mark_val = COL_MARKVAL_NEWTHREAD_HOUR; icon = ICON::NEWTHREAD_HOUR; } //キャッシュ無し else{ mark_val = COL_MARKVAL_NORMAL; icon = ICON::TRANSPARENT; } row[ m_columns.m_col_mark_val ] = mark_val; row[ m_columns.m_col_mark ] = ICON::get_icon( icon ); // スレ立て時間 if( ! art->is_924() ) row[ m_columns.m_col_since ] = art->get_since_date(); else row[ m_columns.m_col_since ] = std::string(); // 書き込み時間 if( art->get_write_time() ){ row[ m_columns.m_col_write ] = art->get_write_date(); row[ m_columns.m_col_write_t ] = art->get_write_time(); } else{ row[ m_columns.m_col_write ] = std::string(); // DAT落ちしたスレや1000に到達したスレなどは書き込んでいてもソート時の優先度を下げる if( mark_val < COL_MARKVAL_NORMAL ) row[ m_columns.m_col_write_t ] = 0; else row[ m_columns.m_col_write_t ] = -1; } // ユーザが最後にロードした時間 if( art->get_access_time() ){ row[ m_columns.m_col_access ] = art->get_access_date(); row[ m_columns.m_col_access_t ] = art->get_access_time(); } else{ row[ m_columns.m_col_access ] = std::string(); // DAT落ちしたスレや1000に到達したスレなどは書き込んでいてもソート時の優先度を下げる if( mark_val < COL_MARKVAL_NORMAL ) row[ m_columns.m_col_access_t ] = 0; else row[ m_columns.m_col_access_t ] = -1; } } // // マウスボタン押した // const bool BoardViewBase::slot_button_press( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "BoardViewBase::slot_button_press\n"; #endif if( m_cancel_openrow_counter ){ #ifdef _DEBUG std::cout << "canceled\n"; #endif return true; } m_clicked = true; // マウスジェスチャ get_control().MG_start( event ); // ホイールマウスジェスチャ get_control().MG_wheel_start( event ); // ダブルクリック // button_release_eventでは event->type に必ず GDK_BUTTON_RELEASE が入る m_dblclicked = false; if( event->type == GDK_2BUTTON_PRESS ) m_dblclicked = true; BOARD::get_admin()->set_command( "switch_admin" ); return true; } // // マウスボタン離した // const bool BoardViewBase::slot_button_release( GdkEventButton* event ) { if( ! m_clicked ) return true; m_clicked = false; /// マウスジェスチャ const int mg = get_control().MG_end( event ); // ホイールマウスジェスチャ // 実行された場合は何もしない if( get_control().MG_wheel_end( event ) ) return true; if( mg != CONTROL::None && enable_mg() ){ operate_view( mg ); return true; } // リサイズするときにラベルをドラッグした場合 if( event->window != m_treeview.get_bin_window()->gobj() ){ save_column_width(); return true; } const int x = (int)event->x; const int y = (int)event->y; Gtk::TreeModel::Path path; Gtk::TreeViewColumn* column; int cell_x; int cell_y; // 座標からpath取得 if( m_treeview.get_path_at_pos( x, y, path, column, cell_x, cell_y ) ){ m_path_selected = path; #ifdef _DEBUG std::cout << "BoardViewBase::slot_button_release : path = " << path.to_string() << " title = " << column->get_title() << " x = " << x << " y = " << y << " cellheight = " << m_treeview.get_row_height() << " cell_x = " << cell_x << " cell_y = " << cell_y << std::endl; #endif // ダブルクリックの処理のため一時的にtypeを切替える GdkEventType type_copy = event->type; if( m_dblclicked ) event->type = GDK_2BUTTON_PRESS; // スレを開く bool openarticle = get_control().button_alloted( event, CONTROL::OpenArticleButton ); bool openarticletab = get_control().button_alloted( event, CONTROL::OpenArticleTabButton ); if( openarticle || openarticletab ){ // 複数行選択中 if( m_treeview.get_selected_iterators().size() >= 2 ) open_selected_rows( false ); else open_row( path, openarticletab, false ); } // ポップアップメニューボタン else if( get_control().button_alloted( event, CONTROL::PopupmenuButton ) ){ show_popupmenu( "", false ); } else operate_view( get_control().button_press( event ) ); event->type = type_copy; } return true; } // // マウス動かした // const bool BoardViewBase::slot_motion_notify( GdkEventMotion* event ) { /// マウスジェスチャ get_control().MG_motion( event ); const int x = (int)event->x; const int y = (int)event->y; Gtk::TreeModel::Path path; Gtk::TreeView::Column* column; int cell_x; int cell_y; // ツールチップに文字列をセットする if( m_treeview.get_path_at_pos( x, y, path, column, cell_x, cell_y ) ){ // 列幅よりもツールチップの幅が広い場合はツールチップを表示する m_treeview.set_tooltip_min_width( column->get_width() ); if( column->get_title() == ITEM_NAME_BOARD ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_board ) ); else if( column->get_title() == ITEM_NAME_NAME ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_subject ) ); else if( column->get_title() == ITEM_NAME_SINCE ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_since ) ); else if( column->get_title() == ITEM_NAME_LASTWRITE ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_write ) ); else if( column->get_title() == ITEM_NAME_ACCESS ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_access ) ); else m_treeview.set_str_tooltip( std::string() ); } return true; } // // キー入力 // const bool BoardViewBase::slot_key_press( GdkEventKey* event ) { m_pressed_key = get_control().key_press( event ); if( m_pressed_key != CONTROL::None ){ // キー入力でスレを開くとkey_releaseイベントがboadviewが画面から // 消えてから送られてWIDGET_REALIZED_FOR_EVENT assertionが出るので // OpenArticle(Tab)は slot_key_release() で処理する if( m_pressed_key == CONTROL::OpenArticle ) return true; if( m_pressed_key == CONTROL::OpenArticleTab ) return true; if( operate_view( m_pressed_key ) ) return true; } else if( release_keyjump_key( event->keyval ) ) return true; return false; } // // キーリリースイベント // const bool BoardViewBase::slot_key_release( GdkEventKey* event ) { const int key = get_control().key_press( event ); // 押したキーと違うときは処理しない if( key == m_pressed_key ){ // キー入力でスレを開くとkey_releaseイベントがboadviewが画面から // 消えてから送られてWIDGET_REALIZED_FOR_EVENT assertionが出るので // OpenArticle(Tab)はここで処理する if( key == CONTROL::OpenArticle ) operate_view( key ); if( key == CONTROL::OpenArticleTab ) operate_view( key ); } return true; } // // マウスホイールイベント // const bool BoardViewBase::slot_scroll_event( GdkEventScroll* event ) { // ホイールマウスジェスチャ const int control = get_control().MG_wheel_scroll( event ); if( enable_mg() && control != CONTROL::None ){ operate_view( control ); return true; } m_treeview.wheelscroll( event ); return true; } // // D&Dで受信側がデータ送信を要求してきた // void BoardViewBase::slot_drag_data_get( const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time ) { #ifdef _DEBUG std::cout << "BoardViewBase::slot_drag_data_get\n"; #endif set_article_to_buffer(); selection_data.set( m_treeview.get_dndtarget(), get_url_board() ); } // // text/url-list がドロップされた // void BoardViewBase::slot_dropped_url_list( const std::list< std::string >& url_list ) { #ifdef _DEBUG std::cout << "BoardViewBase::slot_dropped_url_list\n"; #endif if( ! url_list.size() ) return; // 共有バッファにアドレスをセットしてから import_dat コマンドを発行 CORE::DATA_INFO_LIST list_info; std::list< std::string >::const_iterator it = url_list.begin(); for( ; it != url_list.end(); ++it ){ if( ( *it ).empty() ) continue; if( ( *it ).find( "file://" ) == std::string::npos ) continue; CORE::DATA_INFO info; info.type = TYPE_FILE; info.url = MISC::remove_str( ( *it ), "file://" ); list_info.push_back( info ); #ifdef _DEBUG std::cout << "append " << info.url << std::endl; #endif } CORE::SBUF_set_list( list_info ); CORE::core_set_command( "import_dat", get_url_board(), "no_show_diag", "use_sbuf" ); } // // ブックマーク設定、解除 // void BoardViewBase::slot_bookmark( const int bookmark ) { std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); for( ; it != list_it.end(); ++it ){ Gtk::TreeModel::Row row = *( *it ); DBTREE::ArticleBase* art = row[ m_columns.m_col_article ]; if( art ){ bool set = bookmark; if( bookmark == BOOKMARK_AUTO ) set = ! art->is_bookmarked_thread(); #ifdef _DEBUG std::cout << "BoardViewBase::slot_bookmark url = " << art->get_url() << " set = " << set << std::endl; #endif art->set_bookmarked_thread( set ); } } } // // popupmenu でタブで開くを選択 // void BoardViewBase::slot_open_tab() { if( ! m_path_selected.empty() ) open_row( m_path_selected, true, false ); } // // popupmenu でスレ情報を消さずに再取得を選択 // void BoardViewBase::slot_reget_article() { if( ! m_path_selected.empty() ) open_row( m_path_selected, true, true ); } // // スレをお気に入りに登録 // // ポップアップメニューのslot // void BoardViewBase::slot_favorite_thread() { // 共有バッファにデータをセットしてから append_favorite コマンド実行 set_article_to_buffer(); CORE::core_set_command( "append_favorite", URL_FAVORITEVIEW ); } // // 板をお気に入りに追加 // void BoardViewBase::slot_favorite_board() { // 共有バッファにデータをセットしてから append_favorite コマンド実行 set_board_to_buffer(); CORE::core_set_command( "append_favorite", URL_FAVORITEVIEW ); } // // 新スレをたてる // void BoardViewBase::write() { CORE::core_set_command( "create_new_thread", get_url_board() ); } // // ツールバーの削除ボタン // void BoardViewBase::delete_view() { show_popupmenu( "popup_menu_delete", false ); } // // ツールバーのお気に入りボタン // void BoardViewBase::set_favorite() { show_popupmenu( "popup_menu_favorite", false ); } // // スレのURLをコピー // void BoardViewBase::slot_copy_url() { if( m_path_selected.empty() ) return; const std::string url = DBTREE::url_readcgi( path2daturl( m_path_selected ), 0, 0 ); MISC::CopyClipboard( url ); } // スレの名前とURLをコピー // void BoardViewBase::slot_copy_title_url() { if( m_path_selected.empty() ) return; const std::string url = DBTREE::url_readcgi( path2daturl( m_path_selected ), 0, 0 ); const std::string name = DBTREE::article_subject( url ); MISC::CopyClipboard( name + '\n' + url ); } // // 全選択 // void BoardViewBase::slot_select_all() { SKELETON::MsgDiag mdiag( get_parent_win(), "全ての行を選択しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; Gtk::TreeModel::Children child = m_liststore->children(); Gtk::TreeModel::Children::iterator it = child.begin(); for( ; it != child.end() ; ++it ) m_treeview.get_selection()->select( *it ); } // // ポップアップメニューでブラウザで開くを選択 // void BoardViewBase::slot_open_browser() { const std::string url = DBTREE::url_readcgi( path2daturl( m_path_selected ), 0, 0 ); CORE::core_set_command( "open_url_browser", url ); } // // 記事を開く // const bool BoardViewBase::open_row( Gtk::TreePath& path, const bool tab, const bool reget ) { std::string str_tab = "false"; if( tab ) str_tab = "true"; std::string mode = std::string();; const std::string url_target = path2daturl( path ); #ifdef _DEBUG std::cout << "BoardViewBase::open_row " << url_target << std::endl; #endif if( url_target.empty() ) return false; if( reget ){ if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); return false; } if( ! DBTREE::article_is_cached( url_target ) ) return false; if( DBTREE::article_status( url_target ) & STATUS_OLD ){ SKELETON::MsgDiag mdiag( get_parent_win(), "DAT落ちしています。\n\nログが消える恐れがあります。実行しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return false; } mode = "reget"; } // datロード終了時に次スレ移行チェックを行う DBTREE::article_set_url_pre_article( url_target, get_url_pre_article() ); CORE::core_set_command( "open_article", url_target, str_tab, mode ); // 行を長押ししてから素早くクリックし直すとslot_button_press()が呼び出されて // スレビューが表示されてから一瞬スレ一覧に切り替わるのを防ぐ m_cancel_openrow_counter = CANCEL_OPENROW / TIMER_TIMEOUT; return true; } // // 選択した行をまとめて開く // void BoardViewBase::open_selected_rows( const bool reget ) { std::string mode = std::string();; std::string list_url; std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); std::list< Gtk::TreeModel::iterator >::iterator it; if( reget ){ if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); return; } it = list_it.begin(); for( ; it != list_it.end(); ++it ){ Gtk::TreeModel::Row row = *( *it ); DBTREE::ArticleBase *art = row[ m_columns.m_col_article ]; if( ! art->is_cached() ) continue; if( art->get_status() & STATUS_OLD ){ SKELETON::MsgDiag mdiag( get_parent_win(), "DAT落ちしているスレを含んでいます。\n\nログが消える恐れがあります。実行しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; break; } } mode = "reget"; } it = list_it.begin(); for( ; it != list_it.end(); ++it ){ if( !list_url.empty() ) list_url += " "; Gtk::TreeModel::Row row = *( *it ); DBTREE::ArticleBase *art = row[ m_columns.m_col_article ]; if( reget && ! art->is_cached() ) continue; list_url += art->get_url(); // datロード終了時に次スレ移行チェックを行う art->set_url_pre_article( get_url_pre_article() ); } if( list_url.size() ) CORE::core_set_command( "open_article_list", std::string(), list_url, mode ); } // // path -> スレッドの(dat型)URL変換 // const std::string BoardViewBase::path2daturl( const Gtk::TreePath& path ) { Gtk::TreeModel::Row row = m_treeview.get_row( path ); if( !row ) return std::string(); DBTREE::ArticleBase *art = row[ m_columns.m_col_article ]; return art->get_url(); } // // path -> 板URL変換 // const std::string BoardViewBase::path2url_board( const Gtk::TreePath& path ) { if( ! get_url_board().empty() ) return get_url_board(); if( path.empty() ) return std::string(); return DBTREE::url_subject( path2daturl( path ) ); } // // 抽出 // const bool BoardViewBase::drawout( const bool force_reset ) { int hit = 0; bool reset = false; const std::string query = get_search_query(); // 空の時はリセット if( force_reset || query.empty() ) reset = true; #ifdef _DEBUG std::cout << "BoardViewBase::drawout query = " << query << std::endl; #endif unsorted_column(); JDLIB::Regex regex; const bool icase = true; // 大文字小文字区別しない const bool newline = true; // . に改行をマッチさせない const bool usemigemo = true; // migemo使用 const bool wchar = true; // 全角半角の区別をしない Gtk::TreeModel::Children child = m_liststore->children(); Gtk::TreeModel::Children::iterator it = child.begin(); if ( ! reset ) regex.compile( query, icase, newline, usemigemo, wchar ); for( ; it != child.end() ; ++it ){ Gtk::TreeModel::Row row = *( it ); const Glib::ustring subject = row[ m_columns.m_col_subject ]; if( reset ) row[ m_columns.m_col_drawbg ] = false; else if( regex.exec( subject, 0 ) ){ row[ m_columns.m_col_drawbg ] = true; ++hit; #ifdef _DEBUG std::cout << subject << " " << row[ m_columns.m_col_mark_val ] << std::endl; #endif } else row[ m_columns.m_col_drawbg ] = false; } restore_sort(); if( reset ) CORE::core_set_command( "set_info", "", "" ); else if( ! hit ) CORE::core_set_command( "set_info", "", "検索結果: ヒット無し" ); else CORE::core_set_command( "set_info", "", "検索結果: " + MISC::itostr( hit ) + "件" ); return true; } // // 検索ボックスの文字列が変わった // void BoardViewBase::set_search_query( const std::string& query ) { SKELETON::View::set_search_query( query ); #ifdef _DEBUG std::cout << "BoardViewBase::set_search_query query = " << get_search_query() << std::endl; #endif if( CONFIG::get_inc_search_board() ){ drawout( false ); m_pre_query = std::string(); } } // // 検索実行 // void BoardViewBase::exec_search() { const std::string query = get_search_query(); if( m_pre_query != query ){ drawout( false ); focus_view(); m_pre_query = query; CORE::get_completion_manager()->set_query( CORE::COMP_SEARCH_BOARD, query ); return; } focus_view(); if( query.empty() ) return; Gtk::TreePath path = m_treeview.get_current_path();; if( path.empty() ){ if( m_search_invert ) path = GET_PATH( *( m_liststore->children().begin() ) ); else GET_PATH( *( m_liststore->children().rbegin() ) ); } Gtk::TreePath path_start = path; JDLIB::Regex regex; const size_t offset = 0; const bool icase = true; // 大文字小文字区別しない const bool newline = true; // . に改行をマッチさせない const bool usemigemo = true; // migemo使用 const bool wchar = true; // 全角半角の区別をしない #ifdef _DEBUG std::cout << "BoardViewBase::search start = " << path_start.to_string() << " query = " << query << std::endl; #endif for(;;){ if( !m_search_invert ){ // 次へ path.next(); // 先頭に戻る if( ! m_treeview.get_row( path ) ) path = GET_PATH( *( m_liststore->children().begin() ) ); } else{ // 前へ if( ! path.prev() ){ // 一番後へ path = GET_PATH( *( m_liststore->children().rbegin() ) ); } } if( path == path_start ) break; Glib::ustring subject = get_name_of_cell( path, m_columns.m_col_subject ); if( regex.exec( query, subject, offset, icase, newline, usemigemo, wchar ) ){ m_treeview.scroll_to_row( path, 0 ); m_treeview.set_cursor( path ); return; } } } // 前検索 void BoardViewBase::up_search() { m_search_invert = true; exec_search(); } // 後検索 void BoardViewBase::down_search() { m_search_invert = false; exec_search(); } // // 検索entryの操作 // void BoardViewBase::operate_search( const std::string& controlid ) { const int id = atoi( controlid.c_str() ); if( id == CONTROL::Cancel ) focus_view(); else if( id == CONTROL::SearchCache ) CORE::core_set_command( "open_article_searchlog", get_url_board() , get_search_query(), "exec" ); } // // ハイライト解除 // void BoardViewBase::clear_highlight() { drawout( true ); focus_view(); m_pre_query = std::string(); } // // 板プロパティ表示 // void BoardViewBase::show_preference() { const std::string url_board = path2url_board( m_path_selected ); if( url_board.empty() ) return; SKELETON::PrefDiag* pref = CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_BOARD, url_board ); pref->run(); delete pref; } // // スレプロパティ表示 // void BoardViewBase::slot_preferences_article() { if( m_path_selected.empty() ) return; const std::string url = path2daturl( m_path_selected ); SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_ARTICLE, url ); pref->run(); delete pref; } // // 戻る // void BoardViewBase::back_viewhistory( const int count ) { BOARD::get_admin()->set_command( "back_viewhistory", get_url(), MISC::itostr( count ) ); } // // 進む // void BoardViewBase::forward_viewhistory( const int count ) { BOARD::get_admin()->set_command( "forward_viewhistory", get_url(), MISC::itostr( count ) ); } // // datを保存 // void BoardViewBase::slot_save_dat() { if( ! m_enable_menuslot ) return; std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); #ifdef _DEBUG std::cout << "BoardViewBase::slot_save_dat size = " << list_it.size() << std::endl; #endif if( ! list_it.size() ) return; // ひとつだけ名前を付けて保存 if( list_it.size() == 1 ){ Gtk::TreePath path = m_treeview.get_current_path(); if( path.empty() ) return; const std::string url = path2daturl( path ); DBTREE::article_save_dat( url, std::string() ); return; } // 複数のdatを保存 int overwrite = Gtk::RESPONSE_NO; // ディレクトリ選択 SKELETON::FileDiag diag( get_parent_win(), "保存先選択", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER ); diag.set_current_folder( SESSION::get_dir_dat() ); if( diag.run() != Gtk::RESPONSE_ACCEPT ) return; diag.hide(); std::string path_dir = MISC::recover_path( diag.get_filename() ); if( path_dir.empty() ) return; if( path_dir.c_str()[ path_dir.length()-1 ] != '/' ) path_dir += "/"; #ifdef _DEBUG std::cout << "dir = " << path_dir << std::endl; #endif if( ! CACHE::jdmkdir( path_dir ) ){ SKELETON::MsgDiag mdiag( get_parent_win(), path_dir + "\n\nの作成に失敗しました。\nハードディスクの容量やパーミッションなどを確認してください。\n\ndatファイルの保存をキャンセルしました。原因を解決してからもう一度保存を行ってください。" ); mdiag.run(); return; } SESSION::set_dir_dat( path_dir ); for( ; it != list_it.end(); ++it ){ Gtk::TreeModel::Row row = *( *it ); DBTREE::ArticleBase *art = row[ m_columns.m_col_article ]; if( ! art->is_cached() ) continue; const std::string path_from = CACHE::path_dat( art->get_url() ); const std::string path_to = path_dir + MISC::get_filename( art->get_url() ); #ifdef _DEBUG std::cout << "from = " << path_from << std::endl; std::cout << "to = " << path_to << std::endl; #endif bool copy_file = true; // 既にファイルがある場合 if( CACHE::file_exists( path_to ) == CACHE::EXIST_FILE ){ // すべて上書き if( overwrite == SKELETON::OVERWRITE_YES_ALL ) copy_file = true; // すべていいえ else if( overwrite == SKELETON::OVERWRITE_NO_ALL ) copy_file = false; else{ for(;;){ SKELETON::MsgOverwriteDiag mdiag( get_parent_win() ); overwrite = mdiag.run(); mdiag.hide(); switch( overwrite ){ // すべて上書き case SKELETON::OVERWRITE_YES_ALL: // 上書き case SKELETON::OVERWRITE_YES: copy_file = true; break; // 名前変更 case Gtk::RESPONSE_YES: if( ! art->save_dat( path_to ) ) continue; default: copy_file = false; break; } break; // for(;;) } } } if( copy_file ){ #ifdef _DEBUG std::cout << "copy\n"; #endif if( ! CACHE::jdcopy( path_from, path_to ) ){ SKELETON::MsgDiag mdiag( get_parent_win(), path_to + "\n\nの保存に失敗しました。\nハードディスクの容量やパーミッションなどを確認してください。\n\ndatファイルの保存をキャンセルしました。原因を解決してからもう一度保存を行ってください。" ); mdiag.run(); return; } } } } // // 次スレ検索 // void BoardViewBase::slot_search_next() { if( m_path_selected.empty() ) return; const std::string url = path2daturl( m_path_selected ); CORE::core_set_command( "open_board_next", DBTREE::url_subject( url ) , url ); } // // 選択したスレをあぼーん // void BoardViewBase::slot_abone_thread() { std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); if( ! list_it.size() ) return; std::list< std::string > threads = DBTREE::get_abone_list_thread( get_url_board() ); for( ; it != list_it.end(); ++it ){ Gtk::TreeModel::Row row = *( *it ); Glib::ustring subject = row[ m_columns.m_col_subject ]; threads.push_back( subject ); } // あぼーん情報更新 std::list< std::string > words = DBTREE::get_abone_list_word_thread( get_url_board() ); std::list< std::string > regexs = DBTREE::get_abone_list_regex_thread( get_url_board() ); const int number = DBTREE::get_abone_number_thread( get_url_board() ); const int hour = DBTREE::get_abone_hour_thread( get_url_board() ); const bool redraw = false; // 板の再描画はしない DBTREE::reset_abone_thread( get_url_board(), threads, words, regexs, number, hour, redraw ); m_treeview.delete_selected_rows( true ); } // // path と column からそのセルの内容を取得 // template < typename ColumnType > const std::string BoardViewBase::get_name_of_cell( Gtk::TreePath& path, const Gtk::TreeModelColumn< ColumnType >& column ) { Gtk::TreeModel::Row row = m_treeview.get_row( path ); if( !row ) return std::string(); const Glib::ustring name = row[ column ]; return name; } // // 共有バッファに選択中の行を登録する // void BoardViewBase::set_article_to_buffer() { std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); if( list_it.size() ){ CORE::DATA_INFO_LIST list_info; Gtk::TreePath path( "0" ); std::list< Gtk::TreeModel::iterator >::iterator it = list_it.begin(); for( ; it != list_it.end(); ++it ){ Gtk::TreeModel::Row row = *( *it ); DBTREE::ArticleBase *art = row[ m_columns.m_col_article ]; const Glib::ustring name = row[ m_columns.m_col_subject ]; CORE::DATA_INFO info; info.type = TYPE_THREAD; info.parent = BOARD::get_admin()->get_win(); info.url = art->get_url(); info.name = name.raw(); info.path = path.to_string(); list_info.push_back( info ); #ifdef _DEBUG std::cout << "append " << info.name << std::endl; #endif path.next(); } CORE::SBUF_set_list( list_info ); } } // // 共有バッファに板を登録する // void BoardViewBase::set_board_to_buffer() { CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; const std::string url_board = path2url_board( m_path_selected ); if( url_board.empty() ) return; info.type = TYPE_BOARD; info.parent = BOARD::get_admin()->get_win(); info.url = DBTREE::url_boardbase( url_board ); info.name = DBTREE::board_name( url_board ); info.path = Gtk::TreePath( "0" ).to_string(); list_info.push_back( info ); CORE::SBUF_set_list( list_info ); } // // 指定したスレを強調して表示 // dat 落ち等で表示されていないスレも強制的に表示する // 共有バッファに表示したいスレをセットしてから set_command 経由で呼び出す // void BoardViewBase::draw_bg_articles() { // 共有バッファから追加するスレのURLのリストを作成 if( ! m_list_draw_bg_articles.size() ){ if( CORE::SBUF_size() == 0 ) return; const CORE::DATA_INFO_LIST list_info = CORE::SBUF_list_info(); CORE::DATA_INFO_LIST::const_iterator it = list_info.begin(); for( ; it != list_info.end(); ++it ){ if( ( *it ).type != TYPE_THREAD ) continue; m_list_draw_bg_articles.push_back( ( *it ).url ); } } if( ! m_list_draw_bg_articles.size() ) return; // ロード中の時はロード後にもう一度呼び出す if( is_loading() ) return; #ifdef _DEBUG std::cout << "BoardViewBase::draw_bg_articles size = " << m_list_draw_bg_articles.size() << std::endl; #endif unsorted_column(); std::list< std::string >::const_iterator it = m_list_draw_bg_articles.begin(); for( ; it != m_list_draw_bg_articles.end(); ++it ){ const std::string& url = ( *it ); #ifdef _DEBUG std::cout << url << std::endl; #endif Gtk::TreeModel::Row row = get_row_from_url( url ); // row が無ければ作成 if( ! row ){ DBTREE::ArticleBase* art = DBTREE::get_article( url ); row = prepend_row( art, get_row_size() + 1 ); } // 強調表示 row[ m_columns.m_col_drawbg ] = true; } restore_sort(); m_list_draw_bg_articles.clear(); } jd-2.8.7-140104/src/board/boardviewbase.h0000644000076400010400000002365412175137371014455 0ustar // ライセンス: GPL2 // スレ一覧ビューの基底クラス #ifndef _BOARDVIEWBASE_H #define _BOARDVIEWBASE_H #include "skeleton/view.h" #include "skeleton/dragtreeview.h" #include "columns.h" #include #include namespace SKELETON { class Admin; } namespace DBTREE { class ArticleBase; } namespace BOARD { class BoardViewBase : public SKELETON::View { // viewに表示するboardのURL ( SKELETON::View::m_url はview自身のURLなのに注意すること ) std::string m_url_board; SKELETON::DragTreeView m_treeview; BOARD::TreeColumns m_columns; Glib::RefPtr< Gtk::ListStore > m_liststore; Gtk::ScrolledWindow m_scrwin; // 列 Gtk::TreeView::Column* m_col_mark; Gtk::TreeView::Column* m_col_id; Gtk::TreeView::Column* m_col_board; Gtk::TreeView::Column* m_col_subject; Gtk::TreeView::Column* m_col_res; Gtk::TreeView::Column* m_col_str_load; Gtk::TreeView::Column* m_col_str_new; Gtk::TreeView::Column* m_col_since; Gtk::TreeView::Column* m_col_write; Gtk::TreeView::Column* m_col_access; Gtk::TreeView::Column* m_col_speed; Gtk::TreeView::Column* m_col_diff; // クリック状態 bool m_clicked; // ダブルクリック状態 bool m_dblclicked; // 押したキー int m_pressed_key; // ソートで使う変数 int m_col; int m_previous_col; int m_sortmode; int m_previous_sortmode; // サーチで使う変数 bool m_search_invert; std::string m_pre_query; // ポップアップメニュー用 Gtk::TreeModel::Path m_path_selected; // ロード中 bool m_loading; // ロード前の最終アクセス時刻 ( 新着判定用 ) time_t m_last_access_time; // ロード中に draw_bg_articles() を呼び出したときに使う一時変数 // draw_bg_articles() を参照せよ std::list< std::string > m_list_draw_bg_articles; // ポップアップメニュー表示のときにactivate_act_before_popupmenu()で使う変数 bool m_enable_menuslot; // subject.txt をロードする bool m_load_subject_txt; // 先頭に「板」列を表示 bool m_show_col_board; // 増分行が表示されている bool m_col_diff_is_shown; // 連続クリック防止用カウンタ int m_cancel_openrow_counter; public: BoardViewBase( const std::string& url, const bool show_col_board ); virtual ~BoardViewBase(); const std::string& get_url_board() const { return m_url_board; } virtual const std::string url_for_copy(); // 行数 const int get_row_size(); // SKELETON::View の関数のオーバロード virtual void save_session(){} virtual void update_url( const std::string& url_old, const std::string& url_new ); virtual const int get_icon( const std::string& iconname ); virtual const bool is_loading(){ return m_loading; } virtual const bool set_command( const std::string& command, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() ); virtual void clock_in(); // キーを押した virtual const bool slot_key_press( GdkEventKey* event ); virtual void write(); virtual void stop(); virtual void show_view(); virtual void redraw_scrollbar(); virtual void relayout(); virtual void focus_view(); virtual void focus_out(); virtual void close_view(); virtual void delete_view(); virtual void set_favorite(); // 特定の行だけの表示内容更新 // url : subject.txt のアドレス // id : DAT の ID(拡張子付き) // もし ID が empty() なら全ての行の表示内容を更新する virtual void update_item( const std::string& url, const std::string& id ); virtual const bool operate_view( const int control ); virtual void goto_top(); virtual void goto_bottom(); virtual void goto_num( const int num_to, const int num_from ); virtual void scroll_left(); virtual void scroll_right(); virtual void show_preference(); // 進む、戻る virtual void back_viewhistory( const int count ); virtual void forward_viewhistory( const int count ); // 検索 virtual void exec_search(); virtual void up_search(); virtual void down_search(); virtual void operate_search( const std::string& controlid ); virtual void set_search_query( const std::string& query ); void clear_highlight(); void row_up(); void row_down(); void page_up(); void page_down(); protected: // 自動ソート抑制 void unsorted_column(); // url から row を取得 Gtk::TreeModel::Row get_row_from_url( const std::string& url ); SKELETON::DragTreeView& get_treeview(){ return m_treeview; } // Viewが所属するAdminクラス virtual SKELETON::Admin* get_admin(); // ポップアップメニューを表示する前にメニューのアクティブ状態を切り替える virtual void activate_act_before_popupmenu( const std::string& url ); // ポップアップメニュー取得 virtual Gtk::Menu* get_popupmenu( const std::string& url ); // view更新 void update_view_impl( const std::vector< DBTREE::ArticleBase* >& list_article, const bool loading_fin ); // ステータスバー更新 void update_status(); // URLを選択 void select_item( const std::string& url ); // subject.txt をロードする void set_load_subject_txt( const bool load ){ m_load_subject_txt = load; } // 行を作って内容をセット const Gtk::TreeModel::Row prepend_row( DBTREE::ArticleBase* art, const int id ); // デフォルトのソート状態 virtual const int get_default_sort_column(); virtual const int get_default_view_sort_mode(); virtual const int get_default_view_sort_pre_column(); virtual const int get_default_view_sort_pre_mode(); private: void setup_action(); // 通常の右クリックメニューの作成 const std::string create_context_menu(); const char* get_menu_item( const int item ); // 次スレ移行処理に使用する前スレのアドレス // BOARD::BoardViewNext と BoardViewBase::open_row()を参照せよ virtual const std::string get_url_pre_article(){ return std::string(); } void update_columns(); const int get_title_id( const int col ); // ソート列やソートモードの保存 virtual void save_sort_columns(); // 列の幅の保存 virtual void save_column_width(); void slot_cell_data( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ); // 全ての行の表示内容更新 void update_item_all(); // ソート実行 void exec_sort(); // ソート状態回復 void restore_sort(); // ヘッダをクリックしたときのslot関数 void slot_col_clicked( const int col ); const int compare_drawbg( Gtk::TreeModel::Row& row_a, Gtk::TreeModel::Row& row_b ); const int compare_col( const int col, const int sortmode, Gtk::TreeModel::Row& row_a, Gtk::TreeModel::Row& row_b ); const int slot_compare_row( const Gtk::TreeModel::iterator& a, const Gtk::TreeModel::iterator& b ); // UI const bool slot_button_press( GdkEventButton* event ); const bool slot_button_release( GdkEventButton* event ); const bool slot_motion_notify( GdkEventMotion* event ); const bool slot_key_release( GdkEventKey* event ); const bool slot_scroll_event( GdkEventScroll* event ); void slot_bookmark( int bookmark ); void slot_open_tab(); void slot_reget_article(); void slot_favorite_thread(); void slot_favorite_board(); void slot_copy_url(); void slot_copy_title_url(); void slot_select_all(); void slot_open_browser(); void slot_preferences_article(); void slot_save_dat(); void slot_search_next(); virtual void slot_abone_thread(); void slot_delete_logs(); // ドラッグアンドドロップ void slot_drag_data_get( const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time ); void slot_dropped_url_list( const std::list< std::string >& ); const bool open_row( Gtk::TreePath& path, const bool tab, const bool reget ); void open_selected_rows( const bool reget ); const std::string path2daturl( const Gtk::TreePath& path ); const std::string path2url_board( const Gtk::TreePath& path ); // 検索 const bool drawout( const bool force_reset ); void update_row_common( const Gtk::TreeModel::Row& row ); const std::string get_subject_from_path( Gtk::TreePath& path ); template < typename ColumnType > const std::string get_name_of_cell( Gtk::TreePath& path, const Gtk::TreeModelColumn< ColumnType >& column ); void set_article_to_buffer(); void set_board_to_buffer(); // 指定したスレを強調して表示 // dat 落ち等で表示されていないスレも強制的に表示する // 共有バッファに表示したいスレをセットしてから set_command 経由で呼び出す void draw_bg_articles(); }; }; #endif jd-2.8.7-140104/src/board/boardviewlog.cpp0000644000076400010400000001236211376762460014656 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boardadmin.h" #include "boardviewlog.h" #include "skeleton/msgdiag.h" #include "dbtree/interface.h" #include "dbtree/articlebase.h" #include "searchmanager.h" #include "session.h" #include "global.h" using namespace BOARD; BoardViewLog::BoardViewLog( const std::string& url ) : BoardViewBase( url, ( url == URL_ALLLOG ) ) { set_writeable( false ); set_load_subject_txt( false ); CORE::get_search_manager()->sig_search_fin().connect( sigc::mem_fun( *this, &BoardViewLog::slot_search_fin ) ); #ifdef _DEBUG std::cout << "BoardViewLog::BoardViewLog : url = " << get_url() << std::endl; #endif } BoardViewLog::~BoardViewLog() { #ifdef _DEBUG std::cout << "BoardViewLog::~BoardViewLog : url = " << get_url() << std::endl; #endif } // // 検索停止 // void BoardViewLog::stop() { CORE::get_search_manager()->stop( get_url() ); } // // リロード // void BoardViewLog::reload() { if( CORE::get_search_manager()->is_searching() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "他の検索スレッドが実行中です" ); mdiag.run(); return; } show_view(); } // // ビュー表示 // void BoardViewLog::show_view() { #ifdef _DEBUG std::cout << "BoardViewLog::show_view " << get_url() << std::endl; #endif if( ! SESSION::is_booting() ){ const std::string id = get_url(); int searchmode = CORE::SEARCHMODE_LOG; if( get_url() == URL_ALLLOG ) searchmode = CORE::SEARCHMODE_ALLLOG; const bool mode_or = false; const bool bm = false; const bool calc_data = false; CORE::get_search_manager()->search( id, searchmode, get_url_board(), "", mode_or, bm, calc_data ); } BoardViewBase::show_view(); } // // 検索終了 // void BoardViewLog::slot_search_fin( const std::string& id ) { if( id != get_url() ) return; #ifdef _DEBUG std::cout << "BoardViewLog::slot_search_fin size = " << CORE::get_search_manager()->get_list_article().size() << std::endl; #endif const bool loading_fin = true; const std::vector< DBTREE::ArticleBase* >& list_article = CORE::get_search_manager()->get_list_article(); update_view_impl( list_article, loading_fin ); m_set_thread.clear(); for( size_t i = 0; i < list_article.size(); ++i ){ const DBTREE::ArticleBase* art = list_article[ i ]; m_set_thread.insert( art->get_url() ); } } void BoardViewLog::slot_abone_thread() { SKELETON::MsgDiag mdiag( get_parent_win(), "ログ一覧ではあぼ〜ん出来ません" ); mdiag.run(); return; } // // 板名更新 // void BoardViewLog::update_boardname() { std::string title; if( get_url() == URL_ALLLOG ) title = "[ 全ログ一覧 ]"; else if( ! get_url_board().empty() ) title = "[ ログ一覧 ] - " + DBTREE::board_name( get_url_board() ); // ウィンドウタイトル表示 set_title( title ); BOARD::get_admin()->set_command( "set_title", get_url(), get_title() ); // タブに名前をセット BOARD::get_admin()->set_command( "set_tablabel", get_url(), title ); } // // 特定の行だけの表示内容更新 // // url : subject.txt のアドレス // id : DAT の ID(拡張子付き), empty なら全ての行の表示内容を更新する // void BoardViewLog::update_item( const std::string& url, const std::string& id ) { // url が URL_ALLLOG の時は get_url_board() の戻り値は empty if( get_url() != URL_ALLLOG && get_url_board() != url ) return; if( CORE::get_search_manager()->is_searching( get_url() ) ) return; const std::string url_dat = DBTREE::url_datbase( url ) + id; Gtk::TreeModel::Row row; if( ! id.empty() && m_set_thread.find_if( url_dat ) ) row = get_row_from_url( url_dat ); #ifdef _DEBUG std::cout << "BoardViewLog::update_item " << get_url() << std::endl << "url = " << url << " id = " << id << " url_dat = " << url_dat << std::endl; #endif if( id.empty() || row ) BoardViewBase::update_item( url, id ); // もし row が無く、かつキャッシュがあるならば行を追加 else if( ! id.empty() ){ DBTREE::ArticleBase* art = DBTREE::get_article( url_dat ); if( art && art->is_cached() ){ #ifdef _DEBUG std::cout << "prepend\n"; #endif unsorted_column(); prepend_row( art, get_row_size() + 1 ); m_set_thread.insert( art->get_url() ); goto_top(); update_status(); } } } // // デフォルトのソート状態 // const int BoardViewLog::get_default_sort_column() { if( get_url() != URL_ALLLOG ) return BoardViewBase::get_default_sort_column(); return COL_BOARD; } const int BoardViewLog::get_default_view_sort_mode() { if( get_url() != URL_ALLLOG ) return BoardViewBase::get_default_view_sort_mode(); return SORTMODE_ASCEND; } const int BoardViewLog::get_default_view_sort_pre_column() { if( get_url() != URL_ALLLOG ) return BoardViewBase::get_default_view_sort_pre_column(); return COL_ID; } const int BoardViewLog::get_default_view_sort_pre_mode() { if( get_url() != URL_ALLLOG ) return BoardViewBase::get_default_view_sort_pre_mode(); return SORTMODE_ASCEND; } jd-2.8.7-140104/src/board/boardviewlog.h0000644000076400010400000000232111350440352014276 0ustar // ライセンス: GPL2 // ログ一覧ビュー #ifndef _BOARDVIEWLOG_H #define _BOARDVIEWLOG_H #include "boardviewbase.h" #include "jdlib/hash_set.h" namespace BOARD { class BoardViewLog : public BOARD::BoardViewBase { JDLIB::hash_set_thread m_set_thread; public: BoardViewLog( const std::string& url ); virtual ~BoardViewLog(); virtual void stop(); virtual void reload(); virtual void show_view(); virtual void update_boardname(); virtual void update_item( const std::string& url, const std::string& id ); protected: // デフォルトのソート状態 virtual const int get_default_sort_column(); virtual const int get_default_view_sort_mode(); virtual const int get_default_view_sort_pre_column(); virtual const int get_default_view_sort_pre_mode(); private: void slot_search_fin( const std::string& id ); virtual void slot_abone_thread(); // ソート列やソートモードの保存 virtual void save_sort_columns(){} // 保存しない // 列幅の保存 virtual void save_column_width(){} // 保存しない }; }; #endif jd-2.8.7-140104/src/board/boardviewnext.cpp0000644000076400010400000001361211350440352015033 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boardadmin.h" #include "boardviewnext.h" #include "dbtree/interface.h" #include "dbtree/articlebase.h" #include "skeleton/msgdiag.h" #include "jdlib/tfidf.h" #include "config/globalconf.h" #include "session.h" using namespace BOARD; BoardViewNext::BoardViewNext( const std::string& url, const std::string& url_pre_article ) : BoardViewBase( url, false ), m_url_pre_article( url_pre_article ) { set_writeable( false ); #ifdef _DEBUG std::cout << "BoardViewNext::BoardViewNext : url = " << get_url() << std::endl; #endif } BoardViewNext::~BoardViewNext() { #ifdef _DEBUG std::cout << "BoardViewNext::~BoardViewNext : url = " << get_url() << std::endl; #endif } // // リロード // void BoardViewNext::reload() { // オフライン if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); return; } show_view(); } // // view更新 // // subject.txtのロードが終わったら呼ばれる // void BoardViewNext::update_view() { std::vector< NEXT_ITEM > next_items; update_by_tfidf( next_items ); std::vector< DBTREE::ArticleBase* >list_article; std::vector< NEXT_ITEM >::iterator it_next_items = next_items.begin(); for( ; it_next_items != next_items.end(); ++it_next_items ) list_article.push_back( ( *it_next_items ).article ); const bool loading_fin = true; update_view_impl( list_article, loading_fin ); } // // TFIDFで次スレ検索 // void BoardViewNext::update_by_tfidf( std::vector< NEXT_ITEM >& next_items ) { const Glib::ustring subject_src = DBTREE::article_subject( m_url_pre_article ); const time_t since_src = DBTREE::article_since_time( m_url_pre_article ); #ifdef _DEBUG const int code = DBTREE::board_code( get_url_board() ); std::cout << "BoardViewNext::update_by_tfidf " << get_url() << " code = " << code << " " << subject_src << std::endl << "since_src = " << since_src << std::endl; #endif // 高速化のためデータベースに直接アクセス const std::vector< DBTREE::ArticleBase* >& list_subject = DBTREE::board_list_subject( get_url_board() ); if( ! list_subject.size() ) return; // 単語ベクトル作成 MISC::VEC_WORDS vec_words; MISC::tfidf_create_vec_words( vec_words, subject_src ); // IDFベクトル計算 MISC::VEC_IDF vec_idf; MISC::tfidf_create_vec_idf_from_board( vec_idf, subject_src, list_subject, vec_words ); // subject_src の TFIDFベクトル計算 MISC::VEC_TFIDF vec_tfidf_src; MISC::VEC_TFIDF vec_tfidf; vec_tfidf_src.resize( vec_words.size() ); vec_tfidf.resize( vec_words.size() ); MISC::tfidf_calc_vec_tfifd( vec_tfidf_src, subject_src, vec_idf, vec_words ); // 類似度検索 std::vector< DBTREE::ArticleBase* >::const_iterator it = list_subject.begin(); for( ; it != list_subject.end(); ++it ){ NEXT_ITEM item; // 読み込み済みのスレは除外 item.article = ( *it ); if( item.article->get_number_load() ) continue; item.since = item.article->get_since_time(); const Glib::ustring subject = item.article->get_subject(); MISC::tfidf_calc_vec_tfifd( vec_tfidf, subject, vec_idf, vec_words ); item.value = ( int )( MISC::tfidf_cos_similarity( vec_tfidf_src, vec_tfidf ) * 10 + .5 ); if( item.value >= CONFIG::get_threshold_next() ){ #ifdef _DEBUG std::cout << item.value << " , " << item.since << " | " << subject << std::endl; #endif std::vector< NEXT_ITEM >::iterator it_next_items = next_items.begin(); for( ; it_next_items != next_items.end(); ++it_next_items ){ // next が src よりも以前に立てられて、item が src よりも後に立てられた // 時は item を前に挿入する if( ( *it_next_items ).since < since_src && item.since > since_src ){ next_items.insert( it_next_items, item ); break; } else if( ( ( *it_next_items ).since > since_src && item.since > since_src ) || ( ( *it_next_items ).since < since_src && item.since < since_src ) ){ // value -> since の優先度で挿入 if( ( *it_next_items ).value < item.value ){ next_items.insert( it_next_items, item ); break; } else if( ( *it_next_items ).value == item.value ){ if( ( *it_next_items ).since > item.since ){ next_items.insert( it_next_items, item ); break; } } } } if( it_next_items == next_items.end() ) next_items.push_back( item ); } } } void BoardViewNext::slot_abone_thread() { SKELETON::MsgDiag mdiag( get_parent_win(), "次スレ検索ではあぼ〜ん出来ません" ); mdiag.run(); return; } // // 板名更新 // void BoardViewNext::update_boardname() { const std::string title = "[ 次スレ検索 ] - " + DBTREE::article_subject( m_url_pre_article ); // ウィンドウタイトル表示 set_title( title ); BOARD::get_admin()->set_command( "set_title", get_url(), get_title() ); // タブに名前をセット BOARD::get_admin()->set_command( "set_tablabel", get_url(), title ); } // // デフォルトのソート状態 // const int BoardViewNext::get_default_sort_column() { return COL_ID; } const int BoardViewNext::get_default_view_sort_mode() { return SORTMODE_ASCEND; } const int BoardViewNext::get_default_view_sort_pre_column() { return COL_ID; } const int BoardViewNext::get_default_view_sort_pre_mode() { return SORTMODE_ASCEND; } jd-2.8.7-140104/src/board/boardviewnext.h0000644000076400010400000000304511362077452014511 0ustar // ライセンス: GPL2 // 次スレ検索ビュー #ifndef _BOARDVIEWNEXT_H #define _BOARDVIEWNEXT_H #include "boardviewbase.h" #include namespace BOARD { typedef struct { DBTREE::ArticleBase* article; int value; time_t since; } NEXT_ITEM; class BoardViewNext : public BOARD::BoardViewBase { std::string m_url_pre_article; public: BoardViewNext( const std::string& url, const std::string& url_pre_article ); virtual ~BoardViewNext(); virtual void reload(); virtual void update_view(); virtual void update_boardname(); protected: // デフォルトのソート状態 virtual const int get_default_sort_column(); virtual const int get_default_view_sort_mode(); virtual const int get_default_view_sort_pre_column(); virtual const int get_default_view_sort_pre_mode(); private: // TFIDFで次スレ検索 void update_by_tfidf( std::vector< NEXT_ITEM >& next_items ); // 次スレ移行処理に使用する前スレのアドレス // 次スレ移行処理に使用する。BoardViewBase::open_row()を参照せよ virtual const std::string get_url_pre_article(){ return m_url_pre_article; } virtual void slot_abone_thread(); // ソート列やソートモードの保存 virtual void save_sort_columns(){} // 保存しない // 列幅の保存 virtual void save_column_width(){} // 保存しない }; }; #endif jd-2.8.7-140104/src/board/boardviewsidebar.cpp0000644000076400010400000000765711357123206015505 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boardadmin.h" #include "boardviewsidebar.h" #include "skeleton/msgdiag.h" #include "dbtree/interface.h" #include "dbtree/articlebase.h" #include "history/historymanager.h" #include "global.h" #include "session.h" #include "updatemanager.h" #include using namespace BOARD; BoardViewSidebar::BoardViewSidebar( const std::string& url, const bool set_history ) : BoardViewBase( url, true ), m_set_history( set_history ) { m_sidebar_url = url.substr( 0, url.find( SIDEBAR_SIGN ) ); m_dirid = atoi( url.substr( url.find( SIDEBAR_SIGN ) + strlen( SIDEBAR_SIGN ) ).c_str() ); set_writeable( false ); set_load_subject_txt( false ); #ifdef _DEBUG std::cout << "BoardViewSidebar::BoardViewSidebar : sidebar_url = " << m_sidebar_url << " dirid = " << m_dirid << " url = " << get_url() << std::endl; #endif } BoardViewSidebar::~BoardViewSidebar() { #ifdef _DEBUG std::cout << "BoardViewSidebar::~BoardViewSidebar : url = " << get_url() << std::endl; #endif } // // リロード // void BoardViewSidebar::reload() { show_view(); } // // ビュー表示 // void BoardViewSidebar::show_view() { #ifdef _DEBUG std::cout << "BoardViewSidebar::show_view " << get_url() << std::endl; #endif BoardViewBase::show_view(); std::vector< std::string > list_url; SESSION::get_sidebar_threads( m_sidebar_url, m_dirid, list_url ); if( list_url.empty() ) return; std::vector< DBTREE::ArticleBase* > list_article; m_set_thread.clear(); for( size_t i = 0; i < list_url.size(); ++i ){ DBTREE::ArticleBase* art = DBTREE::get_article( list_url[ i ] ); if( art ){ list_article.push_back( art ); m_set_thread.insert( art->get_url() ); if( SESSION::is_online() ) CORE::get_checkupdate_manager()->push_back( DBTREE::url_dat( art->get_url() ), false ); } } const bool loading_fin = true; update_view_impl( list_article, loading_fin ); // 板の履歴に登録 if( m_set_history ){ HISTORY::append_history( URL_HISTBOARDVIEW, get_url(), get_title(), TYPE_VBOARD ); } // 更新チェック if( SESSION::is_online() ) CORE::get_checkupdate_manager()->run(); } void BoardViewSidebar::slot_abone_thread() { SKELETON::MsgDiag mdiag( get_parent_win(), "お気に入り一覧ではあぼ〜ん出来ません" ); mdiag.run(); return; } // // 板名更新 // void BoardViewSidebar::update_boardname() { const std::string title = SESSION::get_sidebar_dirname( m_sidebar_url, m_dirid ); // ウィンドウタイトル表示 set_title( title ); BOARD::get_admin()->set_command( "set_title", get_url(), get_title() ); // タブに名前をセット BOARD::get_admin()->set_command( "set_tablabel", get_url(), title ); } // // 特定の行だけの表示内容更新 // // url : subject.txt のアドレス // id : DAT の ID(拡張子付き), empty なら全ての行の表示内容を更新する // void BoardViewSidebar::update_item( const std::string& url, const std::string& id ) { const std::string url_dat = DBTREE::url_datbase( url ) + id; if( id.empty() || m_set_thread.find_if( url_dat ) ){ #ifdef _DEBUG std::cout << "BoardViewSidebar::update_item " << get_url() << std::endl << "url = " << url << " id = " << id << " url_dat = " << url_dat << std::endl; #endif BoardViewBase::update_item( url, id ); } } // // デフォルトのソート状態 // const int BoardViewSidebar::get_default_sort_column() { return COL_ID; } const int BoardViewSidebar::get_default_view_sort_mode() { return SORTMODE_ASCEND; } const int BoardViewSidebar::get_default_view_sort_pre_column() { return COL_ID; } const int BoardViewSidebar::get_default_view_sort_pre_mode() { return SORTMODE_ASCEND; } jd-2.8.7-140104/src/board/boardviewsidebar.h0000644000076400010400000000245011350440352015131 0ustar // ライセンス: GPL2 // サイドバー一覧ビュー #ifndef _BOARDVIEWSIDEBAR_H #define _BOARDVIEWSIDEBAR_H #include "boardviewbase.h" #include "jdlib/hash_set.h" namespace BOARD { class BoardViewSidebar : public BOARD::BoardViewBase { std::string m_sidebar_url; size_t m_dirid; bool m_set_history; JDLIB::hash_set_thread m_set_thread; public: BoardViewSidebar( const std::string& url, const bool set_history ); virtual ~BoardViewSidebar(); virtual void stop(){} virtual void reload(); virtual void show_view(); virtual void update_boardname(); virtual void update_item( const std::string& url, const std::string& id ); protected: // デフォルトのソート状態 virtual const int get_default_sort_column(); virtual const int get_default_view_sort_mode(); virtual const int get_default_view_sort_pre_column(); virtual const int get_default_view_sort_pre_mode(); private: virtual void slot_abone_thread(); // ソート列やソートモードの保存 virtual void save_sort_columns(){} // 保存しない // 列幅の保存 virtual void save_column_width(){} // 保存しない }; }; #endif jd-2.8.7-140104/src/board/columns.h0000644000076400010400000000407011724350130013274 0ustar // ライセンス: GPL2 // コラム #ifndef _BOARDCOLUMNS_H #define _BOARDCOLUMNS_H #include "boardcolumnsid.h" #include #include namespace DBTREE { class ArticleBase; } namespace BOARD { // 列 class TreeColumns : public Gtk::TreeModel::ColumnRecord { public: Gtk::TreeModelColumn< Glib::RefPtr< Gdk::Pixbuf > > m_col_mark; Gtk::TreeModelColumn< int > m_col_id; Gtk::TreeModelColumn< Glib::ustring > m_col_subject; Gtk::TreeModelColumn< int > m_col_res; Gtk::TreeModelColumn< Glib::ustring > m_col_str_load; Gtk::TreeModelColumn< Glib::ustring > m_col_str_new; Gtk::TreeModelColumn< Glib::ustring > m_col_since; Gtk::TreeModelColumn< Glib::ustring > m_col_write; Gtk::TreeModelColumn< Glib::ustring > m_col_access; Gtk::TreeModelColumn< int > m_col_speed; Gtk::TreeModelColumn< int > m_col_diff; Gtk::TreeModelColumn< Glib::ustring > m_col_board; // 以下は不可視 Gtk::TreeModelColumn< int > m_col_mark_val; Gtk::TreeModelColumn< bool > m_col_drawbg; // true なら背景を塗る Gtk::TreeModelColumn< int > m_col_new; Gtk::TreeModelColumn< time_t > m_col_write_t; Gtk::TreeModelColumn< time_t > m_col_access_t; Gtk::TreeModelColumn< DBTREE::ArticleBase* > m_col_article; TreeColumns(){ add( m_col_mark ); add( m_col_id ); add( m_col_subject ); add( m_col_res ); add( m_col_str_load ); add( m_col_str_new ); add( m_col_since ); add( m_col_write ); add( m_col_access ); add( m_col_speed ); add( m_col_diff ); add( m_col_board ); add( m_col_mark_val ); add( m_col_drawbg ); add( m_col_new ); add( m_col_write_t ); add( m_col_access_t ); add( m_col_article ); } ~TreeColumns(){} }; } #endif jd-2.8.7-140104/src/board/Makefile.am0000644000076400010400000000066712072045132013507 0ustar noinst_LIBRARIES = libboard.a libboard_a_SOURCES = \ boardadmin.cpp \ boardviewbase.cpp \ boardview.cpp \ boardviewnext.cpp \ boardviewlog.cpp \ boardviewsidebar.cpp \ toolbar.cpp \ preference.cpp noinst_HEADERS = \ boardadmin.h \ boardviewbase.h \ boardview.h \ boardviewnext.h \ boardviewlog.h \ boardviewsidebar.h \ toolbar.h \ columns.h \ preference.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/board/preference.cpp0000644000076400010400000005663611527756110014315 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "preference.h" #include "dbtree/interface.h" #include "dbtree/boardbase.h" #include "skeleton/msgdiag.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "config/globalconf.h" #include "cache.h" #include "command.h" #include "global.h" #include "viewfactory.h" using namespace BOARD; Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std::string command ) : SKELETON::PrefDiag( parent, url ), m_frame_write( "書き込み設定" ), m_entry_writename( true, "名前:" ), m_entry_writemail( true, "メール:" ), m_check_noname( "名前欄が空白の時は書き込まない" ), m_bt_clear_post_history( "この板にある全スレの書き込み履歴クリア" ), m_bt_set_default_namemail( "デフォルト" ), m_frame_cookie( "クッキーと書き込みキーワード" ), m_button_cookie( "削除" ) , m_check_live( "実況する" ), m_proxy_frame( "読み込み用" ), m_proxy_frame_w( "書き込み用" ), m_label_name( false, "板タイトル:", DBTREE::board_name( get_url() ) ), m_label_url( false, "板のURL:", DBTREE::url_boardbase( get_url() ) ), m_label_cache( false, "ローカルキャッシュのルートパス", CACHE::path_board_root( DBTREE::url_boardbase( get_url() ) ) ), m_label_noname( false, "デフォルト名無し:", DBTREE::default_noname( get_url() ) ), m_label_max_line( false, "1レスの最大改行数:" ), m_label_max_byte( false, "1レスの最大バイト数:" ), m_label_last_access( false, "最終アクセス日時 :" ), m_label_modified( false, "最終更新日時 :" ), m_button_clearmodified( "日時クリア" ), m_label_samba( false, "書き込み規制秒数 (Samba24) :" ), m_button_clearsamba( "秒数クリア" ), m_check_oldlog( "過去ログを表示する" ), m_button_remove_old_title( "dat落ちしたスレのタイトルを削除する" ), m_localrule( NULL ) { m_edit_cookies.set_editable( false ); // 書き込み設定 const int samba_sec = DBTREE::board_samba_sec( get_url() ); if( ! samba_sec ) m_label_samba.set_text( "未取得" ); else m_label_samba.set_text( MISC::itostr( samba_sec ) ); m_button_clearsamba.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_clear_samba ) ); m_hbox_samba.pack_start( m_label_samba ); m_hbox_samba.pack_start( m_button_clearsamba, Gtk::PACK_SHRINK ); m_check_noname.set_active( DBTREE::board_check_noname( get_url() ) ); m_entry_writename.set_text( DBTREE::board_get_write_name( get_url() ) ); if( m_entry_writename.get_text().empty() ) m_entry_writename.set_text( CONFIG::get_write_name() ); // JD_NAME_BLANK の場合空白をセットする else if( m_entry_writename.get_text() == JD_NAME_BLANK ) m_entry_writename.set_text( std::string() ); m_entry_writemail.set_text( DBTREE::board_get_write_mail( get_url() ) ); if( m_entry_writemail.get_text().empty() ) m_entry_writemail.set_text( CONFIG::get_write_mail() ); // JD_MAIL_BLANK の場合空白をセットする else if( m_entry_writemail.get_text() == JD_MAIL_BLANK ) m_entry_writemail.set_text( std::string() ); m_bt_clear_post_history.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_clear_post_history ) ); m_hbox_write1.set_spacing( 8 ); m_hbox_write1.pack_start( m_check_noname ); m_hbox_write1.pack_start( m_bt_clear_post_history ); m_bt_set_default_namemail.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_set_default_namemail ) ); m_hbox_write2.set_spacing( 8 ); m_hbox_write2.pack_start( m_entry_writename ); m_hbox_write2.pack_end( m_bt_set_default_namemail, Gtk::PACK_SHRINK ); m_hbox_write2.pack_end( m_entry_writemail, Gtk::PACK_SHRINK ); m_vbox_write.set_border_width( 8 ); m_vbox_write.set_spacing( 8 ); m_vbox_write.pack_start( m_hbox_samba, Gtk::PACK_SHRINK ); m_vbox_write.pack_start( m_hbox_write1, Gtk::PACK_SHRINK ); m_vbox_write.pack_start( m_hbox_write2, Gtk::PACK_SHRINK ); m_frame_write.add( m_vbox_write ); set_activate_entry( m_entry_writename ); set_activate_entry( m_entry_writemail ); // cookie と 書き込みキーワード の設定 std::string str_cookies; std::list< std::string > list_cookies = DBTREE::board_list_cookies_for_write( get_url() ); if( list_cookies.empty() ) str_cookies = "クッキー:\n未取得\n"; else{ str_cookies = "クッキー:\n"; std::list< std::string >::iterator it = list_cookies.begin(); for( ; it != list_cookies.end(); ++it ) str_cookies += MISC::Iconv( (*it), DBTREE::board_charset( get_url() ), "UTF-8" ) + "\n"; } const std::string keyword = DBTREE::board_keyword_for_write( get_url() ); if( ! keyword.empty() ) str_cookies += "\nキーワード: " + keyword + "\n"; m_edit_cookies.set_text( str_cookies ); m_hbox_cookie.set_border_width( 8 ); m_hbox_cookie.set_spacing( 8 ); m_hbox_cookie.pack_start( m_edit_cookies ); m_hbox_cookie.pack_start( m_vbox_cookie, Gtk::PACK_SHRINK ); m_vbox_cookie.pack_end( m_button_cookie, Gtk::PACK_SHRINK ); m_button_cookie.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_delete_cookie ) ); m_frame_cookie.add( m_hbox_cookie ); // 実況 const int live_sec = DBTREE::board_get_live_sec( get_url() ); m_label_live.set_text( "実況時の更新間隔(秒):" ); m_spin_live.set_range( MIN_LIVE_RELOAD_SEC, 1200 ); m_spin_live.set_increments( 1, 1 ); m_spin_live.set_value( MAX( live_sec, MIN_LIVE_RELOAD_SEC ) ); if( live_sec ){ m_check_live.set_active( true ); m_spin_live.set_sensitive( true ); } else{ m_check_live.set_active( false ); m_spin_live.set_sensitive( false ); } m_check_live.signal_toggled().connect( sigc::mem_fun(*this, &Preferences::slot_check_live ) ); m_hbox_live.set_spacing( 4 ); m_hbox_live.pack_start( m_label_live, Gtk::PACK_SHRINK ); m_hbox_live.pack_start( m_spin_live, Gtk::PACK_SHRINK ); m_hbox_live.pack_start( m_check_live, Gtk::PACK_SHRINK ); set_activate_entry( m_spin_live ); // 一般ページのパッキング m_label_max_line.set_text( MISC::itostr( DBTREE::line_number( get_url() ) * 2 ) ); m_label_max_byte.set_text( MISC::itostr( DBTREE::message_count( get_url() ) ) ); m_hbox_max.pack_start( m_label_max_line ); m_hbox_max.pack_start( m_label_max_byte ); // 最大レス数 const int max_res = DBTREE::board_get_number_max_res( get_url() ); m_label_maxres.set_text( "最大レス数 (0 : 未設定):" ); m_spin_maxres.set_range( 0, MAX_RESNUMBER ); m_spin_maxres.set_increments( 1, 1 ); m_spin_maxres.set_value( max_res ); m_spin_maxres.set_sensitive( true ); m_hbox_max.pack_start( m_label_maxres, Gtk::PACK_SHRINK ); m_hbox_max.pack_start( m_spin_maxres, Gtk::PACK_SHRINK ); set_activate_entry( m_spin_maxres ); const time_t last_access = DBTREE::board_last_access_time( get_url() ); if( last_access ) m_label_last_access.set_text( MISC::timettostr( last_access, MISC::TIME_WEEK ) + " ( " + MISC::timettostr( last_access, MISC::TIME_PASSED ) + " )" ); if( DBTREE::board_date_modified( get_url() ).empty() ) m_label_modified.set_text( "未取得" ); else m_label_modified.set_text( MISC::timettostr( DBTREE::board_time_modified( get_url() ), MISC::TIME_WEEK ) + " ( " + MISC::timettostr( DBTREE::board_time_modified( get_url() ), MISC::TIME_PASSED ) + " )" ); m_button_clearmodified.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_clear_modified ) ); m_hbox_modified.pack_start( m_label_modified ); m_hbox_modified.pack_start( m_button_clearmodified, Gtk::PACK_SHRINK ); // 過去ログ表示 if( CONFIG::get_show_oldarticle() ){ m_check_oldlog.set_active( true ); m_check_oldlog.set_sensitive( false ); } else m_check_oldlog.set_active( DBTREE::board_show_oldlog( get_url() ) ); m_vbox.set_border_width( 16 ); m_vbox.set_spacing( 8 ); m_vbox.pack_start( m_label_name, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_label_url, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_label_cache, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_label_noname, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox_max, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_label_last_access, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox_modified, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox_live, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_check_oldlog, Gtk::PACK_SHRINK ); m_vbox.pack_end( m_frame_cookie, Gtk::PACK_SHRINK ); m_vbox.pack_end( m_frame_write, Gtk::PACK_SHRINK ); // ローカルルール m_localrule = CORE::ViewFactory( CORE::VIEW_ARTICLEINFO, get_url() ); // プロキシ std::string host; m_vbox_proxy.set_border_width( 16 ); m_vbox_proxy.set_spacing( 8 ); m_label_proxy.set_text( "通常は全体プロキシ設定でプロキシを設定します\n全体プロキシ設定と異なるプロキシを使用する場合はここで設定して下さい"); switch( DBTREE::board_get_mode_local_proxy( get_url() ) ){ case DBTREE::PROXY_GLOBAL: m_proxy_frame.rd_global.set_active(); break; case DBTREE::PROXY_DISABLE: m_proxy_frame.rd_disable.set_active(); break; case DBTREE::PROXY_LOCAL: m_proxy_frame.rd_local.set_active(); break; } if( DBTREE::board_get_local_proxy_basicauth( get_url() ).empty() ) host = DBTREE::board_get_local_proxy( get_url() ); else host = DBTREE::board_get_local_proxy_basicauth( get_url() ) + "@" + DBTREE::board_get_local_proxy( get_url() ); m_proxy_frame.entry_host.set_text( host ); m_proxy_frame.entry_port.set_text( MISC::itostr( DBTREE::board_get_local_proxy_port( get_url() ) ) ); switch( DBTREE::board_get_mode_local_proxy_w( get_url() ) ){ case DBTREE::PROXY_GLOBAL: m_proxy_frame_w.rd_global.set_active(); break; case DBTREE::PROXY_DISABLE: m_proxy_frame_w.rd_disable.set_active(); break; case DBTREE::PROXY_LOCAL: m_proxy_frame_w.rd_local.set_active(); break; } if( DBTREE::board_get_local_proxy_basicauth_w( get_url() ).empty() ) host = DBTREE::board_get_local_proxy_w( get_url() ); else host = DBTREE::board_get_local_proxy_basicauth_w( get_url() ) + "@" + DBTREE::board_get_local_proxy_w( get_url() ); m_proxy_frame_w.entry_host.set_text( host ); m_proxy_frame_w.entry_port.set_text( MISC::itostr( DBTREE::board_get_local_proxy_port_w( get_url() ) ) ); m_vbox_proxy.pack_start( m_label_proxy, Gtk::PACK_SHRINK ); m_vbox_proxy.pack_start( m_proxy_frame, Gtk::PACK_SHRINK ); m_vbox_proxy.pack_start( m_proxy_frame_w, Gtk::PACK_SHRINK ); set_activate_entry( m_proxy_frame.entry_host ); set_activate_entry( m_proxy_frame.entry_port ); set_activate_entry( m_proxy_frame_w.entry_host ); set_activate_entry( m_proxy_frame_w.entry_port ); // あぼーん std::string str_id, str_name, str_word, str_regex; std::string str_thread, str_word_thread, str_regex_thread; std::list< std::string >::iterator it; // ID std::list< std::string > list_id = DBTREE::get_abone_list_id_board( get_url() ); for( it = list_id.begin(); it != list_id.end(); ++it ) if( ! ( *it ).empty() ) str_id += ( *it ) + "\n"; m_edit_id.set_text( str_id ); // name std::list< std::string > list_name = DBTREE::get_abone_list_name_board( get_url() ); for( it = list_name.begin(); it != list_name.end(); ++it ) if( ! ( *it ).empty() ) str_name += ( *it ) + "\n"; m_edit_name.set_text( str_name ); // word std::list< std::string > list_word = DBTREE::get_abone_list_word_board( get_url() ); for( it = list_word.begin(); it != list_word.end(); ++it ) if( ! ( *it ).empty() ) str_word += ( *it ) + "\n"; m_edit_word.set_text( str_word ); // regex std::list< std::string > list_regex = DBTREE::get_abone_list_regex_board( get_url() ); for( it = list_regex.begin(); it != list_regex.end(); ++it ) if( ! ( *it ).empty() ) str_regex += ( *it ) + "\n"; m_edit_regex.set_text( str_regex ); m_label_warning.set_text( "ここでのあぼーん設定は「" + DBTREE::board_name( get_url() ) + "」板の全スレに適用されます。\n\n設定のし過ぎは板内の全スレの表示速度を低下させます。\n\n設定のし過ぎに気を付けてください。\n\nなおNG IDはJDを再起動するとリセットされます。" ); m_notebook_abone.append_page( m_label_warning, "注意" ); m_notebook_abone.append_page( m_edit_id, "NG ID" ); m_notebook_abone.append_page( m_edit_name, "NG 名前" ); m_notebook_abone.append_page( m_edit_word, "NG ワード" ); m_notebook_abone.append_page( m_edit_regex, "NG 正規表現" ); // スレッドあぼーん // スレ数、時間 m_label_abone_thread.set_text( "以下の数字が0の時は、設定メニューの全体あぼ〜ん設定で指定した数字が用いられます。\nまたキャッシュにログがあるスレはあぼ〜んされません。\n\n" ); m_label_number.set_text( "レス以上のスレをあぼ〜ん" ); m_spin_number.set_range( 0, 9999 ); m_spin_number.set_increments( 1, 1 ); m_spin_number.set_value( DBTREE::get_abone_number_thread( get_url() ) ); m_hbox_number.set_spacing( 4 ); m_hbox_number.pack_start( m_spin_number, Gtk::PACK_SHRINK ); m_hbox_number.pack_start( m_label_number, Gtk::PACK_SHRINK ); set_activate_entry( m_spin_number ); m_label_hour.set_text( "時間以上スレ立てから経過したスレをあぼ〜ん" ); m_spin_hour.set_range( 0, 9999 ); m_spin_hour.set_increments( 1, 1 ); m_spin_hour.set_value( DBTREE::get_abone_hour_thread( get_url() ) ); m_hbox_hour.set_spacing( 4 ); m_hbox_hour.pack_start( m_spin_hour, Gtk::PACK_SHRINK ); m_hbox_hour.pack_start( m_label_hour, Gtk::PACK_SHRINK ); set_activate_entry( m_spin_hour ); m_vbox_abone_thread.set_border_width( 16 ); m_vbox_abone_thread.set_spacing( 8 ); m_vbox_abone_thread.pack_start( m_label_abone_thread, Gtk::PACK_SHRINK ); m_vbox_abone_thread.pack_start( m_hbox_number, Gtk::PACK_SHRINK ); m_vbox_abone_thread.pack_start( m_hbox_hour, Gtk::PACK_SHRINK ); // スレあぼーん std::list< std::string > list_thread = DBTREE::get_abone_list_thread( get_url() ); for( it = list_thread.begin(); it != list_thread.end(); ++it ) if( ! ( *it ).empty() ) str_thread += ( *it ) + "\n"; m_edit_thread.set_text( str_thread ); m_button_remove_old_title.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_remove_old_title ) ); m_vbox_abone_title.pack_start( m_edit_thread ); m_vbox_abone_title.pack_start( m_button_remove_old_title, Gtk::PACK_SHRINK ); // スレwordあぼーん std::list< std::string > list_word_thread = DBTREE::get_abone_list_word_thread( get_url() ); for( it = list_word_thread.begin(); it != list_word_thread.end(); ++it ) if( ! ( *it ).empty() ) str_word_thread += ( *it ) + "\n"; m_edit_word_thread.set_text( str_word_thread ); // スレregexあぼーん std::list< std::string > list_regex_thread = DBTREE::get_abone_list_regex_thread( get_url() ); for( it = list_regex_thread.begin(); it != list_regex_thread.end(); ++it ) if( ! ( *it ).empty() ) str_regex_thread += ( *it ) + "\n"; m_edit_regex_thread.set_text( str_regex_thread ); m_notebook_abone_thread.append_page( m_vbox_abone_thread, "一般" ); m_notebook_abone_thread.append_page( m_vbox_abone_title, "NG スレタイトル" ); m_notebook_abone_thread.append_page( m_edit_word_thread, "NG ワード" ); m_notebook_abone_thread.append_page( m_edit_regex_thread, "NG 正規表現" ); // SETTING.TXT m_edit_settingtxt.set_editable( false ); m_edit_settingtxt.set_text( DBTREE::settingtxt( get_url() ) ); m_notebook.append_page( m_vbox, "一般" ); const int page_localrule = 1; m_notebook.append_page( *m_localrule, "ローカルルール" ); m_notebook.append_page( m_vbox_proxy, "プロキシ設定" ); const int page_abone_article = 3; m_notebook.append_page( m_notebook_abone, "あぼ〜ん設定(スレビュー)" ); m_notebook.append_page( m_notebook_abone_thread, "あぼ〜ん設定(スレ一覧)" ); m_notebook.append_page( m_edit_settingtxt, "SETTING.TXT" ); m_notebook.signal_switch_page().connect( sigc::mem_fun( *this, &Preferences::slot_switch_page ) ); get_vbox()->pack_start( m_notebook ); set_title( "「" + DBTREE::board_name( get_url() ) + "」のプロパティ" ); resize( 600, 400 ); show_all_children(); if( command == "show_localrule" ) m_notebook.set_current_page( page_localrule ); else if( command == "show_abone_article" ) m_notebook.set_current_page( page_abone_article ); } Preferences::~Preferences() { if( m_localrule ) delete m_localrule; m_localrule = NULL; } void Preferences::slot_clear_modified() { DBTREE::board_set_date_modified( get_url(), "" ); if( DBTREE::board_date_modified( get_url() ).empty() ) m_label_modified.set_text( "未取得" ); else m_label_modified.set_text( MISC::timettostr( DBTREE::board_time_modified( get_url() ), MISC::TIME_WEEK ) + " ( " + MISC::timettostr( DBTREE::board_time_modified( get_url() ), MISC::TIME_PASSED ) + " )" ); } void Preferences::slot_clear_samba() { DBTREE::board_set_samba_sec( get_url(), 0 ); const int samba_sec = DBTREE::board_samba_sec( get_url() ); if( ! samba_sec ) m_label_samba.set_text( "未取得" ); else m_label_samba.set_text( MISC::itostr( samba_sec ) ); } void Preferences::slot_clear_post_history() { SKELETON::MsgDiag mdiag( NULL, "この板にある全てのスレの書き込み履歴を削除しますか?\n\nスレ数によっては時間がかかります。", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; DBTREE::board_clear_all_post_history( get_url() ); // スレ一覧とスレビューの表示更新 CORE::core_set_command( "update_board", DBTREE::url_subject( get_url() ) ); CORE::core_set_command( "redraw_article" ); } void Preferences::slot_set_default_namemail() { m_entry_writename.set_text( CONFIG::get_write_name() ); m_entry_writemail.set_text( CONFIG::get_write_mail() ); } void Preferences::slot_delete_cookie() { DBTREE::board_reset_list_cookies_for_write( get_url() ); DBTREE::board_set_keyword_for_write( get_url(), std::string() ); m_edit_cookies.set_text( "クッキー:\n未取得\n" ); } void Preferences::slot_check_live() { if( m_check_live.get_active() ){ m_spin_live.set_sensitive( true ); SKELETON::MsgDiag mdiag( NULL, "実況を許された板以外では実況しないようにして下さい。\n\n実況状態のまま閉じたスレはJD終了時に削除されます。詳しくはマニュアルの実況の項目を参照して下さい。", false, Gtk::MESSAGE_WARNING ); mdiag.run(); } else m_spin_live.set_sensitive( false ); } void Preferences::slot_remove_old_title() { if( ! DBTREE::board_list_subject( get_url() ).size() ){ SKELETON::MsgDiag mdiag( NULL, "再読み込みしてスレ一覧を更新して下さい。", false, Gtk::MESSAGE_WARNING ); mdiag.run(); return; } const std::list< std::string > list_thread = DBTREE::get_abone_list_thread_remove( get_url() ); std::list< std::string >::const_iterator it = list_thread.begin(); std::string str; for( ; it != list_thread.end(); ++it ) if( ! ( *it ).empty() ) str += ( *it ) + "\n"; m_edit_thread.set_text( str ); } void Preferences::slot_switch_page( GtkNotebookPage*, guint page ) { if( m_notebook.get_nth_page( page ) == m_localrule ){ m_localrule->set_command( "clear_screen" ); m_localrule->set_command( "append_html", DBTREE::localrule( get_url() ) ); } } // // OK 押した // void Preferences::slot_ok_clicked() { // プロクシ int mode = DBTREE::PROXY_GLOBAL; if( m_proxy_frame.rd_disable.get_active() ) mode = DBTREE::PROXY_DISABLE; else if( m_proxy_frame.rd_local.get_active() ) mode = DBTREE::PROXY_LOCAL; DBTREE::board_set_mode_local_proxy( get_url(), mode ); DBTREE::board_set_local_proxy( get_url(), MISC::remove_space( m_proxy_frame.entry_host.get_text() ) ); DBTREE::board_set_local_proxy_port( get_url(), atoi( m_proxy_frame.entry_port.get_text().c_str() ) ); mode = DBTREE::PROXY_GLOBAL; if( m_proxy_frame_w.rd_disable.get_active() ) mode = DBTREE::PROXY_DISABLE; else if( m_proxy_frame_w.rd_local.get_active() ) mode = DBTREE::PROXY_LOCAL; DBTREE::board_set_mode_local_proxy_w( get_url(), mode ); DBTREE::board_set_local_proxy_w( get_url(), MISC::remove_space( m_proxy_frame_w.entry_host.get_text() ) ); DBTREE::board_set_local_proxy_port_w( get_url(), atoi( m_proxy_frame_w.entry_port.get_text().c_str() ) ); // 書き込み設定 DBTREE::board_set_check_noname( get_url(), m_check_noname.get_active() ); std::string tmpname = m_entry_writename.get_text(); if( tmpname == CONFIG::get_write_name() ) tmpname = std::string(); else if( tmpname.empty() ) tmpname = JD_NAME_BLANK; // 空白の場合 JD_NAME_BLANK をセットする DBTREE::board_set_write_name( get_url(), tmpname ); std::string tmpmail = m_entry_writemail.get_text(); if( tmpmail == CONFIG::get_write_mail() ) tmpmail = std::string(); else if( tmpmail.empty() ) tmpmail = JD_MAIL_BLANK; // 空白の場合 JD_MAIL_BLANK をセットする DBTREE::board_set_write_mail( get_url(), tmpmail ); // 実況間隔 int live_sec = 0; if( m_check_live.get_active() ) live_sec = m_spin_live.get_value_as_int(); DBTREE::board_set_live_sec( get_url(), live_sec ); CORE::core_set_command( "redraw_article_toolbar" ); // 最大レス数 const int number_max_res = m_spin_maxres.get_value_as_int(); DBTREE::board_set_number_max_res( get_url(), number_max_res ); // 過去ログ表示 if( ! CONFIG::get_show_oldarticle() ) DBTREE::board_set_show_oldlog( get_url(), m_check_oldlog.get_active() ); // あぼーん再設定 std::list< std::string > list_id = MISC::get_lines( m_edit_id.get_text() ); std::list< std::string > list_name = MISC::get_lines( m_edit_name.get_text() ); std::list< std::string > list_word = MISC::get_lines( m_edit_word.get_text() ); std::list< std::string > list_regex = MISC::get_lines( m_edit_regex.get_text() ); DBTREE::reset_abone_board( get_url(), list_id, list_name, list_word, list_regex ); // スレあぼーん再設定 std::list< std::string > list_thread = MISC::get_lines( m_edit_thread.get_text() ); std::list< std::string > list_word_thread = MISC::get_lines( m_edit_word_thread.get_text() ); std::list< std::string > list_regex_thread = MISC::get_lines( m_edit_regex_thread.get_text() ); const int number = m_spin_number.get_value_as_int(); const int hour = m_spin_hour.get_value_as_int(); const bool redraw = true; // ここでスレ一覧の再描画指定をする DBTREE::reset_abone_thread( get_url(), list_thread, list_word_thread, list_regex_thread, number, hour, redraw ); DBTREE::board_save_info( get_url() ); } void Preferences::timeout() { if( m_localrule ) m_localrule->clock_in(); } jd-2.8.7-140104/src/board/preference.h0000644000076400010400000001155711527756110013753 0ustar // ライセンス: GPL2 #ifndef _BOARD_PREFERENCES_H #define _BOARD_PREFERENCES_H #include "skeleton/view.h" #include "skeleton/prefdiag.h" #include "skeleton/editview.h" #include "skeleton/label_entry.h" #include "skeleton/spinbutton.h" namespace BOARD { class ProxyFrame : public Gtk::Frame { Gtk::VBox m_vbox; Gtk::HBox m_hbox; public: Gtk::RadioButton rd_global, rd_disable, rd_local; SKELETON::LabelEntry entry_host; SKELETON::LabelEntry entry_port; ProxyFrame( const std::string& title ) : rd_global( "全体設定を使用する" ), rd_disable( "全体設定を無効にする" ), rd_local( "ローカル設定を使用する" ), entry_host( true, "ホスト:" ), entry_port( true, "ポート:" ) { Gtk::RadioButton::Group grp = rd_global.get_group(); rd_disable.set_group( grp ); rd_local.set_group( grp ); m_hbox.set_spacing( 8 ); m_hbox.set_border_width( 8 ); m_hbox.pack_start( entry_host ); m_hbox.pack_start( entry_port, Gtk::PACK_SHRINK ); m_vbox.set_spacing( 8 ); m_vbox.set_border_width( 8 ); m_vbox.pack_start( rd_global, Gtk::PACK_SHRINK ); m_vbox.pack_start( rd_disable, Gtk::PACK_SHRINK ); m_vbox.pack_start( rd_local, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox, Gtk::PACK_SHRINK ); set_label( title ); set_border_width( 8 ); add( m_vbox ); } }; class Preferences : public SKELETON::PrefDiag { Gtk::Notebook m_notebook; Gtk::VBox m_vbox; // 書き込み時のデフォルト名とメール Gtk::Frame m_frame_write; Gtk::VBox m_vbox_write; Gtk::HBox m_hbox_write1; Gtk::HBox m_hbox_write2; SKELETON::LabelEntry m_entry_writename; SKELETON::LabelEntry m_entry_writemail; Gtk::CheckButton m_check_noname; // 名無し書き込みチェック Gtk::Button m_bt_clear_post_history; Gtk::Button m_bt_set_default_namemail; // クッキー と キーワード表示 Gtk::Frame m_frame_cookie; Gtk::HBox m_hbox_cookie; SKELETON::EditView m_edit_cookies; Gtk::VBox m_vbox_cookie; Gtk::Button m_button_cookie; // 実況の更新間隔 Gtk::HBox m_hbox_live; Gtk::Label m_label_live; Gtk::CheckButton m_check_live; SKELETON::SpinButton m_spin_live; // プロキシ Gtk::VBox m_vbox_proxy; Gtk::Label m_label_proxy; ProxyFrame m_proxy_frame; ProxyFrame m_proxy_frame_w; // 情報 SKELETON::LabelEntry m_label_name; SKELETON::LabelEntry m_label_url; SKELETON::LabelEntry m_label_cache; SKELETON::LabelEntry m_label_noname; Gtk::HBox m_hbox_max; SKELETON::LabelEntry m_label_max_line; SKELETON::LabelEntry m_label_max_byte; // 最大レス数 Gtk::Label m_label_maxres; SKELETON::SpinButton m_spin_maxres; SKELETON::LabelEntry m_label_last_access; Gtk::HBox m_hbox_modified; SKELETON::LabelEntry m_label_modified; Gtk::Button m_button_clearmodified; // samba24 Gtk::HBox m_hbox_samba; SKELETON::LabelEntry m_label_samba; Gtk::Button m_button_clearsamba; // 過去ログ表示 Gtk::CheckButton m_check_oldlog; // あぼーん Gtk::Notebook m_notebook_abone; Gtk::Label m_label_warning; SKELETON::EditView m_edit_id, m_edit_name, m_edit_word, m_edit_regex; // スレッドあぼーん Gtk::Notebook m_notebook_abone_thread; SKELETON::EditView m_edit_thread, m_edit_word_thread, m_edit_regex_thread; Gtk::VBox m_vbox_abone_thread; Gtk::Label m_label_abone_thread; Gtk::HBox m_hbox_number; Gtk::Label m_label_number; SKELETON::SpinButton m_spin_number; Gtk::HBox m_hbox_hour; Gtk::Label m_label_hour; SKELETON::SpinButton m_spin_hour; Gtk::VBox m_vbox_abone_title; Gtk::Button m_button_remove_old_title; // ローカルルール SKELETON::View* m_localrule; // SETTING.TXT SKELETON::EditView m_edit_settingtxt; public: Preferences( Gtk::Window* parent, const std::string& url, const std::string command ); virtual ~Preferences(); private: void slot_clear_modified(); void slot_clear_samba(); void slot_clear_post_history(); void slot_set_default_namemail(); void slot_delete_cookie(); void slot_check_live(); void slot_remove_old_title(); void slot_switch_page( GtkNotebookPage*, guint page ); virtual void slot_ok_clicked(); virtual void timeout(); }; } #endif jd-2.8.7-140104/src/board/toolbar.cpp0000644000076400010400000000724611570731371013632 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "toolbar.h" #include "boardadmin.h" #include "control/controlutil.h" #include "control/controlid.h" #include "session.h" #include "compmanager.h" #include "global.h" using namespace BOARD; BoardToolBar::BoardToolBar() : SKELETON::ToolBar( BOARD::get_admin() ) { pack_buttons(); // JDEntry::on_key_release_event()で // CONTROL::SearchCache を有効にする add_search_control_mode( CONTROL::MODE_BOARD ); } // ボタンのパッキング // virtual void BoardToolBar::pack_buttons() { // ツールバー非表示の場合は検索バーに検索関係の wiget を表示する if( SESSION::get_show_board_toolbar() ) pack_toolbar(); else pack_search_toolbar(); set_relief(); show_all_children(); } void BoardToolBar::pack_toolbar() { #ifdef _DEBUG std::cout << "BoardToolBar::pack_toolbar\n"; #endif int num = 0; for(;;){ int item = SESSION::get_item_board_toolbar( num ); if( item == ITEM_END ) break; switch( item ){ case ITEM_NEWARTICLE: get_buttonbar().append( *get_button_write() ); set_tooltip( *get_button_write(), CONTROL::get_label_motions( CONTROL::NewArticle ) ); break; case ITEM_SEARCHBOX: get_buttonbar().append( *get_tool_search( CORE::COMP_SEARCH_BOARD ) ); break; case ITEM_SEARCH_NEXT: get_buttonbar().append( *get_button_down_search() ); break; case ITEM_SEARCH_PREV: get_buttonbar().append( *get_button_up_search() ); break; case ITEM_RELOAD: get_buttonbar().append( *get_button_reload() ); break; case ITEM_STOPLOADING: get_buttonbar().append( *get_button_stop() ); break; case ITEM_APPENDFAVORITE: get_buttonbar().append( *get_button_favorite() ); set_tooltip( *get_button_favorite(), CONTROL::get_label_motions( CONTROL::AppendFavorite ) + "\n\nスレ一覧のタブか選択したスレをお気に入りに直接D&Dしても登録可能" ); break; case ITEM_DELETE: get_buttonbar().append( *get_button_delete() ); break; case ITEM_QUIT: get_buttonbar().append( *get_button_close() ); break; case ITEM_BACK: get_buttonbar().append( *get_button_back() ); break; case ITEM_FORWARD: get_buttonbar().append( *get_button_forward() ); break; case ITEM_LOCK: get_buttonbar().append( *get_button_lock() ); break; case ITEM_CLEAR_HIGHLIGHT: get_buttonbar().append( *get_button_clear_highlight() ); break; case ITEM_SEPARATOR: pack_separator(); break; } ++num; } } void BoardToolBar::pack_search_toolbar() { #ifdef _DEBUG std::cout << "BoardToolBar::pack_search_toolbar\n"; #endif get_searchbar()->append( *get_tool_search( CORE::COMP_SEARCH_BOARD ) ); get_searchbar()->append( *get_button_down_search() ); get_searchbar()->append( *get_button_up_search() ); get_searchbar()->append( *get_button_close_searchbar() ); } // ツールバー表示切り替え時に検索関係の wiget の位置を変更する void BoardToolBar::unpack_pack() { unpack_buttons(); unpack_search_buttons(); pack_buttons(); } jd-2.8.7-140104/src/board/toolbar.h0000644000076400010400000000111511241425222013252 0ustar // ライセンス: GPL2 // ツールバーのクラス #ifndef _BOARD_TOOLBAR_H #define _BOARD_TOOLBAR_H #include #include "skeleton/toolbar.h" namespace BOARD { class BoardToolBar : public SKELETON::ToolBar { public: BoardToolBar(); virtual ~BoardToolBar(){} // ツールバー表示切り替え時に検索関係の wiget の位置を変更する void unpack_pack(); protected: virtual void pack_buttons(); private: void pack_toolbar(); void pack_search_toolbar(); }; } #endif jd-2.8.7-140104/src/boardcolumnsid.h0000644000076400010400000000146611724350130013540 0ustar // スレ一覧の列IDと並び替えモード #ifndef _BOARDCOLUMNS_ID_H #define _BOARDCOLUMNS_ID_H // 列ID enum { COL_MARK = 0, COL_ID, COL_BOARD, COL_SUBJECT, COL_RES, COL_STR_LOAD, COL_STR_NEW, COL_SINCE, COL_WRITE, COL_ACCESS, COL_SPEED, COL_DIFF, COL_VISIBLE_END, // 以下は不可視 COL_MARK_VAL = COL_VISIBLE_END, COL_DRAWBG, COL_NEW, COL_WRITE_T, COL_ACCESS_T, COL_ARTICLE, COL_NUM_COL }; // 並び替えのモード enum { SORTMODE_ASCEND = 0, SORTMODE_DESCEND, SORTMODE_MARK1, // 通常 SORTMODE_MARK2, // 新着をキャッシュの上に。後は通常 SORTMODE_MARK3, // 新着を一番上に。後は通常 SORTMODE_MARK4, // 反転 SORTMODE_NUM }; #endif jd-2.8.7-140104/src/boarditemmenupref.cpp0000644000076400010400000000327411506370702014602 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boarditemmenupref.h" #include "icons/iconmanager.h" #include "skeleton/msgdiag.h" #include "global.h" #include "session.h" #include "command.h" using namespace CORE; BoardItemMenuPref::BoardItemMenuPref( Gtk::Window* parent, const std::string& url ) : SKELETON::SelectItemPref( parent, url ) { // デフォルトの項目を設定 append_default_pair( ITEM_NAME_BOOKMARK ); append_default_pair( ITEM_NAME_OPENARTICLETAB ); append_default_pair( ITEM_NAME_OPEN_BROWSER ); append_default_pair( ITEM_NAME_REGETARTICLE ); append_default_pair( ITEM_NAME_COPY_URL ); append_default_pair( ITEM_NAME_COPY_TITLE_URL_THREAD ); append_default_pair( ITEM_NAME_SAVE_DAT ); append_default_pair( ITEM_NAME_FAVORITE_ARTICLE ); append_default_pair( ITEM_NAME_NEXTARTICLE ); append_default_pair( ITEM_NAME_ABONE_ARTICLE ); append_default_pair( ITEM_NAME_DELETE ); append_default_pair( ITEM_NAME_PREF_THREAD ); append_default_pair( ITEM_NAME_PREF_BOARD ); append_default_pair( ITEM_NAME_ETC ); append_default_pair( ITEM_NAME_SEPARATOR ); // 文字列を元に行を追加 append_rows( SESSION::get_items_board_menu_str() ); set_title( "コンテキストメニュー項目設定(スレ一覧)" ); } // // OKを押した // void BoardItemMenuPref::slot_ok_clicked() { SKELETON::MsgDiag mdiag( NULL, "次に開いたスレ一覧から有効になります" ); mdiag.run(); SESSION::set_items_board_menu_str( get_items() ); } // // デフォルトボタン // void BoardItemMenuPref::slot_default() { append_rows( SESSION::get_items_board_menu_default_str() ); } jd-2.8.7-140104/src/boarditemmenupref.h0000644000076400010400000000110311334022056014227 0ustar // ライセンス: GPL2 // スレ一覧のコンテキストメニューの表示項目設定 #ifndef _BOARDITEMMENUPREF_H #define _BOARDITEMMENUPREF_H #include "skeleton/selectitempref.h" namespace CORE { class BoardItemMenuPref : public SKELETON::SelectItemPref { public: BoardItemMenuPref( Gtk::Window* parent, const std::string& url ); virtual ~BoardItemMenuPref(){} private: // OKボタン virtual void slot_ok_clicked(); // デフォルトボタン virtual void slot_default(); }; } #endif jd-2.8.7-140104/src/boarditempref.cpp0000644000076400010400000000642211724350130013706 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boarditempref.h" #include "icons/iconmanager.h" #include "jdlib/miscutil.h" #include "global.h" #include "session.h" #include "command.h" using namespace CORE; BoardItemColumnPref::BoardItemColumnPref( Gtk::Window* parent, const std::string& url ) : SKELETON::SelectItemPref( parent, url ) { // デフォルトの項目を設定( 無効にする場合には後に", Glib::RefPtr< Gdk::Pixbuf >(), false" を付ける ) append_default_pair( ITEM_NAME_MARK ); append_default_pair( ITEM_NAME_ID ); append_default_pair( ITEM_NAME_BOARD ); append_default_pair( ITEM_NAME_NAME ); append_default_pair( ITEM_NAME_RES ); append_default_pair( ITEM_NAME_LOAD ); append_default_pair( ITEM_NAME_NEW ); append_default_pair( ITEM_NAME_SINCE ); append_default_pair( ITEM_NAME_LASTWRITE ); append_default_pair( ITEM_NAME_ACCESS ); append_default_pair( ITEM_NAME_SPEED ); append_default_pair( ITEM_NAME_DIFF ); // 文字列を元に列を追加 append_rows( SESSION::get_items_board_col_str() ); set_title( "リスト項目設定(スレ一覧)" ); } // OKを押した void BoardItemColumnPref::slot_ok_clicked() { SESSION::set_items_board_col_str( get_items() ); CORE::core_set_command( "update_board_columns" ); } // // デフォルトボタン // void BoardItemColumnPref::slot_default() { append_rows( SESSION::get_items_board_col_default_str() ); } /////////////////////////////////// BoardItemPref::BoardItemPref( Gtk::Window* parent, const std::string& url ) : SKELETON::SelectItemPref( parent, url ) { // デフォルトの項目を設定 append_default_pair( ITEM_NAME_NEWARTICLE, ICON::get_icon( ICON::WRITE ) ); append_default_pair( ITEM_NAME_SEARCHBOX, ICON::get_icon( ICON::TRANSPARENT ) ); append_default_pair( ITEM_NAME_SEARCH_NEXT, ICON::get_icon( ICON::SEARCH_NEXT) ); append_default_pair( ITEM_NAME_SEARCH_PREV, ICON::get_icon( ICON::SEARCH_PREV ) ); append_default_pair( ITEM_NAME_RELOAD, ICON::get_icon( ICON::RELOAD ) ); append_default_pair( ITEM_NAME_STOPLOADING, ICON::get_icon( ICON::STOPLOADING ) ); append_default_pair( ITEM_NAME_APPENDFAVORITE, ICON::get_icon( ICON::APPENDFAVORITE ) ); append_default_pair( ITEM_NAME_DELETE, ICON::get_icon( ICON::DELETE ) ); append_default_pair( ITEM_NAME_QUIT, ICON::get_icon( ICON::QUIT ) ); append_default_pair( ITEM_NAME_BACK, ICON::get_icon( ICON::BACK ) ); append_default_pair( ITEM_NAME_FORWARD, ICON::get_icon( ICON::FORWARD ) ); append_default_pair( ITEM_NAME_LOCK, ICON::get_icon( ICON::LOCK ) ); append_default_pair( ITEM_NAME_CLEAR_HIGHLIGHT, ICON::get_icon( ICON::CLEAR_SEARCH ) ); append_default_pair( ITEM_NAME_SEPARATOR, ICON::get_icon( ICON::TRANSPARENT ) ); // 文字列を元に列を追加 append_rows( SESSION::get_items_board_toolbar_str() ); set_title( "ツールバー項目表示設定(スレ一覧)" ); } // OKを押した void BoardItemPref::slot_ok_clicked() { SESSION::set_items_board_toolbar_str( get_items() ); CORE::core_set_command( "update_board_toolbar_button" ); } // // デフォルトボタン // void BoardItemPref::slot_default() { append_rows( SESSION::get_items_board_toolbar_default_str() ); } jd-2.8.7-140104/src/boarditempref.h0000644000076400010400000000162111235056116013353 0ustar // ライセンス: GPL2 // スレ一覧のツールバーと列の表示項目設定 #ifndef _BOARDITEMPREF_H #define _BOARDITEMPREF_H #include "skeleton/selectitempref.h" namespace CORE { class BoardItemColumnPref : public SKELETON::SelectItemPref { public: BoardItemColumnPref( Gtk::Window* parent, const std::string& url ); virtual ~BoardItemColumnPref(){} private: // OK押した virtual void slot_ok_clicked(); // デフォルトボタン virtual void slot_default(); }; class BoardItemPref : public SKELETON::SelectItemPref { public: BoardItemPref( Gtk::Window* parent, const std::string& url ); virtual ~BoardItemPref(){} private: // OK押した virtual void slot_ok_clicked(); // デフォルトボタン virtual void slot_default(); }; } #endif jd-2.8.7-140104/src/browserpref.h0000644000076400010400000000474111360116564013101 0ustar // ライセンス: GPL2 // ブラウザ設定ダイアログ #ifndef _BROWSER_H #define _BROWSER_H #include "skeleton/prefdiag.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" #include "browsers.h" namespace CORE { class BrowserPref : public SKELETON::PrefDiag { Gtk::VBox m_vbox; Gtk::Label m_label_notice; Gtk::ComboBoxText m_combo; Gtk::Frame m_frame; Gtk::HBox m_hbox; Gtk::Entry m_entry_browser; // OK押した virtual void slot_ok_clicked(){ CONFIG::set_browsercombo_id( m_combo.get_active_row_number() ); CONFIG::set_command_openurl( MISC::remove_space( m_entry_browser.get_text() ) ); } // コンボボックスが変わった void slot_changed(){ m_entry_browser.set_text( CORE::get_browser_name( m_combo.get_active_row_number() ) ); } public: BrowserPref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url ), m_label_notice( "使用するWebブラウザを選択して下さい\nリンククリック時に %LINK をURLに置換します" ) { const int mrg = 8; int i = 0; for(;;){ std::string label = CORE::get_browser_label( i++ ); if( label.empty() ) break; m_combo.append_text( label ); } m_combo.set_active( CONFIG::get_browsercombo_id() ); m_combo.signal_changed().connect( sigc::mem_fun(*this, &BrowserPref::slot_changed ) ); m_entry_browser.set_text( CONFIG::get_command_openurl() ); m_hbox.set_spacing( mrg ); m_hbox.set_border_width( mrg ); m_hbox.add( m_entry_browser ); m_frame.set_label( "ブラウザ起動コマンド" ); m_frame.add( m_hbox ); m_label_notice.set_alignment( Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER ); m_vbox.set_border_width( mrg ); m_vbox.pack_start( m_label_notice, Gtk::PACK_EXPAND_WIDGET, mrg ); m_vbox.pack_start( m_combo, Gtk::PACK_EXPAND_WIDGET, 0 ); m_vbox.pack_start( m_frame, Gtk::PACK_EXPAND_WIDGET, mrg ); get_vbox()->set_spacing( 0 ); get_vbox()->pack_start( m_vbox ); set_activate_entry( m_entry_browser ); set_title( "Webブラウザ設定" ); show_all_children(); resize( 400, 100 ); } }; } #endif jd-2.8.7-140104/src/browsers.cpp0000644000076400010400000000407711715443613012746 0ustar // ライセンス: GPL2 #include "browsers.h" #include "jdlib/miscutil.h" enum { MAX_TEXT = 256, BROWSER_NUM = 8, #ifdef _WIN32 MAX_SAFE_PATH = 1024, #endif }; namespace CORE { char browsers[ BROWSER_NUM ][ 2 ][ MAX_TEXT ]={ { "ユーザ設定", "" }, #ifdef _WIN32 { "ie", "\"C:/Program Files/Internet Explorer/iexplore.exe\" \"%LINK\"" }, { "Firefox", "\"C:/Program Files/Mozilla Firefox/firefox.exe\" \"%LINK\"" }, { "opera 9.* 以降", "\"C:/Program Files/Opera/opera.exe\" \"%LINK\"" }, { "chrome (Vista/7)", "\"%USERPROFILE%/AppData/Local/Google/Chrome/Application/chrome.exe\" \"%LINK\"" }, { "chrome (XP)", "\"%USERPROFILE%/Local Settings/Application Data/Google/Chrome/Application/chrome.exe\" \"%LINK\"" }, { "chrome (Google pack)", "\"C:/Program Files/Google/Chrome/Application/chrome.exe\" \"%LINK\"" } #else { "標準ブラウザ(xdg-open)", "xdg-open \"%LINK\"" }, { "Firefox", "firefox \"%LINK\"" }, { "konqeror", "konqeror \"%LINK\"" }, { "opera 9.* 以降", "opera -remote \"openURL(%LINK,new-tab)\"" }, { "chrome", "google-chrome \"%LINK\"" }, { "chromium", "chromium \"%LINK\"" }, { "w3m", "w3m \"%LINK\"" } #endif }; const std::string get_browser_label( const int num ){ if( num >= BROWSER_NUM ) return std::string(); return browsers[ num ][ 0 ]; } const std::string get_browser_name( const int num ){ if( num >= BROWSER_NUM ) return std::string(); std::string name = browsers[ num ][ 1 ]; #ifdef _WIN32 if( name.find( "%USERPROFILE%", 0 ) != std::string::npos ){ std::string home = MISC::getenv_limited( "USERPROFILE" , MAX_SAFE_PATH ); name = MISC::replace_str( name, "%USERPROFILE%", home ); } #endif return name; } const int get_browser_number(){ return BROWSER_NUM; } } jd-2.8.7-140104/src/browsers.h0000644000076400010400000000044211211244372012373 0ustar // ライセンス: GPL2 // ブラウザ設定 #ifndef _BROWSERS_H #define _BROWSERS_H #include namespace CORE { const std::string get_browser_label( const int num ); const std::string get_browser_name( const int num ); const int get_browser_number(); } #endif jd-2.8.7-140104/src/cache.cpp0000644000076400010400000006624612110176460012142 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "cache.h" #include "skeleton/msgdiag.h" #include "skeleton/filediag.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/misctime.h" #include "dbtree/interface.h" #include #include #include #include #include #include #include #include #if defined(_WIN32) #include #endif enum { MAX_SAFE_PATH = 1024 }; std::string root_path; // 設定ファイル std::string CACHE::path_conf() { return CACHE::path_root() + "jd.conf"; } std::string CACHE::path_conf_bkup() { return CACHE::path_conf() + ".bkup"; } // 旧設定ファイル std::string CACHE::path_conf_old() { std::string home = MISC::getenv_limited( ENV_HOME, MAX_SAFE_PATH ); return home + "/.jdrc"; } // セッション情報ファイル std::string CACHE::path_session() { return CACHE::path_root() + "session.info"; } // ロックファイル std::string CACHE::path_lock() { const std::string jd_lock = MISC::getenv_limited( "JD_LOCK", MAX_SAFE_PATH ); if( ! jd_lock.empty() ) return jd_lock; return CACHE::path_root() + "JDLOCK"; } // パスワード設定ファイル std::string CACHE::path_passwd( const std::string& basename ) { return CACHE::path_root() + basename + ".conf"; } // キャッシュルートの絶対パス std::string CACHE::path_root() { if( root_path.empty() ){ const std::string jd_cache = MISC::getenv_limited( "JD_CACHE", MAX_SAFE_PATH ); root_path = jd_cache.empty() ? "~/.jd/" : jd_cache; if( root_path[ root_path.length() -1 ] != '/' ) root_path = root_path + "/"; if( root_path[ 0 ] == '~' ){ std::string home = MISC::getenv_limited( ENV_HOME , MAX_SAFE_PATH ); root_path.replace( 0, 1, home ); } } return root_path; } // 板リスト std::string CACHE::path_xml_listmain() { return CACHE::path_root() + "boards.xml"; } std::string CACHE::path_xml_listmain_bkup() { return CACHE::path_xml_listmain() + ".bkup"; } // 1.9.5-beta070611以前 std::string CACHE::path_xml_listmain_old() { return CACHE::path_root() + "list_main.xml"; } // お気に入り std::string CACHE::path_xml_favorite() { return CACHE::path_root() + "bookmark.xml"; } std::string CACHE::path_xml_favorite_bkup() { return CACHE::path_xml_favorite() + ".bkup"; } // 1.9.5-beta070611以前 std::string CACHE::path_xml_favorite_old() { return CACHE::path_root() + "favorite.xml"; } // 外部板設定ファイル( navi2ch 互換 ) std::string CACHE::path_etcboard() { return CACHE::path_root() + "etc.txt"; } // ユーザーコマンド設定ファイル std::string CACHE::path_usrcmd() { return CACHE::path_root() + "usrcmd.xml"; } std::string CACHE::path_usrcmd_old() { return CACHE::path_root() + "usrcmd.txt"; } // リンクフィルタ設定ファイル std::string CACHE::path_linkfilter() { return CACHE::path_root() + "linkfilter.xml"; } // URL変換設定ファイル std::string CACHE::path_urlreplace() { return CACHE::path_root() + "urlreplace.conf"; } // 履歴 std::string CACHE::path_xml_history() { return CACHE::path_root() + "hist.xml"; } // 板履歴 std::string CACHE::path_xml_history_board() { return CACHE::path_root() + "hist_board.xml"; } // 最近閉じたスレの履歴 std::string CACHE::path_xml_history_close() { return CACHE::path_root() + "hist_close.xml"; } // 最近閉じた板の履歴 std::string CACHE::path_xml_history_closeboard() { return CACHE::path_root() + "hist_closeboard.xml"; } // 最近閉じた画像の履歴 std::string CACHE::path_xml_history_closeimg() { return CACHE::path_root() + "hist_closeimg.xml"; } // View履歴 std::string CACHE::path_xml_history_view() { return CACHE::path_root() + "hist_view.xml"; } // 板移転情報 std::string CACHE::path_movetable() { return CACHE::path_root() + "move.info"; } // キーボード設定 std::string CACHE::path_keyconf() { return CACHE::path_root() + "key.conf"; } // マウスジェスチャ設定 std::string CACHE::path_mouseconf() { return CACHE::path_root() + "mouse.conf"; } // マウスボタン設定 std::string CACHE::path_buttonconf() { return CACHE::path_root() + "button.conf"; } // 板のルートパス std::string CACHE::path_board_root( const std::string& url ) { std::string boardbase = DBTREE::url_boardbase( url ); return path_board_root_fast( boardbase ); } // // 板のルートパス(高速版) // // DBTREE::url_boardbase( url ) を使わないであらかじめ boardbase を与える // std::string CACHE::path_board_root_fast( const std::string& boardbase ) { // http:// を取り除く size_t i = boardbase.find( "://" ); if( i == std::string::npos ) return std::string(); return CACHE::path_root() + boardbase.substr( i + 3 ); } std::string CACHE::path_article_summary( const std::string& url ) { return CACHE::path_board_root( url ) + "article-summary"; } // board情報( navi2ch互換用 ) std::string CACHE::path_board_info( const std::string& url ) { return CACHE::path_board_root( url ) + "board.info"; } // board情報( jd 用 ) std::string CACHE::path_jdboard_info( const std::string& url ) { return CACHE::path_board_root( url ) + "jdboard.info"; } std::string CACHE::path_article_info_root( const std::string& url ) { return CACHE::path_board_root( url ) + "info/"; } // スレの情報ファイル( navi2ch互換、実際には使用しない ) std::string CACHE::path_article_info( const std::string& url, const std::string& id ) { std::string id_str = id; // idに拡張子が付いてたら取る size_t i = id.find( "." ); if( i != std::string::npos ) id_str = id.substr( 0, i ); return CACHE::path_article_info_root( url ) + id_str; } // スレの拡張情報ファイル std::string CACHE::path_article_ext_info( const std::string& url, const std::string& id ) { return CACHE::path_article_info( url, id ) + ".info"; } std::string CACHE::path_dat( const std::string& url ) { // file:// の場合 if( url.c_str()[ 0 ] == 'f' && url.c_str()[ 1 ] == 'i' ) return url.substr( strlen( "file://" ) ); return CACHE::path_board_root( url ) + DBTREE::article_id( url ); } // // 画像キャッシュのルートパス // std::string CACHE::path_img_root() { return CACHE::path_root() + "image/"; } // // 画像キャッシュのinfoファイルのルートパス // std::string CACHE::path_img_info_root() { return path_img_root() + "info/"; } // // 保護画像キャッシュのルートパス // std::string CACHE::path_img_protect_root() { return CACHE::path_root() + "image_protect/"; } // // 保護画像キャッシュのinfoファイルのルートパス // std::string CACHE::path_img_protect_info_root() { return path_img_protect_root() + "info/"; } // // 画像あぼーんinfoファイルのルートパス // std::string CACHE::path_img_abone_root() { return path_root() + "image_abone/"; } // // ログのルートパス // std::string CACHE::path_logroot() { return CACHE::path_root() + "log/"; } // // 書き込みログ // std::string CACHE::path_postlog() { return path_logroot() + "postlog"; } // // メッセージログ(-lオプション) // std::string CACHE::path_msglog() { return path_logroot() + "msglog"; } // // 検索や名前などの補完情報 // std::string CACHE::path_completion( int mode ) { return CACHE::path_root() + "comp" + MISC::itostr( mode ) + ".info"; } // // サウンドファイルのルートパス // std::string CACHE::path_sound_root() { return CACHE::path_root() + "sound/"; } // // 画像キャッシュファイルの名前 // std::string CACHE::filename_img( const std::string& url ) { std::string file = MISC::tolower_str( url ); file = MISC::replace_str( file, "http://", "" ); file = MISC::replace_str( file, "/", "-" ); file = MISC::url_encode( file.c_str(), file.length() ); file = MISC::replace_str( file, "%", "" ); return file; } // // 画像キャッシュ情報ファイルの名前 // std::string CACHE::filename_img_info( const std::string& url ) { return filename_img( url ) + ".info"; } // // 画像キャッシュファイルのパス // std::string CACHE::path_img( const std::string& url ) { return CACHE::path_img_root() + filename_img( url ); } // // 画像infoファイルのパス // std::string CACHE::path_img_info( const std::string& url ) { return CACHE::path_img_info_root() + filename_img_info( url ); } // // 保護画像キャッシュファイルのパス // std::string CACHE::path_img_protect( const std::string& url ) { return CACHE::path_img_protect_root() + filename_img( url ); } // // 保護画像infoファイルのパス // std::string CACHE::path_img_protect_info( const std::string& url ) { return CACHE::path_img_protect_info_root() + filename_img_info( url ); } // // 画像あぼーんinfoファイルのパス // std::string CACHE::path_img_abone( const std::string& url ) { return CACHE::path_img_abone_root() + filename_img_info( url ); } // // アスキーアートファイル // std::string CACHE::path_aalist() { return CACHE::path_root() + "aalist.txt"; } // // アスキーアートファイル格納用ディレクトリ .jd/aa/ // std::string CACHE::path_aadir() { return CACHE::path_root() + "aa/"; } // // AAの使用履歴ファイル // std::string CACHE::path_aahistory() { return CACHE::path_root() + "hist_aa.xml"; } // // テーマのルートパス // const std::string CACHE::path_theme_root() { return CACHE::path_root() + "theme/"; } // // アイコンテーマのルートパス // const std::string CACHE::path_theme_icon_root() { return CACHE::path_theme_root() + "icons/"; } // // css // std::string CACHE::path_css() { return CACHE::path_theme_root() + "jd.css"; } // // res.html // std::string CACHE::path_reshtml() { return CACHE::path_theme_root() + "Res.html"; } // // css (旧バージョンとの互換性のため) // std::string CACHE::path_css_old() { return CACHE::path_root() + "jd.css"; } // // res.html (旧バージョンとの互換性のため) // std::string CACHE::path_reshtml_old() { return CACHE::path_root() + "Res.html"; } // // キャッシュのルートディレクトリをmkdir // // 例えば "/home/hoge/.jd/" を作成 // bool CACHE::mkdir_root() { std::string path_root = CACHE::path_root(); if( ! CACHE::jdmkdir( path_root ) ){ MISC::ERRMSG( "can't create " + path_root ); return false; } return true; } // // 画像キャッシュのルートディレクトリをmkdir // // 例えば "/home/hoge/.jd/image/" と "/home/hoge/.jd/image/info/" などを作成 // bool CACHE::mkdir_imgroot() { // root std::string path_img_root = CACHE::path_img_root(); if( ! CACHE::jdmkdir( path_img_root ) ){ MISC::ERRMSG( "can't create " + path_img_root ); return false; } // info ディレクトリ std::string path_info_root = CACHE::path_img_info_root(); if( ! CACHE::jdmkdir( path_info_root ) ){ MISC::ERRMSG( "can't create " + path_info_root ); return false; } // abone ディレクトリ std::string path_abone_root = CACHE::path_img_abone_root(); if( ! CACHE::jdmkdir( path_abone_root ) ){ MISC::ERRMSG( "can't create " + path_abone_root ); return false; } return true; } // // 保護画像キャッシュのルートディレクトリをmkdir // bool CACHE::mkdir_imgroot_favorite() { // root std::string path_img_root = CACHE::path_img_protect_root(); if( ! CACHE::jdmkdir( path_img_root ) ){ MISC::ERRMSG( "can't create " + path_img_root ); return false; } // info ディレクトリ std::string path_info_root = CACHE::path_img_protect_info_root(); if( ! CACHE::jdmkdir( path_info_root ) ){ MISC::ERRMSG( "can't create " + path_info_root ); return false; } return true; } // // キャッシュのひとつ上のディレクトリをmkdir // // 例えばキャッシュのルートディレクトリが "/home/hoge/.jd/hoge.2ch.net/hogeboard/" だったら // "/home/hoge/.jd/hoge.2ch.net/" を作成する // bool CACHE::mkdir_parent_of_board( const std::string& url ) { std::string path_tmp = CACHE::path_board_root( url ); size_t i = path_tmp.rfind( "/", path_tmp.length() -2 ); if( i == std::string::npos ) return false; std::string path_parent = path_tmp.substr( 0, i ); if( ! CACHE::jdmkdir( path_parent ) ){ MISC::ERRMSG( "can't create " + path_parent ); return false; } return true; } // // ある板のキャッシュのルートディレクトリをmkdir // // 例えば "/home/hoge/.jd/hoge.2ch.net/hogeboard/" と "/home/hoge/.jd/hoge.2ch.net/hogeboard/info/" を作成 // bool CACHE::mkdir_boardroot( const std::string& url ) { // root std::string path_board_root = CACHE::path_board_root( url ); if( ! CACHE::jdmkdir( path_board_root ) ){ MISC::ERRMSG( "can't create " + path_board_root ); return false; } // info ディレクトリ std::string path_info_root = CACHE::path_article_info_root( url ); if( ! CACHE::jdmkdir( path_info_root ) ){ MISC::ERRMSG( "can't create " + path_info_root ); return false; } return true; } // // ログのルートディレクトリをmkdir // bool CACHE::mkdir_logroot() { // root std::string path_logroot = CACHE::path_logroot(); if( ! CACHE::jdmkdir( path_logroot ) ){ MISC::ERRMSG( "can't create " + path_logroot ); return false; } return true; } size_t CACHE::load_rawdata( const std::string& path, std::string& str ) { str.clear(); std::ifstream fin; fin.open( to_locale_cstr( path ) ); if( !fin.is_open() ) return 0; getline( fin, str, '\0' ); fin.close(); return str.length(); } size_t CACHE::load_rawdata( const std::string& path, char* data, const size_t n ) { size_t count = 0; std::ifstream fin; fin.open( to_locale_cstr( path ), std::ios::binary ); if( !fin.is_open() ) return 0; fin.read( data, n ); count = fin.gcount(); fin.close(); return count; } size_t CACHE::save_rawdata( const std::string& path, const std::string& str, const bool append ) { return save_rawdata( path, str.c_str(), str.length(), append ); } size_t CACHE::save_rawdata( const std::string& path, const char* data, size_t n, const bool append ) { size_t count = 0; size_t byte = 0; std::ofstream fout; std::ofstream::openmode fmode; if( append ) fmode = std::ios::app | std::ios::ate | std::ios::binary; else fmode = std::ios::binary; fout.open( to_locale_cstr( path ), fmode ); if( !fout.is_open() ){ MISC::ERRMSG( "can't open " + path ); return 0; } if( append ) count = fout.tellp(); #ifdef _DEBUG std::cout << "CACHE::save_rawdata current = " << count << std::endl; #endif fout.write( data, n ); byte = fout.tellp(); byte -= count; fout.close(); #ifdef _DEBUG std::cout << "n = " << n << " byte = " << byte << std::endl; #endif if( n != byte ){ MISC::ERRMSG( "failed to save " + path ); return 0; } return byte; } const int CACHE::file_exists( const std::string& path ) { struct stat buf_stat; if( path.empty() ) return EXIST_ERROR; std::string path_s = path; #ifdef _WIN32 // on windows fail stat() directory path with ends '/' // "c:/" = ok, "c:" = fail // "c:/dir/" = fail, "c:/dir" = ok if( path.length() > 3 && path[ path.length() - 1 ] == '/' ){ path_s = path.substr( 0, path.length() - 1 ); } #endif if( stat( to_locale_cstr( path_s ), &buf_stat ) != 0 ) return EXIST_ERROR; if( S_ISREG( buf_stat.st_mode ) ) return EXIST_FILE; if( S_ISDIR( buf_stat.st_mode ) ) return EXIST_DIR; if( S_ISFIFO( buf_stat.st_mode ) ) return EXIST_FIFO; return EXIST; } size_t CACHE::get_filesize( const std::string& path ) { struct stat buf_stat; if( stat( to_locale_cstr( path ), &buf_stat ) != 0 ) return 0; if( S_ISREG( buf_stat.st_mode ) ) return buf_stat.st_size; return 0; } time_t CACHE::get_filemtime( const std::string& path ) { struct stat buf_stat; if( stat( to_locale_cstr( path ), &buf_stat ) != 0 ) return 0; if( S_ISREG( buf_stat.st_mode ) ) return buf_stat.st_mtime; return 0; } const bool CACHE::set_filemtime( const std::string& path, const time_t mtime ) { #ifdef _DEBUG std::cout << "CACHE::set_filemtime path = " << path << " mtime = " << MISC::timettostr( mtime, MISC::TIME_NORMAL ) << std::endl; #endif struct stat buf_stat; if( stat( to_locale_cstr( path ), &buf_stat ) != 0 ) return false; if( S_ISREG( buf_stat.st_mode ) ){ #if defined(_WIN32) struct utimbuf tb; tb.actime = buf_stat.st_atime; tb.modtime = mtime; if( ! utime( to_locale_cstr( path ), &tb ) ) return true; #else // WIN32 struct timeval tv[2]; tv[0].tv_sec = buf_stat.st_atime; tv[0].tv_usec = 0; tv[1].tv_sec = mtime; tv[1].tv_usec = 0; if( ! utimes( to_locale_cstr( path ), tv ) ) return true; #endif // WIN32 } return false; } // // mkdir // bool CACHE::jdmkdir( const std::string& path ) { #ifdef _DEBUG std::cout << "CACHE::jdmkdir : path = " + path << std::endl; #endif if( CACHE::file_exists( path ) == EXIST_DIR ) return true; std::string target = path; if( path.find( "~/" ) == 0 ){ std::string homedir = MISC::getenv_limited( ENV_HOME, MAX_SAFE_PATH ); if( homedir.empty() ) return false; target = homedir + path.substr( 2 ); } #ifdef _WIN32 // on windows has case of start drive letter "c:/...", or UNC "//pcname/..." if( target[ 0 ] != '/' && target[ 1 ] != ':' ) return false; #else if( target[ 0 ] != '/' ) return false; #endif if( target[ target.length() -1 ] != '/' ) target += "/"; #ifdef _DEBUG std::cout << "target = " << target << std::endl; #endif // ルートからディレクトリがあるかチェックしていく。無ければ作る size_t i = 0; while( ( i = target.find( "/", i ) ) != std::string::npos ){ ++i; std::string currentdir = target.substr( 0, i ); #ifdef _DEBUG std::cout << "mkdir " << currentdir << std::endl; #endif if( CACHE::file_exists( currentdir ) == EXIST_DIR ) continue; #ifdef _WIN32 if( mkdir( to_locale_cstr( currentdir ) ) != 0 ){ #else if( mkdir( to_locale_cstr( currentdir ), 0755 ) != 0 ){ #endif MISC::ERRMSG( "mkdir failed " + currentdir ); return false; } } return true; } // // file copy // bool CACHE::jdcopy( const std::string& file_from, const std::string& file_to ) { struct stat buf_stat; if( stat( to_locale_cstr( file_from ), &buf_stat ) != 0 ) return false; #ifdef _DEBUG std::cout << "CACHE::jdcopy : from = " << file_from << std::endl; std::cout << "to = " << file_to << std::endl; std::cout << "read size = " << buf_stat.st_size << std::endl; #endif // 32Mより大きい画像はエラー出す if( buf_stat.st_size > 32 * 1024 * 1024 ){ MISC::ERRMSG( "CACHE::jdcopy: size is too big : " + file_from ); return false; } bool ret = false; char* data = (char*)malloc( sizeof( char ) * buf_stat.st_size ); size_t readsize = load_rawdata( file_from, data, buf_stat.st_size ); if( readsize ){ size_t savesize = save_rawdata( file_to, data, buf_stat.st_size ); if( readsize == savesize ) ret = true; #ifdef _DEBUG std::cout << "save size = " << savesize << std::endl; #endif } free( data ); return ret; } // // mv // bool CACHE::jdmv( const std::string& file_from, const std::string& file_to ) { if( CACHE::jdcopy( file_from, file_to ) ){ unlink( to_locale_cstr( file_from ) ); return true; } return false; } // // 保存ダイアログを表示して file_from を file_to に保存する // // parent == NULL の時はメインウィンドウをparentにする // file_toはデフォルトの保存先 // 戻り値は保存先(保存に失敗したらempty()) // std::string CACHE::copy_file( Gtk::Window* parent, const std::string& file_from, const std::string& file_to, const int type ) { if( file_from.empty() ) return std::string(); if( file_to.empty() ) return std::string(); std::string name = MISC::get_filename( file_to ); std::string dir = MISC::get_dir( file_to ); if( dir.empty() ) dir = MISC::get_dir( file_from ); #ifdef _DEBUG std::cout << "CACHE::open_copy_diag\n"; std::cout << "from = " << file_from << std::endl; std::cout << "dir = " << dir << std::endl; std::cout << "name = " << name << std::endl; #endif std::string path_to = CACHE::open_save_diag( parent, dir, name, type ); if( path_to.empty() ) return std::string(); if( CACHE::jdcopy( file_from, path_to ) ) return path_to; else{ SKELETON::MsgDiag mdiag( parent, path_to + "\n\nの保存に失敗しました。\nハードディスクの容量やパーミッションなどを確認してください。" ); mdiag.run(); } return std::string(); } // ファイル選択ダイアログにフィルタ追加 void CACHE::add_filter_to_diag( Gtk::FileChooserDialog& diag, const int type ) { if( type == FILE_TYPE_ALL ) return; Gtk::FileFilter filter; switch( type ) { case FILE_TYPE_TEXT: filter.set_name( "全てのテキストファイル" ); filter.add_mime_type( "text/plain" ); diag.add_filter( filter ); break; case FILE_TYPE_DAT: filter.set_name( "全てのDATファイル" ); filter.add_pattern( "*.dat" ); diag.add_filter( filter ); break; } Gtk::FileFilter all; all.set_name( "全てのファイル" ); all.add_pattern( "*" ); diag.add_filter( all ); } // // ファイル選択ダイアログを表示する // // parent == NULL の時はメインウィンドウをparentにする // open_path はデフォルトの参照先 // multi == true なら複数選択可能 // 戻り値は選択されたファイルのpathのリスト // const std::list< std::string > CACHE::open_load_diag( Gtk::Window* parent, const std::string& open_path, const int type, const bool multi ) { std::string dir = MISC::get_dir( open_path ); if( dir.empty() ) dir = MISC::getenv_limited( ENV_HOME, MAX_SAFE_PATH ); SKELETON::FileDiag diag( parent, "ファイルを開く", Gtk::FILE_CHOOSER_ACTION_OPEN ); diag.set_select_multiple( multi ); diag.set_current_folder( dir ); add_filter_to_diag( diag, type ); if( diag.run() == Gtk::RESPONSE_ACCEPT ) { diag.hide(); return MISC::recover_path( diag.get_filenames() ); } return std::list< std::string >(); } // // 保存ファイル選択ダイアログを表示する // // parent == NULL の時はメインウィンドウをparentにする // dirとnameはデフォルトの参照先 // 戻り値は選択されたファイルのpath // std::string CACHE::open_save_diag( Gtk::Window* parent, const std::string& dir, const std::string& name, const int type ) { #ifdef _DEBUG std::cout << "CACHE::open_save_diag\n"; std::cout << "dir = " << dir << std::endl; std::cout << "name = " << name << std::endl; #endif SKELETON::FileDiag diag( parent, "保存先選択", Gtk::FILE_CHOOSER_ACTION_SAVE ); if( dir.empty() ) { const std::string home = MISC::getenv_limited( ENV_HOME, MAX_SAFE_PATH ); if( ! home.empty() ) diag.set_current_folder( home ); } else { diag.set_current_folder( dir ); } diag.set_current_name( name ); add_filter_to_diag( diag, type ); if( diag.run() != Gtk::RESPONSE_ACCEPT ) return std::string(); diag.hide(); std::string path_to = MISC::recover_path( diag.get_filename() ); #ifdef _DEBUG std::cout << "to = " << path_to << std::endl; #endif // 既にファイルがある場合は問い合わせる if( CACHE::file_exists( path_to ) == CACHE::EXIST_FILE ){ SKELETON::MsgDiag mdiag( parent, "ファイルが存在します。ファイル名を変更して保存しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE ); mdiag.add_button( Gtk::Stock::NO, Gtk::RESPONSE_NO ); mdiag.add_button( Gtk::Stock::YES, Gtk::RESPONSE_YES ); mdiag.add_button( "上書き", Gtk::RESPONSE_YES + 100 ); int ret = mdiag.run(); mdiag.hide(); if( ret == Gtk::RESPONSE_YES ){ return CACHE::open_save_diag( parent, MISC::get_dir( path_to ), MISC::get_filename( path_to ), type ); } else if( ret == Gtk::RESPONSE_NO ) return std::string(); } return path_to; } // // dir ディレクトリ内のレギュラーファイルのリストを取得 // std::list< std::string > CACHE::get_filelist( const std::string& dir ) { std::list< std::string > list_files; #ifdef _DEBUG std::cout << "CACHE::get_filelist " << dir << std::endl; #endif DIR *dirp = opendir( to_locale_cstr( dir ) ); if( !dirp ) return list_files; struct dirent *direntry; while( ( direntry = readdir( dirp ) ) ){ std::string filename = dir + direntry->d_name; if( file_exists( filename ) == EXIST_FILE ){ #ifdef _DEBUG std::cout << filename << std::endl; #endif list_files.push_back( direntry->d_name ); } } closedir( dirp ); return list_files; } // // dir ディレクトリ内のレギュラーファイルの合計サイズを取得 // guint64 CACHE::get_dirsize( const std::string& dir ) { guint64 total_size = 0; #ifdef _DEBUG std::cout << "CACHE::get_dirsize " << dir << std::endl; #endif DIR *dirp = opendir( to_locale_cstr( dir ) ); if( !dirp ) return 0; struct dirent *direntry; while( ( direntry = readdir( dirp ) ) ){ std::string filename = dir + direntry->d_name; total_size += CACHE::get_filesize( filename ); } closedir( dirp ); #ifdef _DEBUG std::cout << "size = " << total_size << std::endl; #endif return total_size; } // 相対パスから絶対パスを取得してファイルが存在すれば絶対パスを返す // ファイルが存在しない場合は std::string() を返す const std::string CACHE::get_realpath( const std::string& path ) { std::string path_real; char resolved_path[ PATH_MAX + 1 ]; #ifdef _WIN32 // _fullpath() are not checked the path is completely available char* ret = _fullpath( resolved_path, to_locale_cstr( path ), PATH_MAX ); #else char* ret = realpath( to_locale_cstr( path ), resolved_path ); #endif if( ret ){ path_real = ret; } else return std::string(); if( CACHE::file_exists( path_real ) == EXIST_ERROR ){ return std::string(); } #ifdef _DEBUG std::cout << "CACHE::get_realpath path = " << path << " real = " << path_real << std::endl; #endif return path_real; } jd-2.8.7-140104/src/cache.h0000644000076400010400000001725712110176460011605 0ustar // ライセンス: GPL2 // キャッシュ、ファイル操作まわり #ifndef _CACHE_H #define _CACHE_H #include #include #include #include #ifdef _WIN32 #define ENV_HOME "USERPROFILE" #else #define ENV_HOME "HOME" #endif // GNU/Hurd doen't have PATH_MAX #ifndef PATH_MAX #define PATH_MAX 1024 #endif // UTF-8からロケールでエンコードされた文字列に変換 #ifdef _WIN32 #define to_locale_cstr( path ) Glib::locale_from_utf8((path)).c_str() #else #define to_locale_cstr( path ) (path).c_str() #endif namespace Gtk { class Window; class FileChooserDialog; } namespace CACHE { ///////////////////////////////////////////////// // // 設定ファイルのパス // 設定ファイル std::string path_conf(); std::string path_conf_bkup(); std::string path_conf_old(); // 旧ファイル // セッション情報ファイル std::string path_session(); // ロックファイル std::string path_lock(); // パスワード保存ファイル std::string path_passwd( const std::string& basename ); // キャッシュルートの絶対パス std::string path_root(); // 板 std::string path_xml_listmain(); std::string path_xml_listmain_bkup(); std::string path_xml_listmain_old(); // お気に入り std::string path_xml_favorite(); std::string path_xml_favorite_bkup(); std::string path_xml_favorite_old(); // 外部板設定ファイル( navi2ch 互換 ) std::string path_etcboard(); // ユーザーコマンド設定ファイル std::string path_usrcmd(); std::string path_usrcmd_old(); // リンクフィルタ std::string path_linkfilter(); // URL変換設定ファイル std::string path_urlreplace(); // スレ履歴 std::string path_xml_history(); // 板履歴 std::string path_xml_history_board(); // 最近閉じたスレの履歴 std::string path_xml_history_close(); // 最近閉じた板の履歴 std::string path_xml_history_closeboard(); // 最近閉じた画像の履歴 std::string path_xml_history_closeimg(); // View履歴 std::string path_xml_history_view(); // 板移転情報 std::string path_movetable(); // キーボード設定 std::string path_keyconf(); // マウスジェスチャ設定 std::string path_mouseconf(); // マウスボタン設定 std::string path_buttonconf(); std::string path_board_root( const std::string& url ); std::string path_board_root_fast( const std::string& boardbase ); std::string path_article_summary( const std::string& url ); std::string path_board_info( const std::string& url ); std::string path_jdboard_info( const std::string& url ); std::string path_article_info_root( const std::string& url ); std::string path_article_info( const std::string& url, const std::string& id ); std::string path_article_ext_info( const std::string& url, const std::string& id ); std::string path_dat( const std::string& url ); // 画像関係 std::string path_img_root(); std::string path_img_info_root(); std::string path_img_protect_root(); std::string path_img_protect_info_root(); std::string path_img_abone_root(); std::string filename_img( const std::string& url ); std::string filename_img_info( const std::string& url ); std::string path_img( const std::string& url ); std::string path_img_info( const std::string& url ); std::string path_img_protect( const std::string& url ); std::string path_img_protect_info( const std::string& url ); std::string path_img_abone( const std::string& url ); // AA std::string path_aalist(); // アスキーアートファイル std::string path_aadir(); // アスキーアートファイル格納用ディレクトリ .jd/aa/ std::string path_aahistory(); // AAの使用履歴ファイル // テーマのルートパス const std::string path_theme_root(); // アイコンテーマのルートパス const std::string path_theme_icon_root(); // css std::string path_css(); std::string path_css_old(); // html std::string path_reshtml(); std::string path_reshtml_old(); // ログ std::string path_logroot(); std::string path_postlog(); // 書き込みログ std::string path_msglog(); // メッセージログ(-lオプション) // 検索や名前などの補完情報 std::string path_completion( int mode ); // サウンドファイルのルートパス std::string path_sound_root(); ///////////////////////////////////////////////// // // ユーティリティ関数 // file_exists の戻り値 enum { EXIST_FILE = 0, // ファイル EXIST_DIR, // ディレクトリ EXIST_FIFO, // FIFO EXIST, // 存在しない or 何か存在してる EXIST_ERROR // エラー }; // ファイルタイプ( file_open_diag() で使用 ) enum { FILE_TYPE_ALL = 0, FILE_TYPE_TEXT, FILE_TYPE_DAT }; // キャッシュの mkdir 関係 bool mkdir_root(); bool mkdir_imgroot(); bool mkdir_imgroot_favorite(); bool mkdir_parent_of_board( const std::string& url ); bool mkdir_boardroot( const std::string& url ); bool mkdir_logroot(); // 生データ読み書き size_t load_rawdata( const std::string& path, std::string& str ); size_t load_rawdata( const std::string& path, char* data, const size_t n ); size_t save_rawdata( const std::string& path, const std::string& str, const bool append = false ); size_t save_rawdata( const std::string& path, const char* data, const size_t n, const bool append = false ); // ファイル情報 const int file_exists( const std::string& path ); size_t get_filesize( const std::string& path ); time_t get_filemtime( const std::string& path ); const bool set_filemtime( const std::string& path, const time_t mtime ); // ファイル操作 bool jdmkdir( const std::string& path ); bool jdcopy( const std::string& file_from, const std::string& file_to ); bool jdmv( const std::string& file_from, const std::string& file_to ); // 保存ダイアログを表示して file_from を file_to に保存する std::string copy_file( Gtk::Window* parent, const std::string& file_from, const std::string& file_to, const int type ); // ファイル選択ダイアログにフィルタ追加 void add_filter_to_diag( Gtk::FileChooserDialog& diag, const int type ); // ファイル選択ダイアログを表示する // parent == NULL の時はメインウィンドウをparentにする // open_path はデフォルトの参照先 // multi == true なら複数選択可能 // 戻り値は選択されたファイルのpathのリスト const std::list< std::string > open_load_diag( Gtk::Window* parent, const std::string& open_path, const int type, const bool multi ); // 保存ファイル選択ダイアログを表示する std::string open_save_diag( Gtk::Window* parent, const std::string& dir, const std::string& name, const int type ); // dir ディレクトリ内のレギュラーファイルのリストを取得 std::list< std::string > get_filelist( const std::string& dir ); // dir ディレクトリ内のレギュラーファイルの合計サイズを取得 guint64 get_dirsize( const std::string& dir ); // 相対パスから絶対パスを取得してファイルが存在すれば絶対パスを返す // ファイルが存在しない場合は std::string() を返す const std::string get_realpath( const std::string& path ); } #endif jd-2.8.7-140104/src/colorid.h0000644000076400010400000000534511543661705012202 0ustar // カラーID #ifndef _COLOR_ID_H #define _COLOR_ID_H enum { COLOR_NONE = 0, // スレビューで使用する色 COLOR_FOR_THREAD = 0, COLOR_CHAR, // スレビューなど基本の文字 COLOR_CHAR_NAME, // 名前欄 COLOR_CHAR_NAME_B, // トリップや fusianasan 等、が含まれている名前欄 COLOR_CHAR_NAME_NOMAIL, // メールが無いときの名前欄 COLOR_CHAR_AGE, // 非sageのメール欄 COLOR_CHAR_SELECTION, // 選択範囲の文字 COLOR_CHAR_HIGHLIGHT, // ハイライトの文字 COLOR_CHAR_LINK, // 通常のリンクの文字色 COLOR_CHAR_LINK_ID_LOW, // 複数発言したIDの文字色 COLOR_CHAR_LINK_ID_HIGH,// 多く発言したIDの文字色 COLOR_CHAR_LINK_RES, // 参照されていないレス番号の文字色 COLOR_CHAR_LINK_LOW, // 他のレスから参照されたレス番号の文字色 COLOR_CHAR_LINK_HIGH, // 参照された数が多いレス番号の文字色 COLOR_CHAR_MESSAGE, // メッセージビューの文字 COLOR_CHAR_MESSAGE_SELECTION, // メッセージビュー(選択範囲)の文字 COLOR_CHAR_ENTRY_DEFAULT, // Gtk::Entryのデフォルトの文字色 COLOR_IMG_NOCACHE, // 画像のリンク(キャッシュ無) COLOR_IMG_CACHED, // 画像のリンク(キャッシュ有) COLOR_IMG_LOADING, // 画像のリンク(ロード中) COLOR_IMG_ERR, // 画像のリンク(エラー) COLOR_BACK, // スレビューなど基本の背景 COLOR_BACK_POPUP, // ポップアップの背景 COLOR_BACK_SELECTION, // 選択範囲 COLOR_BACK_HIGHLIGHT, // ハイライト文字の背景色 COLOR_BACK_HIGHLIGHT_TREE, // ハイライト文字の背景色(ツリー用) COLOR_BACK_MESSAGE, // メッセージビューの背景色 COLOR_BACK_MESSAGE_SELECTION, // メッセージビュー(選択範囲)の背景色 COLOR_BACK_ENTRY_DEFAULT, // Gtk::Entryのデフォルトの背景色 COLOR_SEPARATOR_NEW, // 新着セパレータ COLOR_FRAME, // ポップアップフレーム色 COLOR_MARKER, // オートスクロールのマーク色 END_COLOR_FOR_THREAD, USRCOLOR_BASE = END_COLOR_FOR_THREAD, // cssで使用する色番号のベース // その他の色 COLOR_CHAR_BBS, // 板一覧の文字 COLOR_CHAR_BBS_COMMENT, // 板一覧のコメント COLOR_CHAR_BOARD, // スレ一覧の文字 COLOR_BACK_BBS, // 板一覧の背景 COLOR_BACK_BBS_EVEN, // 板一覧の背景(偶数行) COLOR_BACK_BOARD, // スレ一覧の背景 COLOR_BACK_BOARD_EVEN, // スレ一覧の背景(偶数行) COLOR_NUM }; #endif jd-2.8.7-140104/src/command.cpp0000644000076400010400000000160510567751602012514 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "command.h" #include "global.h" #include "core.h" void CORE::core_set_command( const std::string& command, const std::string& url, const std::string& arg1, const std::string& arg2, const std::string& arg3, const std::string& arg4, const std::string& arg5, const std::string& arg6 ) { COMMAND_ARGS command_arg; command_arg.command = command; command_arg.url = url; command_arg.arg1 = arg1; command_arg.arg2 = arg2; command_arg.arg3 = arg3; command_arg.arg4 = arg4; command_arg.arg5 = arg5; command_arg.arg6 = arg6; CORE::get_instance()->set_command( command_arg ); } Gtk::Window* CORE::get_mainwindow() { return dynamic_cast< Gtk::Window* >( CORE::get_instance()->get_toplevel() ); } jd-2.8.7-140104/src/command.h0000644000076400010400000000147110567751602012162 0ustar // ライセンス: GPL2 // // コアのインターフェース // #ifndef _COMMAND_H #define _COMMAND_H #include namespace Gtk { class Widget; class Window; } namespace CORE { void core_set_command( const std::string& command, const std::string& url = std::string(), const std::string& arg1 = std::string(), const std::string& arg2 = std::string(), const std::string& arg3 = std::string(), const std::string& arg4 = std::string(), const std::string& arg5 = std::string(), const std::string& arg6 = std::string() ); // メインウィンドウ取得 Gtk::Window* get_mainwindow(); } #endif jd-2.8.7-140104/src/command_args.h0000644000076400010400000000054611376762460013203 0ustar // CoreやAdminクラスで使うコマンド構造体 #ifndef COMMAND_ARGS_H #define COMMAND_ARGS_H struct COMMAND_ARGS { std::string command; std::string url; std::string arg1; std::string arg2; std::string arg3; std::string arg4; std::string arg5; std::string arg6; std::string arg7; std::string arg8; }; #endif jd-2.8.7-140104/src/compmanager.cpp0000644000076400010400000000726511437471144013374 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "jdlib/miscutil.h" #include "compmanager.h" #include "cache.h" #include enum { MAX_COMPLETION = 50 }; CORE::Completion_Manager* instance_completion_manager = NULL; CORE::Completion_Manager* CORE::get_completion_manager() { if( ! instance_completion_manager ) instance_completion_manager = new Completion_Manager(); assert( instance_completion_manager ); return instance_completion_manager; } void CORE::delete_completion_manager() { if( instance_completion_manager ) delete instance_completion_manager; instance_completion_manager = NULL; } /////////////////////////////////////////////// using namespace CORE; Completion_Manager::Completion_Manager() { for( int i = 0; i < COMP_SIZE; ++i ){ m_lists.push_back( new COMPLIST ); load_info( i ); } } Completion_Manager::~Completion_Manager() { for( int i = 0; i < COMP_SIZE; ++i ){ delete m_lists[ i ]; } } void Completion_Manager::save_session() { for( int i = 0; i < COMP_SIZE; ++i ){ save_info( i ); } } COMPLIST Completion_Manager::get_list( const int mode, const std::string& query ) { COMPLIST complist; if( mode < COMP_SIZE ){ #ifdef _DEBUG std::cout << "Completion_Manager::get_list mode = " << mode << " query = " << query << std::endl; #endif if( query.empty() || query == " " || query == " " // 全角スペース ) complist = *m_lists[ mode ]; else{ std::string tmp_query = MISC::tolower_str( query ); CORE::COMPLIST_ITERATOR it = m_lists[ mode ]->begin(); for( ; it != m_lists[ mode ]->end(); ++it ){ std::string tmp_str = MISC::tolower_str( *it ); if( tmp_str.find( tmp_query ) != std::string::npos ) complist.push_back( *it ); } } } return complist; } void Completion_Manager::set_query( const int mode, const std::string& query ) { if( ! query.empty() && mode < COMP_SIZE ){ #ifdef _DEBUG std::cout << "Completion_Manager::set_query mode = " << mode << " query = " << query << std::endl; #endif COMPLIST* complist = m_lists[ mode ]; complist->remove( query ); complist->push_front( query ); if( complist->size() > MAX_COMPLETION ) complist->pop_back(); } } void Completion_Manager::clear( const int mode ) { if( mode < COMP_SIZE ){ m_lists[ mode ]->clear(); std::string path = CACHE::path_completion( mode ); unlink( to_locale_cstr( path ) ); } } // 情報ファイル読み書き void Completion_Manager::load_info( const int mode ) { std::string path = CACHE::path_completion( mode ); std::string info; CACHE::load_rawdata( path, info ); #ifdef _DEBUG std::cout << "Completion_Manager::load_info path = " << path << std::endl << info << std::endl; #endif if( ! info.empty() ){ *m_lists[ mode ] = MISC::get_lines( info ); *m_lists[ mode ] = MISC::remove_nullline_from_list( *m_lists[ mode ] ); *m_lists[ mode ] = MISC::remove_space_from_list( *m_lists[ mode ] ); } } void Completion_Manager::save_info( const int mode ) { std::string info; COMPLIST* complist = m_lists[ mode ]; if( complist->size() ){ std::string path = CACHE::path_completion( mode ); COMPLIST_ITERATOR it = complist->begin(); for(; it != complist->end(); ++it ) info += (*it) + "\n"; #ifdef _DEBUG std::cout << "Completion_Manager::save_info path = " << path << std::endl << info << std::endl; #endif CACHE::save_rawdata( path, info ); } } jd-2.8.7-140104/src/compmanager.h0000644000076400010400000000221611437471144013030 0ustar // ライセンス: GPL2 // // Entryなどの補完管理クラス // #ifndef _COMPMANAGER_H #define _COMPMANAGER_H #include #include #include namespace CORE { enum { COMP_SEARCH_ARTICLE = 0, COMP_NAME, COMP_MAIL, COMP_SEARCH_BBSLIST, COMP_SEARCH_BOARD, COMP_SIZE }; typedef std::list COMPLIST; typedef std::list::iterator COMPLIST_ITERATOR; class Completion_Manager { std::vector< COMPLIST* > m_lists; public: Completion_Manager(); virtual ~Completion_Manager(); COMPLIST get_list( const int mode, const std::string& query ); void set_query( const int mode, const std::string& query ); void clear( const int mode ); void save_session(); private: // 情報ファイル読み書き void load_info( const int mode ); void save_info( const int mode ); }; /////////////////////////////////////// // インターフェース Completion_Manager* get_completion_manager(); void delete_completion_manager(); } #endif jd-2.8.7-140104/src/config/0000755000076400010400000000000012261751612011627 5ustar jd-2.8.7-140104/src/config/aboutconfig.cpp0000644000076400010400000006056512201335554014644 0ustar // ライセンス: GPL2 #ifdef HAVE_CONFIG_H #include "config.h" #endif //#define _DEBUG #include "jddebug.h" #include "aboutconfig.h" #include "aboutconfigdiag.h" #include "globalconf.h" #include "configitems.h" #include "defaultconf.h" #include "skeleton/msgdiag.h" #include "jdlib/miscutil.h" #include "colorid.h" enum { CONFTYPE_STR = 0, CONFTYPE_INT, CONFTYPE_BOOL, CONFTYPE_COMMENT }; using namespace CONFIG; AboutConfig::AboutConfig( Gtk::Window* parent ) : SKELETON::PrefDiag( parent, "", true ) { CONFIG::bkup_conf(); pack_widgets(); } // // widgetのパック // void AboutConfig::pack_widgets() { m_label.set_text( "動作保証外です。高度な設定を変更するとJDが誤作動する場合があります。" ); m_liststore = Gtk::ListStore::create( m_columns ); m_treeview.set_model( m_liststore ); m_treeview.set_size_request( 700, 400 ); m_treeview.signal_row_activated().connect( sigc::mem_fun( *this, &AboutConfig::slot_row_activated ) ); Gtk::TreeViewColumn* column = Gtk::manage( new Gtk::TreeViewColumn( "設定名", m_columns.m_col_name ) ); column->set_fixed_width( 540 ); column->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ); column->set_resizable( true ); m_treeview.append_column( *column ); Gtk::CellRenderer *cell = column->get_first_cell_renderer(); if( cell ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &AboutConfig::slot_cell_data ) ); column = Gtk::manage( new Gtk::TreeViewColumn( "値", m_columns.m_col_value ) ); m_treeview.append_column( *column ); cell = column->get_first_cell_renderer(); if( cell ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &AboutConfig::slot_cell_data ) ); m_scrollwin.add( m_treeview ); m_scrollwin.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_label, Gtk::PACK_SHRINK ); get_vbox()->pack_start( m_scrollwin ); set_title( "about:config 高度な設定" ); show_all_children(); append_rows(); } // // OK // void AboutConfig::slot_ok_clicked() { SKELETON::MsgDiag mdiag( NULL, "一部の設定はJDを再起動しない限り有効になりません。JDを再起動してください。" ); mdiag.run(); } // // キャンセルが押されたら設定を戻す // void AboutConfig::slot_cancel_clicked() { CONFIG::restore_conf(); } // // 実際の描画の際に cellrendere のプロパティをセットするスロット関数 // void AboutConfig::slot_cell_data( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ) { Gtk::TreeModel::Row row = *it; if( row[ m_columns.m_col_drawbg ] ){ cell->property_cell_background() = CONFIG::get_color( COLOR_BACK_HIGHLIGHT_TREE ); cell->property_cell_background_set() = true; } else cell->property_cell_background_set() = false; } void AboutConfig::append_rows() { // ネットワーク append_row( "■ ネットワーク" ); append_row( "JD ホームページのアドレス", get_confitem()->url_jdhp, CONF_URL_JDHP ); append_row( "板一覧を取得するサーバ", get_confitem()->url_bbsmenu, CONF_URL_BBSMENU ); append_row( "2chログイン認証サーバのアドレス", get_confitem()->url_login2ch, CONF_LOGIN2CH ); append_row( "p2ログイン認証サーバのアドレス", get_confitem()->url_loginp2, CONF_LOGINP2 ); append_row( "BE認証サーバのアドレス", get_confitem()->url_loginbe, CONF_LOGINBE ); append_row( "2chにアクセスするときのエージェント名", get_confitem()->agent_for2ch, CONF_AGENT_FOR2CH ); append_row( "2ch以外のサーバにアクセスするときのエージェント名", get_confitem()->agent_for_data, CONF_AGENT_FOR_DATA ); append_row( "2chログイン認証サーバにアクセスするときのエージェント名", get_confitem()->x_2ch_ua, CONF_X_2CH_UA ); append_row( "スレの読み込み時のタイムアウト値(秒)", get_confitem()->loader_timeout, CONF_LOADER_TIMEOUT ); append_row( "書き込み時のタイムアウト値(秒)", get_confitem()->loader_timeout_post, CONF_LOADER_TIMEOUT_POST ); append_row( "画像等のデータのロード時のタイムアウト値(秒)", get_confitem()->loader_timeout_img, CONF_LOADER_TIMEOUT_IMG ); append_row( "更新チェック時のタイムアウト値(秒)", get_confitem()->loader_timeout_checkupdate, CONF_LOADER_TIMEOUT_CHECKUPDATE ); append_row( "一般データのダウンロード時のバッファサイズ(Kbyte)", get_confitem()->loader_bufsize, CONF_LOADER_BUFSIZE ); append_row( "スレ一覧のダウンロード時のバッファサイズ(Kbyte)", get_confitem()->loader_bufsize_board, CONF_LOADER_BUFSIZE_BOARD ); append_row( "同一ホストに対する最大コネクション数( 1 または 2 )", get_confitem()->connection_num, CONF_CONNECTION_NUM ); append_row( "2chのクッキー:HAPを保存する", get_confitem()->use_cookie_hap, CONF_USE_COOKIE_HAP ); append_row( "2chのクッキー:HAP", get_confitem()->cookie_hap, CONF_COOKIE_HAP ); append_row( "BBSPINKのクッキー:HAP", get_confitem()->cookie_hap_bbspink, CONF_COOKIE_HAP_BBSPINK ); // ツリービュー append_row( "" ); append_row( "■ ツリービュー(板一覧、スレ一覧)" ); append_row( "ツリービューでマウスホイールを回したときのスクロール量(行数)", get_confitem()->tree_scroll_size, CONF_TREE_SCROLL_SIZE ); append_row( "ツリービューの行間スペース", get_confitem()->tree_ypad, CONF_TREE_YPAD ); append_row( "ツリービューのエクスパンダを表示する", get_confitem()->tree_show_expanders, CONF_TREE_SHOW_EXPANDERS ); append_row( "ツリービューのレベルインデント調整量(ピクセル)", get_confitem()->tree_level_indent, CONF_TREE_LEVEL_INDENT ); append_row( "カテゴリを開いたときにスクロールする", get_confitem()->scroll_tree, CONF_SCROLL_TREE ); append_row( "ツリービューの選択を、表示中のビューと同期する ( 0: 同期しない 1: 同期する 2: 同期する(フォルダを開く) )", get_confitem()->select_item_sync, CONF_SCROLL_TREE ); // 板一覧、履歴ビュー append_row( "" ); append_row( "■ 板一覧、履歴ビュー" ); append_row( "板移転時に確認ダイアログを表示する", get_confitem()->show_movediag, CONF_SHOW_MOVEDIAG ); append_row( "板一覧内にあるリンクを全て板とみなす", get_confitem()->use_link_as_board, CONF_USE_LINK_AS_BOARD ); append_row( "板一覧でカテゴリを常にひとつだけ開く", get_confitem()->open_one_category, CONF_OPEN_ONE_CATEGORY ); append_row( "右ペーンが空の時にサイドバーを最大化する", get_confitem()->expand_sidebar, CONF_EXPAND_SIDEBAR ); append_row( "ペーン境界をクリックしてサイドバーを開け閉めする", get_confitem()->open_sidebar_by_click, CONF_OPEN_SIDEBAR_BY_CLICK ); append_row( "更新チェック時に板の更新もチェックする", get_confitem()->check_update_board, CONF_CHECK_UPDATE_BOARD ); append_row( "履歴ビューの最大表示数", get_confitem()->historyview_size, CONF_HISTORYVIEW_SIZE ); // お気に入り append_row( "" ); append_row( "■ お気に入り" ); append_row( "お気に入りでカテゴリを常にひとつだけ開く", get_confitem()->open_one_favorite, CONF_OPEN_ONE_FAVORITE ); append_row( "スレをお気に入りに追加した時にしおりをセットする", get_confitem()->bookmark_drop, CONF_BOOKMARK_DROP ); append_row( "起動時にお気に入りを自動でチェックする", get_confitem()->check_update_boot, CONF_CHECK_UPDATE_BOOT ); append_row( "重複項目を登録する ( 0: 登録する 1: ダイアログ表示 2: 登録しない )", get_confitem()->check_favorite_dup, CONF_CHECK_FAVORITE_DUP ); append_row( "登録時に挿入先ダイアログ表示 ( 0 : 表示 1: 表示せず先頭に追加 2: 表示せず最後に追加 )", get_confitem()->show_favorite_select_diag, CONF_SHOW_FAVORITE_SELECT_DIAG ); // スレ一覧 append_row( "" ); append_row( "■ スレ一覧" ); append_row( "インクリメント検索をする", get_confitem()->inc_search_board, CONF_INC_SEARCH_BOARD ); append_row( "deleteを押したときに確認ダイアログを表示", get_confitem()->show_deldiag, CONF_SHOW_DELDIAG ); append_row( "指定した値(時間)よりも後に立てられたスレを新着とみなす", get_confitem()->newthread_hour, CONF_NEWTHREAD_HOUR ); append_row( "3ペーン時にスレ一覧やスレビューを最大化する", get_confitem()->expand_rpane, CONF_EXPAND_RPANE ); append_row( "スレ一覧をロードする前にキャッシュにある一覧を表示する", get_confitem()->show_cached_board, CONF_SHOW_CACHED_BOARD ); append_row( "お知らせスレ(924)のアイコンを表示する", get_confitem()->show_924, CONF_SHOW_924 ); append_row( "dat落ちしたスレをNGスレタイトルから除く( 0: ダイアログ表示 1: 除く 2: 除かない )", get_confitem()->remove_old_abone_thread, CONF_REMOVE_OLD_ABONE_THREAD ); append_row( "dat落ちしたスレを表示する", get_confitem()->show_oldarticle, CONF_SHOW_OLDARTICLE ); // スレビュー append_row( "" ); append_row( "■ スレビュー" ); append_row( "マウスホイールを回したときのスクロール速度", get_confitem()->scroll_size, CONF_SCROLL_SIZE ); append_row( "上下キーを押したときのスクロール速度", get_confitem()->key_scroll_size, CONF_KEY_SCROLL_SIZE ); append_row( "pageup、pagedownキーを押したときのスクロール速度", get_confitem()->key_fastscroll_size, CONF_KEY_FASTSCROLL_SIZE ); append_row( "リロード後に末尾に自動的に移動する", get_confitem()->jump_after_reload, CONF_JUMP_AFTER_RELOAD ); append_row( "リロード後に新着レスに自動的に移動する", get_confitem()->jump_new_after_reload, CONF_JUMP_NEW_AFTER_RELOAD ); append_row( "ポップアップとカーソルの間の間隔(ピクセル)", get_confitem()->margin_popup, CONF_MARGIN_POPUP ); append_row( "画像ポップアップとカーソルの間の水平間隔(ピクセル)", get_confitem()->margin_imgpopup_x, CONF_MARGIN_IMGPOPUP_X ); append_row( "画像ポップアップとカーソルの間の垂直間隔(ピクセル)", get_confitem()->margin_imgpopup, CONF_MARGIN_IMGPOPUP ); append_row( "ポップアップが消えるまでの時間(ミリ秒)", get_confitem()->hide_popup_msec, CONF_HIDE_POPUP_MSEC ); append_row( "多重ポップアップの説明を表示する", get_confitem()->instruct_popup, CONF_INSTRUCT_POPUP ); append_row( "レス番号の上にマウスオーバーしたときに参照ポップアップ表示する", get_confitem()->refpopup_by_mo, CONF_REFPOPUP_BY_MO ); append_row( "「名前」の上にマウスオーバーしたときにポップアップ表示する", get_confitem()->namepopup_by_mo, CONF_NAMEPOPUP_BY_MO ); append_row( "IDの上にマウスオーバーしたときにIDをポップアップ表示する", get_confitem()->idpopup_by_mo, CONF_IDPOPUP_BY_MO ); append_row( "スレビューとスレ一覧の切り替え方法説明ダイアログを表示する", get_confitem()->instruct_tglart, CONF_INSTRUCT_TGLART ); append_row( "画像ビューとスレビューの切り替え方法説明ダイアログを表示する", get_confitem()->instruct_tglimg, CONF_INSTRUCT_TGLIMG ); append_row( "deleteを押したときに確認ダイアログを表示", get_confitem()->show_delartdiag, CONF_SHOW_DELARTDIAG ); append_row( "リンクの下線を表示する", get_confitem()->draw_underline, CONF_DRAW_UNDERLINE ); append_row( "レスを引用コピーするときに前に付ける引用文字", get_confitem()->ref_prefix, CONF_REF_PREFIX ); append_row( "引用文字の後のスペース数", get_confitem()->ref_prefix_space, CONF_REF_PREFIX_SPACE ); append_row( "RFC規定外の文字(^など)もURL判定に用いる", get_confitem()->loose_url, CONF_LOOSE_URL ); append_row( "再読み込みボタンを押したときに全タブを更新する", get_confitem()->reload_allthreads, CONF_RELOAD_ALLTHREAD ); append_row( "発言(同一ID)数をカウントする", get_confitem()->check_id, CONF_CHECK_ID ); append_row( "レス参照数で色を変える回数(高)", get_confitem()->num_reference_high, CONF_NUM_REFERENCE_HIGH ); append_row( "レス参照数で色を変える回数(低)", get_confitem()->num_reference_low, CONF_NUM_REFERENCE_LOW ); append_row( "発言数で色を変える回数(高)", get_confitem()->num_id_high, CONF_NUM_ID_HIGH ); append_row( "発言数で色を変える回数(低)", get_confitem()->num_id_low, CONF_NUM_ID_LOW ); append_row( "WEB検索用のメニュー項目名", get_confitem()->menu_search_web, CONF_MENU_SEARCH_WEB ); append_row( "WEB検索用のアドレス", get_confitem()->url_search_web, CONF_URL_SEARCH_WEB ); append_row( "デフォルトで透明あぼーん", get_confitem()->abone_transparent, CONF_ABONE_TRANSPARENT ); append_row( "デフォルトで連鎖あぼーん", get_confitem()->abone_chain, CONF_ABONE_CHAIN ); append_row( "書き込み履歴のあるスレを削除する時にダイアログを表示", get_confitem()->show_del_written_thread_diag, CONF_SHOW_DEL_WRITTEN_THREAD_DIAG ); append_row( "スレを削除する時に画像キャッシュも削除する ( 0: ダイアログ表示 1: 削除 2: 削除しない )", get_confitem()->delete_img_in_thread, CONF_DELETE_IMG_IN_THREAD ); // 書き込みウィンドウ append_row( "" ); append_row( "■ 書き込みビュー" ); append_row( "デフォルトの書き込み名", get_confitem()->write_name, CONF_WRITE_NAME ); append_row( "デフォルトのメールアドレス", get_confitem()->write_mail, CONF_WRITE_MAIL ); append_row( "書き込み時に確認ダイアログを表示しない", get_confitem()->always_write_ok, CONF_ALWAYS_WRITE_OK ); append_row( "書き込み中ダイアログを表示しない", get_confitem()->hide_writing_dialog, CONF_HIDE_WRITING_DIALOG ); append_row( "編集中のメッセージの保存確認ダイアログを表示する", get_confitem()->show_savemsgdiag, CONF_SHOW_SAVEMSGDIAG ); append_row( "アスキーアートメニューの履歴の保持数", get_confitem()->aahistory_size, CONF_AAHISTORY ); append_row( "書き込みログの最大サイズ(バイト)", get_confitem()->maxsize_postlog, CONF_MAXSIZE_POSTLOG ); append_row( "ビューを閉じても書き込み欄の日本語のON/OFF状態を保つ", get_confitem()->keep_im_status, CONF_KEEP_IM_STATUS ); // 画像 append_row( "" ); append_row( "■ 画像" ); append_row( "画像ポップアップの幅(ピクセル)", get_confitem()->imgpopup_width, CONF_IMGPOPUP_WIDTH ); append_row( "画像ポップアップの高さ(ピクセル)", get_confitem()->imgpopup_height, CONF_IMGPOPUP_HEIGHT ); append_row( "画像ビューを開いたときにウィンドウサイズに合わせる", get_confitem()->zoom_to_fit, CONF_ZOOM_TO_FIT ); append_row( "画像ビューのフォーカスが外れたら折りたたむ", get_confitem()->fold_image, CONF_FOLD_IMAGE ); append_row( "埋め込み画像ビューを閉じたときにタブも閉じる", get_confitem()->hide_imagetab, CONF_HIDE_IMAGETAB ); append_row( "指定したサイズ(M byte)より大きい画像を表示するときに警告する", get_confitem()->max_img_size, CONF_MAX_IMG_SIZE ); append_row( "指定した画素数(M pixel)より大きい画像を表示するときに警告する", get_confitem()->max_img_pixel, CONF_MAX_IMG_PIXEL ); append_row( "モザイクのレベル", get_confitem()->mosaic_size, CONF_MOSAIC_SIZE ); append_row( "画像ビューのスムージングレベル(0-2, 大きい程高画質で低速)", get_confitem()->imgmain_interp, CONF_IMGMAIN_INTERP ); append_row( "インライン画像のスムージングレベル(0-2, 大きい程高画質で低速)", get_confitem()->imgemb_interp, CONF_IMGEMB_INTERP ); append_row( "インライン画像の最大幅", get_confitem()->embimg_width, CONF_EMBIMG_WIDTH ); append_row( "インライン画像の最大高さ", get_confitem()->embimg_height, CONF_EMBIMG_HEIGHT ); append_row( "ポップアップ画像のスムージングレベル(0-2, 大きい程高画質で低速)", get_confitem()->imgpopup_interp, CONF_IMGPOPUP_INTERP ); append_row( "画像のメモリキャッシュ枚数", get_confitem()->imgcache_size, CONF_IMGCACHE_SIZE ); append_row( "deleteを押したときに確認ダイアログを表示", get_confitem()->show_delimgdiag, CONF_SHOW_DELIMGDIAG ); // ウィンドウ append_row( "" ); append_row( "■ ウィンドウ" ); append_row( "タブにアイコンを表示する", get_confitem()->show_tab_icon, CONF_SHOW_TAB_ICON ); append_row( "タブに表示する文字列の最小文字数", get_confitem()->tab_min_str, CONF_TAB_MIN_STR ); append_row( "タブ上でマウスホイールを回転してタブを切り替える", get_confitem()->switchtab_wheel, CONF_SWITCHTAB_WHEEL ); append_row( "ビュー内から他のビューを開いたときのタブの位置 ( 0: 一番右端 1:右隣 2:左隣 )", get_confitem()->newtab_pos, CONF_NEWTAB_POS ); append_row( "各ビューと枠との間の余白", get_confitem()->view_margin, CONF_VIEW_MARGIN ); append_row( "自前でウィンドウ配置を管理する", get_confitem()->manage_winpos, CONF_MANAGE_WINPOS ); append_row( "スレビューのスクロールバーを左に配置する", get_confitem()->left_scrbar, CONF_LEFT_SCRBAR ); append_row( "メニューバーを非表示にした時にダイアログを表示", get_confitem()->show_hide_menubar_diag, CONF_SHOW_HIDE_MENUBAR_DIAG ); append_row( "状態変更時にメインステータスバーの色を変える", get_confitem()->change_stastatus_color, CONF_CHANGE_STASTATUS_COLOR ); // 次スレ検索 append_row( "" ); append_row( "■ 次スレ検索" ); append_row( "類似度判定のしきい値(小さいほど判定が甘くなる、最大10)", get_confitem()->threshold_next, CONF_THRESHOLD_NEXT ); append_row( "移行時にお気に入りのアドレスと名前を自動更新する(0: しない, 1:する, 2:追加)", get_confitem()->replace_favorite_next, CONF_REPLACE_FAVORITE_NEXT ); append_row( "お気に入り自動更新の確認ダイアログを表示する", get_confitem()->show_diag_replace_favorite, CONF_SHOW_DIAG_REPLACE_FAVORITE ); append_row( "次スレ検索を開くときのタブの位置 ( 0: 次スレ検索タブ 1:新しいタブ 2:アクティブなタブを置き換え )", get_confitem()->boardnexttab_pos, CONF_BOARDNEXTTAB_POS ); // スレタイ検索 append_row( "" ); append_row( "■ スレタイ検索" ); append_row( "スレタイ検索用のメニュー項目名", get_confitem()->menu_search_title, CONF_MENU_SEARCH_TITLE ); append_row( "スレタイ検索用のアドレス", get_confitem()->url_search_title, CONF_URL_SEARCH_TITLE ); append_row( "スレタイ検索時にアドレスとスレタイを取得する正規表現", get_confitem()->regex_search_title, CONF_REGEX_SEARCH_TITLE ); // その他 append_row( "" ); append_row( "■ その他" ); append_row( "履歴メニューの表示数", get_confitem()->history_size, CONF_HISTORY_SIZE ); append_row( "マウスジェスチャを有効にする", get_confitem()->enable_mg, CONF_ENABLE_MG ); append_row( "マウスジェスチャの判定開始半径", get_confitem()->mouse_radius, CONF_MOUSE_RADIUS ); append_row( "数字入力ジャンプの待ち時間(ミリ秒)", get_confitem()->numberjmp_msec, CONF_NUMBERJMP_MSEC ); append_row( "起動時に開いていたスレ一覧を復元する", get_confitem()->restore_board, CONF_RESTORE_BOARD ); append_row( "起動時に開いていたスレを復元する", get_confitem()->restore_article, CONF_RESTORE_ARTICLE ); append_row( "起動時に開いていた画像を復元する", get_confitem()->restore_image, CONF_RESTORE_IMAGE ); #ifdef HAVE_MIGEMO_H append_row( "migemoの辞書ファイルの場所(migemo使用時のみ)", get_confitem()->migemodict_path, CONF_MIGEMO_PATH ); #endif append_row( "FIFOの作成などにエラーがあったらダイアログを表示する", get_confitem()->show_diag_fifo_error, CONF_SHOW_DIAG_FIFO_ERROR ); append_row( "指定した分ごとにセッションを自動保存 (0: 保存しない)", get_confitem()->save_session, CONF_SAVE_SESSION ); } void AboutConfig::append_row( const std::string& name, std::string& value, const std::string& defaultval ) { Gtk::TreeModel::Row row; row = *( m_liststore->append() ); row[ m_columns.m_col_name ] = name; row[ m_columns.m_col_type ] = CONFTYPE_STR; row[ m_columns.m_col_drawbg ] = false; row[ m_columns.m_col_value_str ] = &value; row[ m_columns.m_col_default_str ] = defaultval; set_value( row, value ); } void AboutConfig::append_row( const std::string& name, int& value, const int defaultval ) { Gtk::TreeModel::Row row; row = *( m_liststore->append() ); row[ m_columns.m_col_name ] = name; row[ m_columns.m_col_type ] = CONFTYPE_INT; row[ m_columns.m_col_drawbg ] = false; row[ m_columns.m_col_value_int ] = &value; row[ m_columns.m_col_default_int ] = defaultval; set_value( row, value ); } void AboutConfig::append_row( const std::string& name, bool& value, const bool defaultval ) { Gtk::TreeModel::Row row; row = *( m_liststore->append() ); row[ m_columns.m_col_name ] = name; row[ m_columns.m_col_type ] = CONFTYPE_BOOL; row[ m_columns.m_col_drawbg ] = false; row[ m_columns.m_col_value_bool ] = &value; row[ m_columns.m_col_default_bool ] = defaultval; set_value( row, value ); } void AboutConfig::append_row( const std::string& comment ) { Gtk::TreeModel::Row row; row = *( m_liststore->append() ); row[ m_columns.m_col_name ] = comment; row[ m_columns.m_col_type ] = CONFTYPE_COMMENT; } void AboutConfig::set_value( Gtk::TreeModel::Row& row, const std::string& value ) { row[ m_columns.m_col_value ] = value; const std::string defaultval = row[ m_columns.m_col_default_str ]; if( value != defaultval ) row[ m_columns.m_col_drawbg ] = true; else row[ m_columns.m_col_drawbg ] = false; } void AboutConfig::set_value( Gtk::TreeModel::Row& row, const int& value ) { row[ m_columns.m_col_value ] = MISC::itostr( value ); const int defaultval = row[ m_columns.m_col_default_int ]; if( value != defaultval ) row[ m_columns.m_col_drawbg ] = true; else row[ m_columns.m_col_drawbg ] = false; } void AboutConfig::set_value( Gtk::TreeModel::Row& row, const bool& value ) { if( value ) row[ m_columns.m_col_value ] = "はい"; else row[ m_columns.m_col_value ] = "いいえ"; const bool defaultval = row[ m_columns.m_col_default_bool ]; if( value != defaultval ) row[ m_columns.m_col_drawbg ] = true; else row[ m_columns.m_col_drawbg ] = false; } void AboutConfig::slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ) { #ifdef _DEBUG std::cout << "AboutConfig::slot_row_activated path = " << path.to_string() << std::endl; #endif Gtk::TreeModel::Row row = *( m_liststore->get_iter( path ) ); if( ! row ) return; const int type = row[ m_columns.m_col_type ]; if( type == CONFTYPE_COMMENT ) return; SKELETON::PrefDiag* pref = NULL; switch( type ){ case CONFTYPE_STR: pref = new AboutConfigDiagStr( this, row[ m_columns.m_col_value_str ], row[ m_columns.m_col_default_str ] ); pref->run(); set_value( row, *row[ m_columns.m_col_value_str ] ); break; case CONFTYPE_INT: pref = new AboutConfigDiagInt( this, row[ m_columns.m_col_value_int ], row[ m_columns.m_col_default_int ] ); pref->run(); set_value( row, *row[ m_columns.m_col_value_int ] ); break; case CONFTYPE_BOOL: pref = new AboutConfigDiagBool( this, row[ m_columns.m_col_value_bool ], row[ m_columns.m_col_default_bool ] ); pref->run(); set_value( row, *row[ m_columns.m_col_value_bool ] ); break; } if( pref ) delete pref; } jd-2.8.7-140104/src/config/aboutconfig.h0000644000076400010400000000466611076363467014326 0ustar // ライセンス: GPL2 // about:config #ifndef _ABOUTCONFIG_H #define _ABOUTCONFIG_H #include "skeleton/prefdiag.h" namespace CONFIG { class TreeColumn : public Gtk::TreeModel::ColumnRecord { public: Gtk::TreeModelColumn< Glib::ustring > m_col_name; Gtk::TreeModelColumn< Glib::ustring > m_col_value; Gtk::TreeModelColumn< int > m_col_type; Gtk::TreeModelColumn< bool > m_col_drawbg; Gtk::TreeModelColumn< std::string* > m_col_value_str; Gtk::TreeModelColumn< int* > m_col_value_int; Gtk::TreeModelColumn< bool* > m_col_value_bool; Gtk::TreeModelColumn< std::string > m_col_default_str; Gtk::TreeModelColumn< int > m_col_default_int; Gtk::TreeModelColumn< bool > m_col_default_bool; TreeColumn() { add( m_col_name ); add( m_col_value ); add( m_col_type ); add( m_col_drawbg ); add( m_col_value_str ); add( m_col_value_int ); add( m_col_value_bool ); add( m_col_default_str ); add( m_col_default_int ); add( m_col_default_bool ); } }; //////////////////////////////// class AboutConfig : public SKELETON::PrefDiag { Gtk::Label m_label; Gtk::TreeView m_treeview; Glib::RefPtr< Gtk::ListStore > m_liststore; TreeColumn m_columns; Gtk::ScrolledWindow m_scrollwin; public: AboutConfig( Gtk::Window* parent ); virtual ~AboutConfig(){} private: void pack_widgets(); virtual void slot_ok_clicked(); virtual void slot_cancel_clicked(); void slot_cell_data( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ); void append_rows(); void append_row( const std::string& name, std::string& value, const std::string& defaultval ); void append_row( const std::string& name, int& value, const int defaultval ); void append_row( const std::string& name, bool& value, const bool defaultval ); void append_row( const std::string& comment ); void set_value( Gtk::TreeModel::Row& row, const std::string& value ); void set_value( Gtk::TreeModel::Row& row, const int& value ); void set_value( Gtk::TreeModel::Row& row, const bool& value ); void slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ); }; } #endif jd-2.8.7-140104/src/config/aboutconfigdiag.cpp0000644000076400010400000000604111357364652015472 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "aboutconfigdiag.h" #include "jdlib/miscutil.h" using namespace CONFIG; AboutConfigDiagStr::AboutConfigDiagStr( Gtk::Window* parent, std::string* value, const std::string& defaultval ) : SKELETON::PrefDiag( parent, "", true ), m_value( value ), m_defaultval( defaultval ), m_button_default( "デフォルト" ) { resize( 600, 1 ); m_entry.set_text( *value ); m_hbox.pack_start( m_entry ); m_button_default.signal_clicked().connect( sigc::mem_fun( *this, &AboutConfigDiagStr::slot_default ) ); m_hbox.pack_start( m_button_default, Gtk::PACK_SHRINK ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_hbox ); set_activate_entry( m_entry ); set_title( "文字列設定" ); show_all_children(); } void AboutConfigDiagStr::slot_ok_clicked() { if( m_value ) *m_value = m_entry.get_text(); } void AboutConfigDiagStr::slot_default() { m_entry.set_text( m_defaultval ); } /////////////////////////////////////////// AboutConfigDiagInt::AboutConfigDiagInt( Gtk::Window* parent, int* value, const int defaultval ) : SKELETON::PrefDiag( parent, "", true ), m_value( value ), m_defaultval( defaultval ), m_button_default( "デフォルト" ) { resize( 200, 1 ); m_entry.set_text( MISC::itostr( *value ) ); m_hbox.pack_start( m_entry ); m_button_default.signal_clicked().connect( sigc::mem_fun( *this, &AboutConfigDiagInt::slot_default ) ); m_hbox.pack_start( m_button_default, Gtk::PACK_SHRINK ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_hbox ); set_activate_entry( m_entry ); set_title( "整数値設定" ); show_all_children(); } void AboutConfigDiagInt::slot_ok_clicked() { if( m_value ) *m_value = atoi( m_entry.get_text().c_str() ); } void AboutConfigDiagInt::slot_default() { m_entry.set_text( MISC::itostr( m_defaultval ) ); } /////////////////////////////////////////// AboutConfigDiagBool::AboutConfigDiagBool( Gtk::Window* parent, bool* value, const bool defaultval ) : SKELETON::PrefDiag( parent, "", true ), m_value( value ), m_defaultval( defaultval ), m_radio_true( "はい" ), m_radio_false( "いいえ" ), m_button_default( "デフォルト" ) { m_radio_true.set_group( m_radiogroup ); m_radio_false.set_group( m_radiogroup ); if( *value ) m_radio_true.set_active(); else m_radio_false.set_active(); m_hbox.pack_start( m_radio_true ); m_hbox.pack_start( m_radio_false ); m_button_default.signal_clicked().connect( sigc::mem_fun( *this, &AboutConfigDiagBool::slot_default ) ); m_hbox.pack_start( m_button_default, Gtk::PACK_SHRINK ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_hbox ); set_title( "真偽値設定" ); show_all_children(); } void AboutConfigDiagBool::slot_ok_clicked() { if( m_value ) *m_value = m_radio_true.get_active(); } void AboutConfigDiagBool::slot_default() { if( m_defaultval ) m_radio_true.set_active(); else m_radio_false.set_active(); } jd-2.8.7-140104/src/config/aboutconfigdiag.h0000644000076400010400000000316611022525245015126 0ustar // ライセンス: GPL2 // about:config から開く設定ダイアログ #ifndef _ABOUTCONFIGDIAG_H #define _ABOUTCONFIGDIAG_H #include "skeleton/prefdiag.h" namespace CONFIG { class AboutConfigDiagStr : public SKELETON::PrefDiag { std::string* m_value; const std::string m_defaultval; Gtk::HBox m_hbox; Gtk::Entry m_entry; Gtk::Button m_button_default; public: AboutConfigDiagStr( Gtk::Window* parent, std::string* value, const std::string& defaultval ); protected: virtual void slot_ok_clicked(); void slot_default(); }; ///////////////////////////////////////////// class AboutConfigDiagInt : public SKELETON::PrefDiag { int* m_value; const int m_defaultval; Gtk::HBox m_hbox; Gtk::Entry m_entry; Gtk::Button m_button_default; public: AboutConfigDiagInt( Gtk::Window* parent, int* value, const int defaultval ); protected: virtual void slot_ok_clicked(); void slot_default(); }; ///////////////////////////////////////////// class AboutConfigDiagBool : public SKELETON::PrefDiag { bool* m_value; const bool m_defaultval; Gtk::HBox m_hbox; Gtk::RadioButtonGroup m_radiogroup; Gtk::RadioButton m_radio_true; Gtk::RadioButton m_radio_false; Gtk::Button m_button_default; public: AboutConfigDiagBool( Gtk::Window* parent, bool* value, const bool defaultval ); protected: virtual void slot_ok_clicked(); void slot_default(); }; } #endif jd-2.8.7-140104/src/config/configitems.cpp0000644000076400010400000014462012177057552014661 0ustar // ライセンス: GPL2 #ifdef HAVE_CONFIG_H #include "config.h" #endif //#define _DEBUG #include "jddebug.h" #include "configitems.h" #include "defaultconf.h" #include "jdlib/confloader.h" #include "jdlib/miscutil.h" #include "jdlib/miscgtk.h" #include "jdlib/jdregex.h" #include "skeleton/msgdiag.h" #include "colorid.h" #include "fontid.h" #include "global.h" #include "cache.h" #include "browsers.h" #include using namespace CONFIG; // // デフォルトフォント取得 // #define IS_DEFAULT_FONT( name ) do{ if( set_fonts.find( name ) != set_fonts.end() ) return name; } while(0) std::string get_default_font() { std::set< std::string > set_fonts = MISC::get_font_families(); // 上の方が優先順位が高い #ifdef _WIN32 IS_DEFAULT_FONT( "MS PGothic" ); IS_DEFAULT_FONT( "MS UI Gothic" ); #endif IS_DEFAULT_FONT( "IPA モナー Pゴシック" ); IS_DEFAULT_FONT( "IPAMonaPGothic" ); IS_DEFAULT_FONT( "Mona-VLGothic" ); IS_DEFAULT_FONT( "Mona" ); IS_DEFAULT_FONT( "Konatu" ); IS_DEFAULT_FONT( "VL Pゴシック" ); IS_DEFAULT_FONT( "VL PGothic" ); IS_DEFAULT_FONT( "さざなみゴシック" ); IS_DEFAULT_FONT( "Sazanami Gothic" ); IS_DEFAULT_FONT( "Sans" ); return std::string(); } //////////////////////////////////////// ConfigItems::ConfigItems() : m_loaded( false ) { str_color.resize( COLOR_NUM ); fontname.resize( FONT_NUM ); } ConfigItems::~ConfigItems() {} // 設定読み込み const bool ConfigItems::load( const bool restore ) { std::string path_conf; // restoreモード if( restore ) { path_conf = CACHE::path_conf_bkup(); } else { path_conf = CACHE::path_conf(); // 新設定ファイルが無く、かつキャッシュディレクトリが存在していたら旧ファイルから設定を引き継ぐ if( CACHE::file_exists( path_conf ) != CACHE::EXIST_FILE && CACHE::file_exists( CACHE::path_root() ) == CACHE::EXIST_DIR && CACHE::file_exists( CACHE::path_conf_old() ) == CACHE::EXIST_FILE ){ path_conf = CACHE::path_conf_old(); } } JDLIB::ConfLoader cf( path_conf, std::string() ); #ifdef _DEBUG std::cout << "ConfigItems::load" << std::endl << "conffile = " << path_conf << " empty = " << cf.empty() << std::endl; #endif std::string str_tmp; // 色 set_colors( cf ); // 前回開いたviewを復元するか restore_board = cf.get_option_bool( "restore_board", CONF_RESTORE_BOARD ); restore_article = cf.get_option_bool( "restore_article", CONF_RESTORE_ARTICLE ); restore_image = cf.get_option_bool( "restore_image", CONF_RESTORE_IMAGE ); // 自前でウィンドウ配置を管理する manage_winpos = cf.get_option_bool( "manage_winpos", CONF_MANAGE_WINPOS ); // フォント set_fonts( cf ); // レスを参照するときに前に付ける文字 ref_prefix = cf.get_option_str( "ref_prefix", CONF_REF_PREFIX, 16 ); // 参照文字( ref_prefix ) の後のスペースの数 // JDLIB::ConfLoader の中で MISC::remove_space() が呼ばれて空白が消えるので別設定とした ref_prefix_space = cf.get_option_int( "ref_prefix_space", CONF_REF_PREFIX_SPACE, 0, 16 ); for( int i = 0; i < ref_prefix_space; ++i ) ref_prefix_space_str += " "; // レスにアスキーアートがあると判定する正規表現 regex_res_aa = cf.get_option_str( "regex_res_aa", CONF_REGEX_RES_AA ); // キャッシュのルートディレクトリ(旧バージョンとの互換のため残している) path_cacheroot = cf.get_option_str( "path_cacheroot", CONF_PATH_CACHEROOT ); // 読み込み用プロクシとポート番号 use_proxy_for2ch = cf.get_option_bool( "use_proxy_for2ch", CONF_USE_PROXY_FOR2CH ); str_tmp = cf.get_option_str( "proxy_for2ch", "" ); set_proxy_for2ch( str_tmp ); proxy_port_for2ch = cf.get_option_int( "proxy_port_for2ch", CONF_PROXY_PORT_FOR2CH, 1, 65535 ); // 書き込み用プロクシとポート番号 use_proxy_for2ch_w = cf.get_option_bool( "use_proxy_for2ch_w", CONF_USE_PROXY_FOR2CH_W ); str_tmp = cf.get_option_str( "proxy_for2ch_w", "" ); set_proxy_for2ch_w( str_tmp ); proxy_port_for2ch_w = cf.get_option_int( "proxy_port_for2ch_w", CONF_PROXY_PORT_FOR2CH_W, 1, 65535 ); // 2chの外にアクセスするときのプロクシとポート番号 use_proxy_for_data = cf.get_option_bool( "use_proxy_for_data", CONF_USE_PROXY_FOR_DATA ); str_tmp = cf.get_option_str( "proxy_for_data", "" ); set_proxy_for_data( str_tmp ); proxy_port_for_data = cf.get_option_int( "proxy_port_for_data", CONF_PROXY_PORT_FOR_DATA, 1, 65535 ); // 2ch にアクセスするときのエージェント名 agent_for2ch = cf.get_option_str( "agent_for2ch", CONF_AGENT_FOR2CH ); // 2ch外にアクセスするときのエージェント名 agent_for_data = cf.get_option_str( "agent_for_data", CONF_AGENT_FOR_DATA ); // 2ch にログインするときのX-2ch-UA x_2ch_ua = cf.get_option_str( "x_2ch_ua", CONF_X_2CH_UA ); // ローダのバッファサイズ loader_bufsize = cf.get_option_int( "loader_bufsize", CONF_LOADER_BUFSIZE, 1, 4096 ); // 一般 loader_bufsize_board = cf.get_option_int( "loader_bufsize_board", CONF_LOADER_BUFSIZE_BOARD, 1, 4096 ); // スレ一覧用 // ローダのタイムアウト値 loader_timeout = cf.get_option_int( "loader_timeout", CONF_LOADER_TIMEOUT, 1, 120 ); loader_timeout_post = cf.get_option_int( "loader_timeout_post", CONF_LOADER_TIMEOUT_POST, 1, 120 ); // ポスト loader_timeout_img = cf.get_option_int( "loader_timeout_img", CONF_LOADER_TIMEOUT_IMG, 1, 120 ); // 画像 loader_timeout_checkupdate = cf.get_option_int( "loader_timeout_checkupdate", CONF_LOADER_TIMEOUT_CHECKUPDATE, 1, 120 ); // 更新チェック // ipv6使用 use_ipv6 = cf.get_option_bool( "use_ipv6", CONF_USE_IPV6 ); // 同一ホストに対する最大コネクション数( 1 または 2 ) connection_num = cf.get_option_int( "connection_num", CONF_CONNECTION_NUM, 1, 2 ); // 2chのクッキー:HAPを保存する use_cookie_hap = cf.get_option_bool( "use_cookie_hap", CONF_USE_COOKIE_HAP ); // 2chのクッキー:HAP cookie_hap = cf.get_option_str( "cookie_hap", CONF_COOKIE_HAP ); cookie_hap_bbspink = cf.get_option_str( "cookie_hap_bbspink", CONF_COOKIE_HAP_BBSPINK ); // ブラウザ設定ダイアログのコンボボックスの番号 browsercombo_id = cf.get_option_int( "browsercombo_id", CONF_BROWSER_NO, 0, CORE::get_browser_number() -1 ); // リンクをクリックしたときに実行するコマンド command_openurl = cf.get_option_str( "command_openurl", CORE::get_browser_name( CONF_BROWSER_NO ) ); // レス番号の上にマウスオーバーしたときに参照ポップアップ表示する refpopup_by_mo = cf.get_option_bool( "refpopup_by_mo", CONF_REFPOPUP_BY_MO ); // 名前の上にマウスオーバーしたときにポップアップ表示する namepopup_by_mo = cf.get_option_bool( "namepopup_by_mo", CONF_NAMEPOPUP_BY_MO ); // IDの上にマウスオーバーしたときにIDをポップアップ表示する idpopup_by_mo = cf.get_option_bool( "idpopup_by_mo", CONF_IDPOPUP_BY_MO ); // 画像のスムージングレベル(0-2, 2が最も高画質かつ低速) imgemb_interp = cf.get_option_int( "imgemb_interp", CONF_IMGEMB_INTERP, 0, 2 ); imgmain_interp = cf.get_option_int( "imgmain_interp", CONF_IMGMAIN_INTERP, 0, 2 ); imgpopup_interp = cf.get_option_int( "imgpopup_interp", CONF_IMGPOPUP_INTERP, 0, 2 ); // 画像ポップアップサイズ imgpopup_width = cf.get_option_int( "imgpopup_width", CONF_IMGPOPUP_WIDTH, 16, 8192 ); imgpopup_height = cf.get_option_int( "imgpopup_height", CONF_IMGPOPUP_HEIGHT, 16, 8192 ); // 画像ポップアップを使用する use_image_popup = cf.get_option_bool( "use_image_popup", CONF_USE_IMAGE_POPUP ); // 画像ビューを使用する use_image_view = cf.get_option_bool( "use_image_view", CONF_USE_IMAGE_VIEW ); // インライン画像を表示する use_inline_image = cf.get_option_bool( "use_inline_image", CONF_INLINE_IMG ); // ssspアイコン表示 show_ssspicon = cf.get_option_bool( "show_ssspicon", CONF_SHOW_SSSPICON ); // インライン画像の最大幅と高さ embimg_width = cf.get_option_int( "embimg_width", CONF_EMBIMG_WIDTH, 16, 8192 ); embimg_height = cf.get_option_int( "embimg_height", CONF_EMBIMG_HEIGHT, 16, 8192 ); // 埋め込み画像ビューを閉じたときにタブも閉じる hide_imagetab = cf.get_option_bool( "hide_imagetab", CONF_HIDE_IMAGETAB ); // 画像ビューでdeleteを押したときに確認ダイアログを表示する show_delimgdiag = cf.get_option_bool( "show_delimgdiag", CONF_SHOW_DELIMGDIAG ); // 画像にモザイクをかける use_mosaic = cf.get_option_bool( "use_mosaic", CONF_USE_MOSAIC ); // モザイクの大きさ mosaic_size = cf.get_option_int( "mosaic_size", CONF_MOSAIC_SIZE, 1, 1024 ); // 画像をデフォルトでウィンドウサイズに合わせる zoom_to_fit = cf.get_option_bool( "zoom_to_fit", CONF_ZOOM_TO_FIT ); // 画像キャッシュ削除の日数 del_img_day = cf.get_option_int( "del_img_day", CONF_DEL_IMG_DAY, 0, 65535 ); // 画像あぼーん削除の日数 del_imgabone_day = cf.get_option_int( "del_imgabone_day", CONF_DEL_IMGABONE_DAY, 0, 65535 ); // ダウンロードする画像の最大ファイルサイズ(Mbyte) max_img_size = cf.get_option_int( "max_img_size", CONF_MAX_IMG_SIZE, 1, 1024 ); // 画像の最大サイズ(Mピクセル) max_img_pixel = cf.get_option_int( "max_img_pixel", CONF_MAX_IMG_PIXEL, 1, 1024 ); // 画像のメモリキャッシュ枚数 imgcache_size = cf.get_option_int( "imgcache_size", CONF_IMGCACHE_SIZE, 0, 20 ); // JD ホームページのアドレス url_jdhp = cf.get_option_str( "url_jdhp", CONF_URL_JDHP ); // 2chの認証サーバのアドレス url_login2ch = cf.get_option_str( "url_login2ch", CONF_LOGIN2CH ); // p2の認証サーバのアドレス url_loginp2 = cf.get_option_str( "url_loginp2", CONF_LOGINP2 ); // BEの認証サーバのアドレス url_loginbe = cf.get_option_str( "url_loginbe", CONF_LOGINBE ); // bbsmenu.htmlのURL url_bbsmenu = cf.get_option_str( "url_bbsmenu", CONF_URL_BBSMENU ); // bbsmenu.html内にあるリンクは全て板とみなす use_link_as_board = cf.get_option_bool( "use_link_as_board", CONF_USE_LINK_AS_BOARD ); // 板移転時に確認ダイアログを表示する show_movediag = cf.get_option_bool( "show_movediag", CONF_SHOW_MOVEDIAG ); // スレタイ検索用メニュータイトルアドレス menu_search_title = cf.get_option_str( "menu_search_title", CONF_MENU_SEARCH_TITLE ); url_search_title = cf.get_option_str( "url_search_title", CONF_URL_SEARCH_TITLE ); // p2 書き込み用アドレス url_writep2 = cf.get_option_str( "url_writep2", CONF_URL_WRITEP2 ); url_resp2 = cf.get_option_str( "url_resp2", CONF_URL_RESP2 ); // スレタイ検索用正規表現 regex_search_title = cf.get_option_str( "regex_search_title", CONF_REGEX_SEARCH_TITLE ); // web検索用メニュータイトルアドレス menu_search_web = cf.get_option_str( "menu_search_web", CONF_MENU_SEARCH_WEB ); url_search_web = cf.get_option_str( "url_search_web", CONF_URL_SEARCH_WEB ); // ツリービューでgtkrcの設定を使用するか use_tree_gtkrc = cf.get_option_bool( "use_tree_gtkrc", CONF_USE_TREE_GTKRC ); // スレビューの選択色でgtkrcの設定を使用するか use_select_gtkrc = cf.get_option_bool( "use_select_gtkrc", CONF_USE_SELECT_GTKRC ); // ツリービューの行間スペース tree_ypad = cf.get_option_int( "tree_ypad", CONF_TREE_YPAD, 0, 64 ); // ツリービューにエクスパンダを表示 tree_show_expanders = cf.get_option_bool( "tree_show_expanders", CONF_TREE_SHOW_EXPANDERS ); // ツリービューのレベルインデント調整量(ピクセル) tree_level_indent = cf.get_option_int( "tree_level_indent", CONF_TREE_LEVEL_INDENT, -256, 256 ); // カテゴリを開いたときにツリービューをスクロールする scroll_tree = cf.get_option_bool( "scroll_tree", CONF_SCROLL_TREE ); // ツリービューの選択を、表示中のビューと同期するか select_item_sync = cf.get_option_int( "select_item_sync", CONF_SELECT_ITEM_SYNC, 0, 2 ); // 各ビューと枠との間の余白 view_margin = cf.get_option_int( "view_margin", CONF_VIEW_MARGIN, 0, 64 ); // スクロールバーを左に配置 left_scrbar = cf.get_option_bool( "left_scrbar", CONF_LEFT_SCRBAR ); // スレ一覧で古いスレも表示 show_oldarticle = cf.get_option_bool( "show_oldarticle", CONF_SHOW_OLDARTICLE ); // スレ一覧で指定した値(時間)よりも後に立てられたスレを新着とみなす newthread_hour = cf.get_option_int( "newthread_hour", CONF_NEWTHREAD_HOUR, 1, 65535 ); // スレ一覧でインクリメント検索をする inc_search_board = cf.get_option_bool( "inc_search_board", CONF_INC_SEARCH_BOARD ); // スレ一覧でdeleteを押したときに確認ダイアログを表示する show_deldiag = cf.get_option_bool( "show_deldiag", CONF_SHOW_DELDIAG ); // スレ一覧をロードする前にキャッシュにある一覧を表示 show_cached_board = cf.get_option_bool( "show_cached_board", CONF_SHOW_CACHED_BOARD ); // スレ一覧でお知らせスレ(924)のアイコンを表示する show_924 = cf.get_option_bool( "show_924", CONF_SHOW_924 ); // ツリービューのスクロール量(行数) tree_scroll_size = cf.get_option_int( "tree_scroll_size", CONF_TREE_SCROLL_SIZE, 1, 64 ); // スレビューのスクロール量 scroll_size = cf.get_option_int( "scroll_size", CONF_SCROLL_SIZE, 1, 64 ); // スレビューのスクロール量(キー上下) key_scroll_size = cf.get_option_int( "key_scroll_size", CONF_KEY_SCROLL_SIZE, 1, 64 ); // スレビューの高速スクロール量(キー上下・ ページ高 - 行高 * key_fastscroll_size ) key_fastscroll_size = cf.get_option_int( "key_fastscroll_size", CONF_KEY_FASTSCROLL_SIZE, 1, 64 ); // スレビューでリロード後に一番下までスクロール jump_after_reload = cf.get_option_bool( "jump_after_reload", CONF_JUMP_AFTER_RELOAD ); // スレビューでリロード後に新着までスクロール jump_new_after_reload = cf.get_option_bool( "jump_new_after_reload", CONF_JUMP_NEW_AFTER_RELOAD ); // 実況モード live_mode = cf.get_option_int( "live_mode", LIVE_SCRMODE_VARIABLE, 0, LIVE_SCRMODE_NUM -1 ); // 実況速度 live_speed = cf.get_option_int( "live_speed", CONF_LIVE_SPEED, 0, 50 ); // 実況のスクロールモードを切り替えるしきい値 live_threshold = cf.get_option_int( "live_threshold", CONF_LIVE_THRESHOLD, 1, 1024 ); // 板一覧でカテゴリを常にひとつだけ開く open_one_category = cf.get_option_bool( "open_one_category", CONF_OPEN_ONE_CATEGORY ); // お気に入りでカテゴリを常にひとつだけ開く open_one_favorite = cf.get_option_bool( "open_one_favorite", CONF_OPEN_ONE_FAVORITE ); // デフォルトの書き込み名 write_name = cf.get_option_str( "write_name", CONF_WRITE_NAME ); // デフォルトのメールアドレス write_mail = cf.get_option_str( "write_mail", CONF_WRITE_MAIL ); // 書き込み時に書き込み確認ダイアログを出さない always_write_ok = cf.get_option_bool( "always_write_ok", CONF_ALWAYS_WRITE_OK ); // 書き込みログを保存 save_postlog = cf.get_option_bool( "save_postlog", CONF_SAVE_POSTLOG ); // 書き込みログの最大サイズ maxsize_postlog = cf.get_option_int( "maxsize_postlog", CONF_MAXSIZE_POSTLOG, 1024, 1024 * 1024 ); // 書き込み履歴を保存 save_posthist = cf.get_option_bool( "save_posthist", CONF_SAVE_POSTHIST ); // 「書き込み中」のダイアログを表示しない hide_writing_dialog = cf.get_option_bool( "hide_writing_dialog", CONF_HIDE_WRITING_DIALOG ); // 編集中のメッセージの保存確認ダイアログを表示する show_savemsgdiag = cf.get_option_bool( "show_savemsgdiag", CONF_SHOW_SAVEMSGDIAG ); // 書き込みビューでテキストを折り返す message_wrap = cf.get_option_bool( "message_wrap", CONF_MESSAGE_WRAP ); // 非アクティブ時に書き込みビューを折りたたむ fold_message = cf.get_option_bool( "fold_message", CONF_FOLD_MESSAGE ); // 非アクティブ時に画像ビューを折りたたむ fold_image = cf.get_option_bool( "fold_image", CONF_FOLD_IMAGE ); // 書き込み欄の日本語のON/OFF状態を保存 keep_im_status = cf.get_option_bool( "keep_im_status", CONF_KEEP_IM_STATUS ); // ポップアップとカーソルの間のマージン margin_popup = cf.get_option_int( "margin_popup", CONF_MARGIN_POPUP, 0, 1024 ); // 画像ポップアップとカーソルの間のマージン margin_imgpopup_x = cf.get_option_int( "margin_imgpopup_x", CONF_MARGIN_IMGPOPUP_X, 0, 1024 ); margin_imgpopup = cf.get_option_int( "margin_imgpopup", CONF_MARGIN_IMGPOPUP, 0, 1024 ); // ポップアップが消えるまでの時間(ミリ秒) hide_popup_msec = cf.get_option_int( "hide_popup_msec", CONF_HIDE_POPUP_MSEC, 0, 2000 ); // マウスジェスチャを有効 enable_mg = cf.get_option_bool( "enable_mg", CONF_ENABLE_MG ); // マウスジェスチャの判定開始半径 mouse_radius = cf.get_option_int( "mouse_radius", CONF_MOUSE_RADIUS, 4, 1024 ); // 数字入力ジャンプの待ち時間(ミリ秒) numberjmp_msec = cf.get_option_int( "numberjmp_msec", CONF_NUMBERJMP_MSEC, 1, 5000 ); // 履歴メニューの表示数 history_size = cf.get_option_int( "history_size", CONF_HISTORY_SIZE, 0, 256 ); // 履歴ビューの表示数 historyview_size = cf.get_option_int( "historyview_size", CONF_HISTORYVIEW_SIZE, 0, 1024 ); // AA履歴の保持数 aahistory_size = cf.get_option_int( "aahistory_size", CONF_AAHISTORY, 0, 65535 ); // 0以上なら多重ポップアップの説明を表示する instruct_popup = cf.get_option_int( "instruct_popup", CONF_INSTRUCT_POPUP, 0, CONF_INSTRUCT_POPUP ); // スレビューを開いたときにスレ一覧との切り替え方法を説明する instruct_tglart = cf.get_option_bool( "instruct_tglart", CONF_INSTRUCT_TGLART ); instruct_tglart_end = false; // 画像ビューを開いたときにスレビューとの切り替え方法を説明する instruct_tglimg = cf.get_option_bool( "instruct_tglimg", CONF_INSTRUCT_TGLIMG ); instruct_tglimg_end = false; // スレビューでdeleteを押したときに確認ダイアログを表示する show_delartdiag = cf.get_option_bool( "show_delartdiag", CONF_SHOW_DELARTDIAG ); // 下線位置 adjust_underline_pos = cf.get_option_double( "adjust_underline_pos", ( double )CONF_ADJUST_UNDERLINE_POS, ( double )0, ( double )64 ); // 行間スペース adjust_line_space = cf.get_option_double( "adjust_line_space", ( double )CONF_ADJUST_LINE_SPACE, ( double )0, ( double )64 ); // リンク下線を表示 draw_underline = cf.get_option_bool( "draw_underline", CONF_DRAW_UNDERLINE ); // スレビューで文字幅の近似を厳密にする strict_char_width = cf.get_option_bool( "strict_char_width", CONF_STRICT_CHAR_WIDTH ); // スレビューで発言数(ID)をカウントする check_id = cf.get_option_bool( "check_id", CONF_CHECK_ID ); // レス参照で色を変える回数 num_reference_high = cf.get_option_int( "num_reference_high", CONF_NUM_REFERENCE_HIGH, 1, 256 ); num_reference_low = cf.get_option_int( "num_reference_low", CONF_NUM_REFERENCE_LOW, 1, 128 ); // 発言数で色を変える回数 num_id_high = cf.get_option_int( "num_id_high", CONF_NUM_ID_HIGH, 1, 256 ); num_id_low = cf.get_option_int( "num_id_low", CONF_NUM_ID_LOW, 1, 128 ); // datのパース時にURL判定を甘くする(^なども含める) loose_url = cf.get_option_bool( "loose_url", CONF_LOOSE_URL ); // ユーザーコマンドで選択できない項目を非表示にする hide_usrcmd = cf.get_option_bool( "hide_usrcmd", CONF_HIDE_USRCMD ); // スレビューで再読み込みボタンを押したときに全タブを更新する reload_allthreads = cf.get_option_bool( "reload_allthreads", CONF_RELOAD_ALLTHREAD ); // タブに表示する文字列の最小値 tab_min_str = cf.get_option_int( "tab_min_str", CONF_TAB_MIN_STR, 1, 256 ); // タブにアイコンを表示するか show_tab_icon = cf.get_option_bool( "show_tab_icon", CONF_SHOW_TAB_ICON ); // タブ上でマウスホイールを回転してタブを切り替える switchtab_wheel = cf.get_option_bool( "switchtab_wheel", CONF_SWITCHTAB_WHEEL ); // ビュー内から他のビューを開いたときのタブの位置 ( 0: 一番右端 1:右隣 2:左隣 ) newtab_pos = cf.get_option_int( "newtab_pos", CONF_NEWTAB_POS, 0, 2 ); // 次スレ検索を開くときのタブの位置 ( 0: 次スレ検索タブ 1:新しいタブ 2:アクティブなタブを置き換え -1:2.8.5以前の動作 ) boardnexttab_pos = cf.get_option_int( "boardnexttab_pos", CONF_BOARDNEXTTAB_POS, -1, 2 ); // スレビューに書き込みマークを表示するか show_post_mark = cf.get_option_bool( "show_post_mark", CONF_SHOW_POST_MARK ); // ボタンをフラットにするか flat_button = cf.get_option_bool( "flat_button", CONF_FLAT_BUTTON ); // ツールバーの背景描画 draw_toolbarback = cf.get_option_bool( "draw_toolbarback", CONF_DRAW_TOOLBARBACK ); std::list< std::string > list_tmp; std::list< std::string >::iterator it_tmp; // スレ あぼーん word str_tmp = cf.get_option_str( "abonewordthread", "" ); if( ! str_tmp.empty() ) list_abone_word_thread = MISC::strtolist( str_tmp ); // スレ あぼーん regex str_tmp = cf.get_option_str( "aboneregexthread", "" ); if( ! str_tmp.empty() ) list_abone_regex_thread = MISC::strtolist( str_tmp ); // dat落ちしたスレをNGスレタイトルリストから取り除くか( 0: ダイアログ表示 1: 取り除く 2: 除かない ) remove_old_abone_thread = cf.get_option_int( "remove_old_abone_thread", CONF_REMOVE_OLD_ABONE_THREAD, 0, 2 ); // スレ あぼーん( レス数 ) abone_number_thread = cf.get_option_int( "abone_number_thread", CONF_ABONE_NUMBER_THREAD, 0, 9999 ); // スレ あぼーん( スレ立てからの経過時間 ) abone_hour_thread = cf.get_option_int( "abone_hour_thread", CONF_ABONE_HOUR_THREAD, 0, 9999 ); // あぼーん name str_tmp = cf.get_option_str( "abonename", "" ); if( ! str_tmp.empty() ) list_abone_name = MISC::strtolist( str_tmp ); // あぼーん word str_tmp = cf.get_option_str( "aboneword", "" ); if( ! str_tmp.empty() ) list_abone_word = MISC::strtolist( str_tmp ); // あぼーん regex str_tmp = cf.get_option_str( "aboneregex", "" ); if( ! str_tmp.empty() ) list_abone_regex = MISC::strtolist( str_tmp ); // デフォルトで透明、連鎖あぼーんをするか abone_transparent = cf.get_option_bool( "abone_transparent", CONF_ABONE_TRANSPARENT ); abone_chain = cf.get_option_bool( "abone_chain", CONF_ABONE_CHAIN ); // NG正規表現によるあぼーん時に大小と全半角文字の違いを無視 abone_icase = cf.get_option_bool( "abone_icase", CONF_ABONE_ICASE ); abone_wchar = cf.get_option_bool( "abone_wchar", CONF_ABONE_WCHAR ); // 右ペーンが空の時にサイドバーを閉じるか expand_sidebar = cf.get_option_bool( "expand_sidebar", CONF_EXPAND_SIDEBAR ); // 3ペーン時にスレ一覧やスレビューを最大化する expand_rpane = cf.get_option_bool( "expand_rpane", CONF_EXPAND_RPANE ); // ペーンの境界をクリックしてサイドバーを開け閉めする open_sidebar_by_click = cf.get_option_bool( "open_sidebar_by_click", CONF_OPEN_SIDEBAR_BY_CLICK ); // 次スレ検索の類似度のしきい値 threshold_next = cf.get_option_int( "threshold_next", CONF_THRESHOLD_NEXT, 1, 10 ); // 次スレを開いたときにお気に入りのアドレスと名前を自動更新 replace_favorite_next = cf.get_option_int( "replace_favorite_next", CONF_REPLACE_FAVORITE_NEXT, 0, 2 ); // お気に入りの自動更新をするかダイアログを出す show_diag_replace_favorite = cf.get_option_bool( "show_diag_replace_favorite", CONF_SHOW_DIAG_REPLACE_FAVORITE ); // スレをお気に入りに追加したときにしおりをセットする bookmark_drop = cf.get_option_bool( "bookmark_drop", CONF_BOOKMARK_DROP ); // お気に入りの更新チェック時に板の更新もチェックする check_update_board = cf.get_option_bool( "check_update_board", CONF_CHECK_UPDATE_BOARD ); // 起動時にお気に入りを自動でチェックする check_update_boot = cf.get_option_bool( "check_update_boot", CONF_CHECK_UPDATE_BOOT ); // お気に入り登録時に重複項目を登録するか ( 0: 登録する 1: ダイアログ表示 2: 登録しない ) check_favorite_dup = cf.get_option_int( "check_favorite_dup", CONF_CHECK_FAVORITE_DUP, 0, 2 ); // お気に入り登録時に挿入先ダイアログを表示する ( 0 : 表示する 1: 表示せず先頭に追加 2: 表示せず最後に追加 ) show_favorite_select_diag = cf.get_option_int( "show_favorite_select_diag", CONF_SHOW_FAVORITE_SELECT_DIAG, 0, 2 ); // Ctrl+qでウィンドウを閉じない disable_close = cf.get_option_bool( "disable_close", CONF_DISABLE_CLOSE ); // メニューバーを非表示にした時にダイアログを表示 show_hide_menubar_diag = cf.get_option_bool( "show_hide_menubar_diag", CONF_SHOW_HIDE_MENUBAR_DIAG ); // 状態変更時にメインステータスバーの色を変える change_stastatus_color = cf.get_option_bool( "change_stastatus_color", CONF_CHANGE_STASTATUS_COLOR ); // まちBBSの取得に offlaw.cgi を使用する use_machi_offlaw = cf.get_option_bool( "use_machi_offlaw", CONF_USE_MACHI_OFFLAW ); // 書き込み履歴のあるスレを削除する時にダイアログを表示 show_del_written_thread_diag = cf.get_option_bool( "show_del_written_thread_diag", CONF_SHOW_DEL_WRITTEN_THREAD_DIAG ); // スレを削除する時に画像キャッシュも削除する ( 0: ダイアログ表示 1: 削除 2: 削除しない ) delete_img_in_thread = cf.get_option_int( "delete_img_in_thread", CONF_DELETE_IMG_IN_THREAD, 0, 2 ); // FIFOの作成などにエラーがあったらダイアログを表示する show_diag_fifo_error = cf.get_option_bool( "show_diag_fifo_error", CONF_SHOW_DIAG_FIFO_ERROR ); // 指定した分ごとにセッションを自動保存 (0: 保存しない) save_session = cf.get_option_int( "save_session", CONF_SAVE_SESSION, 0, (24*60) ); #ifdef HAVE_MIGEMO_H // migemo-dictの場所 migemodict_path = cf.get_option_str( "migemodict_path", CONF_MIGEMO_PATH ); #endif m_loaded = true; // 設定値に壊れている物がある if( cf.is_broken() ) { std::string msg; Gtk::MessageDialog *mdiag; // 非resotreモードでバックアップが存在する if( ! restore && CACHE::file_exists( CACHE::path_conf_bkup() ) == CACHE::EXIST_FILE ) { msg = "設定ファイル (" + path_conf + ")に異常な値があります。全設定をバックアップから復元しますか?"; mdiag = new Gtk::MessageDialog( msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); int ret = mdiag->run(); delete mdiag; if( ret != Gtk::RESPONSE_YES ) load( true ); // resotreモードで再帰 } else { msg = "設定ファイル (" + path_conf + ")に異常な値があるため、一部をデフォルトに設定しました。"; mdiag = new Gtk::MessageDialog( msg ); mdiag->run(); delete mdiag; } } // 正常ならバックアップ else if( CACHE::file_exists( CACHE::path_root() ) == CACHE::EXIST_DIR ) { save_impl( CACHE::path_conf_bkup() ); } return ! cf.empty(); } // 保存 void ConfigItems::save() { save_impl( CACHE::path_conf() ); if( CACHE::file_exists( CACHE::path_conf_old() ) == CACHE::EXIST_FILE ) save_impl( CACHE::path_conf_old() ); } void ConfigItems::save_impl( const std::string& path ) { if( ! m_loaded ) return; #ifdef _DEBUG std::cout << "ConfigItems::save_impl path = " << path << std::endl; #endif JDLIB::ConfLoader cf( path, std::string() ); cf.update( "restore_board", restore_board ); cf.update( "restore_article", restore_article ); cf.update( "restore_image", restore_image ); cf.update( "manage_winpos", manage_winpos ); cf.update( "url_jdhp", url_jdhp ); cf.update( "url_login2ch", url_login2ch ); cf.update( "url_loginp2", url_loginp2 ); cf.update( "url_loginbe", url_loginbe ); cf.update( "url_bbsmenu", url_bbsmenu ); cf.update( "use_link_as_board", use_link_as_board ); cf.update( "show_movediag", show_movediag ); cf.update( "menu_search_title", menu_search_title ); cf.update( "url_search_title", url_search_title ); cf.update( "regex_search_title", regex_search_title ); cf.update( "menu_search_web", menu_search_web ); cf.update( "url_search_web", url_search_web ); cf.update( "url_writep2", url_writep2 ); cf.update( "url_resp2", url_resp2 ); cf.update( "fontname_main", fontname[ FONT_MAIN ] ); cf.update( "fontname_popup", fontname[ FONT_POPUP ] ); cf.update( "fontname_aa", fontname[ FONT_AA ] ); cf.update( "fontname_bbs", fontname[ FONT_BBS ] ); cf.update( "fontname_board", fontname[ FONT_BOARD ] ); cf.update( "fontname_message", fontname[ FONT_MESSAGE ] ); cf.update( "ref_prefix", ref_prefix ); cf.update( "ref_prefix_space", ref_prefix_space ); cf.update( "regex_res_aa", regex_res_aa ); cf.update( "path_cacheroot", path_cacheroot ); cf.update( "agent_for2ch", agent_for2ch ); std::string tmp_proxy; if( proxy_basicauth_for2ch.empty() ) tmp_proxy = proxy_for2ch; else tmp_proxy = proxy_basicauth_for2ch + "@" + proxy_for2ch; cf.update( "use_proxy_for2ch", use_proxy_for2ch ); cf.update( "proxy_for2ch", tmp_proxy ); cf.update( "proxy_port_for2ch", proxy_port_for2ch ); if( proxy_basicauth_for2ch_w.empty() ) tmp_proxy = proxy_for2ch_w; else tmp_proxy = proxy_basicauth_for2ch_w + "@" + proxy_for2ch_w; cf.update( "use_proxy_for2ch_w", use_proxy_for2ch_w ); cf.update( "proxy_for2ch_w", tmp_proxy ); cf.update( "proxy_port_for2ch_w", proxy_port_for2ch_w ); cf.update( "agent_for_data", agent_for_data ); if( proxy_basicauth_for_data.empty() ) tmp_proxy = proxy_for_data; else tmp_proxy = proxy_basicauth_for_data + "@" + proxy_for_data; cf.update( "use_proxy_for_data", use_proxy_for_data ); cf.update( "proxy_for_data", tmp_proxy ); cf.update( "proxy_port_for_data", proxy_port_for_data ); cf.update( "x_2ch_ua", x_2ch_ua ); cf.update( "loader_bufsize", loader_bufsize ); cf.update( "loader_bufsize_board", loader_bufsize_board ); cf.update( "loader_timeout", loader_timeout ); cf.update( "loader_timeout_post", loader_timeout_post ); cf.update( "loader_timeout_img", loader_timeout_img ); cf.update( "loader_timeout_checkupdate", loader_timeout_checkupdate ); cf.update( "use_ipv6", use_ipv6 ); cf.update( "connection_num", connection_num ); cf.update( "use_cookie_hap", use_cookie_hap ); cf.update( "cookie_hap", cookie_hap ); cf.update( "cookie_hap_bbspink", cookie_hap_bbspink ); cf.update( "command_openurl", command_openurl ); cf.update( "browsercombo_id", browsercombo_id ); cf.update( "refpopup_by_mo", refpopup_by_mo ); cf.update( "namepopup_by_mo", namepopup_by_mo ); cf.update( "idpopup_by_mo", idpopup_by_mo ); cf.update( "imgemb_interp", imgemb_interp ); cf.update( "imgmain_interp", imgmain_interp ); cf.update( "imgpopup_interp", imgpopup_interp ); cf.update( "imgpopup_width", imgpopup_width ); cf.update( "imgpopup_height", imgpopup_height ); cf.update( "use_image_popup", use_image_popup ); cf.update( "use_image_view", use_image_view ); cf.update( "use_inline_image", use_inline_image ); cf.update( "show_ssspicon", show_ssspicon ); cf.update( "embimg_width", embimg_width ); cf.update( "embimg_height", embimg_height ); cf.update( "hide_imagetab", hide_imagetab ); cf.update( "show_delimgdiag", show_delimgdiag ); cf.update( "use_mosaic", use_mosaic ); cf.update( "mosaic_size", mosaic_size ); cf.update( "zoom_to_fit", zoom_to_fit ); cf.update( "del_img_day", del_img_day ); cf.update( "del_imgabone_day", del_imgabone_day ); cf.update( "max_img_size", max_img_size ); cf.update( "max_img_pixel", max_img_pixel ); cf.update( "imgcache_size", imgcache_size ); cf.update( "cl_char", str_color[ COLOR_CHAR ] ); cf.update( "cl_char_name", str_color[ COLOR_CHAR_NAME ] ); cf.update( "cl_char_name_b", str_color[ COLOR_CHAR_NAME_B ] ); cf.update( "cl_char_name_nomail", str_color[ COLOR_CHAR_NAME_NOMAIL ] ); cf.update( "cl_char_age", str_color[ COLOR_CHAR_AGE ] ); cf.update( "cl_char_selection", str_color[ COLOR_CHAR_SELECTION ] ); cf.update( "cl_char_highlight", str_color[ COLOR_CHAR_HIGHLIGHT ] ); cf.update( "cl_char_link", str_color[ COLOR_CHAR_LINK ] ); cf.update( "cl_char_link_id_low", str_color[ COLOR_CHAR_LINK_ID_LOW ] ); cf.update( "cl_char_link_id_high", str_color[ COLOR_CHAR_LINK_ID_HIGH ] ); cf.update( "cl_char_link_res", str_color[ COLOR_CHAR_LINK_RES ] ); cf.update( "cl_char_link_low", str_color[ COLOR_CHAR_LINK_LOW ] ); cf.update( "cl_char_link_high", str_color[ COLOR_CHAR_LINK_HIGH ] ); cf.update( "cl_char_message", str_color[ COLOR_CHAR_MESSAGE ] ); cf.update( "cl_char_message_selection", str_color[ COLOR_CHAR_MESSAGE_SELECTION ] ); cf.update( "cl_img_nocache", str_color[ COLOR_IMG_NOCACHE ] ); cf.update( "cl_img_cached", str_color[ COLOR_IMG_CACHED ] ); cf.update( "cl_img_loading", str_color[ COLOR_IMG_LOADING ] ); cf.update( "cl_img_err", str_color[ COLOR_IMG_ERR ] ); cf.update( "cl_back", str_color[ COLOR_BACK ] ); cf.update( "cl_back_popup", str_color[ COLOR_BACK_POPUP ] ); cf.update( "cl_back_selection", str_color[ COLOR_BACK_SELECTION ] ); cf.update( "cl_back_highlight",str_color[ COLOR_BACK_HIGHLIGHT ] ); cf.update( "cl_back_highlight_tree",str_color[ COLOR_BACK_HIGHLIGHT_TREE ] ); cf.update( "cl_back_message", str_color[ COLOR_BACK_MESSAGE ] ); cf.update( "cl_back_message_selection", str_color[ COLOR_BACK_MESSAGE_SELECTION ] ); cf.update( "cl_sepa_new", str_color[ COLOR_SEPARATOR_NEW ] ); cf.update( "cl_frame", str_color[ COLOR_FRAME ] ); cf.update( "cl_marker", str_color[ COLOR_MARKER ] ); cf.update( "cl_chr_bbs", str_color[ COLOR_CHAR_BBS ] ); cf.update( "cl_chr_bbs_com", str_color[ COLOR_CHAR_BBS_COMMENT ] ); cf.update( "cl_chr_board", str_color[ COLOR_CHAR_BOARD ] ); cf.update( "cl_back_bbs", str_color[ COLOR_BACK_BBS ] ); cf.update( "cl_back_bbs_even", str_color[ COLOR_BACK_BBS_EVEN ] ); cf.update( "cl_back_board", str_color[ COLOR_BACK_BOARD ] ); cf.update( "cl_back_board_even", str_color[ COLOR_BACK_BOARD_EVEN ] ); cf.update( "use_tree_gtkrc", use_tree_gtkrc ); cf.update( "use_select_gtkrc", use_select_gtkrc ); cf.update( "tree_ypad", tree_ypad ); cf.update( "tree_show_expanders", tree_show_expanders ); cf.update( "tree_level_indent", tree_level_indent ); cf.update( "scroll_tree", scroll_tree ); cf.update( "select_item_sync", select_item_sync ); cf.update( "view_margin", view_margin ); cf.update( "left_scrbar", left_scrbar ); cf.update( "show_oldarticle", show_oldarticle ); cf.update( "newthread_hour", newthread_hour ); cf.update( "inc_search_board", inc_search_board ); cf.update( "show_deldiag", show_deldiag ); cf.update( "show_cached_board", show_cached_board ); cf.update( "show_924", show_924 ); cf.update( "tree_scroll_size", tree_scroll_size ); cf.update( "scroll_size", scroll_size ); cf.update( "key_scroll_size", key_scroll_size ); cf.update( "key_fastscroll_size", key_fastscroll_size ); cf.update( "jump_after_reload", jump_after_reload ); cf.update( "jump_new_after_reload", jump_new_after_reload ); cf.update( "live_mode", live_mode ); cf.update( "live_speed", live_speed ); cf.update( "live_threshold", live_threshold ); cf.update( "open_one_category", open_one_category ); cf.update( "open_one_favorite", open_one_favorite ); cf.update( "write_mail", write_mail ); cf.update( "write_name", write_name ); cf.update( "always_write_ok", always_write_ok ); cf.update( "save_postlog", save_postlog ); cf.update( "maxsize_postlog", maxsize_postlog ); cf.update( "save_posthist", save_posthist ); cf.update( "hide_writing_dialog", hide_writing_dialog ); cf.update( "show_savemsgdiag", show_savemsgdiag ); cf.update( "message_wrap", message_wrap ); cf.update( "fold_message", fold_message ); cf.update( "fold_image", fold_image ); cf.update( "keep_im_status", keep_im_status ); cf.update( "margin_popup", margin_popup ); cf.update( "margin_imgpopup_x", margin_imgpopup_x ); cf.update( "margin_imgpopup", margin_imgpopup ); cf.update( "hide_popup_msec", hide_popup_msec ); cf.update( "enable_mg", enable_mg ); cf.update( "mouse_radius", mouse_radius ); cf.update( "numberjmp_msec", numberjmp_msec ); cf.update( "history_size", history_size ); cf.update( "historyview_size", historyview_size ); cf.update( "aahistory_size", aahistory_size ); cf.update( "instruct_popup", instruct_popup ); cf.update( "instruct_tglart", instruct_tglart ); cf.update( "instruct_tglimg", instruct_tglimg ); cf.update( "show_delartdiag", show_delartdiag ); cf.update( "adjust_underline_pos", adjust_underline_pos ); cf.update( "adjust_line_space", adjust_line_space ); cf.update( "draw_underline", draw_underline ); cf.update( "strict_char_width", strict_char_width ); cf.update( "check_id", check_id ); cf.update( "num_reference_high", num_reference_high ); cf.update( "num_reference_low", num_reference_low ); cf.update( "num_id_high", num_id_high ); cf.update( "num_id_low", num_id_low ); cf.update( "loose_url", loose_url ); cf.update( "hide_usrcmd", hide_usrcmd ); cf.update( "reload_allthreads", reload_allthreads ); cf.update( "tab_min_str", tab_min_str ); cf.update( "show_tab_icon", show_tab_icon ); cf.update( "switchtab_wheel", switchtab_wheel ); cf.update( "newtab_pos", newtab_pos ); cf.update( "boardnexttab_pos", boardnexttab_pos ); cf.update( "show_post_mark", show_post_mark ); cf.update( "flat_button", flat_button ); cf.update( "draw_toolbarback", draw_toolbarback ); // スレあぼーん情報 std::string str_abone_word_thread = MISC::listtostr( list_abone_word_thread ); std::string str_abone_regex_thread = MISC::listtostr( list_abone_regex_thread ); cf.update( "abonewordthread", str_abone_word_thread ); cf.update( "aboneregexthread", str_abone_regex_thread ); cf.update( "remove_old_abone_thread", remove_old_abone_thread ); cf.update( "abone_number_thread", abone_number_thread ); cf.update( "abone_hour_thread", abone_hour_thread ); // あぼーん情報 std::string str_abone_name = MISC::listtostr( list_abone_name ); std::string str_abone_word = MISC::listtostr( list_abone_word ); std::string str_abone_regex = MISC::listtostr( list_abone_regex ); cf.update( "abonename", str_abone_name ); cf.update( "aboneword", str_abone_word ); cf.update( "aboneregex", str_abone_regex ); cf.update( "abone_transparent", abone_transparent ); cf.update( "abone_chain", abone_chain ); cf.update( "abone_icase", abone_icase ); cf.update( "abone_wchar", abone_wchar ); cf.update( "expand_sidebar", expand_sidebar ); cf.update( "expand_rpane", expand_rpane ); cf.update( "open_sidebar_by_click", open_sidebar_by_click ); cf.update( "threshold_next", threshold_next ); cf.update( "replace_favorite_next", replace_favorite_next ); cf.update( "show_diag_replace_favorite", show_diag_replace_favorite ); cf.update( "bookmark_drop", bookmark_drop ); cf.update( "check_update_board", check_update_board ); cf.update( "check_update_boot", check_update_boot ); cf.update( "check_favorite_dup", check_favorite_dup ); cf.update( "show_favorite_select_diag", show_favorite_select_diag ); cf.update( "disable_close", disable_close ); cf.update( "show_hide_menubar_diag", show_hide_menubar_diag ); cf.update( "change_stastatus_color", change_stastatus_color ); cf.update( "use_machi_offlaw", use_machi_offlaw ); cf.update( "show_del_written_thread_diag", show_del_written_thread_diag ); cf.update( "delete_img_in_thread", delete_img_in_thread ); cf.update( "show_diag_fifo_error", show_diag_fifo_error ); cf.update( "save_session", save_session ); #ifdef HAVE_MIGEMO_H cf.update( "migemodict_path", migemodict_path ); #endif cf.save(); } // // フォントのセット // void ConfigItems::set_fonts( JDLIB::ConfLoader& cf ) { const std::string defaultfont = get_default_font(); // フォント fontname[ FONT_MAIN ] = cf.get_option_str( "fontname_main", defaultfont + " " + std::string( CONF_FONTSIZE_THREAD ) ); // ポップアップのフォント fontname[ FONT_POPUP ] = cf.get_option_str( "fontname_popup", defaultfont + " " + std::string( CONF_FONTSIZE_POPUP ) ); // AA(スレビュー)のフォント fontname[ FONT_AA ] = cf.get_option_str( "fontname_aa", fontname[ FONT_MAIN ] ); aafont_enabled = ( fontname[ FONT_MAIN ] != fontname[ FONT_AA ] ); // スレ一覧のフォント fontname[ FONT_BBS ] = cf.get_option_str( "fontname_bbs", defaultfont + " " + std::string( CONF_FONTSIZE_TREE ) ); // 板一覧のフォント fontname[ FONT_BOARD ] = cf.get_option_str( "fontname_board", fontname[ FONT_BBS ] ); // 書き込みウィンドウのフォント fontname[ FONT_MESSAGE ] = cf.get_option_str( "fontname_message", fontname[ FONT_MAIN ] ); // Gtk::Entryのデフォルトフォント fontname[ FONT_ENTRY_DEFAULT ] = MISC::get_entry_font(); } // // フォントのリセット // void ConfigItems::reset_fonts() { // dummyのConfLoaderをset_fonts()に渡してデフォルト値をセットする JDLIB::ConfLoader cf( "", "dummy = dummy" ); set_fonts( cf ); } // // 色のセット // void ConfigItems::set_colors( JDLIB::ConfLoader& cf ) { // 文字色 13 = "#FFFFFFFFFFFF" or "#%DDx%DDx%DDx" str_color[ COLOR_CHAR ] = cf.get_option_str( "cl_char", CONF_COLOR_CHAR, 13 ); // 名前欄の文字色 str_color[ COLOR_CHAR_NAME ] = cf.get_option_str( "cl_char_name", CONF_COLOR_CHAR_NAME, 13 ); // トリップ等の名前欄の文字色 str_color[ COLOR_CHAR_NAME_B ] = cf.get_option_str( "cl_char_name_b", CONF_COLOR_CHAR_NAME_B, 13 ); // 名前無し時の名前欄の文字色 str_color[ COLOR_CHAR_NAME_NOMAIL ] = cf.get_option_str( "cl_char_name_nomail", CONF_COLOR_CHAR_NAME_NOMAIL, 13 ); // ageの時のメール欄の文字色 str_color[ COLOR_CHAR_AGE ] = cf.get_option_str( "cl_char_age", CONF_COLOR_CHAR_AGE, 13 ); // 選択範囲の文字色 str_color[ COLOR_CHAR_SELECTION ] = cf.get_option_str( "cl_char_selection", CONF_COLOR_CHAR_SELECTION, 13 ); // ハイライトの文字色 str_color[ COLOR_CHAR_HIGHLIGHT ] = cf.get_option_str( "cl_char_highlight", CONF_COLOR_CHAR_HIGHLIGHT, 13 ); // 通常のリンクの文字色 str_color[ COLOR_CHAR_LINK ] = cf.get_option_str( "cl_char_link", CONF_COLOR_CHAR_LINK, 13 ); // 複数発言したIDの文字色 str_color[ COLOR_CHAR_LINK_ID_LOW ] = cf.get_option_str( "cl_char_link_id_low", CONF_COLOR_CHAR_LINK_ID_LOW, 13 ); // 多く発言したIDの文字色 str_color[ COLOR_CHAR_LINK_ID_HIGH ] = cf.get_option_str( "cl_char_link_id_high", CONF_COLOR_CHAR_LINK_ID_HIGH, 13 ); // 参照されていないレス番号の文字色 str_color[ COLOR_CHAR_LINK_RES ] = cf.get_option_str( "cl_char_link_res", CONF_COLOR_CHAR_LINK_RES, 13 ); // 他のレスから参照されたレス番号の文字色 str_color[ COLOR_CHAR_LINK_LOW ] = cf.get_option_str( "cl_char_link_low", CONF_COLOR_CHAR_LINK_LOW, 13 ); // 参照された数が多いレス番号の文字色 str_color[ COLOR_CHAR_LINK_HIGH ] = cf.get_option_str( "cl_char_link_high", CONF_COLOR_CHAR_LINK_HIGH, 13 ); // メッセージビューの文字色 str_color[ COLOR_CHAR_MESSAGE ] = cf.get_option_str( "cl_char_message", CONF_COLOR_CHAR_MESSAGE, 13 ); // メッセージビュー(選択範囲)の文字色 str_color[ COLOR_CHAR_MESSAGE_SELECTION ] = cf.get_option_str( "cl_char_message_selection", CONF_COLOR_CHAR_MESSAGE_SELECTION, 13 ); // Gtk::Entryのデフォルトの文字色 str_color[ COLOR_CHAR_ENTRY_DEFAULT ] = MISC::get_entry_color_text(); // 画像(キャッシュ無)の色 str_color[ COLOR_IMG_NOCACHE ] = cf.get_option_str( "cl_img_nocache", CONF_COLOR_IMG_NOCACHE, 13 ); // 画像(キャッシュ有)の色 str_color[ COLOR_IMG_CACHED ] = cf.get_option_str( "cl_img_cached", CONF_COLOR_IMG_CACHED, 13 ); // 画像(ロード中)の色 str_color[ COLOR_IMG_LOADING ] = cf.get_option_str( "cl_img_loading", CONF_COLOR_IMG_LOADING, 13 ); // 画像(エラー)の色 str_color[ COLOR_IMG_ERR ] = cf.get_option_str( "cl_img_err", CONF_COLOR_IMG_ERR, 13 ); // スレ背景色 str_color[ COLOR_BACK ] = cf.get_option_str( "cl_back", CONF_COLOR_BACK, 13 ); // ポップアップの背景色 str_color[ COLOR_BACK_POPUP ] = cf.get_option_str( "cl_back_popup", CONF_COLOR_BACK_POPUP, 13 ); // 選択範囲の背景色 str_color[ COLOR_BACK_SELECTION ] = cf.get_option_str( "cl_back_selection", CONF_COLOR_BACK_SELECTION, 13 ); // ハイライトの背景色 str_color[ COLOR_BACK_HIGHLIGHT ] = cf.get_option_str( "cl_back_highlight", CONF_COLOR_BACK_HIGHLIGHT, 13 ); // ハイライトの背景色(ツリー用) str_color[ COLOR_BACK_HIGHLIGHT_TREE ] = cf.get_option_str( "cl_back_highlight_tree", CONF_COLOR_BACK_HIGHLIGHT_TREE, 13 ); // メッセージビューの背景色 str_color[ COLOR_BACK_MESSAGE ] = cf.get_option_str( "cl_back_message", CONF_COLOR_BACK_MESSAGE, 13 ); // メッセージビューの選択色 str_color[ COLOR_BACK_MESSAGE_SELECTION ] = cf.get_option_str( "cl_back_message_selection", CONF_COLOR_BACK_MESSAGE_SELECTION, 13 ); // Gtk::Entryのデフォルトの背景色 str_color[ COLOR_BACK_ENTRY_DEFAULT ] = MISC::get_entry_color_base(); // 新着セパレータ str_color[ COLOR_SEPARATOR_NEW ] = cf.get_option_str( "cl_sepa_new", CONF_COLOR_SEPARATOR_NEW, 13 ); // ポップアップフレーム色 str_color[ COLOR_FRAME ] = cf.get_option_str( "cl_frame", CONF_COLOR_FRAME, 13 ); // オートスクロールマーカー色 str_color[ COLOR_MARKER ] = cf.get_option_str( "cl_marker", CONF_COLOR_MARKER, 13 ); // 板一覧の文字 str_color[ COLOR_CHAR_BBS ] = cf.get_option_str( "cl_chr_bbs", CONF_COLOR_CHAR_BBS, 13 ); // 板一覧のコメント str_color[ COLOR_CHAR_BBS_COMMENT ] = cf.get_option_str( "cl_chr_bbs_com", CONF_COLOR_CHAR_BBS_COMMENT, 13 ); // スレ一覧の文字 str_color[ COLOR_CHAR_BOARD ] = cf.get_option_str( "cl_chr_board", CONF_COLOR_CHAR_BOARD, 13 ); // 板一覧の背景色 str_color[ COLOR_BACK_BBS ] = cf.get_option_str( "cl_back_bbs", CONF_COLOR_BACK_BBS, 13 ); // 板一覧の背景色(偶数行) str_color[ COLOR_BACK_BBS_EVEN ] = cf.get_option_str( "cl_back_bbs_even", CONF_COLOR_BACK_BBS_EVEN, 13 ); // スレ一覧の背景色 str_color[ COLOR_BACK_BOARD ] = cf.get_option_str( "cl_back_board", CONF_COLOR_BACK_BOARD, 13 ); // スレ一覧の背景色(偶数行) str_color[ COLOR_BACK_BOARD_EVEN ] = cf.get_option_str( "cl_back_board_even", CONF_COLOR_BACK_BOARD_EVEN, 13 ); } // // 色のリセット // void ConfigItems::reset_colors() { // dummyのConfLoaderをset_colors()に渡してデフォルト値をセットする JDLIB::ConfLoader cf( "", "dummy = dummy" ); set_colors( cf ); } // // プロクシ設定 // void ConfigItems::set_proxy_for2ch( const std::string& proxy ) { proxy_for2ch = proxy; proxy_basicauth_for2ch = std::string(); if( proxy.empty() ) return; // basic認証 JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "([^/]+:[^/]+@)(.+)$" , proxy, offset, icase, newline, usemigemo, wchar ) ) { proxy_basicauth_for2ch = regex.str( 1 ).substr( 0, regex.str( 1 ).length() - 1 ); proxy_for2ch = regex.str( 2 ); } } void ConfigItems::set_proxy_for2ch_w( const std::string& proxy ) { proxy_for2ch_w = proxy; proxy_basicauth_for2ch_w = std::string(); if( proxy.empty() ) return; // basic認証 JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "([^/]+:[^/]+@)(.+)$" , proxy, offset, icase, newline, usemigemo, wchar ) ) { proxy_basicauth_for2ch_w = regex.str( 1 ).substr( 0, regex.str( 1 ).length() - 1 ); proxy_for2ch_w = regex.str( 2 ); } } void ConfigItems::set_proxy_for_data( const std::string& proxy ) { proxy_for_data = proxy; proxy_basicauth_for_data = std::string(); if( proxy.empty() ) return; // basic認証 JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "([^/]+:[^/]+@)(.+)$" , proxy, offset, icase, newline, usemigemo, wchar ) ) { proxy_basicauth_for_data = regex.str( 1 ).substr( 0, regex.str( 1 ).length() - 1 ); proxy_for_data = regex.str( 2 ); } } jd-2.8.7-140104/src/config/configitems.h0000644000076400010400000004177112177057552014331 0ustar // ライセンス: GPL2 // // 設定項目クラス // #ifndef _CONFIGITEMS_H #define _CONFIGITEMS_H #include #include #include namespace JDLIB { class ConfLoader; } namespace CONFIG { class ConfigItems { // 設定をロード済み bool m_loaded; public: // 前回開いたviewを復元するか bool restore_board; bool restore_article; bool restore_image; // 自前でウィンドウ配置を管理する bool manage_winpos; // フォント std::vector< std::string > fontname; // レスを参照するときに前に付ける文字 std::string ref_prefix; // ref_prefix の後のスペースの数 int ref_prefix_space; std::string ref_prefix_space_str; // レスにアスキーアートがあると判定する正規表現 std::string regex_res_aa; bool aafont_enabled; // キャッシュのルートディレクトリ // 旧バージョンとの互換のため残しているだけで使用していない std::string path_cacheroot; // 読み込み用プロクシとポート番号 bool use_proxy_for2ch; std::string proxy_for2ch; int proxy_port_for2ch; std::string proxy_basicauth_for2ch; // 書き込み用プロクシとポート番号 bool use_proxy_for2ch_w; std::string proxy_for2ch_w; int proxy_port_for2ch_w; std::string proxy_basicauth_for2ch_w; // 2chの外にアクセスするときのプロクシとポート番号 bool use_proxy_for_data; std::string proxy_for_data; int proxy_port_for_data; std::string proxy_basicauth_for_data; // 2ch にアクセスするときのエージェント名 std::string agent_for2ch; // 2ch外にアクセスするときのエージェント名 std::string agent_for_data; // 2ch にログインするときのX-2ch-UA std::string x_2ch_ua; // ローダのバッファサイズ int loader_bufsize; // 一般 int loader_bufsize_board; // スレ一覧用 // ローダのタイムアウト値 int loader_timeout; int loader_timeout_post; int loader_timeout_img; int loader_timeout_checkupdate; // ipv6使用 bool use_ipv6; // 同一ホストに対する最大コネクション数( 1 または 2 ) int connection_num; // 2chのクッキー:HAPを保存する bool use_cookie_hap; // 2chのクッキー:HAP std::string cookie_hap; std::string cookie_hap_bbspink; // リンクをクリックしたときに実行するコマンド std::string command_openurl; // ブラウザ設定ダイアログのコンボボックスの番号 int browsercombo_id; // レス番号の上にマウスオーバーしたときに参照ポップアップ表示する bool refpopup_by_mo; // 名前の上にマウスオーバーしたときにポップアップ表示する bool namepopup_by_mo; // IDの上にマウスオーバーしたときにIDをポップアップ表示する bool idpopup_by_mo; // 画像のスムージングレベル(0-2, 2が最も高画質かつ低速) int imgemb_interp; int imgmain_interp; int imgpopup_interp; // 画像ポップアップサイズ int imgpopup_width; int imgpopup_height; // 画像ポップアップを使用する bool use_image_popup; // 画像ビューを使用する bool use_image_view; // インライン画像を表示する bool use_inline_image; // ssspアイコン表示 bool show_ssspicon; // インライン画像の最大幅と高さ int embimg_width; int embimg_height; // 埋め込み画像ビューを閉じたときにタブも閉じる bool hide_imagetab; // 画像ビューでdeleteを押したときに確認ダイアログを表示する bool show_delimgdiag; // 画像にモザイクかける bool use_mosaic; // モザイクの大きさ // 画像を一度mosaic_sizeまで縮めてから表示する // 画像のサイズがmosaic_sizeより小さい場合はモザイクをかけない int mosaic_size; // 画像をデフォルトでウィンドウサイズに合わせる bool zoom_to_fit; // 画像キャッシュ削除の日数 int del_img_day; // 画像あぼーん削除の日数 int del_imgabone_day; // ダウンロードする画像の最大ファイルサイズ(Mbyte) int max_img_size; // 画像の最大サイズ(Mピクセル) int max_img_pixel; // 画像のメモリキャッシュ枚数 int imgcache_size; // JD ホームページのアドレス std::string url_jdhp; // 2chの認証サーバのアドレス std::string url_login2ch; // p2の認証サーバのアドレス std::string url_loginp2; // BEの認証サーバのアドレス std::string url_loginbe; // bbsmenu.htmlのURL std::string url_bbsmenu; // bbsmenu.htmlの内にあるリンクは全て板とみなす bool use_link_as_board; // 板移転時に確認ダイアログを表示する bool show_movediag; // スレタイ検索用メニュータイトルアドレス std::string menu_search_title; std::string url_search_title; // スレタイ検索用正規表現 std::string regex_search_title; // web検索用メニュータイトルアドレス std::string menu_search_web; std::string url_search_web; // p2 書き込み用アドレス std::string url_writep2; std::string url_resp2; // 色 std::vector< std::string > str_color; // ツリービューでgtkrcの設定を使用するか bool use_tree_gtkrc; // スレビューの選択色でgtkrcの設定を使用するか bool use_select_gtkrc; // ツリービューの行間スペース int tree_ypad; // ツリービューにエクスパンダを表示 bool tree_show_expanders; // ツリービューのレベルインデント調整量(ピクセル) int tree_level_indent; // カテゴリを開いたときにツリービューをスクロールする bool scroll_tree; // ツリービューの選択を、表示中のビューと同期するか ( 0: 同期しない 1: 同期する 2: 同期する(フォルダを開く) ) int select_item_sync; // 各ビューと枠との間の余白 int view_margin; // スクロールバーを左に配置 bool left_scrbar; // スレ一覧で古いスレも表示 bool show_oldarticle; // スレ一覧で指定した値(時間)よりも後に立てられたスレを新着とみなす int newthread_hour; // スレ一覧でインクリメント検索をする bool inc_search_board; // スレ一覧でdeleteを押したときに確認ダイアログを表示する bool show_deldiag; // スレ一覧をロードする前にキャッシュにある一覧を表示 bool show_cached_board; // スレ一覧でお知らせスレ(924)のアイコンを表示する bool show_924; // ツリービューのスクロール量(マウスホイール上下・行数) int tree_scroll_size; // スレビューのスクロール量(マウスホイール上下・行数) int scroll_size; // スレビューのスクロール量(キー上下・行数) int key_scroll_size; // スレビューの高速スクロール量(キー上下・ ページ高 - 行高 * key_fastscroll_size ) int key_fastscroll_size; // スレビューでリロード後に一番下までスクロール bool jump_after_reload; // スレビューでリロード後に新着までスクロール bool jump_new_after_reload; // 実況モード int live_mode; // 実況速度 int live_speed; // 実況のスクロールモードを切り替えるしきい値 int live_threshold; // 板一覧でカテゴリを常にひとつだけ開く bool open_one_category; // お気に入りでカテゴリを常にひとつだけ開く bool open_one_favorite; // デフォルトの書き込み名 std::string write_name; // デフォルトのメールアドレス std::string write_mail; // 書き込み時に書き込み確認ダイアログを出さない bool always_write_ok; // 書き込みログを保存 bool save_postlog; // 書き込みログの最大サイズ int maxsize_postlog; // 書き込み履歴を保存 bool save_posthist; // 「書き込み中」のダイアログを表示しない bool hide_writing_dialog; // 編集中のメッセージの保存確認ダイアログを表示する bool show_savemsgdiag; // 書き込みビューでテキストを折り返す bool message_wrap; // 非アクティブ時に書き込みビューを折りたたむ bool fold_message; // 非アクティブ時に画像ビューを折りたたむ bool fold_image; // 書き込み欄の日本語のON/OFF状態を保存 bool keep_im_status; // ポップアップとカーソルの間のマージン int margin_popup; // 画像ポップアップとカーソルの間のマージン int margin_imgpopup_x; // 水平方向 int margin_imgpopup; // 垂直方向 // ポップアップが消えるまでの時間(ミリ秒) int hide_popup_msec; // マウスジェスチャを有効 bool enable_mg; // マウスジェスチャの判定開始半径 int mouse_radius; // 数字入力ジャンプの待ち時間(ミリ秒) int numberjmp_msec; // 履歴メニューの表示数 int history_size; // 履歴ビューの表示数 int historyview_size; // AA履歴の保持数 int aahistory_size; // 0以上なら多重ポップアップの説明を表示する int instruct_popup; // スレビューを開いたときにスレ一覧との切り替え方法を説明する bool instruct_tglart; bool instruct_tglart_end; // 画像ビューを開いたときにスレビューとの切り替え方法を説明する bool instruct_tglimg; bool instruct_tglimg_end; // スレビューでdeleteを押したときに確認ダイアログを表示する bool show_delartdiag; // 下線位置 double adjust_underline_pos; // 行間スペース double adjust_line_space; // リンク下線を表示 bool draw_underline; // スレビューで文字幅の近似を厳密にする bool strict_char_width; // スレビューで発言数(ID)をカウントする bool check_id; // レス参照で色を変える回数 int num_reference_high; int num_reference_low; // 発言数で色を変える回数 int num_id_high; int num_id_low; // datのパース時にURL判定を甘くする(^なども含める) bool loose_url; // ユーザーコマンドで選択できない項目を非表示にする bool hide_usrcmd; // スレビューで再読み込みボタンを押したときに全タブを更新する bool reload_allthreads; // タブに表示する文字列の最小値 int tab_min_str; // タブにアイコンを表示するか bool show_tab_icon; // タブ上でマウスホイールを回転してタブを切り替える bool switchtab_wheel; // ビュー内から他のビューを開いたときのタブの位置 ( 0: 一番右端 1:右隣 2:左隣 ) int newtab_pos; // 次スレ検索を開くときのタブの位置 ( 0: 次スレ検索タブ 1:新しいタブ 2:アクティブなタブを置き換え ) int boardnexttab_pos; // スレビューに書き込みマークを表示するか bool show_post_mark; // ボタンをフラットにするか bool flat_button; // ツールバーの背景描画 bool draw_toolbarback; // スレ あぼーん word std::list< std::string > list_abone_word_thread; // スレ あぼーん regex std::list< std::string > list_abone_regex_thread; // dat落ちしたスレをNGスレタイトルリストから取り除くか( 0: ダイアログ表示 1: 取り除く 2: 除かない ) int remove_old_abone_thread; // スレ あぼーん レス数 int abone_number_thread; // スレ あぼーん スレ立てからの経過時間 int abone_hour_thread; // あぼーん name std::list< std::string > list_abone_name; // あぼーん word std::list< std::string > list_abone_word; // あぼーん regex std::list< std::string > list_abone_regex; // デフォルトで透明、連鎖あぼーんをするか bool abone_transparent; bool abone_chain; // NG正規表現によるあぼーん時に大小と全半角文字の違いを無視 bool abone_icase; bool abone_wchar; // 右ペーンが空の時にサイドバーを閉じるか bool expand_sidebar; // 3ペーン時にスレ一覧やスレビューを最大化するか bool expand_rpane; // ペーンの境界をクリックしてサイドバーを開け閉めする bool open_sidebar_by_click; // 次スレ検索の類似度のしきい値 int threshold_next; // 次スレを開いたときにお気に入りのアドレスと名前を自動更新 int replace_favorite_next; // お気に入りの自動更新をするかダイアログを出す bool show_diag_replace_favorite; // スレをお気に入りに追加したときにしおりをセットする bool bookmark_drop; // お気に入りの更新チェック時に板の更新もチェックする bool check_update_board; // 起動時にお気に入りを自動でチェックする bool check_update_boot; // お気に入り登録時に重複項目を登録するか ( 0: 登録する 1: ダイアログ表示 2: 登録しない ) int check_favorite_dup; // お気に入り登録時に挿入先ダイアログを表示する ( 0 : 表示する 1: 表示せず先頭に追加 2: 表示せず最後に追加 ) int show_favorite_select_diag; // Ctrl+qでウィンドウを閉じない bool disable_close; // メニューバーを非表示にした時にダイアログを表示 bool show_hide_menubar_diag; // 状態変更時にメインステータスバーの色を変える bool change_stastatus_color; // まちBBSの取得に offlaw.cgi を使用する bool use_machi_offlaw; // 書き込み履歴のあるスレを削除する時にダイアログを表示 bool show_del_written_thread_diag; // スレを削除する時に画像キャッシュも削除する ( 0: ダイアログ表示 1: 削除 2: 削除しない ) int delete_img_in_thread; // FIFOの作成などにエラーがあったらダイアログを表示する bool show_diag_fifo_error; // 指定した分ごとにセッションを自動保存 (0: 保存しない) int save_session; #ifdef HAVE_MIGEMO_H // migemo-dictの場所 std::string migemodict_path; #endif ///////////////////////// ConfigItems(); virtual ~ConfigItems(); // 設定読み込み const bool load( const bool restore = false ); // 保存 void save(); // フォントのリセット void reset_fonts(); // 色のリセット void reset_colors(); // プロクシ設定 void set_proxy_for2ch( const std::string& proxy ); void set_proxy_for2ch_w( const std::string& proxy ); void set_proxy_for_data( const std::string& proxy ); private: void save_impl( const std::string& path ); void set_fonts( JDLIB::ConfLoader& cf ); void set_colors( JDLIB::ConfLoader& cf ); }; } #endif jd-2.8.7-140104/src/config/defaultconf.h0000644000076400010400000004734412177057552014316 0ustar // ライセンス: GPL2 // // 設定のデフォルト値 // #ifndef _DEFAULTCONF_H #define _DEFAULTCONF_H #ifdef HAVE_CONFIG_H #include "config.h" #endif namespace CONFIG { enum{ CONF_RESTORE_BOARD = 0, // スレ一覧を復元 CONF_RESTORE_ARTICLE = 0, // スレを復元 CONF_RESTORE_IMAGE = 0, // 画像を復元 #ifndef _WIN32 CONF_MANAGE_WINPOS = 1, // 自前でウィンドウ配置を管理する #else CONF_MANAGE_WINPOS = 0, // Windowsがウインドウ配置を管理する #endif CONF_REF_PREFIX_SPACE = 1, // 参照文字( CONF_REF_PREFIX ) の後のスペースの数 CONF_USE_PROXY_FOR2CH = 0, // 2ch 読み込み用プロクシを使用するか CONF_PROXY_PORT_FOR2CH = 8080, // 2ch 読み込み用プロクシポート番号 CONF_USE_PROXY_FOR2CH_W = 0, // 2ch 書き込み用プロクシを使用するか CONF_PROXY_PORT_FOR2CH_W = 8080, // 2ch 書き込み用プロクシポート番号 CONF_USE_PROXY_FOR_DATA = 0, // 2ch 以外にアクセスするときにプロクシを使用するか CONF_PROXY_PORT_FOR_DATA = 8080, // 2ch 以外にアクセスするときのプロクシポート番号 CONF_LOADER_BUFSIZE = 32, // ローダのバッファサイズ (一般) CONF_LOADER_BUFSIZE_BOARD = 2, // ローダのバッファサイズ (スレ一覧用) CONF_LOADER_TIMEOUT = 10, // ローダのタイムアウト値 CONF_LOADER_TIMEOUT_POST = 30, // ポストローダのタイムアウト値 CONF_LOADER_TIMEOUT_IMG = 30, // 画像ローダのタイムアウト値 CONF_LOADER_TIMEOUT_CHECKUPDATE = 10, // 更新チェックのタイムアウト値 CONF_USE_IPV6 = 1, // ipv6使用 CONF_CONNECTION_NUM = 2, // 同一ホストに対する最大コネクション数( 1 または 2 ) CONF_USE_COOKIE_HAP = 1, // 2chのクッキー:HAPを保存する CONF_REFPOPUP_BY_MO = 0, // レス番号の上にマウスオーバーしたときに参照ポップアップ表示する CONF_NAMEPOPUP_BY_MO = 0, // 名前の上にマウスオーバーしたときにポップアップ表示する CONF_IDPOPUP_BY_MO = 0, // IDの上にマウスオーバーしたときにIDをポップアップ表示する CONF_USE_TREE_GTKRC = 0, // ツリービューでgtkrcの設定を使用するか CONF_USE_SELECT_GTKRC = 0, // スレビューの選択色でgtkrcの設定を使用するか CONF_TREE_YPAD = 1, // ツリービューの行間スペース CONF_TREE_SHOW_EXPANDERS = 1, // ツリービューにエクスパンダを表示 CONF_TREE_LEVEL_INDENT = 0, // ツリービューのレベルインデント調整量(ピクセル) CONF_SCROLL_TREE = 1, // カテゴリを開いたときにツリービューをスクロールする CONF_SELECT_ITEM_SYNC = 1, // ツリービューの選択を、表示中のビューと同期するか ( 0: 同期しない 1: 同期する 2: 同期する(フォルダを開く) ) CONF_VIEW_MARGIN = 0, // 各ビューと枠との間の余白 CONF_LEFT_SCRBAR = 0, // スクロールバーを左に配置 CONF_SHOW_OLDARTICLE = 0, // スレ一覧で古いスレも表示 CONF_NEWTHREAD_HOUR = 24, // スレ一覧で指定した値(時間)よりも後に立てられたスレを新着とみなす CONF_INC_SEARCH_BOARD = 0, // スレ一覧でインクリメント検索をする CONF_SHOW_DELDIAG = 1 , // スレ一覧でdeleteを押したときに確認ダイアログを表示する CONF_SHOW_CACHED_BOARD = 1, // スレ一覧をロードする前にキャッシュにある一覧を表示 CONF_SHOW_924 = 1, // スレ一覧でお知らせスレ(924)のアイコンを表示する CONF_TREE_SCROLL_SIZE = 4, // ツリービューのスクロール量(行数) CONF_SCROLL_SIZE = 3, // スレビューのスクロール量 CONF_KEY_SCROLL_SIZE = 2, // スレビューのスクロール量(キー上下) CONF_KEY_FASTSCROLL_SIZE = 2, // スレビューの高速スクロール量(キー上下・ ページ高 - 行高 * key_fastscroll_size ) CONF_JUMP_AFTER_RELOAD = 0, // スレビューでリロード後に一番下までスクロール CONF_JUMP_NEW_AFTER_RELOAD = 0, // スレビューでリロード後に新着までスクロール CONF_LIVE_SPEED = 2, // 実況速度 CONF_LIVE_THRESHOLD = 10, // 実況のスクロールモードを切り替えるしきい値 CONF_OPEN_ONE_CATEGORY = 0, // 板一覧でカテゴリを常にひとつだけ開く CONF_OPEN_ONE_FAVORITE = 0, // お気に入りでカテゴリを常にひとつだけ開く CONF_ALWAYS_WRITE_OK = 0, // 書き込み時に書き込み確認ダイアログを出さない CONF_SAVE_POSTLOG = 0, //書き込みログを保存 CONF_SAVE_POSTHIST = 1, //書き込み履歴を保存 CONF_MAXSIZE_POSTLOG = ( 256 * 1024 ), // 書き込みログの最大サイズ CONF_HIDE_WRITING_DIALOG = 0, // 「書き込み中」のダイアログを表示しない CONF_SHOW_SAVEMSGDIAG = 1, // 編集中のメッセージの保存確認ダイアログを表示する CONF_MESSAGE_WRAP = 1, // 書き込みビューでテキストを折り返す CONF_FOLD_MESSAGE = 0, // 非アクティブ時に書き込みビューを折りたたむ CONF_FOLD_IMAGE = 1, // 非アクティブ時に画像ビューを折りたたむ CONF_KEEP_IM_STATUS = 0, // 書き込み欄の日本語のON/OFF状態を保存 CONF_MARGIN_POPUP = 30, // レスアンカーとポップアップの間のマージン ( 垂直方向 ) CONF_MARGIN_IMGPOPUP_X = 0, // レスアンカーと画像ポップアップの間のマージン ( 水平方向 ) CONF_MARGIN_IMGPOPUP = CONF_MARGIN_POPUP, // レスアンカーと画像ポップアップの間のマージン ( 垂直方向 ) CONF_HIDE_POPUP_MSEC = 0, // ポップアップが消えるまでの時間(ミリ秒) CONF_ENABLE_MG = 1, // マウスジェスチャを有効 CONF_MOUSE_RADIUS = 25, // マウスジェスチャの判定開始半径 CONF_NUMBERJMP_MSEC = 1000, // 数字入力ジャンプの待ち時間(ミリ秒) CONF_HISTORY_SIZE = 20, // 履歴メニューの表示数 CONF_HISTORYVIEW_SIZE = 100, // 履歴ビューの表示数 CONF_AAHISTORY = 7, // AA履歴の保持数 CONF_INSTRUCT_POPUP = 100, // 0以上なら多重ポップアップの説明を表示する CONF_INSTRUCT_TGLART = 1, // スレビューを開いたときにスレ一覧との切り替え方法を説明する CONF_INSTRUCT_TGLIMG = 1, // 画像ビューを開いたときにスレビューとの切り替え方法を説明する CONF_SHOW_DELARTDIAG = 1, // スレビューでdeleteを押したときに確認ダイアログを表示する CONF_ADJUST_UNDERLINE_POS = 1, // 下線位置 CONF_ADJUST_LINE_SPACE = 1, // 行間スペース CONF_DRAW_UNDERLINE = 1, // リンク下線を表示 CONF_STRICT_CHAR_WIDTH = 0, // スレビューで文字幅の近似を厳密にする CONF_CHECK_ID = 1, // スレビューで発言数(ID)をカウントする CONF_NUM_REFERENCE_HIGH = 3,//レス参照で色を変える回数 (高) CONF_NUM_REFERENCE_LOW = 1, //レス参照で色を変える回数 (低) CONF_NUM_ID_HIGH = 4, // 発言数で色を変える回数 (高) CONF_NUM_ID_LOW = 2, // 発言数で色を変える回数 (低) CONF_LOOSE_URL = 1, // datのパース時にURL判定を甘くする(^なども含める) CONF_HIDE_USRCMD = 0, // ユーザーコマンドで選択できない項目を非表示にする CONF_RELOAD_ALLTHREAD = 0, // スレビューで再読み込みボタンを押したときに全タブを更新する CONF_TAB_MIN_STR = 4, // タブに表示する文字列の最小値 CONF_SHOW_TAB_ICON = 1, // タブにアイコンを表示するか CONF_SWITCHTAB_WHEEL = 1, // タブ上でマウスホイールを回転してタブを切り替える CONF_NEWTAB_POS = 1, // ビュー内から他のビューを開いたときのタブの位置 ( 0: 一番右端 1:右隣 2:左隣 ) CONF_BOARDNEXTTAB_POS = 0, // 次スレ検索を開くときのタブの位置 ( 0: 次スレ検索タブ 1:新しいタブ 2:アクティブなタブを置き換え ) CONF_SHOW_POST_MARK = 1, // スレビューに書き込みマークを表示するか CONF_FLAT_BUTTON = 1, // ボタンをフラットにするか CONF_DRAW_TOOLBARBACK = 0, // ツールバーの背景描画 CONF_IMGEMB_INTERP = 0, // 埋め込み画像のスムージングレベル(0-2, 2が最も高画質かつ低速) CONF_IMGMAIN_INTERP = 0, // 画像ビューのスムージングレベル(0-2, 2が最も高画質かつ低速) CONF_IMGPOPUP_INTERP = 0, // 画像ポップアップのスムージングレベル(0-2, 2が最も高画質かつ低速) CONF_IMGPOPUP_WIDTH = 320, // 画像ポップアップ幅 CONF_IMGPOPUP_HEIGHT = 240, // 画像ポップアップ高さ CONF_USE_IMAGE_POPUP = 1, // 画像ポップアップを使用する CONF_USE_IMAGE_VIEW = 1, // 画像ビューを使用する CONF_INLINE_IMG = 0, // インライン画像を表示する CONF_SHOW_SSSPICON = 1, // sssp アイコン表示 CONF_EMBIMG_WIDTH = 100, // インライン画像の最大幅 CONF_EMBIMG_HEIGHT = 100, // インライン画像の最大高さ CONF_HIDE_IMAGETAB = 1, // 埋め込み画像ビューを閉じたときにタブも閉じる CONF_SHOW_DELIMGDIAG = 1 , // 画像ビューでdeleteを押したときに確認ダイアログを表示する CONF_USE_MOSAIC = 1, // 画像にモザイクをかける CONF_MOSAIC_SIZE = 60, // モザイクの大きさ CONF_ZOOM_TO_FIT = 1, // 画像をデフォルトでウィンドウサイズに合わせる CONF_DEL_IMG_DAY = 20, // 画像キャッシュ削除の日数 CONF_DEL_IMGABONE_DAY = 20, // 画像あぼーん削除の日数 CONF_MAX_IMG_SIZE = 16, // ダウンロードする画像の最大サイズ(Mbyte) CONF_MAX_IMG_PIXEL = 20, // 画像の最大サイズ(Mピクセル) CONF_IMGCACHE_SIZE = 3, // 画像のメモリキャッシュ枚数 CONF_USE_LINK_AS_BOARD = 0, // bbsmenu.html内にあるリンクは全て板とみなす CONF_SHOW_MOVEDIAG = 1, // 板移転時に確認ダイアログを表示する CONF_REMOVE_OLD_ABONE_THREAD = 0, // dat落ちしたスレをNGスレタイトルリストから取り除くか( 0: ダイアログ表示 1: 取り除く 2: 除かない ) CONF_ABONE_NUMBER_THREAD = 0, // スレあぼーん( レス数 ) CONF_ABONE_HOUR_THREAD = 0, // スレあぼーん( スレ立てからの経過時間 ) CONF_ABONE_TRANSPARENT = 0, // デフォルトで透明あぼーんをする CONF_ABONE_CHAIN = 0, // デフォルトで連鎖あぼーんをする CONF_ABONE_ICASE = 0, // NG正規表現によるあぼーん時に大小文字の違いを無視 CONF_ABONE_WCHAR = 0, // NG正規表現によるあぼーん時に全角半角文字の違いを無視 CONF_EXPAND_SIDEBAR = 0, // 右ペーンが空の時にサイドバーを閉じる CONF_EXPAND_RPANE = 1, // 3ペーン時にスレ一覧やスレビューを最大化する CONF_OPEN_SIDEBAR_BY_CLICK = 1, // ペーンの境界をクリックしてサイドバーを開け閉めする CONF_THRESHOLD_NEXT = 5, // 次スレ検索の類似度のしきい値 CONF_REPLACE_FAVORITE_NEXT = 1, // 次スレを開いたときにお気に入りのアドレスと名前を自動更新 CONF_SHOW_DIAG_REPLACE_FAVORITE = 1, // お気に入りの自動更新をするかダイアログを出す CONF_BOOKMARK_DROP = 0, // スレをお気に入りに追加したときにしおりをセットする CONF_CHECK_UPDATE_BOARD = 0, // お気に入りの更新チェック時に板の更新もチェックする CONF_CHECK_UPDATE_BOOT = 0, // 起動時にお気に入りを自動でチェックする CONF_CHECK_FAVORITE_DUP = 1, // お気に入り登録時に重複項目を登録するか ( 0: 登録する 1: ダイアログ表示 2: 登録しない ) CONF_SHOW_FAVORITE_SELECT_DIAG = 0, // お気に入り登録時に挿入先ダイアログを表示する ( 0 : 表示する 1: 表示せず先頭に追加 2: 表示せず最後に追加 ) CONF_DISABLE_CLOSE = 0, // Ctrl+qでウィンドウを閉じない CONF_SHOW_HIDE_MENUBAR_DIAG = 1, // メニューバーを非表示にした時にダイアログを表示 CONF_CHANGE_STASTATUS_COLOR = 1, // 状態変更時にメインステータスバーの色を変える CONF_USE_MACHI_OFFLAW = 0, // まちBBSの取得に offlaw.cgi を使用する CONF_SHOW_DEL_WRITTEN_THREAD_DIAG = 1, // 書き込み履歴のあるスレを削除する時にダイアログを表示 CONF_DELETE_IMG_IN_THREAD = 0, // スレを削除する時に画像キャッシュも削除する ( 0: ダイアログ表示 1: 削除 2: 削除しない ) CONF_SHOW_DIAG_FIFO_ERROR = 1, // FIFOの作成などにエラーがあったらダイアログを表示する CONF_SAVE_SESSION = 0, // 指定した分ごとにセッションを自動保存 (0: 保存しない) }; // browsers.cpp のデフォルトのラベル番号 // configure で --with-xdg-open を指定すると xdg-open をデフォルトにする // browsers.cpp のブラウザの順番に気をつけること enum{ #ifndef _WIN32 #ifdef XDGOPEN CONF_BROWSER_NO = 1 // xdg-open をデフォルトにする #else CONF_BROWSER_NO = 2 // firefox をデフォルトにする #endif #else /* _WIN32 */ CONF_BROWSER_NO = 1 // ie をデフォルトにする #endif /* _WIN32 */ }; #define CONF_FONTSIZE_THREAD "12" #define CONF_FONTSIZE_POPUP "10" #define CONF_FONTSIZE_TREE "10" // レスを参照するときに前に付ける文字 #define CONF_REF_PREFIX ">" // レスにアスキーアートがあると判定する正規表現 #define CONF_REGEX_RES_AA_DEFAULT "  " #define CONF_REGEX_RES_AA "\"" CONF_REGEX_RES_AA_DEFAULT "\"" // キャッシュのルートディレクトリ(旧バージョンとの互換のため残している) #define CONF_PATH_CACHEROOT "~/.jd/" // 2ch にアクセスするときのエージェント名 #define CONF_AGENT_FOR2CH "Monazilla/1.00 JD" // 2ch外にアクセスするときのエージェント名 #define CONF_AGENT_FOR_DATA "Monazilla/1.00 JD" // 2ch にログインするときのX-2ch-UA #define CONF_X_2CH_UA "Navigator for 2ch 1.7.5" // JD ホームページのアドレス #define CONF_URL_JDHP "http://jd4linux.sourceforge.jp/" // 2chの認証サーバのアドレス #define CONF_LOGIN2CH "https://2chv.tora3.net/futen.cgi" // p2の認証サーバのアドレス #define CONF_LOGINP2 "http://p2.2ch.net/p2/" // BEの認証サーバのアドレス #define CONF_LOGINBE "http://be.2ch.net/test/login.php" // bbsmenu.htmlのURL #define CONF_URL_BBSMENU "http://menu.2ch.net/bbsmenu.html" // スレタイ検索用メニュータイトルアドレス #define CONF_MENU_SEARCH_TITLE "スレタイ検索 (find2ch)" #define CONF_URL_SEARCH_TITLE "http://find.2ch.net/?STR=$TEXTX&COUNT=50&TYPE=TITLE&BBS=ALL" // スレタイ検索用正規表現 #define CONF_REGEX_SEARCH_TITLE "(.+?) \\(([0-9]{1,4})\\)" // WEB検索用メニュータイトルアドレス #define CONF_MENU_SEARCH_WEB "WEB検索 (google)" #define CONF_URL_SEARCH_WEB "http://www.google.co.jp/search?hl=ja&q=$TEXTU&btnG=Google+%E6%A4%9C%E7%B4%A2&lr=" // p2 書き込み用アドレス #define CONF_URL_WRITEP2 "http://p2.2ch.net/p2/post_form.php?host=$HOST&bbs=$BBSNAME&key=$DATNAME" #define CONF_URL_RESP2 "http://p2.2ch.net/p2/post_form.php?host=$HOST&bbs=$BBSNAME&key=$DATNAME&popup=1&inyou=2&resnum=$NUMBER" // 2chのクッキー:HAP #define CONF_COOKIE_HAP "" #define CONF_COOKIE_HAP_BBSPINK "" // 色 #define CONF_COLOR_CHAR "#000000000000" // スレの文字 #define CONF_COLOR_CHAR_NAME "#000064640000" //名前欄の文字色 #define CONF_COLOR_CHAR_NAME_B "#000000008b8b" // トリップ等の名前欄の文字色 #define CONF_COLOR_CHAR_NAME_NOMAIL "#000064640000" //メール無し時の名前欄の文字色 #define CONF_COLOR_CHAR_AGE "#fde800000000" // ageの時のメール欄の文字色 #define CONF_COLOR_CHAR_SELECTION "#ffffffffffff" // 選択範囲の文字色 #define CONF_COLOR_CHAR_HIGHLIGHT CONF_COLOR_CHAR // ハイライトの文字色 #define CONF_COLOR_CHAR_LINK "#00000000ffff" //通常のリンクの文字色 #define CONF_COLOR_CHAR_LINK_ID_LOW CONF_COLOR_CHAR_LINK // 複数発言したIDの文字色 #define CONF_COLOR_CHAR_LINK_ID_HIGH CONF_COLOR_CHAR_AGE // 多く発言したIDの文字色 #define CONF_COLOR_CHAR_LINK_RES CONF_COLOR_CHAR_LINK // 参照されていないレス番号の文字色 #define CONF_COLOR_CHAR_LINK_LOW "#ffff0000ffff" // 他のレスから参照されたレス番号の文字色 #define CONF_COLOR_CHAR_LINK_HIGH CONF_COLOR_CHAR_AGE // 参照された数が多いレス番号の文字色 #define CONF_COLOR_CHAR_MESSAGE CONF_COLOR_CHAR // メッセージビューの文字色 #define CONF_COLOR_CHAR_MESSAGE_SELECTION CONF_COLOR_CHAR_SELECTION // メッセージビュー(選択範囲)の文字色 #define CONF_COLOR_IMG_NOCACHE "#a5a52a2a2a2a" // 画像(キャッシュ無)の色 #define CONF_COLOR_IMG_CACHED "#00008b8b8b8b" // 画像(キャッシュ有)の色 #define CONF_COLOR_IMG_LOADING "#ffff8c8c0000" // 画像(ロード中)の色 #define CONF_COLOR_IMG_ERR CONF_COLOR_CHAR_AGE // 画像(エラー)の色 #define CONF_COLOR_BACK "#fde8fde8f618" // スレ背景色 #define CONF_COLOR_BACK_POPUP CONF_COLOR_BACK // ポップアップ背景色 #define CONF_COLOR_BACK_SELECTION CONF_COLOR_CHAR_LINK // 選択範囲の背景色 #define CONF_COLOR_BACK_HIGHLIGHT "#ffffffff0000" // ハイライト色 #define CONF_COLOR_BACK_HIGHLIGHT_TREE CONF_COLOR_BACK_HIGHLIGHT // ツリーのハイライト色 #define CONF_COLOR_BACK_MESSAGE CONF_COLOR_BACK // メッセージビューの背景色 #define CONF_COLOR_BACK_MESSAGE_SELECTION CONF_COLOR_BACK_SELECTION // メッセージビューの選択色 #define CONF_COLOR_SEPARATOR_NEW "#7d007d007d00" // セパレータ #define CONF_COLOR_FRAME CONF_COLOR_CHAR // ポップアップフレーム色 #define CONF_COLOR_MARKER CONF_COLOR_CHAR // オートスクロールマーカー色 #define CONF_COLOR_CHAR_BBS CONF_COLOR_CHAR // 板一覧の文字 #define CONF_COLOR_CHAR_BBS_COMMENT CONF_COLOR_CHAR // 板一覧のコメント #define CONF_COLOR_CHAR_BOARD CONF_COLOR_CHAR // スレ一覧の文字 #define CONF_COLOR_BACK_BBS CONF_COLOR_BACK // 板一覧の背景色 #define CONF_COLOR_BACK_BBS_EVEN CONF_COLOR_BACK_BBS // 板一覧の背景色(偶数行) #define CONF_COLOR_BACK_BOARD CONF_COLOR_BACK // スレ一覧の背景色 #define CONF_COLOR_BACK_BOARD_EVEN CONF_COLOR_BACK_BOARD // スレ一覧の背景色(偶数行) #define CONF_WRITE_NAME "" // デフォルトの書き込み名 #define CONF_WRITE_MAIL "sage" // デフォルトのメールアドレス // migemo-dictの場所 #ifdef MIGEMODICT #define CONF_MIGEMO_PATH MIGEMODICT #else #define CONF_MIGEMO_PATH "/usr/share/migemo/utf-8/migemo-dict" #endif } #endif jd-2.8.7-140104/src/config/globalconf.cpp0000644000076400010400000007241212201335554014444 0ustar // ライセンス: GPL2 #ifdef HAVE_CONFIG_H #include "config.h" #endif //#define _DEBUG #include "jddebug.h" #include "globalconf.h" #include "configitems.h" #include "jdlib/miscutil.h" CONFIG::ConfigItems* instance_confitem = NULL; CONFIG::ConfigItems* instance_confitem_bkup = NULL; CONFIG::ConfigItems* CONFIG::get_confitem() { if( ! instance_confitem ) instance_confitem = new CONFIG::ConfigItems(); return instance_confitem; } void CONFIG::delete_confitem() { if( instance_confitem ) delete instance_confitem; instance_confitem = NULL; if( instance_confitem_bkup ) delete instance_confitem_bkup; instance_confitem_bkup = NULL; } const bool CONFIG::load_conf() { return get_confitem()->load(); } void CONFIG::save_conf() { get_confitem()->save(); } void CONFIG::bkup_conf() { if( ! instance_confitem_bkup ) instance_confitem_bkup = new CONFIG::ConfigItems(); *instance_confitem_bkup = * instance_confitem; } void CONFIG::restore_conf() { if( ! instance_confitem_bkup ) return; *instance_confitem = * instance_confitem_bkup; } ////////////////////////////////////////////////////////////// const bool CONFIG::get_restore_board(){ return get_confitem()->restore_board; } void CONFIG::set_restore_board( const bool restore ){ get_confitem()->restore_board = restore; } const bool CONFIG::get_restore_article(){ return get_confitem()->restore_article; } void CONFIG::set_restore_article( const bool restore ){ get_confitem()->restore_article = restore; } const bool CONFIG::get_restore_image(){ return get_confitem()->restore_image; } void CONFIG::set_restore_image( const bool restore ){ get_confitem()->restore_image = restore; } const bool CONFIG::get_manage_winpos(){ return get_confitem()->manage_winpos; } void CONFIG::set_manage_winpos( const bool manage ){ get_confitem()->manage_winpos = manage; } // 色 const std::string& CONFIG::get_color( const int id ) { return get_confitem()->str_color[ id ]; } void CONFIG::set_color( const int id, const std::string& color ) { get_confitem()->str_color[ id ] = color; } void CONFIG::reset_colors(){ get_confitem()->reset_colors(); } const bool CONFIG::get_use_tree_gtkrc(){ return get_confitem()->use_tree_gtkrc; } void CONFIG::set_use_tree_gtkrc( const bool use ){ get_confitem()->use_tree_gtkrc = use; } const bool CONFIG::get_use_select_gtkrc(){ return get_confitem()->use_select_gtkrc; } void CONFIG::set_use_select_gtkrc( const bool use ){ get_confitem()->use_select_gtkrc = use; } // ツリービューの行間スペース const int CONFIG::get_tree_ypad(){ return get_confitem()->tree_ypad; } // ツリービューにエクスパンダを表示 const bool CONFIG::get_tree_show_expanders(){ return get_confitem()->tree_show_expanders; } // ツリービューのレベルインデント調整量(ピクセル) const int CONFIG::get_tree_level_indent(){ return get_confitem()->tree_level_indent; } // カテゴリを開いたときにツリービューをスクロールする const bool CONFIG::get_scroll_tree(){ return get_confitem()->scroll_tree; } // ツリービューの選択を、表示中のビューと同期するか ( 0: 同期しない 1: 同期する 2: 同期する(フォルダを開く) ) const int CONFIG::get_select_item_sync(){ return get_confitem()->select_item_sync; } const int CONFIG::get_view_margin(){ return get_confitem()->view_margin; } // スクロールバーを左に配置 const bool CONFIG::get_left_scrbar(){ return get_confitem()->left_scrbar; } // スレ一覧で古いスレも表示 const bool CONFIG::get_show_oldarticle(){ return get_confitem()->show_oldarticle; } // フォント const std::string& CONFIG::get_fontname( const int id ) { return get_confitem()->fontname[ id ]; } void CONFIG::set_fontname( const int id, const std::string& fontname ) { get_confitem()->fontname[ id ] = fontname; } void CONFIG::reset_fonts(){ get_confitem()->reset_fonts(); } const bool CONFIG::get_aafont_enabled(){ return get_confitem()->aafont_enabled; } const std::string CONFIG::get_ref_prefix(){ return get_confitem()->ref_prefix + get_confitem()->ref_prefix_space_str; } const int CONFIG::ref_prefix_space(){ return get_confitem()->ref_prefix_space; } // レスにアスキーアートがあると判定する正規表現 const std::string CONFIG::get_regex_res_aa(){ std::string str = get_confitem()->regex_res_aa; int size = str.size(); // ダブルクオートの削除 if( size >= 2 && str[ 0 ] == '"' && str[ size - 1 ] == '"' ){ str = str.substr( 1, size - 2 ); } return str; } void CONFIG::set_regex_res_aa( const std::string& regex ){ get_confitem()->regex_res_aa = "\"" + regex + "\""; } const std::string& CONFIG::get_url_jdhp() { return get_confitem()->url_jdhp; } // 2chの認証サーバのアドレス const std::string& CONFIG::get_url_login2ch() { return get_confitem()->url_login2ch; } // p2の認証サーバのアドレス const std::string& CONFIG::get_url_loginp2() { return get_confitem()->url_loginp2; } void CONFIG::set_url_loginp2( const std::string& url ) { get_confitem()->url_loginp2 = url; } // BEの認証サーバのアドレス const std::string& CONFIG::get_url_loginbe() { return get_confitem()->url_loginbe; } const std::string& CONFIG::get_url_bbsmenu() { return get_confitem()->url_bbsmenu; } const bool CONFIG::use_link_as_board(){ return get_confitem()->use_link_as_board; } const bool CONFIG::get_show_movediag(){ return get_confitem()->show_movediag; } void CONFIG::set_show_movediag( const bool show ){ get_confitem()->show_movediag = show; } const std::string& CONFIG::get_menu_search_title(){ return get_confitem()->menu_search_title; } const std::string& CONFIG::get_url_search_title(){ return get_confitem()->url_search_title; } const std::string& CONFIG::get_regex_search_title(){ return get_confitem()->regex_search_title; } const std::string& CONFIG::get_menu_search_web(){ return get_confitem()->menu_search_web; } const std::string& CONFIG::get_url_search_web(){ return get_confitem()->url_search_web; } const std::string& CONFIG::get_url_writep2(){ return get_confitem()->url_writep2; } const std::string& CONFIG::get_url_resp2(){ return get_confitem()->url_resp2; } const std::string& CONFIG::get_agent_for2ch() { return get_confitem()->agent_for2ch; } const bool CONFIG::get_use_proxy_for2ch() { return get_confitem()->use_proxy_for2ch; } const std::string& CONFIG::get_proxy_for2ch() { return get_confitem()->proxy_for2ch; } const int CONFIG::get_proxy_port_for2ch() { return get_confitem()->proxy_port_for2ch; } const std::string& CONFIG::get_proxy_basicauth_for2ch() { return get_confitem()->proxy_basicauth_for2ch; } void CONFIG::set_use_proxy_for2ch( bool set ){ get_confitem()->use_proxy_for2ch = set; } void CONFIG::set_proxy_for2ch( const std::string& proxy ){ get_confitem()->set_proxy_for2ch( proxy ); } void CONFIG::set_proxy_port_for2ch( int port ){ get_confitem()->proxy_port_for2ch = port; } const bool CONFIG::get_use_proxy_for2ch_w() { return get_confitem()->use_proxy_for2ch_w; } const std::string& CONFIG::get_proxy_for2ch_w() { return get_confitem()->proxy_for2ch_w; } const int CONFIG::get_proxy_port_for2ch_w() { return get_confitem()->proxy_port_for2ch_w; } const std::string& CONFIG::get_proxy_basicauth_for2ch_w() { return get_confitem()->proxy_basicauth_for2ch_w; } void CONFIG::set_use_proxy_for2ch_w( bool set ){ get_confitem()->use_proxy_for2ch_w = set; } void CONFIG::set_proxy_for2ch_w( const std::string& proxy ){ get_confitem()->set_proxy_for2ch_w( proxy ); } void CONFIG::set_proxy_port_for2ch_w( int port ){ get_confitem()->proxy_port_for2ch_w = port; } const std::string& CONFIG::get_agent_for_data() { return get_confitem()->agent_for_data; } const bool CONFIG::get_use_proxy_for_data() { return get_confitem()->use_proxy_for_data; } const std::string& CONFIG::get_proxy_for_data() { return get_confitem()->proxy_for_data; } const int CONFIG::get_proxy_port_for_data() { return get_confitem()->proxy_port_for_data; } const std::string& CONFIG::get_proxy_basicauth_for_data() { return get_confitem()->proxy_basicauth_for_data; } const std::string& CONFIG::get_x_2ch_ua() { return get_confitem()->x_2ch_ua; } void CONFIG::set_use_proxy_for_data( bool set ){ get_confitem()->use_proxy_for_data = set; } void CONFIG::set_proxy_for_data( const std::string& proxy ){ get_confitem()->set_proxy_for_data( proxy ); } void CONFIG::set_proxy_port_for_data( int port ){ get_confitem()->proxy_port_for_data = port; } const int CONFIG::get_loader_bufsize(){ return get_confitem()->loader_bufsize; } const int CONFIG::get_loader_bufsize_board(){ return get_confitem()->loader_bufsize_board; } const int CONFIG::get_loader_timeout(){ return get_confitem()->loader_timeout; } const int CONFIG::get_loader_timeout_post(){ return get_confitem()->loader_timeout_post; } const int CONFIG::get_loader_timeout_data(){ return get_confitem()->loader_timeout_img; } // 旧 get_loader_timeout_img() 関数 const int CONFIG::get_loader_timeout_checkupdate(){ return get_confitem()->loader_timeout_checkupdate; } const bool CONFIG::get_use_ipv6(){ return get_confitem()->use_ipv6; } void CONFIG::set_use_ipv6( const bool set ){ get_confitem()->use_ipv6 = set; } // 同一ホストに対する最大コネクション数( 1 または 2 ) const int CONFIG::get_connection_num(){ return get_confitem()->connection_num; } // 2chのクッキー:HAP const bool CONFIG::get_use_cookie_hap(){ return get_confitem()->use_cookie_hap; } const std::string& CONFIG::get_cookie_hap(){ return get_confitem()->cookie_hap; } const std::string& CONFIG::get_cookie_hap_bbspink(){ return get_confitem()->cookie_hap_bbspink; } void CONFIG::set_cookie_hap( const std::string& cookie_hap ){ get_confitem()->cookie_hap = cookie_hap; } void CONFIG::set_cookie_hap_bbspink( const std::string& cookie_hap ){ get_confitem()->cookie_hap_bbspink = cookie_hap; } const std::string& CONFIG::get_command_openurl() { return get_confitem()->command_openurl; } void CONFIG::set_command_openurl( const std::string& command ){ get_confitem()->command_openurl = command; } const int CONFIG::get_browsercombo_id(){ return get_confitem()->browsercombo_id; } void CONFIG::set_browsercombo_id( const int id ){ get_confitem()->browsercombo_id = id; } const bool CONFIG::get_refpopup_by_mo(){ return get_confitem()->refpopup_by_mo; } const bool CONFIG::get_namepopup_by_mo(){ return get_confitem()->namepopup_by_mo; } const bool CONFIG::get_idpopup_by_mo(){ return get_confitem()->idpopup_by_mo; } const int CONFIG::get_imgemb_interp(){ return get_confitem()->imgemb_interp; } const int CONFIG::get_imgmain_interp(){ return get_confitem()->imgmain_interp; } const int CONFIG::get_imgpopup_interp(){ return get_confitem()->imgpopup_interp; } const int CONFIG::get_imgpopup_width(){ return get_confitem()->imgpopup_width; } const int CONFIG::get_imgpopup_height(){ return get_confitem()->imgpopup_height; } const bool CONFIG::get_use_image_popup(){ return get_confitem()->use_image_popup; } void CONFIG::set_use_image_popup( const bool use ){ get_confitem()->use_image_popup = use; } const bool CONFIG::get_use_image_view(){ return get_confitem()->use_image_view; } void CONFIG::set_use_image_view( const bool image_view ){ get_confitem()->use_image_view = image_view; } const bool CONFIG::get_use_inline_image(){ return get_confitem()->use_inline_image; } void CONFIG::set_use_inline_image( const bool inline_img ){ get_confitem()->use_inline_image = inline_img; } const bool CONFIG::get_show_ssspicon(){ return get_confitem()->show_ssspicon; } void CONFIG::set_show_sssp_icon( const bool show ){ get_confitem()->show_ssspicon = show; } // インライン画像の最大幅と高さ const int CONFIG::get_embimg_width(){ return get_confitem()->embimg_width; } const int CONFIG::get_embimg_height(){ return get_confitem()->embimg_height; } // 埋め込み画像ビューを閉じたときにタブも閉じる const bool CONFIG::get_hide_imagetab(){ return get_confitem()->hide_imagetab; } // 画像ビューでdeleteを押したときに確認ダイアログを表示する const bool CONFIG::get_show_delimgdiag(){ return get_confitem()->show_delimgdiag; } void CONFIG::set_show_delimgdiag( const bool show ){ get_confitem()->show_delimgdiag = show; } const bool CONFIG::get_use_mosaic(){ return get_confitem()->use_mosaic; } void CONFIG::set_use_mosaic( const bool mosaic ) { get_confitem()->use_mosaic = mosaic; } const int CONFIG::get_mosaic_size(){ return get_confitem()->mosaic_size; } const bool CONFIG::get_zoom_to_fit(){ return get_confitem()->zoom_to_fit; } void CONFIG::set_zoom_to_fit( const bool fit ){ get_confitem()->zoom_to_fit = fit; } const int CONFIG::get_del_img_day(){ return get_confitem()->del_img_day; } void CONFIG::set_del_img_day( const int day ){ get_confitem()->del_img_day = day; } const int CONFIG::get_del_imgabone_day(){ return get_confitem()->del_imgabone_day; } void CONFIG::set_del_imgabone_day( const int day ){ get_confitem()->del_imgabone_day = day; } const int CONFIG::get_max_img_size(){ return get_confitem()->max_img_size; } const int CONFIG::get_max_img_pixel(){ return get_confitem()->max_img_pixel; } const int CONFIG::get_imgcache_size(){ return get_confitem()->imgcache_size; } const int CONFIG::get_newthread_hour(){ return get_confitem()->newthread_hour; } const bool CONFIG::get_inc_search_board(){ return get_confitem()->inc_search_board; } const bool CONFIG::get_show_deldiag(){ return get_confitem()->show_deldiag; } void CONFIG::set_show_deldiag( const bool show ){ get_confitem()->show_deldiag = show; } // スレ一覧をロードする前にキャッシュにある一覧を表示 const bool CONFIG::get_show_cached_board(){ return get_confitem()->show_cached_board; } // スレ一覧でお知らせスレ(924)のアイコンを表示する const bool CONFIG::get_show_924(){ return get_confitem()->show_924; } const int CONFIG::get_tree_scroll_size(){ return get_confitem()->tree_scroll_size; } const int CONFIG::get_scroll_size(){ return get_confitem()->scroll_size; } const int CONFIG::get_key_scroll_size(){ return get_confitem()->key_scroll_size; } const int CONFIG::get_key_fastscroll_size(){ return get_confitem()->key_fastscroll_size; } const bool CONFIG::get_jump_after_reload(){ return get_confitem()->jump_after_reload; } void CONFIG::set_jump_after_reload( const bool set ){ get_confitem()->jump_after_reload = set; } const bool CONFIG::get_jump_new_after_reload(){ return get_confitem()->jump_new_after_reload; } void CONFIG::set_jump_new_after_reload( const bool set ){ get_confitem()->jump_new_after_reload = set; } const int CONFIG::get_live_mode(){ return get_confitem()->live_mode; } void CONFIG::set_live_mode( const int mode ) { get_confitem()->live_mode = mode; } const int CONFIG::get_live_speed(){ return get_confitem()->live_speed; } void CONFIG::set_live_speed( const int speed ){ get_confitem()->live_speed = speed; } const int CONFIG::get_live_threshold(){ return get_confitem()->live_threshold; } void CONFIG::set_live_threshode( const int th ){ get_confitem()->live_threshold = th; } const bool CONFIG::get_open_one_category(){ return get_confitem()->open_one_category; } const bool CONFIG::get_open_one_favorite(){ return get_confitem()->open_one_favorite; } // デフォルトの書き込み名 const std::string CONFIG::get_write_name(){ return get_confitem()->write_name; } // デフォルトのメールアドレス const std::string CONFIG::get_write_mail(){ return get_confitem()->write_mail; } const bool CONFIG::get_always_write_ok() { return get_confitem()->always_write_ok; } void CONFIG::set_always_write_ok( const bool write_ok ){ get_confitem()->always_write_ok = write_ok; } const bool CONFIG::get_save_post_log(){ return get_confitem()->save_postlog; } void CONFIG::set_save_post_log( const bool save ){ get_confitem()->save_postlog = save; } const size_t CONFIG::get_maxsize_post_log(){ return get_confitem()->maxsize_postlog; } // 書き込み履歴を保存 const bool CONFIG::get_save_post_history(){ return get_confitem()->save_posthist; } void CONFIG::set_save_post_history( const bool save ){ get_confitem()->save_posthist = save; } const bool CONFIG::get_hide_writing_dialog(){ return get_confitem()->hide_writing_dialog; } // 編集中のメッセージの保存確認ダイアログを表示する const bool CONFIG::get_show_savemsgdiag(){ return get_confitem()->show_savemsgdiag; } void CONFIG::set_show_savemsgdiag( const bool show ){ get_confitem()->show_savemsgdiag = show; } // 書き込みビューでテキストを折り返す const bool CONFIG::get_message_wrap(){ return get_confitem()->message_wrap; } void CONFIG::set_message_wrap( const bool wrap ){ get_confitem()->message_wrap = wrap; } const bool CONFIG::get_fold_message(){ return get_confitem()->fold_message; } void CONFIG::set_fold_message( const bool fold ){ get_confitem()->fold_message = fold; } const bool CONFIG::get_fold_image(){ return get_confitem()->fold_image; } const bool CONFIG::get_keep_im_status(){ return get_confitem()->keep_im_status; } const int CONFIG::get_margin_popup(){ return get_confitem()->margin_popup; } void CONFIG::set_margin_popup( const int margin ){ get_confitem()->margin_popup = margin; } // 画像ポップアップとカーソルの間のマージン const int CONFIG::get_margin_imgpopup_x(){ return get_confitem()->margin_imgpopup_x; } const int CONFIG::get_margin_imgpopup(){ return get_confitem()->margin_imgpopup; } // ポップアップが消えるまでの時間(ミリ秒) const int CONFIG::get_hide_popup_msec(){ return get_confitem()->hide_popup_msec; } // マウスジェスチャを有効 const bool CONFIG::get_enable_mg(){ return get_confitem()->enable_mg; } // マウスジェスチャの判定開始半径 const int CONFIG::get_mouse_radius(){ return get_confitem()->mouse_radius; } // 数字入力ジャンプのウェイト(ミリ秒) const int CONFIG::get_numberjmp_msec(){ return get_confitem()->numberjmp_msec; } const int CONFIG::get_history_size(){ return get_confitem()->history_size; } const int CONFIG::get_historyview_size(){ return get_confitem()->historyview_size; } const int CONFIG::get_aahistory_size(){ return get_confitem()->aahistory_size; } // 0以上なら多重ポップアップの説明を表示する // 呼び出される度に--する const int CONFIG::get_instruct_popup(){ if( get_confitem()->instruct_popup ) return get_confitem()->instruct_popup--; return 0; } const bool CONFIG::get_instruct_tglart(){ if( get_confitem()->instruct_tglart_end ) return false; get_confitem()->instruct_tglart_end = true; // 一度表示したら表示しない return get_confitem()->instruct_tglart; } void CONFIG::set_instruct_tglart( const bool tgl ){ get_confitem()->instruct_tglart = tgl; } const bool CONFIG::get_instruct_tglimg(){ if( get_confitem()->instruct_tglimg_end ) return false; get_confitem()->instruct_tglimg_end = true; // 一度表示したら表示しない return get_confitem()->instruct_tglimg; } void CONFIG::set_instruct_tglimg( bool tgl ){ get_confitem()->instruct_tglimg = tgl; } // スレビューでdeleteを押したときに確認ダイアログを表示する const bool CONFIG::get_show_delartdiag(){ return get_confitem()->show_delartdiag; } void CONFIG::set_show_delartdiag( const bool show ){ get_confitem()->show_delartdiag = show; } const double CONFIG::get_adjust_underline_pos(){ return get_confitem()->adjust_underline_pos; } void CONFIG::set_adjust_underline_pos( const double pos ){ get_confitem()->adjust_underline_pos = pos; } const double CONFIG::get_adjust_line_space(){ return get_confitem()->adjust_line_space; } void CONFIG::set_adjust_line_space( const double space ){ get_confitem()->adjust_line_space = space; } const bool CONFIG::get_draw_underline(){ return get_confitem()->draw_underline; } const bool CONFIG::get_strict_char_width(){ return get_confitem()->strict_char_width; } void CONFIG::set_strict_char_width( const bool strictwidth ){ get_confitem()->strict_char_width = strictwidth; } const bool CONFIG::get_check_id(){ return get_confitem()->check_id; } const int CONFIG::get_num_reference_high(){ return get_confitem()->num_reference_high; } const int CONFIG::get_num_reference_low(){ return get_confitem()->num_reference_low; } const int CONFIG::get_num_id_high(){ return get_confitem()->num_id_high; } const int CONFIG::get_num_id_low(){ return get_confitem()->num_id_low; } const bool CONFIG::get_loose_url(){ return get_confitem()->loose_url; } const bool CONFIG::get_hide_usrcmd(){ return get_confitem()->hide_usrcmd; } void CONFIG::set_hide_usrcmd( const bool hide ){ get_confitem()->hide_usrcmd = hide; } const bool CONFIG::get_reload_allthreads(){ return get_confitem()->reload_allthreads; } const int CONFIG::get_tab_min_str(){ return get_confitem()->tab_min_str; } const bool CONFIG::get_show_tab_icon(){ return get_confitem()->show_tab_icon; } // タブ上でマウスホイールを回転してタブを切り替える const bool CONFIG::get_switchtab_wheel(){ return get_confitem()->switchtab_wheel; } // ビュー内から他のビューを開いたときのタブの位置 ( 0: 一番右端 1:右隣 2:左隣 ) const int CONFIG::get_newtab_pos(){ return get_confitem()->newtab_pos; } // 次スレ検索を開くときのタブの位置 ( 0: 次スレ検索タブ 1:新しいタブ 2:アクティブなタブを置き換え ) const int CONFIG::get_boardnexttab_pos(){ return get_confitem()->boardnexttab_pos; } const bool CONFIG::get_show_post_mark(){ return get_confitem()->show_post_mark; } void CONFIG::set_show_post_mark( const bool show ){ get_confitem()->show_post_mark = show; } const bool CONFIG::get_flat_button(){ return get_confitem()->flat_button; } void CONFIG::set_flat_button( const bool set ){ get_confitem()->flat_button = set; } // ツールバーの背景描画 const bool CONFIG::get_draw_toolbarback(){ return get_confitem()->draw_toolbarback; } void CONFIG::set_draw_toolbarback( const bool set ){ get_confitem()->draw_toolbarback = set; } std::list< std::string >& CONFIG::get_list_abone_word_thread(){ return get_confitem()->list_abone_word_thread; } std::list< std::string >& CONFIG::get_list_abone_regex_thread(){ return get_confitem()->list_abone_regex_thread; } void CONFIG::set_list_abone_word_thread( std::list< std::string >& word ) { // 前後の空白と空白行を除く get_confitem()->list_abone_word_thread = MISC::remove_space_from_list( word ); get_confitem()->list_abone_word_thread = MISC::remove_nullline_from_list( get_confitem()->list_abone_word_thread ); } void CONFIG::set_list_abone_regex_thread( std::list< std::string >& regex ) { // 前後の空白と空白行を除く get_confitem()->list_abone_regex_thread = MISC::remove_space_from_list( regex ); get_confitem()->list_abone_regex_thread = MISC::remove_nullline_from_list( get_confitem()->list_abone_regex_thread ); } const int CONFIG::get_remove_old_abone_thread(){ return get_confitem()->remove_old_abone_thread; } void CONFIG::set_remove_old_abone_thread( const int remove ){ get_confitem()->remove_old_abone_thread = remove; } const int CONFIG::get_abone_number_thread(){ return get_confitem()->abone_number_thread; } void CONFIG::set_abone_number_thread( const int number ){ get_confitem()->abone_number_thread = number; } const int CONFIG::get_abone_hour_thread(){ return get_confitem()->abone_hour_thread; } void CONFIG::set_abone_hour_thread( const int hour ){ get_confitem()->abone_hour_thread = hour; } const std::list< std::string >& CONFIG::get_list_abone_name(){ return get_confitem()->list_abone_name; } const std::list< std::string >& CONFIG::get_list_abone_word(){ return get_confitem()->list_abone_word; } const std::list< std::string >& CONFIG::get_list_abone_regex(){ return get_confitem()->list_abone_regex; } void CONFIG::set_list_abone_name( const std::list< std::string >& name ) { // 前後の空白と空白行を除く get_confitem()->list_abone_name = MISC::remove_space_from_list( name ); get_confitem()->list_abone_name = MISC::remove_nullline_from_list( get_confitem()->list_abone_name ); } void CONFIG::set_list_abone_word( const std::list< std::string >& word ) { // 前後の空白と空白行を除く get_confitem()->list_abone_word = MISC::remove_space_from_list( word ); get_confitem()->list_abone_word = MISC::remove_nullline_from_list( get_confitem()->list_abone_word ); } void CONFIG::set_list_abone_regex( const std::list< std::string >& regex ) { // 前後の空白と空白行を除く get_confitem()->list_abone_regex = MISC::remove_space_from_list( regex ); get_confitem()->list_abone_regex = MISC::remove_nullline_from_list( get_confitem()->list_abone_regex ); } // デフォルトで透明、連鎖あぼーんをするか const bool CONFIG::get_abone_transparent(){ return get_confitem()->abone_transparent; } void CONFIG::set_abone_transparent( const bool set ){ get_confitem()->abone_transparent = set; } const bool CONFIG::get_abone_chain(){ return get_confitem()->abone_chain; } void CONFIG::set_abone_chain( const bool set ){ get_confitem()->abone_chain = set; } // NG正規表現によるあぼーん時に大小と全半角文字の違いを無視 const bool CONFIG::get_abone_icase(){ return get_confitem()->abone_icase; } void CONFIG::set_abone_icase( const bool set ){ get_confitem()->abone_icase = set; } const bool CONFIG::get_abone_wchar(){ return get_confitem()->abone_wchar; } void CONFIG::set_abone_wchar( const bool set ){ get_confitem()->abone_wchar = set; } const bool CONFIG::get_expand_sidebar(){ return get_confitem()->expand_sidebar; } const bool CONFIG::get_expand_rpane(){ return get_confitem()->expand_rpane; } // ペーンの境界をクリックしてサイドバーを開け閉めする const bool CONFIG::get_open_sidebar_by_click(){ return get_confitem()->open_sidebar_by_click; } // 次スレ検索の類似度のしきい値 const int CONFIG::get_threshold_next(){ return get_confitem()->threshold_next; } // 次スレを開いたときにお気に入りのアドレスと名前を自動更新 const int CONFIG::get_replace_favorite_next(){ return get_confitem()->replace_favorite_next; } void CONFIG::set_replace_favorite_next( const int mode ){ get_confitem()->replace_favorite_next = mode; } // お気に入りの自動更新をするかダイアログを出す const bool CONFIG::show_diag_replace_favorite(){ return get_confitem()->show_diag_replace_favorite; } void CONFIG::set_show_diag_replace_favorite( const bool show ){ get_confitem()->show_diag_replace_favorite = show; } // スレをお気に入りに追加したときにしおりをセットする const bool CONFIG::get_bookmark_drop(){ return get_confitem()->bookmark_drop; } // お気に入りの更新チェック時に板の更新もチェックする const bool CONFIG::get_check_update_board(){ return get_confitem()->check_update_board; } // 起動時にお気に入りを自動でチェックする const bool CONFIG::get_check_update_boot(){ return get_confitem()->check_update_boot; } // お気に入り登録時に重複項目を登録するか ( 0: 登録する 1: ダイアログ表示 2: 登録しない ) const int CONFIG::get_check_favorite_dup(){ return get_confitem()->check_favorite_dup; } void CONFIG::set_check_favorite_dup( const int check ){ get_confitem()->check_favorite_dup = check; } // お気に入り登録時に挿入先ダイアログを表示する ( 0 : 表示する 1: 表示せず先頭に追加 2: 表示せず最後に追加 ) const int CONFIG::get_show_favorite_select_diag(){ return get_confitem()->show_favorite_select_diag; } // Ctrl+qでウィンドウを閉じない ( 2.8.6以前と互換性を保つため残す ) const bool CONFIG::get_disable_close(){ return get_confitem()->disable_close; } void CONFIG::set_disable_close( const bool disable ){ get_confitem()->disable_close = disable; } // メニューバーを非表示にした時にダイアログを表示 const bool CONFIG::get_show_hide_menubar_diag(){ return get_confitem()->show_hide_menubar_diag; } void CONFIG::set_show_hide_menubar_diag( const bool set ){ get_confitem()->show_hide_menubar_diag = set; } // 状態変更時にメインステータスバーの色を変える const bool CONFIG::get_change_stastatus_color(){ return get_confitem()->change_stastatus_color; } // まちBBSの取得に offlaw.cgi を使用する const bool CONFIG::get_use_machi_offlaw(){ return get_confitem()->use_machi_offlaw; } void CONFIG::set_use_machi_offlaw( const bool set ){ get_confitem()->use_machi_offlaw = set; } // 書き込み履歴のあるスレを削除する時にダイアログを表示 const bool CONFIG::get_show_del_written_thread_diag(){ return get_confitem()->show_del_written_thread_diag; } void CONFIG::set_del_written_thread_diag( const bool set ){ get_confitem()->show_del_written_thread_diag = set; } // スレを削除する時に画像キャッシュも削除する ( 0: ダイアログ表示 1: 削除 2: 削除しない ) const int CONFIG::get_delete_img_in_thread(){ return get_confitem()->delete_img_in_thread; } void CONFIG::set_delete_img_in_thread( const int set ){ get_confitem()->delete_img_in_thread = set; } // FIFOの作成などにエラーがあったらダイアログを表示する const bool CONFIG::get_show_diag_fifo_error(){ return get_confitem()->show_diag_fifo_error; } void CONFIG::set_show_diag_fifo_error( const bool set ){ get_confitem()->show_diag_fifo_error = set; } // 指定した分ごとにセッションを自動保存 (0: 保存しない) const int CONFIG::get_save_session(){ return get_confitem()->save_session; } #ifdef HAVE_MIGEMO_H const std::string& CONFIG::get_migemodict_path() { return get_confitem()->migemodict_path; } #endif jd-2.8.7-140104/src/config/globalconf.h0000644000076400010400000005145412201335554014114 0ustar // ライセンス: GPL2 // // グローバル設定 // #ifndef _GLOBALCONF_H #define _GLOBALCONF_H #include #include namespace CONFIG { class ConfigItems; ConfigItems* get_confitem(); void delete_confitem(); // 設定読み込み、書き込み const bool load_conf(); void save_conf(); // 設定の一時的なバックアップと復元 void bkup_conf(); void restore_conf(); ///////////////////////////////////////////// // 前回開いたviewを復元するか const bool get_restore_board(); void set_restore_board( const bool restore ); const bool get_restore_article(); void set_restore_article( const bool restore ); const bool get_restore_image(); void set_restore_image( const bool restore ); // 自前でウィンドウ配置を管理する const bool get_manage_winpos(); void set_manage_winpos( const bool manage ); // 色 ( # + 12桁の16進数 の形式 ) const std::string& get_color( const int id ); void set_color( const int id, const std::string& color ); void reset_colors(); // ツリービューでgtkrcの設定を使用するか const bool get_use_tree_gtkrc(); void set_use_tree_gtkrc( const bool use ); // スレビューの選択色でgtkrcの設定を使用するか const bool get_use_select_gtkrc(); void set_use_select_gtkrc( const bool use ); // ツリービューの行間スペース const int get_tree_ypad(); // ツリービューにエクスパンダを表示 const bool get_tree_show_expanders(); // ツリービューのレベルインデント調整量(ピクセル) const int get_tree_level_indent(); // カテゴリを開いたときにツリービューをスクロールする const bool get_scroll_tree(); // ツリービューの選択を、表示中のビューと同期するか ( 0: 同期しない 1: 同期する 2: 同期する(フォルダを開く) ) const int get_select_item_sync(); // 各ビューと枠との間の余白 const int get_view_margin(); // スクロールバーを左に配置 const bool get_left_scrbar(); // スレ一覧で古いスレも表示 const bool get_show_oldarticle(); // フォント const std::string& get_fontname( const int id ); void set_fontname( const int id, const std::string& fontname ); void reset_fonts(); const bool get_aafont_enabled(); // レスを参照するときに前に付ける文字 const std::string get_ref_prefix(); // 参照文字( ref_prefix ) の後のスペースの数 const int ref_prefix_space(); // レスにアスキーアートがあると判定する正規表現 const std::string get_regex_res_aa(); void set_regex_res_aa( const std::string& regex ); // JD ホームページのアドレス const std::string& get_url_jdhp(); // 2chの認証サーバのアドレス const std::string& get_url_login2ch(); // p2の認証サーバのアドレス const std::string& get_url_loginp2(); void set_url_loginp2( const std::string& url ); // BEの認証サーバのアドレス const std::string& get_url_loginbe(); // bbsmenu.htmlのURL const std::string& get_url_bbsmenu(); // bbsmenu.html内にあるリンクは全て板とみなす const bool use_link_as_board(); // 板移転時に確認ダイアログを表示する const bool get_show_movediag(); void set_show_movediag( const bool show ); // スレタイ検索用メニュータイトルアドレス const std::string& get_menu_search_title(); const std::string& get_url_search_title(); // スレタイ検索用正規表現 const std::string& get_regex_search_title(); // WEB検索用メニュータイトルアドレス const std::string& get_menu_search_web(); const std::string& get_url_search_web(); // p2 書き込み用アドレス const std::string& get_url_writep2(); const std::string& get_url_resp2(); // 2ch にアクセスするときのエージェント名 const std::string& get_agent_for2ch(); // 2ch にログインするときのX-2ch-UA const std::string& get_x_2ch_ua(); // 2ch 読み込み用プロクシとポート番号 const bool get_use_proxy_for2ch(); const std::string& get_proxy_for2ch(); const int get_proxy_port_for2ch(); const std::string& get_proxy_basicauth_for2ch(); void set_use_proxy_for2ch( const bool set ); void set_proxy_for2ch( const std::string& proxy ); void set_proxy_port_for2ch( const int port ); // 2ch 書き込み用プロクシとポート番号 const bool get_use_proxy_for2ch_w(); const std::string& get_proxy_for2ch_w(); const int get_proxy_port_for2ch_w(); const std::string& get_proxy_basicauth_for2ch_w(); void set_use_proxy_for2ch_w( const bool set ); void set_proxy_for2ch_w( const std::string& proxy ); void set_proxy_port_for2ch_w( const int port ); // 2ch外にアクセスするときのエージェント名 const std::string& get_agent_for_data(); // 2chの外にアクセスするときのプロクシとポート番号 const bool get_use_proxy_for_data(); const std::string& get_proxy_for_data(); const int get_proxy_port_for_data(); const std::string& get_proxy_basicauth_for_data(); void set_use_proxy_for_data( const bool set ); void set_proxy_for_data( const std::string& proxy ); void set_proxy_port_for_data( const int port ); // ローダのバッファサイズ const int get_loader_bufsize(); // 一般 const int get_loader_bufsize_board(); // スレ一覧読み込み用 // ローダのタイムアウト値 const int get_loader_timeout(); const int get_loader_timeout_post(); const int get_loader_timeout_data(); const int get_loader_timeout_checkupdate(); // ipv6使用 const bool get_use_ipv6(); void set_use_ipv6( const bool set ); // 同一ホストに対する最大コネクション数( 1 または 2 ) const int get_connection_num(); // 2chのクッキー:HAP const bool get_use_cookie_hap(); const std::string& get_cookie_hap(); const std::string& get_cookie_hap_bbspink(); void set_cookie_hap( const std::string& cookie_hap ); void set_cookie_hap_bbspink( const std::string& cookie_hap ); // リンクをクリックしたときに実行するコマンド const std::string& get_command_openurl(); void set_command_openurl( const std::string& command ); // ブラウザ設定ダイアログのコンボボックスの番号 const int get_browsercombo_id(); void set_browsercombo_id( const int id ); // レス番号の上にマウスオーバーしたときに参照ポップアップ表示する const bool get_refpopup_by_mo(); // 名前の上にマウスオーバーしたときにポップアップ表示する const bool get_namepopup_by_mo(); // IDの上にマウスオーバーしたときにIDをポップアップ表示する const bool get_idpopup_by_mo(); // 画像のスムージングレベル(0-2, 2が最も高画質かつ低速) const int get_imgemb_interp(); const int get_imgmain_interp(); const int get_imgpopup_interp(); // 画像ポップアップサイズ const int get_imgpopup_width(); const int get_imgpopup_height(); // 画像ポップアップを使用する const bool get_use_image_popup(); void set_use_image_popup( const bool use ); // 画像ビューを使用する const bool get_use_image_view(); void set_use_image_view( const bool image_view ); // インライン画像表示をする const bool get_use_inline_image(); void set_use_inline_image( const bool inline_img ); // ssspアイコン表示 const bool get_show_ssspicon(); void set_show_sssp_icon( const bool show ); // インライン画像の最大幅と高さ const int get_embimg_width(); const int get_embimg_height(); // 埋め込み画像ビューを閉じたときにタブも閉じる const bool get_hide_imagetab(); // 画像ビューでdeleteを押したときに確認ダイアログを表示する const bool get_show_delimgdiag(); void set_show_delimgdiag( const bool show ); // 画像にモザイクかける const bool get_use_mosaic(); void set_use_mosaic( const bool mosaic ); // モザイクの大きさ const int get_mosaic_size(); // 画像をデフォルトでウィンドウサイズに合わせる const bool get_zoom_to_fit(); void set_zoom_to_fit( const bool fit ); // 画像キャッシュ削除の日数 const int get_del_img_day(); void set_del_img_day( const int day ); // 画像あぼーん削除の日数 const int get_del_imgabone_day(); void set_del_imgabone_day( const int day ); // ダウンロードする画像の最大ファイルサイズ(Mbyte) const int get_max_img_size(); // 画像の最大サイズ(Mピクセル) const int get_max_img_pixel(); // 画像のメモリキャッシュ枚数 const int get_imgcache_size(); // スレ一覧で指定した値(時間)よりも後に立てられたスレを新着とみなす const int get_newthread_hour(); // スレ一覧でインクリメント検索をする const bool get_inc_search_board(); // スレ一覧でdeleteを押したときに確認ダイアログを表示する const bool get_show_deldiag(); void set_show_deldiag( const bool show ); // スレ一覧をロードする前にキャッシュにある一覧を表示 const bool get_show_cached_board(); // スレ一覧でお知らせスレ(924)のアイコンを表示する const bool get_show_924(); // ツリービューのスクロール量(マウスホイール上下・行数) const int get_tree_scroll_size(); // スレビューのスクロール量(マウスホイール上下・行数) const int get_scroll_size(); // スレビューのスクロール量(キー上下・行数) const int get_key_scroll_size(); // スレビューの高速スクロール量(キー上下・ ページ高 - 行高 * key_fastscroll_size ) const int get_key_fastscroll_size(); // スレビューでリロード後に一番下までスクロール const bool get_jump_after_reload(); void set_jump_after_reload( const bool set ); // スレビューでリロード後に新着までスクロール const bool get_jump_new_after_reload(); void set_jump_new_after_reload( const bool set ); // 実況モード const int get_live_mode(); void set_live_mode( const int mode ); // 実況速度 const int get_live_speed(); void set_live_speed( const int speed ); // 実況のスクロールモードを切り替えるしきい値 const int get_live_threshold(); void set_live_threshode( const int th ); // 板一覧でカテゴリを常にひとつだけ開く const bool get_open_one_category(); // お気に入りでカテゴリを常にひとつだけ開く const bool get_open_one_favorite(); // デフォルトの書き込み名 const std::string get_write_name(); // デフォルトのメールアドレス const std::string get_write_mail(); // 書き込み時に書き込み確認ダイアログを出すかどうか const bool get_always_write_ok(); void set_always_write_ok( const bool write_ok ); // 書き込みログを保存 const bool get_save_post_log(); void set_save_post_log( const bool save ); // 書き込みログの最大サイズ const size_t get_maxsize_post_log(); // 書き込み履歴を保存 const bool get_save_post_history(); void set_save_post_history( const bool save ); // 書き込み中のダイアログを表示しない const bool get_hide_writing_dialog(); // 編集中のメッセージの保存確認ダイアログを表示する const bool get_show_savemsgdiag(); void set_show_savemsgdiag( const bool show ); // 書き込みビューでテキストを折り返す const bool get_message_wrap(); void set_message_wrap( const bool wrap ); // 非アクティブ時に書き込みビューを折りたたむ const bool get_fold_message(); void set_fold_message( const bool fold ); // 非アクティブ時に画像ビューを折りたたむ const bool get_fold_image(); // 書き込み欄の日本語のON/OFF状態を保存 const bool get_keep_im_status(); // ポップアップとカーソルの間のマージン const int get_margin_popup(); void set_margin_popup( const int margin ); // 画像ポップアップとカーソルの間のマージン const int get_margin_imgpopup_x(); // 水平方向 const int get_margin_imgpopup(); // 垂直方向 // ポップアップが消えるまでの時間(ミリ秒) const int get_hide_popup_msec(); // マウスジェスチャを有効 const bool get_enable_mg(); // マウスジェスチャの判定開始半径 const int get_mouse_radius(); // 数字入力ジャンプの待ち時間(ミリ秒) const int get_numberjmp_msec(); // 履歴メニューの表示数 const int get_history_size(); // 履歴ビューの表示数 const int get_historyview_size(); // AA履歴の保持数 const int get_aahistory_size(); // 0以上なら多重ポップアップの説明を表示する const int get_instruct_popup(); // スレビューを開いたときにスレ一覧との切り替え方法を説明する const bool get_instruct_tglart(); void set_instruct_tglart( const bool set ); // 画像ビューを開いたときにスレビューとの切り替え方法を説明する const bool get_instruct_tglimg(); void set_instruct_tglimg( const bool set ); // スレビューでdeleteを押したときに確認ダイアログを表示する const bool get_show_delartdiag(); void set_show_delartdiag( const bool show ); // 下線位置調整 const double get_adjust_underline_pos(); void set_adjust_underline_pos( const double pos ); // スレ表示の行間調整 const double get_adjust_line_space(); void set_adjust_line_space( const double space ); // スレ表示でリンクの下に下線を引く const bool get_draw_underline(); // スレビューで文字幅の近似を厳密にする const bool get_strict_char_width(); void set_strict_char_width( const bool strictwidth ); // スレビューで発言数(ID)をカウントする const bool get_check_id(); // レス参照で色を変える回数 const int get_num_reference_high(); const int get_num_reference_low(); // 発言数で色を変える回数 const int get_num_id_high(); const int get_num_id_low(); // datのパース時にURL判定を甘くする(^なども含める) const bool get_loose_url(); // ユーザーコマンドで選択できない項目を非表示にする const bool get_hide_usrcmd(); void set_hide_usrcmd( const bool hide ); // スレビューで再読み込みボタンを押したときに全タブを更新する const bool get_reload_allthreads(); // タブに表示する文字列の最小値 const int get_tab_min_str(); // タブにアイコンを表示するか const bool get_show_tab_icon(); // タブ上でマウスホイールを回転してタブを切り替える const bool get_switchtab_wheel(); // ビュー内から他のビューを開いたときのタブの位置 ( 0: 一番右端 1:右隣 2:左隣 ) const int get_newtab_pos(); // 次スレ検索を開くときのタブの位置 ( 0: 次スレ検索タブ 1:新しいタブ 2:アクティブなタブを置き換え ) const int get_boardnexttab_pos(); // スレビューに書き込みマークを表示するか const bool get_show_post_mark(); void set_show_post_mark( const bool show ); // ボタンをフラットにするか const bool get_flat_button(); void set_flat_button( const bool set ); // ツールバーの背景描画 const bool get_draw_toolbarback(); void set_draw_toolbarback( const bool set ); // boardviewでのスレの全体あぼーん std::list< std::string >& get_list_abone_word_thread(); // ワード std::list< std::string >& get_list_abone_regex_thread(); // 正規表現 void set_list_abone_word_thread( std::list< std::string >& word ); void set_list_abone_regex_thread( std::list< std::string >& regex ); const int get_remove_old_abone_thread(); // dat落ちしたスレをNGスレタイトルリストから取り除くか( 0: ダイアログ表示 1: 取り除く 2: 除かない ) void set_remove_old_abone_thread( const int remove ); const int get_abone_number_thread(); void set_abone_number_thread( const int number ); const int get_abone_hour_thread(); void set_abone_hour_thread( const int hour ); // articleviewでのレスの全体あぼーん const std::list< std::string >& get_list_abone_name(); // 名前 const std::list< std::string >& get_list_abone_word(); // ワード const std::list< std::string >& get_list_abone_regex(); // 正規表現 void set_list_abone_name( const std::list< std::string >& name ); void set_list_abone_word( const std::list< std::string >& word ); void set_list_abone_regex( const std::list< std::string >& regex ); // デフォルトで透明、連鎖あぼーんをするか const bool get_abone_transparent(); void set_abone_transparent( const bool set ); const bool get_abone_chain(); void set_abone_chain( const bool set ); // NG正規表現によるあぼーん時に大小と全半角文字の違いを無視 const bool get_abone_icase(); void set_abone_icase( const bool set ); const bool get_abone_wchar(); void set_abone_wchar( const bool set ); // 右ペーンが空の時にサイドバーを閉じるか const bool get_expand_sidebar(); // 3ペーン時にスレ一覧やスレビューを最大化するか const bool get_expand_rpane(); // ペーンの境界をクリックしてサイドバーを開け閉めする const bool get_open_sidebar_by_click(); // 次スレ検索の類似度のしきい値 const int get_threshold_next(); // 次スレを開いたときにお気に入りのアドレスと名前を自動更新 const int get_replace_favorite_next(); void set_replace_favorite_next( const int mode ); // お気に入りの自動更新をするかダイアログを出す const bool show_diag_replace_favorite(); void set_show_diag_replace_favorite( const bool show ); // スレをお気に入りに追加したときにしおりをセットする const bool get_bookmark_drop(); // お気に入りの更新チェック時に板の更新もチェックする const bool get_check_update_board(); // 起動時にお気に入りを自動でチェックする const bool get_check_update_boot(); // お気に入り登録時に重複項目を登録するか ( 0: 登録する 1: ダイアログ表示 2: 登録しない ) const int get_check_favorite_dup(); void set_check_favorite_dup( const int check ); // お気に入り登録時に挿入先ダイアログを表示する ( 0 : 表示する 1: 表示せず先頭に追加 2: 表示せず最後に追加 ) const int get_show_favorite_select_diag(); // Ctrl+qでウィンドウを閉じない const bool get_disable_close(); void set_disable_close( const bool disable ); // メニューバーを非表示にした時にダイアログを表示 const bool get_show_hide_menubar_diag(); void set_show_hide_menubar_diag( const bool set ); // 状態変更時にメインステータスバーの色を変える const bool get_change_stastatus_color(); // まちBBSの取得に offlaw.cgi を使用する const bool get_use_machi_offlaw(); void set_use_machi_offlaw( const bool set ); // 書き込み履歴のあるスレを削除する時にダイアログを表示 const bool get_show_del_written_thread_diag(); void set_del_written_thread_diag( const bool set ); // スレを削除する時に画像キャッシュも削除する ( 0: ダイアログ表示 1: 削除 2: 削除しない ) const int get_delete_img_in_thread(); void set_delete_img_in_thread( const int set ); // FIFOの作成などにエラーがあったらダイアログを表示する const bool get_show_diag_fifo_error(); void set_show_diag_fifo_error( const bool set ); // 指定した分ごとにセッションを自動保存 (0: 保存しない) const int get_save_session(); #ifdef HAVE_MIGEMO_H // migemo-dictの場所 const std::string& get_migemodict_path(); #endif } #endif jd-2.8.7-140104/src/config/Makefile.am0000644000076400010400000000043312072045132013654 0ustar noinst_LIBRARIES = libconfig.a libconfig_a_SOURCES = \ configitems.cpp globalconf.cpp aboutconfig.cpp aboutconfigdiag.cpp noinst_HEADERS = \ configitems.h globalconf.h defaultconf.h aboutconfig.h aboutconfigdiag.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/control/0000755000076400010400000000000012261751604012043 5ustar jd-2.8.7-140104/src/control/buttonconfig.cpp0000644000076400010400000001740112201400541015234 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "buttonconfig.h" #include "defaultconf.h" #include "jdlib/confloader.h" #include "jdlib/jdregex.h" #include "cache.h" #ifdef _DEBUG #include "controlutil.h" #endif using namespace CONTROL; ButtonConfig::ButtonConfig() : MouseKeyConf() {} ButtonConfig::~ButtonConfig() {} // // 設定ファイル読み込み // void ButtonConfig::load_conf() { JDLIB::ConfLoader cf( CACHE::path_buttonconf(), std::string() ); // デフォルト動作 load_motions( cf, "ClickButton", BUTTONCONF_ClickButton ); load_motions( cf, "DblClickButton", BUTTONCONF_DblClickButton ); load_motions( cf, "TrpClickButton", BUTTONCONF_TrpClickButton ); load_motions( cf, "CloseTabButton", BUTTONCONF_CloseTabButton ); load_motions( cf, "ReloadTabButton", BUTTONCONF_ReloadTabButton ); load_motions( cf, "AutoScrollButton", BUTTONCONF_AutoScrollButton ); load_motions( cf, "GestureButton", BUTTONCONF_GestureButton ); load_motions( cf, "PopupmenuButton", BUTTONCONF_PopupmenuButton ); load_motions( cf, "DragStartButton", BUTTONCONF_DragStartButton ); load_motions( cf, "TreeRowSelectionButton", BUTTONCONF_TreeRowSelectionButton ); load_motions( cf, "Reload", BUTTONCONF_Reload ); load_motions( cf, "ToggleArticle", BUTTONCONF_ToggleArticle ); load_motions( cf, "Right", BUTTONCONF_Right ); load_motions( cf, "Left", BUTTONCONF_Left ); // BBSLIST用ボタン設定 load_motions( cf, "OpenBoardButton", BUTTONCONF_OpenBoardButton ); load_motions( cf, "OpenBoardTabButton", BUTTONCONF_OpenBoardTabButton ); // BOARD用ボタン設定 load_motions( cf, "OpenArticleButton", BUTTONCONF_OpenArticleButton ); load_motions( cf, "OpenArticleTabButton", BUTTONCONF_OpenArticleTabButton ); load_motions( cf, "ScrollRightBoard", BUTTONCONF_ScrollRightBoard ); load_motions( cf, "ScrollLeftBoard", BUTTONCONF_ScrollLeftBoard ); // ARTICLE用ボタン設定 load_motions( cf, "PopupWarpButton", BUTTONCONF_PopupWarpButton ); load_motions( cf, "ReferResButton", BUTTONCONF_ReferResButton ); load_motions( cf, "BmResButton", BUTTONCONF_BmResButton ); load_motions( cf, "PopupmenuResButton", BUTTONCONF_PopupmenuResButton ); load_motions( cf, "DrawoutAncButton", BUTTONCONF_DrawoutAncButton ); load_motions( cf, "PopupmenuAncButton", BUTTONCONF_PopupmenuAncButton ); load_motions( cf, "JumpAncButton", BUTTONCONF_JumpAncButton ); load_motions( cf, "PopupIDButton", BUTTONCONF_PopupIDButton ); load_motions( cf, "DrawoutIDButton", BUTTONCONF_DrawoutIDButton ); load_motions( cf, "PopupmenuIDButton", BUTTONCONF_PopupmenuIDButton ); load_motions( cf, "OpenImageButton", BUTTONCONF_OpenImageButton ); load_motions( cf, "OpenBackImageButton", BUTTONCONF_OpenBackImageButton ); load_motions( cf, "PopupmenuImageButton", BUTTONCONF_PopupmenuImageButton ); load_motions( cf, "OpenBeButton", BUTTONCONF_OpenBeButton ); load_motions( cf, "PopupmenuBeButton", BUTTONCONF_PopupmenuBeButton ); // IMAGE ICON用ボタン設定 load_motions( cf, "CloseImageTabButton", BUTTONCONF_CloseImageTabButton ); // IMAGE用ボタン設定 load_motions( cf, "CloseImageButton", BUTTONCONF_CloseImageButton ); load_motions( cf, "ScrollImageButton", BUTTONCONF_ScrollImageButton ); load_motions( cf, "CancelMosaicButton", BUTTONCONF_CancelMosaicButton ); load_motions( cf, "SaveImageButton", BUTTONCONF_SaveImageButton ); load_motions( cf, "ResizeImageButton", BUTTONCONF_ResizeImageButton ); } // ひとつの操作をデータベースに登録 void ButtonConfig::set_one_motion_impl( const int id, const int mode, const std::string& name, const std::string& str_motion ) { if( name.empty() ) return; #ifdef _DEBUG std::cout << "ButtonConfig::set_one_motion_impl " << name << std::endl; std::cout << "motion = " << str_motion << std::endl; #endif #ifdef _DEBUG std::cout << CONTROL::get_label( id ) << std::endl; #endif bool ctrl = false; bool shift = false; bool alt = false; bool dblclick = false; bool trpclick = false; guint motion = 0; JDLIB::Regex regex; const size_t offset = 0; const bool icase = true; // 大文字小文字区別しない const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "(Ctrl)?(\\+?Shift)?(\\+?Alt)?\\+?(.*)", str_motion, offset, icase, newline, usemigemo, wchar ) ){ if( ! regex.str( 1 ).empty() ) ctrl = true; if( ! regex.str( 2 ).empty() ) shift = true; if( ! regex.str( 3 ).empty() ) alt = true; std::string str_button = regex.str( 4 ); if( str_button == "Left" ) motion = 1; if( str_button == "Mid" ) motion = 2; if( str_button == "Right" ) motion = 3; if( str_button == "Tilt_Left" ) motion = 6; if( str_button == "Tilt_Right" ) motion = 7; if( str_button == "Button4" ) motion = 8; if( str_button == "Button5" ) motion = 9; if( str_button == "DblLeft" ){ motion = 1; dblclick = true; } if( str_button == "DblMid" ) { motion = 2; dblclick = true; } if( str_button == "DblRight" ) { motion = 3; dblclick = true; } if( str_button == "TrpLeft" ){ motion = 1; trpclick = true; } if( str_button == "TrpMid" ) { motion = 2; trpclick = true; } if( str_button == "TrpRight" ) { motion = 3; trpclick = true; } } else return; #ifdef _DEBUG std::cout << "motion = " << motion << " dblclick = " << dblclick << " trpclick = " << trpclick << std::endl << std::endl; #endif // データベース登録 vec_items().push_back( MouseKeyItem( id, mode, name, str_motion, motion, ctrl, shift, alt, dblclick, trpclick ) ); } // タブで開くボタンを入れ替えているか const bool ButtonConfig::is_toggled_tab_button() { const bool ret = ( get_str_motions( CONTROL::OpenBoardButton ).find( "Mid" ) != std::string::npos && get_str_motions( CONTROL::OpenBoardTabButton ).find( "Left" ) != std::string::npos && get_str_motions( CONTROL::OpenArticleButton ).find( "Mid" ) != std::string::npos && get_str_motions( CONTROL::OpenArticleTabButton ).find( "Left" ) != std::string::npos ); #ifdef _DEBUG std::cout << "KeyConfig::is_toggled_tab_button ret = " << ret << std::endl; #endif return ret; } // タブで開くボタンを入れ替える // toggle == true なら左ボタンをタブで開くボタンにする void ButtonConfig::toggle_tab_button( const bool toggle ) { remove_motions( CONTROL::OpenBoardButton ); remove_motions( CONTROL::OpenBoardTabButton ); remove_motions( CONTROL::OpenArticleButton ); remove_motions( CONTROL::OpenArticleTabButton ); if( toggle ){ set_one_motion( "OpenBoardButton", "Mid" ); set_one_motion( "OpenBoardTabButton", "Left" ); set_one_motion( "OpenArticleButton", "Mid" ); set_one_motion( "OpenArticleTabButton", "Left" ); } else{ set_one_motion( "OpenBoardButton", "Left" ); set_one_motion( "OpenBoardTabButton", "Mid" ); set_one_motion( "OpenArticleButton", "Left" ); set_one_motion( "OpenArticleTabButton", "Mid" ); } } // ポップアップ表示の時にクリックでワープするか const bool ButtonConfig::is_popup_warpmode() { return ( get_str_motions( CONTROL::PopupWarpButton).find( "Left" ) != std::string::npos ); } // ポップアップ表示の時にクリックでワープする void ButtonConfig::toggle_popup_warpmode() { bool warp = is_popup_warpmode(); remove_motions( CONTROL::PopupWarpButton ); if( warp ) set_one_motion( "PopupWarpButton", "" ); else set_one_motion( "PopupWarpButton", "Left" ); } jd-2.8.7-140104/src/control/buttonconfig.h0000644000076400010400000000167111101351617014712 0ustar // ライセンス: GPL2 // // マウスボタン設定 // #ifndef _BUTTONCONFIG_H #define _BUTTONCONFIG_H #include "mousekeyconf.h" namespace CONTROL { class ButtonConfig : public MouseKeyConf { public: ButtonConfig(); virtual ~ButtonConfig(); virtual void load_conf(); const bool is_toggled_tab_button(); // タブで開くボタンを入れ替えているか void toggle_tab_button( const bool toggle ); // タブで開くボタンを入れ替える const bool is_popup_warpmode(); // ポップアップ表示の時にクリックでワープするか void toggle_popup_warpmode(); // ポップアップ表示の時にクリックでワープする private: // ひとつの操作をデータベースに登録 virtual void set_one_motion_impl( const int id, const int mode, const std::string& name, const std::string& str_motion ); }; } #endif jd-2.8.7-140104/src/control/buttonpref.cpp0000644000076400010400000001113612201335554014735 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "buttonpref.h" #include "controlid.h" #include "controlutil.h" using namespace CONTROL; // // ボタン入力をラベルに表示するダイアログ // ButtonInputDiag::ButtonInputDiag( Gtk::Window* parent, const std::string& url, const int id ) : CONTROL::InputDiag( parent, url, id, "マウスボタン", INPUTDIAG_MODE_BUTTON ) {} /////////////////////////////// // // 個別のボタン設定ダイアログ // ButtonDiag::ButtonDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& str_motions ) : CONTROL::MouseKeyDiag( parent, url, id, "マウスボタン", str_motions ) {} InputDiag* ButtonDiag::create_inputdiag() { return new ButtonInputDiag( this, "", get_id() ); } const std::string ButtonDiag::get_default_motions( const int id ) { return CONTROL::get_default_buttonmotions( id ); } const std::vector< int > ButtonDiag::check_conflict( const int mode, const std::string& str_motion ) { // 衝突判定をしない std::vector< int > vec_ids; return vec_ids; } /////////////////////////////////////////////// // // マウスボタン設定ダイアログ // ButtonPref::ButtonPref( Gtk::Window* parent, const std::string& url ) : MouseKeyPref( parent, url, "マウスボタン" ) { // マウスボタンのバックアップを取る // キャンセルを押したら戻す CONTROL::bkup_buttonconfig(); append_comment_row( "■ "+ CONTROL::get_mode_label( CONTROL::MODE_COMMON ) ); append_row( CONTROL::ClickButton ); append_row( CONTROL::DblClickButton ); append_row( CONTROL::TrpClickButton ); append_row( CONTROL::CloseTabButton ); append_row( CONTROL::ReloadTabButton ); append_row( CONTROL::AutoScrollButton ); append_row( CONTROL::GestureButton ); append_row( CONTROL::PopupmenuButton ); append_row( CONTROL::DragStartButton ); append_row( CONTROL::TreeRowSelectionButton ); append_row( CONTROL::Reload ); append_row( CONTROL::ToggleArticle ); append_row( CONTROL::Right ); append_row( CONTROL::Left ); append_comment_row( "" ); append_comment_row( "■ "+ CONTROL::get_mode_label( CONTROL::MODE_BBSLIST ) ); append_row( CONTROL::OpenBoardButton ); append_row( CONTROL::OpenBoardTabButton ); append_comment_row( "" ); append_comment_row( "■ "+ CONTROL::get_mode_label( CONTROL::MODE_BOARD ) ); append_row( CONTROL::OpenArticleButton ); append_row( CONTROL::OpenArticleTabButton ); append_row( CONTROL::ScrollRightBoard ); append_row( CONTROL::ScrollLeftBoard ); append_comment_row( "" ); append_comment_row( "■ "+ CONTROL::get_mode_label( CONTROL::MODE_ARTICLE ) ); append_row( CONTROL::PopupWarpButton ); append_row( CONTROL::ReferResButton ); append_row( CONTROL::BmResButton ); append_row( CONTROL::PopupmenuResButton ); append_row( CONTROL::DrawoutAncButton ); append_row( CONTROL::PopupmenuAncButton ); append_row( CONTROL::JumpAncButton ); append_row( CONTROL::PopupIDButton ); append_row( CONTROL::DrawoutIDButton ); append_row( CONTROL::PopupmenuIDButton ); append_row( CONTROL::OpenImageButton ); append_row( CONTROL::OpenBackImageButton ); append_row( CONTROL::PopupmenuImageButton ); append_row( CONTROL::OpenBeButton ); append_row( CONTROL::PopupmenuBeButton ); append_comment_row( "" ); append_comment_row( "■ "+ CONTROL::get_mode_label( CONTROL::MODE_IMAGEVIEW ) ); append_row( CONTROL::CloseImageTabButton ); append_row( CONTROL::CloseImageButton ); append_row( CONTROL::ScrollImageButton ); append_row( CONTROL::CancelMosaicButton ); append_row( CONTROL::SaveImageButton ); append_row( CONTROL::ResizeImageButton ); } MouseKeyDiag* ButtonPref::create_setting_diag( const int id, const std::string& str_motions ) { return new ButtonDiag( this, "", id, str_motions ); } const std::string ButtonPref::get_str_motions( const int id ) { return CONTROL::get_str_buttonmotions( id ); } const std::string ButtonPref::get_default_motions( const int id ) { return CONTROL::get_default_buttonmotions( id ); } void ButtonPref::set_motions( const int id, const std::string& str_motions ) { CONTROL::set_buttonmotions( id, str_motions ); } const bool ButtonPref::remove_motions( const int id ) { return CONTROL::remove_buttonmotions( id ); } // // キャンセルボタンを押した // void ButtonPref::slot_cancel_clicked() { #ifdef _DEBUG std::cout << "ButtonPref::slot_cancel_clicked\n"; #endif // 設定を戻す CONTROL::restore_buttonconfig(); } jd-2.8.7-140104/src/control/buttonpref.h0000644000076400010400000000364112201335554014404 0ustar // ライセンス: GPL2 // マウスボタン設定ダイアログ // ButtonPref が本体で、ButtonPrefの各行をダブルクリックすると ButtonDiag が開いて個別に操作の設定が出来る // ButtonDiag の各行をダブルクリックすると ButtonInputDiag が開いてキー入力が出来る #ifndef _BUTTONPREFPREF_H #define _BUTTONPREFPREF_H #include "mousekeypref.h" #include "control.h" namespace CONTROL { // // ボタン入力をラベルに表示するダイアログ // class ButtonInputDiag : public CONTROL::InputDiag { public: ButtonInputDiag( Gtk::Window* parent, const std::string& url, const int id ); }; /////////////////////////////////////// // // 個別のボタン設定ダイアログ // class ButtonDiag : public CONTROL::MouseKeyDiag { public: ButtonDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& str_motions ); protected: virtual InputDiag* create_inputdiag(); virtual const std::string get_default_motions( const int id ); virtual const std::vector< int > check_conflict( const int mode, const std::string& str_motion ); }; /////////////////////////////////////// // // ボタン設定ダイアログ // class ButtonPref : public CONTROL::MouseKeyPref { public: ButtonPref( Gtk::Window* parent, const std::string& url ); protected: virtual MouseKeyDiag* create_setting_diag( const int id, const std::string& str_motions ); virtual const std::string get_str_motions( const int id ); virtual const std::string get_default_motions( const int id ); virtual void set_motions( const int id, const std::string& str_motions ); virtual const bool remove_motions( const int id ); private: virtual void slot_cancel_clicked(); }; } #endif jd-2.8.7-140104/src/control/control.cpp0000644000076400010400000002661412076443570014244 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "control.h" #include "controlid.h" #include "controlutil.h" #include "get_config.h" #include "keyconfig.h" #include "mouseconfig.h" #include "buttonconfig.h" #include "config/globalconf.h" #include "command.h" #include "global.h" using namespace CONTROL; // ホイールマウスジェスチャ用( 全てのビューで共通 ) bool mg_wheel_done; Control::Control() : m_send_mg_info( true ) { MG_reset(); MG_wheel_reset(); clear_mode(); } void Control::add_mode( const int mode ) { // 共通モードは最後に検索 if( mode == CONTROL::MODE_COMMON ) return; m_mode[ m_mode.size()-1 ] = mode; m_mode.push_back( CONTROL::MODE_COMMON ); #ifdef _DEBUG std::cout << "Control::add_mode size = " << m_mode.size() << std::endl; std::vector< int >::iterator it = m_mode.begin(); for( ; it != m_mode.end(); ++it ) std::cout << (*it) << std::endl; #endif } void Control::clear_mode() { m_mode.clear(); m_mode.push_back( CONTROL::MODE_COMMON ); } /////////////////////////////////////// // // キー操作 // 戻り値はコントロールID const int Control::key_press( const GdkEventKey* event ) { guint key = event->keyval; const bool ctrl = ( event->state ) & GDK_CONTROL_MASK; bool shift = ( event->state ) & GDK_SHIFT_MASK; const bool alt = ( event->state ) & GDK_MOD1_MASK; const bool caps = ( event->state ) & GDK_LOCK_MASK; // caps lock const bool dblclick = false; const bool trpclick = false; // caps lockされている場合は、アスキー文字を大文字小文字入れ替えて、capsを無視する // InputDiag::on_key_press_event()も参照のこと if( caps ){ if( key >= 'A' && key <= 'Z' ){ key += 'a' - 'A'; } else if( key >= 'a' && key <= 'z' ){ key += 'A' - 'a'; } } // keyがアスキー文字の場合は shift を無視する (大文字除く) // KeyConfig::set_one_motion()も参照せよ if( CONTROL::is_ascii( key ) && ( key < 'A' || key > 'Z' ) ) shift = false; #ifdef _DEBUG std::cout << "Control::key_press key = " << std::hex << key; if( ctrl ) std::cout << " ctrl"; if( shift ) std::cout << " shift"; if( alt ) std::cout << " alt"; if( caps ) std::cout << " caps"; std::cout << "\n"; #endif int control = CONTROL::None; std::vector< int >::iterator it = m_mode.begin(); for( ; it != m_mode.end(); ++it ){ control = CONTROL::get_keyconfig()->get_id( *it, key, ctrl, shift, alt, dblclick, trpclick ); if( control != CONTROL::None ) break; } return control; } /////////////////////////////////////// // // マウスのボタン操作 // 戻り値はコントロールID const int Control::button_press( const GdkEventButton* event ) { const guint button = event->button; const bool ctrl = ( event->state ) & GDK_CONTROL_MASK; const bool shift = ( event->state ) & GDK_SHIFT_MASK; const bool alt = ( event->state ) & GDK_MOD1_MASK; const bool dblclick = ( event->type == GDK_2BUTTON_PRESS ); const bool trpclick = ( event->type == GDK_3BUTTON_PRESS ); int control = CONTROL::None; std::vector< int >::iterator it = m_mode.begin(); for( ; it != m_mode.end(); ++it ){ control = CONTROL::get_buttonconfig()->get_id( *it, button, ctrl, shift, alt, dblclick, trpclick ); if( control != CONTROL::None ) break; } return control; } // eventがidに割り当てられていたらtrue const bool Control::button_alloted( const GdkEventButton* event, const int id ) { const guint button = event->button; const bool ctrl = ( event->state ) & GDK_CONTROL_MASK; const bool shift = ( event->state ) & GDK_SHIFT_MASK; const bool alt = ( event->state ) & GDK_MOD1_MASK; const bool dblclick = ( event->type == GDK_2BUTTON_PRESS ); const bool trpclick = ( event->type == GDK_3BUTTON_PRESS ); return CONTROL::get_buttonconfig()->alloted( id, button, ctrl, shift, alt, dblclick, trpclick ); } // ID からevent取得 const bool Control::get_eventbutton( const int id, GdkEventButton& event ) { guint button; bool ctrl; bool shift; bool alt; bool dblclick; bool trpclick; if( CONTROL::get_buttonconfig()->get_motion( id, button, ctrl, shift, alt, dblclick, trpclick ) ){ if( dblclick ) event.type = GDK_2BUTTON_PRESS; if( trpclick ) event.type = GDK_3BUTTON_PRESS; event.button = button; event.state = ( GDK_CONTROL_MASK & ctrl ) | ( GDK_SHIFT_MASK & shift ) | ( GDK_MOD1_MASK & alt ); return true; } return false; } /////////////////////////////////////// // // マウスジェスチャ void Control::MG_reset() { m_mg = false; m_mg_x = 0; m_mg_y = 0; m_mg_value = 0; m_mg_lng = 0; m_mg_direction = std::string(); } const bool Control::MG_start( const GdkEventButton* event ) { if( ! CONFIG::get_enable_mg() ) return false; MG_reset(); if( ! button_alloted( event, CONTROL::GestureButton ) ) return false; m_mg = true; m_mg_x = ( int ) event->x; m_mg_y = ( int ) event->y; #ifdef _DEBUG std::cout << "Control::MG_start\n"; #endif return true; } const bool Control::MG_motion( const GdkEventMotion* event ) { if( ! m_mg ) return false; if( m_mg_lng >= MAX_MG_LNG ) return false; if( m_mg_direction.empty() ){ if( m_send_mg_info ) CORE::core_set_command( "set_mginfo", "", "■" ); } const int x = ( int ) event->x; const int y = ( int ) event->y; const int dx = x - m_mg_x; const int dy = y - m_mg_y; int direction = 0; std::string str_direction; const int radius = CONFIG::get_mouse_radius(); if( dx < 0 && -dx > radius ){ direction = 4; str_direction = "←"; } else if( dx > 0 && dx > radius ){ direction = 6; str_direction = "→"; } else if( dy < 0 && -dy > radius ){ direction = 8; str_direction = "↑"; } else if( dy > 0 && dy > radius ){ direction = 2; str_direction = "↓"; } #ifdef _DEBUG std::cout << " x = " << x << " y = " << y << " mg_x = " << m_mg_x << " mg_y = " << m_mg_y << " dx = " << dx << " dy = " << dy; #endif if( direction ){ m_mg_x = x; m_mg_y = y; // 方向更新 if( m_mg_value % 10 != direction ){ m_mg_value = m_mg_value * 10 + direction; ++m_mg_lng; m_mg_direction += str_direction; const bool ctrl = false; const bool shift = false; const bool alt = false; const bool dblclick = false; const bool trpclick = false; int control = CONTROL::None; std::vector< int >::iterator it = m_mode.begin(); for( ; it != m_mode.end(); ++it ){ control = CONTROL::get_mouseconfig()->get_id( *it, m_mg_value, ctrl, shift, alt, dblclick, trpclick ); if( control != CONTROL::None ) break; } if( m_send_mg_info ) CORE::core_set_command( "set_mginfo", "", "■" + m_mg_direction + CONTROL::get_label( control ) ); } } #ifdef _DEBUG std::cout << " dir = " << direction << " val = " << m_mg_value << std::endl; #endif return true; } // 戻り値はコントロールID const int Control::MG_end( const GdkEventButton* event ) { if( ! m_mg ) return None; #ifdef _DEBUG std::cout << "Control::MG_end val = " << m_mg_value << std::endl; #endif const bool ctrl = false; const bool shift = false; const bool alt = false; const bool dblclick = false; const bool trpclick = false; int control = CONTROL::None; std::vector< int >::iterator it = m_mode.begin(); for( ; it != m_mode.end(); ++it ){ control = CONTROL::get_mouseconfig()->get_id( *it, m_mg_value, ctrl, shift, alt, dblclick, trpclick ); if( control != CONTROL::None ) break; } std::string str_command = CONTROL::get_label( control ); if( m_mg_lng ){ if( control == CONTROL::None ){ str_command = "Cancel"; control = CONTROL::CancelMG; } m_mg_direction += " " + str_command; if( m_send_mg_info ) CORE::core_set_command( "set_mginfo", "", "■" + m_mg_direction ); } MG_reset(); return control; } /////////////////////////////////////// // // ホイールマウスジェスチャ void Control::MG_wheel_reset() { mg_wheel_done = false; m_wheel_scroll_time = 0; } // ホイールマウスジェスチャ開始 const bool Control::MG_wheel_start( const GdkEventButton* event ) { MG_wheel_reset(); if( ! button_alloted( event, CONTROL::GestureButton ) ) return false; #ifdef _DEBUG std::cout << "Control::MG_wheel_start\n"; #endif return true; } // ホイールマウスジェスチャ。 戻り値はコントロールID const int Control::MG_wheel_scroll( const GdkEventScroll* event ) { int control = CONTROL::None; const guint direction = event->direction; // あまり速く動かした場合はキャンセル const int time_cancel = 15; // msec const int time_tmp = event->time - m_wheel_scroll_time; if( m_wheel_scroll_time && time_tmp < time_cancel ) return control; m_wheel_scroll_time = event->time; // 押しているボタンは event から取れないので // get_pointer()から取る int x, y; Gdk::ModifierType mask; Gdk::Display::get_default()->get_pointer( x, y, mask ); int button = 0; GdkEventButton ev = GdkEventButton(); get_eventbutton( CONTROL::GestureButton, ev ); switch( ev.button ){ case 1: button = Gdk::BUTTON1_MASK; break; case 2: button = Gdk::BUTTON2_MASK; break; case 3: button = Gdk::BUTTON3_MASK; break; } const bool ctrl = false; const bool shift = false; const bool alt = false; const bool dblclick = false; const bool trpclick = false; if( direction == GDK_SCROLL_LEFT ){ button = 6; std::vector< int >::iterator it = m_mode.begin(); for( ; it != m_mode.end(); ++it ){ control = CONTROL::get_buttonconfig()->get_id( *it, button, ctrl, shift, alt, dblclick, trpclick ); if( control != CONTROL::None ) break; } } else if( direction == GDK_SCROLL_RIGHT ){ button = 7; std::vector< int >::iterator it = m_mode.begin(); for( ; it != m_mode.end(); ++it ){ control = CONTROL::get_buttonconfig()->get_id( *it, button, ctrl, shift, alt, dblclick, trpclick ); if( control != CONTROL::None ) break; } } else if( ( mask & button ) && direction == GDK_SCROLL_UP ) control = CONTROL::TabLeft; else if( ( mask & button ) && direction == GDK_SCROLL_DOWN ) control = CONTROL::TabRight; #ifdef _DEBUG std::cout << "Control::MG_wheel_scroll control = " << control << std::endl; #endif if( control != CONTROL::None ){ if( m_send_mg_info ) CORE::core_set_command( "set_mginfo", "", CONTROL::get_label( control ) ); mg_wheel_done = true; } return control; } // ホイールマウスジェスチャ終了 // もしジェスチャが実行されたら true が戻る const bool Control::MG_wheel_end( const GdkEventButton* event ) { #ifdef _DEBUG std::cout << "Control::MG_wheel_end\n"; #endif const bool ret = mg_wheel_done; MG_wheel_reset(); return ret; } jd-2.8.7-140104/src/control/control.h0000644000076400010400000000420511101351617013665 0ustar // ライセンス: GPL2 // // 入力コントロール // // キー入力やマウスジェスチャ管理 // #ifndef _CONTROL_H #define _CONTROL_H #include #include namespace CONTROL { class Control { std::vector< int > m_mode; // マウスジェスチャ用変数 bool m_mg; // true ならマウスジェスチャのモードになっている bool m_send_mg_info; // core にマウスジェスチャを送るか int m_mg_lng; int m_mg_x; int m_mg_y; int m_mg_value; std::string m_mg_direction; guint32 m_wheel_scroll_time; // 前回ホイールを回した時刻 public: Control(); // コントロールモード設定 void add_mode( const int mode ); void clear_mode(); // キー入力 // 戻り値はコントロールID const int key_press( const GdkEventKey* event ); // マウスボタン const int button_press( const GdkEventButton* event ); // 戻り値はコントロールID const bool button_alloted( const GdkEventButton* event, const int id ); // eventがidに割り当てられていたらtrue const bool get_eventbutton( const int id, GdkEventButton& event ); // ID からevent取得 // マウスジェスチャ void MG_reset(); const bool is_mg_mode() const { return m_mg; } void set_send_mg_info( const bool send ){ m_send_mg_info = send; } const std::string& get_mg_direction() const{ return m_mg_direction; } const bool MG_start( const GdkEventButton* event ); const bool MG_motion( const GdkEventMotion* event ); const int MG_end( const GdkEventButton* event ); // 戻り値はコントロールID // ホイールマウスジェスチャ void MG_wheel_reset(); const bool MG_wheel_start( const GdkEventButton* event ); const int MG_wheel_scroll( const GdkEventScroll* event ); // 戻り値はコントロールID const bool MG_wheel_end( const GdkEventButton* event ); // ジェスチャを実行したらtrueを返す }; } #endif jd-2.8.7-140104/src/control/controlid.h0000644000076400010400000001230312201335554014204 0ustar // ライセンス: GPL2 // コントロールID #ifndef _CONTROLID_H #define _CONTROLID_H namespace CONTROL { // コントロールモード // // 項目を増やしたら controllabel.h も修正すること // enum { MODE_START = 0, MODE_COMMON = MODE_START, MODE_BBSLIST, MODE_BOARD, MODE_ARTICLE, MODE_IMAGEICON, MODE_IMAGEVIEW, MODE_MESSAGE, MODE_EDIT, MODE_JDGLOBALS, MODE_END = MODE_JDGLOBALS, MODE_ERROR }; // 動作 // // 項目を増やしたら controllabel.h も修正すること // enum { // 共通 COMMONMOTION = 0, Up, Down, Right, Left, TabRight, TabLeft, TabRightUpdated, TabLeftUpdated, TabNum1, TabNum2, TabNum3, TabNum4, TabNum5, TabNum6, TabNum7, TabNum8, TabNum9, CloseAllTabs, CloseOtherTabs, RestoreLastTab, CheckUpdateTabs, PreBookMark, NextBookMark, PrevView, NextView, ToggleArticle, ShowPopupMenu, ShowMenuBar, ShowToolBarMain, ShowSideBar, PageUp, PageDown, PrevDir, NextDir, Home, End, Back, Undo, Redo, Quit, Save, SaveDat, // alias: Save Delete, Reload, ReloadArticle, StopLoading, Cancel = StopLoading, OpenURL, Copy, SelectAll, AppendFavorite, Lock, PreferenceView, PreferenceBoard, // alias: PreferenceView PreferenceArticle, // alias: PreferenceView PreferenceImage, // alias: PreferenceView Search, CloseSearchBar, HiLightOff, SearchInvert, SearchNext, SearchPrev, SearchTitle, DrawOutAnd, DrawOutOr, CheckUpdateRoot, CheckUpdateOpenRoot, QuitJD, MaximizeMainWin, IconifyMainWin, FullScreen, ClickButton, // 以下、マウスボタン専用の設定 DblClickButton, TrpClickButton, CloseTabButton, ReloadTabButton, AutoScrollButton, GestureButton, PopupmenuButton, DragStartButton, TreeRowSelectionButton, COMMONMOTION_END, // BBSLIST系 BBSLISTMOTION, OpenBoard, OpenBoardTab, OpenBoardButton, // 以下、マウスボタン専用の設定 OpenBoardTabButton, BBSLISTMOTION_END, // BOARD系 BOARDMOTION, OpenArticle, OpenArticleTab, NewArticle, SearchCache, ScrollLeftBoard, ScrollRightBoard, OpenArticleButton, // 以下、マウスボタン専用の設定 OpenArticleTabButton, BOARDMOTION_END, // ARTICLE系 ARTICLEMOTION, UpMid, UpFast, DownMid, DownFast, PrevRes, NextRes, PrePost, NextPost, GotoNew, OpenParentBoard, WriteMessage, LiveStartStop, SearchNextArticle, SearchWeb, SearchCacheLocal, SearchCacheAll, ShowSelectImage, DeleteSelectImage, AboneSelectImage, AboneSelectionRes, PopupWarpButton, // 以下、マウスボタン専用の設定 ReferResButton, BmResButton, PopupmenuResButton, DrawoutAncButton, PopupmenuAncButton, JumpAncButton, PopupIDButton, DrawoutIDButton, PopupmenuIDButton, OpenImageButton, OpenBackImageButton, PopupmenuImageButton, OpenBeButton, PopupmenuBeButton, ARTICLEMOTION_END, // IMAGE ICON 系 IMAGEICONMOTION, CancelMosaic, ZoomFitImage, ZoomInImage, ZoomOutImage, OrgSizeImage, ScrollUpImage, ScrollDownImage, ScrollLeftImage, ScrollRightImage, CloseImageTabButton, // 以下、マウスボタン専用の設定 IMAGEICONMOTION_END, // IMAGE VIEW 系 IMAGEVIEWMOTION, CloseImageButton, // 以下、マウスボタン専用の設定 ScrollImageButton, CancelMosaicButton, SaveImageButton, ResizeImageButton, IMAGEVIEWMOTION_END, // MESSAGE 系 MESSAGEMOTION, CancelWrite, ExecWrite, InsertText, LockMessage, Preview, FocusWrite, ToggleSage, MESSAGEMOTION_END, // EDIT 系 EDITMOTION, HomeEdit, EndEdit, UpEdit, DownEdit, RightEdit, LeftEdit, DeleteEdit, BackspEdit, UndoEdit, EnterEdit, InputAA, EDITMOTION_END, // JD globals JDGLOBALS, JDExit, JDHelp, JDGLOBALS_END, // その他 CancelMG, None, CONTROL_END }; } #endif jd-2.8.7-140104/src/control/controllabel.h0000644000076400010400000002323712201405537014676 0ustar // ライセンス: GPL2 // コントロールのラベル #ifndef _CONTROLLABEL_H #define _CONTROLLABEL_H #include "controlid.h" #include "global.h" enum { MAX_CONTROL_LABEL = 64 }; namespace CONTROL { // // モード名 // char mode_label[][ MAX_CONTROL_LABEL ] ={ "共通", "板一覧/お気に入り", "スレ一覧", "スレビュー", "画像ビュー", "画像ビュー", "書き込みビュー", "編集", "特殊キー (再起動が必要)" }; // // control_label[ id ][ 0 ] を操作名 ( 例えば "Up" ) // control_label[ id ][ 1 ] をラベル ( 例えば "上移動" ) // // と呼ぶことにする // char control_label[][ 2 ][ MAX_CONTROL_LABEL ]={ // 共通 { "", "" }, { "Up", "上移動" }, { "Down", "下移動" }, { "Right", "右移動" }, { "Left", "左移動" }, { "TabRight", "右のタブに移動" }, { "TabLeft", "左のタブに移動" }, { "TabRightUpdated", "右の更新済みタブに移動" }, { "TabLeftUpdated", "左の更新済みタブに移動" }, { "TabNum1", "タブ1に移動" }, { "TabNum2", "タブ2に移動" }, { "TabNum3", "タブ3に移動" }, { "TabNum4", "タブ4に移動" }, { "TabNum5", "タブ5に移動" }, { "TabNum6", "タブ6に移動" }, { "TabNum7", "タブ7に移動" }, { "TabNum8", "タブ8に移動" }, { "TabNum9", "タブ9に移動" }, { "CloseAllTabs", "全てのタブを閉じる" }, { "CloseOtherTabs", "他のタブを閉じる" }, { "RestoreLastTab", "最後に閉じたタブを復元" }, { "CheckUpdateTabs", "全ての更新されたタブを再読み込み" }, { "PreBookMark", "前のしおりヘ移動" }, { "NextBookMark", "次のしおりヘ移動" }, { "PrevView", ITEM_NAME_BACK }, { "NextView", ITEM_NAME_FORWARD }, { "ToggleArticle", "スレ一覧とスレビュー切替" }, { "ShowPopupMenu", "メニュー表示" }, { "ShowMenuBar", "メニューバー表示" }, { "ShowToolBarMain", "メインツールバー表示" }, { "ShowSideBar", "サイドバー表示" }, { "PageUp", "上のページに移動" }, { "PageDown", "下のページに移動" }, { "PrevDir", "前のディレクトリに移動" }, { "NextDir", "次のディレクトリに移動" }, { "Home", "先頭へ移動" }, { "End", "最後へ移動" }, { "Back", "戻る" }, { "Undo", ITEM_NAME_UNDO }, { "Redo", ITEM_NAME_REDO }, { "Quit", ITEM_NAME_QUIT }, { "Save", "名前を付けて保存..." }, { "SaveDat", ITEM_NAME_SAVE_DAT "..." }, { "Delete", ITEM_NAME_DELETE }, { "Reload", ITEM_NAME_RELOAD }, { "ReloadArticle", "元のスレを開く" }, { "StopLoading", ITEM_NAME_STOPLOADING }, { "OpenURL", "URLを開く..." }, { "Copy", ITEM_NAME_COPY }, { "SelectAll", "全て選択" }, { "AppendFavorite", ITEM_NAME_APPENDFAVORITE "..." }, { "Lock", ITEM_NAME_LOCK }, { "PreferenceView", ITEM_NAME_PREFERENCEVIEW "..." }, { "PreferenceBoard", ITEM_NAME_PREF_BOARD "..." }, { "PreferenceArticle", ITEM_NAME_PREF_THREAD "..." }, { "PreferenceImage", ITEM_NAME_PREF_IMAGE "..." }, { "Search", ITEM_NAME_SEARCH }, { "CloseSearchBar", "検索バーを閉じる" }, { "HiLightOff", ITEM_NAME_CLEAR_HIGHLIGHT }, { "SearchInvert", "前方検索" }, { "SearchNext", ITEM_NAME_SEARCH_NEXT }, { "SearchPrev", ITEM_NAME_SEARCH_PREV }, { "SearchTitle", "" }, // CONTROL::get_keyconfig() で名前をセットする { "DrawOutAnd", "AND 抽出" }, { "DrawOutOr", "OR 抽出" }, { "CheckUpdateRoot", ITEM_NAME_CHECK_UPDATE_ROOT }, { "CheckUpdateOpenRoot", ITEM_NAME_CHECK_UPDATE_OPEN_ROOT }, { "QuitJD", "JD終了" }, { "MaximizeMainWin", "最大化 / 最大化解除" }, { "IconifyMainWin", "最小化" }, { "FullScreen", "全画面表示" }, { "ClickButton", "クリック" }, { "DblClickButton", "ダブルクリック" }, { "TrpClickButton", "トリプルクリック" }, { "CloseTabButton", "タブを閉じる" }, { "ReloadTabButton", "タブを再読み込み" }, { "AutoScrollButton", "オートスクロール" }, { "GestureButton", "マウスジェスチャ" }, { "PopupmenuButton", "ポップアップメニュー表示" }, { "DragStartButton", "ドラッグ開始" }, { "TreeRowSelectionButton", "行範囲選択" }, { "", "" }, // BBSLIST { "", "" }, { "OpenBoard", "板を開く" }, { "OpenBoardTab", "タブで板を開く" }, { "OpenBoardButton", "板を開く" }, { "OpenBoardTabButton", "タブで板を開く" }, { "", "" }, // BOARD { "", "" }, { "OpenArticle", "スレを開く" }, { "OpenArticleTab", ITEM_NAME_OPENARTICLETAB }, { "NewArticle", ITEM_NAME_NEWARTICLE }, { "SearchCache", "ログ検索" }, { "ScrollLeftBoard", "左スクロール" }, { "ScrollRightBoard", "右スクロール" }, { "OpenArticleButton", "スレを開く" }, { "OpenArticleTabButton", "タブでスレを開く" }, { "", "" }, // ARTICLE { "", "" }, { "UpMid", "中速上移動" }, { "UpFast", "高速上移動" }, { "DownMid", "中速下移動" }, { "DownFast", "高速下移動" }, { "PrevRes", "前のレスへ移動" }, { "NextRes", "次のレスへ移動" }, { "PrePost", "前の書き込みヘ移動" }, { "NextPost", "次の書き込みヘ移動" }, { "GotoNew", "新着へ移動" }, { "OpenParentBoard", ITEM_NAME_OPENBOARD }, { "WriteMessage", ITEM_NAME_WRITEMSG }, { "LiveStartStop", ITEM_NAME_LIVE }, { "SearchNextArticle", ITEM_NAME_NEXTARTICLE }, { "SearchWeb", "" }, // CONTROL::get_keyconfig() で名前をセットする { "SearchCacheLocal", "ログ検索(対象: 板)" }, { "SearchCacheAll", "ログ検索(対象: 全ログ)" }, { "ShowSelectImage", ITEM_NAME_SELECTIMG }, { "DeleteSelectImage", "削除する" }, { "AboneSelectImage", "あぼ〜んする" }, { "AboneSelectionRes", ITEM_NAME_ABONE_SELECTION }, { "PopupWarpButton", "クリックで多重ポップアップモードに移行" }, { "ReferResButton", "参照レスポップアップ表示" }, { "BmResButton", "ブックマーク" }, { "PopupmenuResButton", "レス番号メニュー表示" }, { "DrawoutAncButton", "レスの周辺を抽出" }, { "PopupmenuAncButton", "アンカーをクリックでメニュー表示" }, { "JumpAncButton", "アンカーをクリックでジャンプ" }, { "PopupIDButton", "ID抽出ポップアップ表示" }, { "DrawoutIDButton", "ID抽出" }, { "PopupmenuIDButton", "IDメニュー表示" }, { "OpenImageButton", "画像を開く" }, { "OpenBackImageButton", "画像をバックで開く" }, { "PopupmenuImageButton", "画像メニュー表示" }, { "OpenBeButton", "ブラウザでBe表示" }, { "PopupmenuBeButton", "Beメニュー表示" }, { "", "" }, // IMAGE ICON { "", "" }, { "CancelMosaic", "モザイク解除" }, { "ZoomFitImage", "画面に画像サイズを合わせる" }, { "ZoomInImage", "ズームイン" }, { "ZoomOutImage", "ズームアウト" }, { "OrgSizeImage", "元の画像サイズ" }, { "ScrollUpImage", "上スクロール" }, { "ScrollDownImage", "下スクロール" }, { "ScrollLeftImage", "左スクロール" }, { "ScrollRightImage", "右スクロール" }, { "CloseImageTabButton", "タブを閉じる" }, { "", "" }, // IMAGE VIEW { "", "" }, { "CloseImageButton", "画像を閉じる" }, { "ScrollImageButton", "画像スクロール" }, { "CancelMosaicButton", "モザイク解除" }, { "SaveImageButton", "画像保存" }, { "ResizeImageButton", "画像サイズ調整" }, { "", "" }, // MESSAGE { "", "" }, { "CancelWrite", ITEM_NAME_QUIT }, { "ExecWrite", ITEM_NAME_WRITEMSG }, { "InsertText", ITEM_NAME_INSERTTEXT }, { "LockMessage", ITEM_NAME_LOCK_MESSAGE }, { "Preview", ITEM_NAME_PREVIEW }, { "FocusWrite", "書き込みボタンにフォーカスを移す" }, { "ToggleSage", "sageのON/OFF切り替え" }, { "", "" }, // EDIT { "", "" }, { "HomeEdit", "Home" }, { "EndEdit", "End" }, { "UpEdit", "カーソルを上へ移動" }, { "DownEdit", "カーソルを下へ移動" }, { "RightEdit", "カーソルを右へ移動" }, { "LeftEdit", "カーソルを左へ移動" }, { "DeleteEdit", "一文字削除" }, { "BackspEdit", "BackSpace" }, { "UndoEdit", ITEM_NAME_UNDO }, { "EnterEdit", "改行" }, { "InputAA", "アスキーアート入力" }, { "", "" }, // JD globals { "", "" }, { "JDExit", "終了" }, { "JDHelp", "オンラインマニュアル" }, { "", "" }, // その他 { "", "" }, { "", "" }, { "", "" } }; } #endif jd-2.8.7-140104/src/control/controlutil.cpp0000644000076400010400000006325412201335554015133 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "controlutil.h" #include "get_config.h" #include "controlid.h" #include "controllabel.h" #include "keysyms.h" #include "keyconfig.h" #include "mouseconfig.h" #include "buttonconfig.h" #include "jdlib/miscutil.h" #include "config/globalconf.h" #include "skeleton/admin.h" #include "cache.h" #include "command.h" #include CONTROL::KeyConfig* instance_keyconfig = NULL; CONTROL::KeyConfig* instance_keyconfig_bkup = NULL; CONTROL::MouseConfig* instance_mouseconfig = NULL; CONTROL::MouseConfig* instance_mouseconfig_bkup = NULL; CONTROL::ButtonConfig* instance_buttonconfig = NULL; CONTROL::ButtonConfig* instance_buttonconfig_bkup = NULL; ////////////////////////////////////////////////////////// CONTROL::KeyConfig* CONTROL::get_keyconfig() { if( ! instance_keyconfig ){ instance_keyconfig = new CONTROL::KeyConfig(); // ラベルをセットしておく strncpy( control_label[ CONTROL::SearchWeb ][ 1 ], CONFIG::get_menu_search_web().c_str(), MAX_CONTROL_LABEL ); strncpy( control_label[ CONTROL::SearchTitle ][ 1 ], CONFIG::get_menu_search_title().c_str(), MAX_CONTROL_LABEL ); } return instance_keyconfig; } void CONTROL::delete_keyconfig() { if( instance_keyconfig ) delete instance_keyconfig; instance_keyconfig = NULL; if( instance_keyconfig_bkup ) delete instance_keyconfig_bkup; instance_keyconfig_bkup = NULL; } CONTROL::MouseConfig* CONTROL::get_mouseconfig() { if( ! instance_mouseconfig ) instance_mouseconfig = new CONTROL::MouseConfig(); return instance_mouseconfig; } void CONTROL::delete_mouseconfig() { if( instance_mouseconfig ) delete instance_mouseconfig; instance_mouseconfig = NULL; if( instance_mouseconfig_bkup ) delete instance_mouseconfig_bkup; instance_mouseconfig_bkup = NULL; } CONTROL::ButtonConfig* CONTROL::get_buttonconfig() { if( ! instance_buttonconfig ) instance_buttonconfig = new CONTROL::ButtonConfig(); return instance_buttonconfig; } void CONTROL::delete_buttonconfig() { if( instance_buttonconfig ) delete instance_buttonconfig; instance_buttonconfig = NULL; if( instance_buttonconfig_bkup ) delete instance_buttonconfig_bkup; instance_buttonconfig_bkup = NULL; } void CONTROL::load_conf() { CONTROL::get_keyconfig()->load_conf(); CONTROL::get_mouseconfig()->load_conf(); CONTROL::get_buttonconfig()->load_conf(); } void CONTROL::save_conf() { CONTROL::get_keyconfig()->save_conf( CACHE::path_keyconf() ); CONTROL::get_mouseconfig()->save_conf( CACHE::path_mouseconf() ); CONTROL::get_buttonconfig()->save_conf( CACHE::path_buttonconf() ); } void CONTROL::delete_conf() { CONTROL::delete_keyconfig(); CONTROL::delete_mouseconfig(); CONTROL::delete_buttonconfig(); } ///////////////////////////////////////////////////////// // keysymはアスキー文字か const bool CONTROL::is_ascii( const guint keysym ) { if( keysym > 32 && keysym < 127 ) return true; return false; } // メニューにショートカットキーやマウスジェスチャを表示 void CONTROL::set_menu_motion( Gtk::Menu* menu ) { if( !menu ) return; Gtk::Menu_Helpers::MenuList& items = menu->items(); Gtk::Menu_Helpers::MenuList::iterator it_item = items.begin(); for( ; it_item != items.end(); ++it_item ){ // menuitemの中の名前を読み込んで ID を取得し、CONTROL::Noneでなかったら // ラベルを置き換える Gtk::Label* label = dynamic_cast< Gtk::Label* >( (*it_item).get_child() ); if( label ){ #ifdef _DEBUG std::cout << label->get_text() << std::endl; #endif int id = CONTROL::get_id( label->get_text() ); if( id != CONTROL::None ){ std::string str_label = CONTROL::get_label_with_mnemonic( id ); std::string str_motions = CONTROL::get_str_motions( id ); ( *it_item ).remove(); Gtk::Label *label = Gtk::manage( new Gtk::Label( str_label + ( str_motions.empty() ? "" : " " ), true ) ); Gtk::Label *label_motion = Gtk::manage( new Gtk::Label( str_motions ) ); Gtk::HBox *box = Gtk::manage( new Gtk::HBox() ); box->pack_start( *label, Gtk::PACK_SHRINK ); box->pack_end( *label_motion, Gtk::PACK_SHRINK ); (*it_item).add( *box ); box->show_all(); } } if( (*it_item).has_submenu() ) CONTROL::set_menu_motion( (*it_item).get_submenu() ); } } // IDからモードを取得 // 例えば id == CONTROL::Up の時は CONTROL::COMMONMOTION を返す const int CONTROL::get_mode( const int id ) { if( id < CONTROL::COMMONMOTION_END ) return CONTROL::MODE_COMMON; if( id < CONTROL::BBSLISTMOTION_END ) return CONTROL::MODE_BBSLIST; if( id < CONTROL::BOARDMOTION_END ) return CONTROL::MODE_BOARD; if( id < CONTROL::ARTICLEMOTION_END ) return CONTROL::MODE_ARTICLE; if( id < CONTROL::IMAGEICONMOTION_END ) return CONTROL::MODE_IMAGEICON; if( id < CONTROL::IMAGEVIEWMOTION_END ) return CONTROL::MODE_IMAGEVIEW; if( id < CONTROL::MESSAGEMOTION_END ) return CONTROL::MODE_MESSAGE; if( id < CONTROL::EDITMOTION_END ) return CONTROL::MODE_EDIT; if( id < CONTROL::JDGLOBALS_END ) return CONTROL::MODE_JDGLOBALS; return CONTROL::MODE_ERROR; } // 操作モードIDからモード名取得 // 例えば mode == CONTROL::MODE_COMMON の時は "共通" を返す const std::string CONTROL::get_mode_label( const int mode ) { if( mode < CONTROL::MODE_START || mode > MODE_END ) return std::string(); return CONTROL::mode_label[ mode ]; } // キー名からkeysymを取得 // 例えば keyname == "Space" の時は GDK_space を返す const guint CONTROL::get_keysym( const std::string& keyname ) { #ifdef _DEBUG std::cout << "CONTROL::get_keysym name = " << keyname; #endif if( keyname.empty() ) return 0; for( size_t i = 0; i < sizeof( CONTROL::keysyms ) / sizeof( KEYSYMS ); ++i ){ if( CONTROL::keysyms[ i ].keyname == keyname ){ #ifdef _DEBUG std::cout << " found sym = " << CONTROL::keysyms[ i ].keysym << std::endl; #endif return CONTROL::keysyms[ i ].keysym; } } // データベース内に見つからなかったらアスキー文字を返す #ifdef _DEBUG std::cout << " not found sym = " << ( guint )keyname[ 0 ] << std::endl; #endif return keyname[ 0 ]; } // keysymからキー名を取得 // 例えば keysym == GDK_space の時は "Space" を返す const std::string CONTROL::get_keyname( const guint keysym ) { #ifdef _DEBUG std::cout << "CONTROL::get_keyname sym = " << keysym; #endif for( size_t i = 0; i < sizeof( CONTROL::keysyms ) / sizeof( KEYSYMS ); ++i ){ if( CONTROL::keysyms[ i ].keysym == keysym ){ #ifdef _DEBUG std::cout << " found name = " << CONTROL::keysyms[ i ].keyname << std::endl; #endif return CONTROL::keysyms[ i ].keyname; } } #ifdef _DEBUG std::cout << " not found\n"; #endif // データベース内に見つからなかったらアスキー文字を返す if( CONTROL::is_ascii( keysym ) ){ char c[ 2 ]; c[ 0 ] = keysym; c[ 1 ] = '\0'; return std::string( c ); } return std::string(); } // 操作名からID取得 // 例えば name == "Up" の時は CONTROL::Up を返す const int CONTROL::get_id( const std::string& name ) { for( int id = CONTROL::COMMONMOTION; id < CONTROL::CONTROL_END; ++id ){ if( name == CONTROL::control_label[ id ][0] ) return id; } return CONTROL::None; } // IDから操作名取得 // 例えば id == CONTROL::Up の時は "Up" を返す const std::string CONTROL::get_name( const int id ) { if( id < CONTROL::COMMONMOTION || id >= CONTROL::CONTROL_END ) return std::string(); return CONTROL::control_label[ id ][0]; } // IDからラベル取得 // 例えば id == CONTROL::Up の時は "上移動" を返す const std::string CONTROL::get_label( const int id ) { if( id < CONTROL::COMMONMOTION || id >= CONTROL::CONTROL_END ) return std::string(); return CONTROL::control_label[ id ][ 1 ]; } // IDからショートカットを付けたラベルを取得 // 例えば id == CONTROL::Save の時は "名前を付けて保存(_S)..." を返す const std::string CONTROL::get_label_with_mnemonic( const int id ) { unsigned int pos; std::string label = CONTROL::get_label ( id ); pos = label.find( "...", 0); if ( pos != std::string::npos ) { switch ( id ) { case CONTROL::Save: //名前を付けて保存... case CONTROL::SaveDat: //datを保存... label.replace( pos, strlen( "..." ), "(_S)..." ); break; case CONTROL::AppendFavorite: //お気に入りに追加.. label.replace( pos, strlen( "..." ), "(_F)..." ); break; case CONTROL::OpenURL: //URLを開く label.replace( pos, strlen( "..." ), "(_U)..." ); break; case CONTROL::PreferenceView: //プロパティ... case CONTROL::PreferenceArticle: //スレのプロパティ... label.replace( pos, strlen( "..." ), "(_P)..." ); break; case CONTROL::PreferenceBoard: //板のプロパティ... label.replace( pos, strlen( "..." ), "(_O)..." ); break; case CONTROL::PreferenceImage: //画像のプロパティ... label.replace( pos, strlen( "..." ), "(_M)..." ); break; } } else { switch ( id ) { case CONTROL::PreBookMark: //前のブックマークへ移動 label += "(_R)"; break; case CONTROL::NextBookMark: //次のブックマークへ移動 label += "(_X)"; break; case CONTROL::PrevView: //前へ戻る label += "(_P)"; break; case CONTROL::NextView: //次へ進む label += "(_N)"; break; case CONTROL::ShowMenuBar: // メニューバー表示 label += "(_M)"; break; case CONTROL::ShowToolBarMain: // メインツールバー表示 label += "(_M)"; break; case CONTROL::Home: //先頭へ移動 label += "(_H)"; break; case CONTROL::End: //最後へ移動 label += "(_E)"; break; case CONTROL::Quit: //閉じる label += "(_C)"; break; case CONTROL::Delete: //削除 label += "(_D)"; break; case CONTROL::Reload: //再読み込み label += "(_R)"; break; case CONTROL::StopLoading: //読み込み中止 label += "(_T)"; break; case CONTROL::Copy: //コピー label += "(_C)"; break; case CONTROL::Search: //検索 label += "(_S)"; break; case CONTROL::SearchNext: //次検索 label += "(_N)"; break; case CONTROL::SearchPrev: //前検索 label += "(_P)"; break; case CONTROL::OpenArticleTab: // タブでスレを開く label += "(_T)"; break; case CONTROL::GotoNew: //新着へ移動 label += "(_W)"; break; case CONTROL::LiveStartStop: // 実況 label += "(_L)"; break; case CONTROL::SearchNextArticle: // 次スレ検索 label += "(_N)"; break; case CONTROL::SearchWeb: // web検索 label += "(_W)"; break; case CONTROL::SearchTitle: // スレタイ検索 label += "(_T)"; break; case CONTROL::SearchCacheLocal: // ログ検索(対象: 板) label += "(_L)"; break; case CONTROL::SearchCacheAll: // ログ検索(対象: 全て) label += "(_A)"; break; case CONTROL::ShowSelectImage: // 選択範囲の画像を開く label += "(_G)"; break; case CONTROL::DeleteSelectImage: // 選択範囲の画像を削除(サブメニュー) label += "(_D)"; break; case CONTROL::AboneSelectImage: // 選択範囲の画像をあぼ〜ん(サブメニュー) label += "(_A)"; break; case CONTROL::AboneSelectionRes: // 選択範囲のレスをあぼ〜ん label += "(_A)"; break; case CONTROL::CancelMosaic: //モザイク解除 label += "(_M)"; break; case CONTROL::ZoomFitImage: //画面に画像サイズを合わせる label += "(_A)"; break; case CONTROL::ZoomInImage: //ズームイン label += "(_I)"; break; case CONTROL::ZoomOutImage: //ズームアウト label += "(_Z)"; break; case CONTROL::OrgSizeImage: //元の画像サイズ label += "(_N)"; break; case CONTROL::FullScreen: // 全画面表示 label += "(_F)"; break; } } return label; } // IDからキーボードとマウスジェスチャの両方を取得 const std::string CONTROL::get_str_motions( const int id ) { int ctl = id; // メニューのラベルとコントロールのIDが異なる、共通コントロールIDの場合は、ここで変換する switch( ctl ){ // 表示中のビューのプロパティを表示 case CONTROL::PreferenceArticle: //スレのプロパティ... case CONTROL::PreferenceBoard: //板のプロパティ... case CONTROL::PreferenceImage: //画像のプロパティ... ctl = CONTROL::PreferenceView; break; //名前を付けて保存... case CONTROL::SaveDat: //datを保存... ctl = CONTROL::Save; break; } std::string str_motion = get_str_keymotions( ctl ); std::string mouse_motion = get_str_mousemotions( ctl ); if( ! mouse_motion.empty() ){ if( !str_motion.empty() ) str_motion += " "; str_motion += "( " + mouse_motion + " )"; } return str_motion; } // IDからラベルと操作の両方を取得 const std::string CONTROL::get_label_motions( const int id ) { std::string motion = CONTROL::get_str_motions( id ); return CONTROL::get_label( id ) + ( motion.empty() ? "" : " " ) + motion; } // 共通操作 const bool CONTROL::operate_common( const int control, const std::string& url, SKELETON::Admin* admin ) { if( control == CONTROL::None ) return false;; switch( control ){ // 全てのタブを閉じる case CONTROL::CloseAllTabs: if( admin ) admin->set_command( "close_view", "", "closealltabs" ); break; // 他のタブを閉じる case CONTROL::CloseOtherTabs: if( admin ) admin->set_command( "close_view", url, "closeother" ); break; // 最後に閉じたタブを復元 case CONTROL::RestoreLastTab: if( admin ) admin->set_command( "restore_lasttab" ); break; // 全ての更新されたタブを再読み込み case CONTROL::CheckUpdateTabs: if( admin ) admin->set_command( "check_update_reload_all_tabs" ); break; // 右、左のタブに切り替え case CONTROL::TabLeft: if( admin ) admin->set_command( "tab_left" ); break; case CONTROL::TabRight: if( admin ) admin->set_command( "tab_right" ); break; case CONTROL::TabLeftUpdated: if( admin ) admin->set_command( "tab_left_updated" ); break; case CONTROL::TabRightUpdated: if( admin ) admin->set_command( "tab_right_updated" ); break; // タブ位置(1-9)で移動 case CONTROL::TabNum1: if( admin ) admin->set_command( "tab_num", "", "1" ); break; case CONTROL::TabNum2: if( admin ) admin->set_command( "tab_num", "", "2" ); break; case CONTROL::TabNum3: if( admin ) admin->set_command( "tab_num", "", "3" ); break; case CONTROL::TabNum4: if( admin ) admin->set_command( "tab_num", "", "4" ); break; case CONTROL::TabNum5: if( admin ) admin->set_command( "tab_num", "", "5" ); break; case CONTROL::TabNum6: if( admin ) admin->set_command( "tab_num", "", "6" ); break; case CONTROL::TabNum7: if( admin ) admin->set_command( "tab_num", "", "7" ); break; case CONTROL::TabNum8: if( admin ) admin->set_command( "tab_num", "", "8" ); break; case CONTROL::TabNum9: if( admin ) admin->set_command( "tab_num", "", "9" ); break; // サイドバー表示/非表示 case CONTROL::ShowSideBar: CORE::core_set_command( "toggle_sidebar" ); break; // メニューバー表示/非表示 case CONTROL::ShowMenuBar: CORE::core_set_command( "toggle_menubar" ); break; // メインツールバー表示/非表示 case CONTROL::ShowToolBarMain: CORE::core_set_command( "toggle_toolbarmain" ); break; // URLを開くダイアログを表示 case CONTROL::OpenURL: CORE::core_set_command( "show_openurl_diag" ); break; // JD終了 case CONTROL::QuitJD: CORE::core_set_command( "quit_jd" ); break; // 最大化 / 最大化解除 case CONTROL::MaximizeMainWin: CORE::core_set_command( "maximize_mainwin" ); break; // 最小化 case CONTROL::IconifyMainWin: CORE::core_set_command( "iconify_mainwin" ); break; // サイドバー更新チェック case CONTROL::CheckUpdateRoot: CORE::core_set_command( "check_update_root" ); break; case CONTROL::CheckUpdateOpenRoot: CORE::core_set_command( "check_update_open_root" ); break; // 全画面表示 case CONTROL::FullScreen: CORE::core_set_command( "toggle_fullscreen" ); break; // スレタイ検索 case CONTROL::SearchTitle: CORE::core_set_command( "open_article_searchtitle", "", "", "noexec" ); break; default: return false; } return true; } ///////////////////////////////////////////////////////// // キーボード設定の一時的なバックアップと復元 void CONTROL::bkup_keyconfig() { if( ! instance_keyconfig_bkup ) instance_keyconfig_bkup = new CONTROL::KeyConfig(); *instance_keyconfig_bkup = * instance_keyconfig; } void CONTROL::restore_keyconfig() { if( ! instance_keyconfig_bkup ) return; *instance_keyconfig = * instance_keyconfig_bkup; } // IDからキーボード操作を取得 const std::string CONTROL::get_str_keymotions( const int id ) { return CONTROL::get_keyconfig()->get_str_motions( id ); } // IDからデフォルトキーボード操作を取得 const std::string CONTROL::get_default_keymotions( const int id ) { return CONTROL::get_keyconfig()->get_default_motions( id ); } // スペースで区切られた複数のキーボード操作をデータベースに登録 void CONTROL::set_keymotions( const int id, const std::string& str_motions ) { CONTROL::get_keyconfig()->set_motions( id, str_motions ); } // 指定したIDのキーボード操作を全て削除 const bool CONTROL::remove_keymotions( const int id ) { return CONTROL::get_keyconfig()->remove_motions( id ); } // キーボード操作が重複していないか const std::vector< int > CONTROL::check_key_conflict( const int mode, const std::string& str_motion ) { return CONTROL::get_keyconfig()->check_conflict( mode, str_motion ); } // editviewの操作をemacs風にする const bool CONTROL::is_emacs_mode() { return CONTROL::get_keyconfig()->is_emacs_mode(); } void CONTROL::toggle_emacs_mode() { CONTROL::get_keyconfig()->toggle_emacs_mode(); } // 「タブで開く」キーを入れ替える const bool CONTROL::is_toggled_tab_key() { return CONTROL::get_keyconfig()->is_toggled_tab_key(); } void CONTROL::toggle_tab_key( const bool toggle ) { CONTROL::get_keyconfig()->toggle_tab_key( toggle ); } // Gtk アクセラレーションキーを取得 Gtk::AccelKey CONTROL::get_accelkey( const int id ) { return CONTROL::get_keyconfig()->get_accelkey( id ); } ///////////////////////////////////////////////////////// const std::string convert_mouse_motions( std::string motions ) { motions = MISC::replace_str( motions, "8", "↑" ); motions = MISC::replace_str( motions, "6", "→" ); motions = MISC::replace_str( motions, "4", "←" ); motions = MISC::replace_str( motions, "2", "↓" ); return motions; } const std::string convert_mouse_motions_reverse( std::string motions ) { motions = MISC::replace_str( motions, "↑", "8" ); motions = MISC::replace_str( motions, "→", "6" ); motions = MISC::replace_str( motions, "←", "4" ); motions = MISC::replace_str( motions, "↓", "2" ); return motions; } // マウスジェスチャ設定の一時的なバックアップと復元 void CONTROL::bkup_mouseconfig() { if( ! instance_mouseconfig_bkup ) instance_mouseconfig_bkup = new CONTROL::MouseConfig(); *instance_mouseconfig_bkup = * instance_mouseconfig; } void CONTROL::restore_mouseconfig() { if( ! instance_mouseconfig_bkup ) return; *instance_mouseconfig = * instance_mouseconfig_bkup; } // IDからマウスジェスチャを取得 const std::string CONTROL::get_str_mousemotions( const int id ) { return convert_mouse_motions( CONTROL::get_mouseconfig()->get_str_motions( id ) ); } // IDからデフォルトマウスジェスチャを取得 const std::string CONTROL::get_default_mousemotions( const int id ) { return convert_mouse_motions( CONTROL::get_mouseconfig()->get_default_motions( id ) ); } // スペースで区切られた複数のマウスジェスチャをデータベースに登録 void CONTROL::set_mousemotions( const int id, const std::string& str_motions ) { const std::string motions = convert_mouse_motions_reverse( str_motions ); CONTROL::get_mouseconfig()->set_motions( id, motions ); } // 指定したIDのマウスジェスチャを全て削除 const bool CONTROL::remove_mousemotions( const int id ) { return CONTROL::get_mouseconfig()->remove_motions( id ); } // マウスジェスチャが重複していないか const std::vector< int > CONTROL::check_mouse_conflict( const int mode, const std::string& str_motion ) { const std::string motion = convert_mouse_motions_reverse( str_motion ); return CONTROL::get_mouseconfig()->check_conflict( mode, motion ); } ///////////////////////////////////////////////////////// // ボタン設定の一時的なバックアップと復元 void CONTROL::bkup_buttonconfig() { if( ! instance_buttonconfig_bkup ) instance_buttonconfig_bkup = new CONTROL::ButtonConfig(); *instance_buttonconfig_bkup = * instance_buttonconfig; } void CONTROL::restore_buttonconfig() { if( ! instance_buttonconfig_bkup ) return; *instance_buttonconfig = * instance_buttonconfig_bkup; } // IDからボタン設定を取得 const std::string CONTROL::get_str_buttonmotions( const int id ) { return CONTROL::get_buttonconfig()->get_str_motions( id ); } // IDからデフォルトボタン設定を取得 const std::string CONTROL::get_default_buttonmotions( const int id ) { return CONTROL::get_buttonconfig()->get_default_motions( id ); } // スペースで区切られた複数のボタン設定をデータベースに登録 void CONTROL::set_buttonmotions( const int id, const std::string& str_motions ) { CONTROL::get_buttonconfig()->set_motions( id, str_motions ); } // 指定したIDのボタン設定を全て削除 const bool CONTROL::remove_buttonmotions( const int id ) { return CONTROL::get_buttonconfig()->remove_motions( id ); } // ボタンが重複していないか const std::vector< int > CONTROL::check_button_conflict( const int mode, const std::string& str_motion ) { return CONTROL::get_buttonconfig()->check_conflict( mode, str_motion ); } ///////////////////////////////////////////////////////// // タブで開くボタンを入れ替える const bool CONTROL::is_toggled_tab_button() { return CONTROL::get_buttonconfig()->is_toggled_tab_button(); } void CONTROL::toggle_tab_button( const bool toggle ) { CONTROL::get_buttonconfig()->toggle_tab_button( toggle ); } // ポップアップ表示の時にクリックでワープ const bool CONTROL::is_popup_warpmode() { return CONTROL::get_buttonconfig()->is_popup_warpmode(); } void CONTROL::toggle_popup_warpmode() { CONTROL::get_buttonconfig()->toggle_popup_warpmode(); } jd-2.8.7-140104/src/control/controlutil.h0000644000076400010400000001240112201335554014564 0ustar // ライセンス: GPL2 // // コントロール系ユーティリティ関数 // #ifndef _CONTROLUTIL_H #define _CONTROLUTIL_H #include namespace SKELETON { class Admin; } namespace CONTROL { void load_conf(); void save_conf(); void delete_conf(); /////////////////////// // keysymはアスキー文字か const bool is_ascii( const guint keysym ); // メニューにショートカットキーやマウスジェスチャを表示 void set_menu_motion( Gtk::Menu* menu ); // IDからモードを取得 // 例えば id == CONTROL::Up の時は CONTROL::COMMONMOTION を返す const int get_mode( const int id ); // 操作モードIDからモード名取得 // 例えば mode == CONTROL::MODE_COMMON の時は "共通" を返す const std::string get_mode_label( const int mode ); // キー名からkeysymを取得 // 例えば keyname == "Space" の時は GDK_space を返す const guint get_keysym( const std::string& keyname ); // keysymからキー名を取得 // 例えば keysym == GDK_space の時は "Space" を返す const std::string get_keyname( const guint keysym ); // 操作名からID取得 // 例えば name == "Up" の時は CONTROL::Up を返す const int get_id( const std::string& name ); // IDから操作名取得 // 例えば id == CONTROL::Up の時は "Up" を返す const std::string get_name( const int id ); // IDからラベル取得 // 例えば id == CONTROL::Up の時は "上移動" を返す const std::string get_label( const int id ); // IDからショートカットを付けたラベルを取得 // 例えば id == CONTROL::Save の時は "名前を付けて保存(_S)..." を返す const std::string get_label_with_mnemonic( const int id ); // IDからキーボードとマウスジェスチャの両方を取得 const std::string get_str_motions( const int id ); // IDからラベルと操作の両方を取得 const std::string get_label_motions( const int id ); // 共通操作 const bool operate_common( const int control, const std::string& url, SKELETON::Admin* admin ); /////////////////////// // キーボード設定の一時的なバックアップと復元 void bkup_keyconfig(); void restore_keyconfig(); // IDからキーボード操作を取得 const std::string get_str_keymotions( const int id ); // IDからデフォルトキーボード操作を取得 const std::string get_default_keymotions( const int id ); // スペースで区切られた複数のキーボード操作をデータベースに登録 void set_keymotions( const int id, const std::string& str_motions ); // 指定したIDのキーボード操作を全て削除 const bool remove_keymotions( const int id ); // キーボード操作が重複していないか const std::vector< int > check_key_conflict( const int mode, const std::string& str_motion ); // editviewの操作をemacs風にする const bool is_emacs_mode(); void toggle_emacs_mode(); // 「タブで開く」キーを入れ替える const bool is_toggled_tab_key(); void toggle_tab_key( const bool toggle ); // Gtk アクセラレーションキーを取得 Gtk::AccelKey get_accelkey( const int id ); /////////////////////// // マウスジェスチャ設定の一時的なバックアップと復元 void bkup_mouseconfig(); void restore_mouseconfig(); // IDからマウスジェスチャを取得 const std::string get_str_mousemotions( const int id ); // IDからデフォルトマウスジェスチャを取得 const std::string get_default_mousemotions( const int id ); // スペースで区切られた複数のマウスジェスチャをデータベースに登録 void set_mousemotions( const int id, const std::string& str_motions ); // 指定したIDのマウスジェスチャを全て削除 const bool remove_mousemotions( const int id ); // マウスジェスチャが重複していないか const std::vector< int > check_mouse_conflict( const int mode, const std::string& str_motion ); /////////////////////// // ボタン設定の一時的なバックアップと復元 void bkup_buttonconfig(); void restore_buttonconfig(); // IDからボタン設定を取得 const std::string get_str_buttonmotions( const int id ); // IDからデフォルトボタン設定を取得 const std::string get_default_buttonmotions( const int id ); // スペースで区切られた複数のボタン設定をデータベースに登録 void set_buttonmotions( const int id, const std::string& str_motions ); // 指定したIDのボタン設定を全て削除 const bool remove_buttonmotions( const int id ); // ボタンが重複していないか const std::vector< int > check_button_conflict( const int mode, const std::string& str_motion ); /////////////////////// // タブで開くボタンを入れ替える const bool is_toggled_tab_button(); void toggle_tab_button( const bool toggle ); // ポップアップ表示の時にクリックでワープ const bool is_popup_warpmode(); void toggle_popup_warpmode(); } #endif jd-2.8.7-140104/src/control/defaultconf.h0000644000076400010400000001745112201335554014512 0ustar // ライセンス: GPL2 // // 設定のデフォルト値 // #ifndef _DEFAULTMOUSEKEYCONF_H #define _DEFAULTMOUSEKEYCONF_H #ifdef HAVE_CONFIG_H #include "config.h" #endif namespace CONTROL { // ショートカットキー #define KEYCONF_Up "k Up KP_Up" #define KEYCONF_Down "j Down KP_Down" #define KEYCONF_Right "l Right KP_Right" #define KEYCONF_Left "h Left KP_left" #define KEYCONF_TabRight "Ctrl+Page_Down Ctrl+Tab Ctrl+Left_Tab Ctrl+l Ctrl+Right" #define KEYCONF_TabLeft "Ctrl+Page_Up Ctrl+Shift+Tab Ctrl+Shift+Left_Tab Ctrl+h Ctrl+Left" #define KEYCONF_TabRightUpdated "Ctrl+Shift+Page_Down Ctrl+L Ctrl+Shift+Right ]" #define KEYCONF_TabLeftUpdated "Ctrl+Shift+Page_Up Ctrl+H Ctrl+Shift+Left [" #define KEYCONF_TabNum1 "Alt+1" #define KEYCONF_TabNum2 "Alt+2" #define KEYCONF_TabNum3 "Alt+3" #define KEYCONF_TabNum4 "Alt+4" #define KEYCONF_TabNum5 "Alt+5" #define KEYCONF_TabNum6 "Alt+6" #define KEYCONF_TabNum7 "Alt+7" #define KEYCONF_TabNum8 "Alt+8" #define KEYCONF_TabNum9 "Alt+9" #define KEYCONF_RestoreLastTab "Ctrl+T" #define KEYCONF_PreBookMark "Ctrl+F2" #define KEYCONF_NextBookMark "F2" #define KEYCONF_PrevView "Alt+Left" #define KEYCONF_NextView "Alt+Right" #define KEYCONF_ToggleArticle "Alt+x" #define KEYCONF_ShowPopupMenu "Shift+F10 Ctrl+m Menu" #define KEYCONF_ShowMenuBar "F8" #define KEYCONF_ShowToolBarMain "" #define KEYCONF_ShowSideBar "F9" #define KEYCONF_PageUp "Page_Up KP_Prior" #define KEYCONF_PageDown "Page_Down KP_Next" #define KEYCONF_PrevDir "{" #define KEYCONF_NextDir "}" #define KEYCONF_Home "Home g < KP_Home" #define KEYCONF_End "End G > KP_End" #define KEYCONF_Back "BackSpace" #define KEYCONF_Undo "Ctrl+/ Ctrl+z" #define KEYCONF_Redo "Ctrl+Z" #define KEYCONF_Quit "Ctrl+w q" #define KEYCONF_Save "Ctrl+s" #define KEYCONF_Delete "Delete KP_Delete" #define KEYCONF_Reload "F5 s" #define KEYCONF_ReloadArticle "Shift+F5 S" #define KEYCONF_StopLoading "Escape" #define KEYCONF_OpenURL "Ctrl+o" #define KEYCONF_Copy "Ctrl+c" #define KEYCONF_SelectAll "Ctrl+a" #define KEYCONF_AppendFavorite "Ctrl+d" #define KEYCONF_PreferenceView "Ctrl+P" #define KEYCONF_Search "Ctrl+f / KP_Divide" #define KEYCONF_SearchInvert "?" #define KEYCONF_SearchNext "Enter F3 Ctrl+g" #define KEYCONF_SearchPrev "Shift+Enter Ctrl+F3 Ctrl+G N" #define KEYCONF_SearchTitle "Ctrl+t" #define KEYCONF_DrawOutAnd "Ctrl+Enter" #define KEYCONF_CheckUpdateRoot "" #define KEYCONF_CheckUpdateOpenRoot "" #define KEYCONF_FullScreen "F11" // BBSLIST #define KEYCONF_OpenBoard "Space" #define KEYCONF_OpenBoardTab "Ctrl+Space" // BOARD #define KEYCONF_OpenArticle "Space" #define KEYCONF_OpenArticleTab "Ctrl+Space" #define KEYCONF_NewArticle "w" #define KEYCONF_SearchCache "Ctrl+Enter" #define KEYCONF_ScrollRightBoard "L Shift+Right" #define KEYCONF_ScrollLeftBoard "H Shift+Left" // ARTICLE #define KEYCONF_UpMid "u" #define KEYCONF_UpFast "b Page_Up KP_Prior" #define KEYCONF_DownMid "d" #define KEYCONF_DownFast "Page_Down Space KP_Next" #define KEYCONF_PrevRes "p" #define KEYCONF_NextRes "n" #define KEYCONF_PrePost "Ctrl+Shift+F2" #define KEYCONF_NextPost "Shift+F2" #define KEYCONF_GotoNew "F4" #define KEYCONF_WriteMessage "w Alt+w" #define KEYCONF_LiveStartStop "F6" #define KEYCONF_SearchNextArticle "Ctrl+Space" #define KEYCONF_SearchWeb "Ctrl+k" #define KEYCONF_SearchCacheLocal "Ctrl+Enter" #define KEYCONF_SearchCacheAll "" #define KEYCONF_ShowSelectImage "Ctrl+I" #define KEYCONF_DeleteSelectImage "" #define KEYCONF_AboneSelectImage "" #define KEYCONF_AboneSelectionRes "" // IMAGE #define KEYCONF_CancelMosaic "c" #define KEYCONF_ZoomFitImage "x" #define KEYCONF_ZoomInImage "+ KP_Add" // (注意) ver.2.0.2 以前は + は Plus だった #define KEYCONF_ZoomOutImage "- KP_Subtract" #define KEYCONF_OrgSizeImage "z" #define KEYCONF_ScrollUpImage "K k Shift+Up Up" #define KEYCONF_ScrollDownImage "J j Shift+Down Down" #define KEYCONF_ScrollLeftImage "H Shift+Left" #define KEYCONF_ScrollRightImage "L Shift+Right" // MESSAGE #define KEYCONF_CancelWrite "Alt+q" #define KEYCONF_ExecWrite "Alt+w" #define KEYCONF_FocusWrite "Tab" #define KEYCONF_ToggleSage "Alt+s" // EDIT #define KEYCONF_HomeEdit "" #define KEYCONF_EndEdit "" #define KEYCONF_UpEdit "" #define KEYCONF_DownEdit "" #define KEYCONF_RightEdit "" #define KEYCONF_LeftEdit "" #define KEYCONF_DeleteEdit "" #define KEYCONF_BackspEdit "" #define KEYCONF_UndoEdit "Ctrl+/ Ctrl+z" #define KEYCONF_EnterEdit "" #define KEYCONF_InputAA "Alt+a" // JD globals #define KEYCONF_JDExit "Ctrl+q" #define KEYCONF_JDHelp "F1" ////////////////////////////////// // マウスジェスチャ // 8 // ↑ // 4 ← → 6 // ↓ // 2 // // ( 例 ) ↑→↓← = 8624 // 共通 #define MOUSECONF_Right "6" #define MOUSECONF_Left "4" #define MOUSECONF_TabRight "86" #define MOUSECONF_TabLeft "84" #define MOUSECONF_TabRightUpdated "" #define MOUSECONF_TabLeftUpdated "" #define MOUSECONF_CloseAllTabs "" #define MOUSECONF_CloseOtherTabs "" #define MOUSECONF_RestoreLastTab "64" #define MOUSECONF_CheckUpdateTabs "" #define MOUSECONF_ToggleArticle "2" #define MOUSECONF_ShowSideBar "" #define MOUSECONF_ShowMenuBar "" #define MOUSECONF_ShowToolBarMain "" #define MOUSECONF_Home "68" #define MOUSECONF_End "62" #define MOUSECONF_Quit "26" #define MOUSECONF_Reload "82" #define MOUSECONF_Delete "262" #define MOUSECONF_StopLoading "8" #define MOUSECONF_AppendFavorite "" #define MOUSECONF_NewArticle "24" #define MOUSECONF_WriteMessage "24" #define MOUSECONF_SearchTitle "" #define MOUSECONF_CheckUpdateRoot "48" #define MOUSECONF_CheckUpdateOpenRoot "42" #define MOUSECONF_QuitJD "" #define MOUSECONF_MaximizeMainWin "" #define MOUSECONF_IconifyMainWin "" // ARTICLE #define MOUSECONF_GotoNew "626" #define MOUSECONF_SearchNextArticle "28" #define MOUSECONF_SearchWeb "" #define MOUSECONF_LiveStartStop "" // IMAGE #define MOUSECONF_CancelMosaicButton "28" ////////////////////////////////// // ボタン割り当て // 共通 #define BUTTONCONF_ClickButton "Left" #define BUTTONCONF_DblClickButton "DblLeft" #define BUTTONCONF_TrpClickButton "TrpLeft" #define BUTTONCONF_CloseTabButton "Mid" #define BUTTONCONF_ReloadTabButton "DblLeft" #define BUTTONCONF_AutoScrollButton "Mid" #define BUTTONCONF_GestureButton "Right" #define BUTTONCONF_PopupmenuButton "Right" #define BUTTONCONF_DragStartButton "Left" #define BUTTONCONF_TreeRowSelectionButton "Mid" #define BUTTONCONF_Reload "Button4" #define BUTTONCONF_ToggleArticle "Button5" #define BUTTONCONF_Right "" #define BUTTONCONF_Left "" // BBSLIST用ボタン設定 #define BUTTONCONF_OpenBoardButton "Left" #define BUTTONCONF_OpenBoardTabButton "Mid" // BOARD用ボタン設定 #define BUTTONCONF_OpenArticleButton "Left" #define BUTTONCONF_OpenArticleTabButton "Mid" #define BUTTONCONF_ScrollRightBoard "Tilt_Right" #define BUTTONCONF_ScrollLeftBoard "Tilt_Left" // ARTICLE用ボタン設定 #define BUTTONCONF_PopupWarpButton "" #define BUTTONCONF_ReferResButton "Right" #define BUTTONCONF_BmResButton "Mid" #define BUTTONCONF_PopupmenuResButton "Left" #define BUTTONCONF_DrawoutAncButton "Mid" #define BUTTONCONF_PopupmenuAncButton "Left Right" #define BUTTONCONF_JumpAncButton "" #define BUTTONCONF_PopupIDButton "Right" #define BUTTONCONF_DrawoutIDButton "Mid" #define BUTTONCONF_PopupmenuIDButton "Left" #define BUTTONCONF_OpenImageButton "Left" #define BUTTONCONF_OpenBackImageButton "Mid Ctrl+Left" #define BUTTONCONF_PopupmenuImageButton "Right" #define BUTTONCONF_OpenBeButton "Left Mid" #define BUTTONCONF_PopupmenuBeButton "Right" // IMAGE ICON用ボタン設定 #define BUTTONCONF_CloseImageTabButton "Mid" // IMAGE用ボタン設定 #define BUTTONCONF_CloseImageButton "Mid" #define BUTTONCONF_ScrollImageButton "Left" #define BUTTONCONF_CancelMosaicButton "" #define BUTTONCONF_SaveImageButton "" #define BUTTONCONF_ResizeImageButton "Left" } #endif jd-2.8.7-140104/src/control/get_config.h0000644000076400010400000000064611101351617014316 0ustar // ライセンス: GPL2 // // KeyConfig, MouseConfig, ButtonConfig 取得 // #ifndef _GET_CONFIG_H #define _GET_CONFIG_H namespace CONTROL { class KeyConfig; class MouseConfig; class ButtonConfig; KeyConfig* get_keyconfig(); MouseConfig* get_mouseconfig(); ButtonConfig* get_buttonconfig(); void delete_keyconfig(); void delete_mouseconfig(); void delete_buttonconfig(); } #endif jd-2.8.7-140104/src/control/keyconfig.cpp0000644000076400010400000003175612201400541014522 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _DEBUG_XML #include "jddebug.h" #include "keyconfig.h" #include "controlutil.h" #include "defaultconf.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" #include "jdlib/jdregex.h" #include "jdlib/confloader.h" #include "cache.h" using namespace CONTROL; KeyConfig::KeyConfig() : MouseKeyConf() {} KeyConfig::~KeyConfig() {} // // 設定ファイル読み込み // // 設定を追加したら CONFIG::KeyPref::append_row() にも追加すること // void KeyConfig::load_conf() { JDLIB::ConfLoader cf( CACHE::path_keyconf(), std::string() ); // 共通設定 load_keymotions( cf, "Up", KEYCONF_Up ); load_keymotions( cf, "Down", KEYCONF_Down ); load_keymotions( cf, "Right", KEYCONF_Right ); load_keymotions( cf, "Left", KEYCONF_Left ); load_keymotions( cf, "TabRight", KEYCONF_TabRight ); load_keymotions( cf, "TabLeft", KEYCONF_TabLeft ); load_keymotions( cf, "TabRightUpdated", KEYCONF_TabRightUpdated ); load_keymotions( cf, "TabLeftUpdated", KEYCONF_TabLeftUpdated ); load_keymotions( cf, "TabNum1", KEYCONF_TabNum1 ); load_keymotions( cf, "TabNum2", KEYCONF_TabNum2 ); load_keymotions( cf, "TabNum3", KEYCONF_TabNum3 ); load_keymotions( cf, "TabNum4", KEYCONF_TabNum4 ); load_keymotions( cf, "TabNum5", KEYCONF_TabNum5 ); load_keymotions( cf, "TabNum6", KEYCONF_TabNum6 ); load_keymotions( cf, "TabNum7", KEYCONF_TabNum7 ); load_keymotions( cf, "TabNum8", KEYCONF_TabNum8 ); load_keymotions( cf, "TabNum9", KEYCONF_TabNum9 ); load_keymotions( cf, "RestoreLastTab", KEYCONF_RestoreLastTab ); load_keymotions( cf, "PreBookMark", KEYCONF_PreBookMark ); load_keymotions( cf, "NextBookMark", KEYCONF_NextBookMark ); load_keymotions( cf, "PrevView", KEYCONF_PrevView ); load_keymotions( cf, "NextView", KEYCONF_NextView ); load_keymotions( cf, "ToggleArticle", KEYCONF_ToggleArticle ); load_keymotions( cf, "ShowPopupMenu", KEYCONF_ShowPopupMenu ); load_keymotions( cf, "ShowMenuBar", KEYCONF_ShowMenuBar ); load_keymotions( cf, "ShowToolBarMain", KEYCONF_ShowToolBarMain ); load_keymotions( cf, "ShowSideBar", KEYCONF_ShowSideBar ); load_keymotions( cf, "PageUp", KEYCONF_PageUp ); load_keymotions( cf, "PageDown", KEYCONF_PageDown ); load_keymotions( cf, "PrevDir", KEYCONF_PrevDir ); load_keymotions( cf, "NextDir", KEYCONF_NextDir ); load_keymotions( cf, "Home", KEYCONF_Home ); load_keymotions( cf, "End", KEYCONF_End ); load_keymotions( cf, "Back", KEYCONF_Back ); load_keymotions( cf, "Undo", KEYCONF_Undo ); load_keymotions( cf, "Redo", KEYCONF_Redo ); load_keymotions( cf, "Quit", KEYCONF_Quit ); load_keymotions( cf, "Save", KEYCONF_Save ); load_keymotions( cf, "Delete", KEYCONF_Delete ); load_keymotions( cf, "Reload", KEYCONF_Reload ); load_keymotions( cf, "ReloadArticle", KEYCONF_ReloadArticle ); load_keymotions( cf, "StopLoading", KEYCONF_StopLoading ); // = CONTROL::Cancel load_keymotions( cf, "OpenURL", KEYCONF_OpenURL ); load_keymotions( cf, "Copy", KEYCONF_Copy ); load_keymotions( cf, "SelectAll", KEYCONF_SelectAll ); load_keymotions( cf, "AppendFavorite", KEYCONF_AppendFavorite ); load_motions( cf, "PreferenceView", KEYCONF_PreferenceView ); load_keymotions( cf, "Search", KEYCONF_Search ); load_keymotions( cf, "SearchInvert", KEYCONF_SearchInvert ); load_keymotions( cf, "SearchNext", KEYCONF_SearchNext ); load_keymotions( cf, "SearchPrev", KEYCONF_SearchPrev ); load_keymotions( cf, "SearchTitle", KEYCONF_SearchTitle ); load_keymotions( cf, "DrawOutAnd", KEYCONF_DrawOutAnd ); load_motions( cf, "CheckUpdateRoot", KEYCONF_CheckUpdateRoot ); load_motions( cf, "CheckUpdateOpenRoot", KEYCONF_CheckUpdateOpenRoot ); load_motions( cf, "FullScreen", KEYCONF_FullScreen ); // BBSLIST load_keymotions( cf, "OpenBoard", KEYCONF_OpenBoard ); load_keymotions( cf, "OpenBoardTab", KEYCONF_OpenBoardTab ); // BOARD load_keymotions( cf, "OpenArticle", KEYCONF_OpenArticle ); load_keymotions( cf, "OpenArticleTab", KEYCONF_OpenArticleTab ); load_keymotions( cf, "NewArticle", KEYCONF_NewArticle ); load_keymotions( cf, "SearchCache", KEYCONF_SearchCache ); load_keymotions( cf, "ScrollRightBoard", KEYCONF_ScrollRightBoard ); load_keymotions( cf, "ScrollLeftBoard", KEYCONF_ScrollLeftBoard ); // ARTICLE load_keymotions( cf, "UpMid", KEYCONF_UpMid ); load_keymotions( cf, "UpFast", KEYCONF_UpFast ); load_keymotions( cf, "DownMid", KEYCONF_DownMid ); load_keymotions( cf, "DownFast", KEYCONF_DownFast ); load_keymotions( cf, "PrevRes", KEYCONF_PrevRes ); load_keymotions( cf, "NextRes", KEYCONF_NextRes ); load_keymotions( cf, "PrePost", KEYCONF_PrePost ); load_keymotions( cf, "NextPost", KEYCONF_NextPost ); load_keymotions( cf, "GotoNew", KEYCONF_GotoNew ); load_keymotions( cf, "WriteMessage", KEYCONF_WriteMessage ); load_keymotions( cf, "LiveStartStop", KEYCONF_LiveStartStop ); load_keymotions( cf, "SearchNextArticle", KEYCONF_SearchNextArticle ); load_keymotions( cf, "SearchWeb", KEYCONF_SearchWeb ); load_keymotions( cf, "SearchCacheLocal", KEYCONF_SearchCacheLocal ); load_keymotions( cf, "SearchCacheAll", KEYCONF_SearchCacheAll ); load_keymotions( cf, "ShowSelectImage", KEYCONF_ShowSelectImage ); load_keymotions( cf, "DeleteSelectImage", KEYCONF_DeleteSelectImage ); load_keymotions( cf, "AboneSelectImage", KEYCONF_AboneSelectImage ); load_keymotions( cf, "AboneSelectionRes", KEYCONF_AboneSelectionRes ); // IMAGE load_keymotions( cf, "CancelMosaic", KEYCONF_CancelMosaic ); load_keymotions( cf, "ZoomFitImage", KEYCONF_ZoomFitImage ); load_keymotions( cf, "ZoomInImage", KEYCONF_ZoomInImage ); load_keymotions( cf, "ZoomOutImage", KEYCONF_ZoomOutImage ); load_keymotions( cf, "OrgSizeImage", KEYCONF_OrgSizeImage ); load_keymotions( cf, "ScrollUpImage", KEYCONF_ScrollUpImage ); load_keymotions( cf, "ScrollDownImage", KEYCONF_ScrollDownImage ); load_keymotions( cf, "ScrollLeftImage", KEYCONF_ScrollLeftImage ); load_keymotions( cf, "ScrollRightImage", KEYCONF_ScrollRightImage ); // MESSAGE load_keymotions( cf, "CancelWrite", KEYCONF_CancelWrite ); load_keymotions( cf, "ExecWrite", KEYCONF_ExecWrite ); load_keymotions( cf, "FocusWrite", KEYCONF_FocusWrite ); load_keymotions( cf, "ToggleSage", KEYCONF_ToggleSage ); // EDIT load_keymotions( cf, "HomeEdit", KEYCONF_HomeEdit ); load_keymotions( cf, "EndEdit", KEYCONF_EndEdit ); load_keymotions( cf, "UpEdit", KEYCONF_UpEdit ); load_keymotions( cf, "DownEdit", KEYCONF_DownEdit ); load_keymotions( cf, "RightEdit", KEYCONF_RightEdit ); load_keymotions( cf, "LeftEdit", KEYCONF_LeftEdit ); load_keymotions( cf, "DeleteEdit", KEYCONF_DeleteEdit ); load_keymotions( cf, "BackspEdit", KEYCONF_BackspEdit ); load_keymotions( cf, "UndoEdit", KEYCONF_UndoEdit ); load_keymotions( cf, "EnterEdit", KEYCONF_EnterEdit ); load_keymotions( cf, "InputAA", KEYCONF_InputAA ); // JD globals load_motions( cf, "JDExit", KEYCONF_JDExit ); if( CONFIG::get_disable_close() ) remove_motions( CONTROL::JDExit ); load_motions( cf, "JDHelp", KEYCONF_JDHelp ); } // ひとつの操作をデータベースに登録 void KeyConfig::set_one_motion_impl( const int id, const int mode, const std::string& name, const std::string& str_motion ) { if( name.empty() ) return; #ifdef _DEBUG std::cout << "KeyConfig::set_one_motion_impl " << name << std::endl; std::cout << "motion = " << str_motion << std::endl; #endif #ifdef _DEBUG std::cout << CONTROL::get_label( id ) << std::endl; #endif guint key = 0; bool ctrl = false; bool shift = false; bool alt = false; const bool dblclick = false; const bool trpclick = false; JDLIB::Regex regex; const size_t offset = 0; const bool icase = true; // 大文字小文字区別しない const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "(Ctrl\\+)?(Shift\\+)?(Alt\\+)?(.*)", str_motion, offset, icase, newline, usemigemo, wchar ) ){ if( ! regex.str( 1 ).empty() ) ctrl = true; if( ! regex.str( 2 ).empty() ) shift = true; if( ! regex.str( 3 ).empty() ) alt = true; const std::string str_key = regex.str( 4 ); if( str_key.empty() ) return; key = CONTROL::get_keysym( str_key ); // keyがアスキー文字の場合は shift を無視する (大文字除く) // Control::key_press() も参照せよ if( CONTROL::is_ascii( key ) ){ if( regex.str( 4 ).length() == 1 && key >= 'A' && key <= 'Z' ) shift = true; else shift = false; } } else return; #ifdef _DEBUG std::cout << "str_motion = " << str_motion << " key = " << key; if( ctrl ) std::cout << " ctrl"; if( shift ) std::cout << " shift"; if( alt ) std::cout << " alt"; std::cout << "\n"; #endif vec_items().push_back( MouseKeyItem( id, mode, name, str_motion, key, ctrl, shift, alt, dblclick, trpclick ) ); } // editviewの操作をemacs風か const bool KeyConfig::is_emacs_mode() { return ( get_str_motions( CONTROL::UpEdit ).find( "Ctrl+p" ) != std::string::npos ); } // editviewの操作をemacs風にする void KeyConfig::toggle_emacs_mode() { bool mode = is_emacs_mode(); remove_motions( CONTROL::HomeEdit ); remove_motions( CONTROL::HomeEdit ); remove_motions( CONTROL::EndEdit ); remove_motions( CONTROL::UpEdit ); remove_motions( CONTROL::DownEdit ); remove_motions( CONTROL::RightEdit ); remove_motions( CONTROL::LeftEdit ); remove_motions( CONTROL::DeleteEdit ); remove_motions( CONTROL::EnterEdit ); if( mode ){ set_one_motion( "HomeEdit", KEYCONF_HomeEdit ); set_one_motion( "EndEdit", KEYCONF_EndEdit ); set_one_motion( "UpEdit", KEYCONF_UpEdit ); set_one_motion( "DownEdit", KEYCONF_DownEdit ); set_one_motion( "RightEdit", KEYCONF_RightEdit ); set_one_motion( "LeftEdit", KEYCONF_LeftEdit ); set_one_motion( "DeleteEdit", KEYCONF_DeleteEdit ); set_one_motion( "EnterEdit", KEYCONF_EnterEdit ); } else{ set_one_motion( "HomeEdit", "Ctrl+a" ); set_one_motion( "EndEdit", "Ctrl+e" ); set_one_motion( "UpEdit", "Ctrl+p" ); set_one_motion( "DownEdit", "Ctrl+n" ); set_one_motion( "RightEdit", "Ctrl+f" ); set_one_motion( "LeftEdit", "Ctrl+b" ); set_one_motion( "DeleteEdit", "Ctrl+d" ); set_one_motion( "EnterEdit", "Ctrl+m" ); } } // タブで開くキーを入れ替えているか const bool KeyConfig::is_toggled_tab_key() { const bool ret = ( get_str_motions( CONTROL::OpenBoard ).find( "Ctrl+Space" ) != std::string::npos && get_str_motions( CONTROL::OpenBoardTab ).find( "Space" ) != std::string::npos && get_str_motions( CONTROL::OpenArticle ).find( "Ctrl+Space" ) != std::string::npos && get_str_motions( CONTROL::OpenArticleTab ).find( "Space" ) != std::string::npos ); #ifdef _DEBUG std::cout << "KeyConfig::is_toggled_tab_key ret = " << ret << std::endl; #endif return ret; } // タブで開くキーを入れ替える // toggle == true ならスペースをタブで開くボタンにする void KeyConfig::toggle_tab_key( const bool toggle ) { remove_motions( CONTROL::OpenBoard ); remove_motions( CONTROL::OpenBoardTab ); remove_motions( CONTROL::OpenArticle ); remove_motions( CONTROL::OpenArticleTab ); if( toggle ){ set_one_motion( "OpenBoard", "Ctrl+Space" ); set_one_motion( "OpenBoardTab", "Space" ); set_one_motion( "OpenArticle", "Ctrl+Space" ); set_one_motion( "OpenArticleTab", "Space" ); } else{ set_one_motion( "OpenBoard", "Space" ); set_one_motion( "OpenBoardTab", "Ctrl+Space" ); set_one_motion( "OpenArticle", "Space" ); set_one_motion( "OpenArticleTab", "Ctrl+Space" ); } } // // Gtk アクセラレーションキーを取得 // Gtk::AccelKey KeyConfig::get_accelkey( const int id ) { guint motion; bool ctrl, shift, alt, dblclick, trpclick; bool found = get_motion( id, motion, ctrl, shift, alt, dblclick, trpclick ); if( ! found ){ #ifdef _DEBUG std::cout << "KeyConfig::get_accelkey id = " << id << " (" << CONTROL::get_name( id ) << ") notfound " << std::endl; #endif return Gtk::AccelKey(); } Gdk::ModifierType type = static_cast(0); if( ctrl ) type |= Gdk::CONTROL_MASK; if( shift ) type |= Gdk::SHIFT_MASK; if( alt) type |= Gdk::MOD1_MASK; #ifdef _DEBUG std::cout << "KeyConfig::get_accelkey id = " << id << " (" << CONTROL::get_name( id ) << ") motion = " << motion << " ctrl = " << ctrl << " shift = " << shift << " alt = " << alt << std::endl; #endif return Gtk::AccelKey( motion, type ); } jd-2.8.7-140104/src/control/keyconfig.h0000644000076400010400000000167712201335554014201 0ustar // ライセンス: GPL2 // // キー設定クラス // #ifndef _KEYCONFIG_H #define _KEYCONFIG_H #include "mousekeyconf.h" #include namespace CONTROL { class KeyConfig : public MouseKeyConf { public: KeyConfig(); virtual ~KeyConfig(); virtual void load_conf(); // editviewの操作をemacs風にする const bool is_emacs_mode(); void toggle_emacs_mode(); const bool is_toggled_tab_key(); // タブで開くキーを入れ替えているか void toggle_tab_key( const bool toggle ); // タブで開くキーを入れ替える // Gtk アクセラレーションキーを取得 Gtk::AccelKey get_accelkey( const int id ); private: // ひとつの操作をデータベースに登録 virtual void set_one_motion_impl( const int id, const int mode, const std::string& name, const std::string& str_motion ); }; } #endif jd-2.8.7-140104/src/control/keypref.cpp0000644000076400010400000001733712201405212014210 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "keypref.h" #include "controlid.h" #include "controlutil.h" #include "global.h" #include "config/globalconf.h" using namespace CONTROL; // // キーボード入力をラベルに表示するダイアログ // KeyInputDiag::KeyInputDiag( Gtk::Window* parent, const std::string& url,const int id ) : CONTROL::InputDiag( parent, url, id, "ショートカットキー", INPUTDIAG_MODE_KEY ) {} /////////////////////////////// // // 個別のショートカットキー設定ダイアログ // KeyDiag::KeyDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& str_motions ) : CONTROL::MouseKeyDiag( parent, url, id, "ショートカットキー", str_motions ) { // Gtkアクセラレーションキーは、1つだけしか設定できないようにする set_single( get_controlmode() == CONTROL::MODE_JDGLOBALS ); } InputDiag* KeyDiag::create_inputdiag() { return new KeyInputDiag( this, "", get_id() ); } const std::string KeyDiag::get_default_motions( const int id ) { return CONTROL::get_default_keymotions( id ); } const std::vector< int > KeyDiag::check_conflict( const int mode, const std::string& str_motion ) { return CONTROL::check_key_conflict( mode, str_motion ); } /////////////////////////////////////////////// // // キーボード設定ダイアログ // KeyPref::KeyPref( Gtk::Window* parent, const std::string& url ) : MouseKeyPref( parent, url, "ショートカットキー" ) { // キー設定のバックアップを取る // キャンセルを押したら戻す CONTROL::bkup_keyconfig(); append_comment_row( "■ " + CONTROL::get_mode_label( CONTROL::MODE_COMMON ) ); append_row( CONTROL::Up ); append_row( CONTROL::Down ); append_row( CONTROL::Right ); append_row( CONTROL::Left ); append_row( CONTROL::TabRight ); append_row( CONTROL::TabLeft ); append_row( CONTROL::TabRightUpdated ); append_row( CONTROL::TabLeftUpdated ); append_row( CONTROL::TabNum1 ); append_row( CONTROL::TabNum2 ); append_row( CONTROL::TabNum3 ); append_row( CONTROL::TabNum4 ); append_row( CONTROL::TabNum5 ); append_row( CONTROL::TabNum6 ); append_row( CONTROL::TabNum7 ); append_row( CONTROL::TabNum8 ); append_row( CONTROL::TabNum9 ); append_row( CONTROL::RestoreLastTab ); append_row( CONTROL::PreBookMark ); append_row( CONTROL::NextBookMark ); append_row( CONTROL::PrevView ); append_row( CONTROL::NextView ); append_row( CONTROL::ToggleArticle ); append_row( CONTROL::ShowPopupMenu ); append_row( CONTROL::ShowMenuBar ); append_row( CONTROL::ShowToolBarMain ); append_row( CONTROL::ShowSideBar ); append_row( CONTROL::PageUp ); append_row( CONTROL::PageDown ); append_row( CONTROL::PrevDir ); append_row( CONTROL::NextDir ); append_row( CONTROL::Home ); append_row( CONTROL::End ); append_row( CONTROL::Back ); append_row( CONTROL::Undo ); append_row( CONTROL::Redo ); append_row( CONTROL::Quit ); append_row( CONTROL::Save ); append_row( CONTROL::Delete ); append_row( CONTROL::Reload ); append_row( CONTROL::ReloadArticle ); append_row( CONTROL::StopLoading ); append_row( CONTROL::OpenURL ); append_row( CONTROL::Copy ); append_row( CONTROL::SelectAll ); append_row( CONTROL::AppendFavorite ); append_row( CONTROL::PreferenceView ); append_row( CONTROL::Search ); append_row( CONTROL::SearchInvert ); append_row( CONTROL::SearchNext ); append_row( CONTROL::SearchPrev ); append_row( CONTROL::SearchTitle ); append_row( CONTROL::DrawOutAnd ); append_row( CONTROL::CheckUpdateRoot ); append_row( CONTROL::CheckUpdateOpenRoot ); append_row( CONTROL::FullScreen ); append_comment_row( "" ); append_comment_row( "■ " + CONTROL::get_mode_label( CONTROL::MODE_EDIT ) ); append_row( CONTROL::HomeEdit ); append_row( CONTROL::EndEdit ); append_row( CONTROL::UpEdit ); append_row( CONTROL::DownEdit ); append_row( CONTROL::RightEdit ); append_row( CONTROL::LeftEdit ); append_row( CONTROL::DeleteEdit ); append_row( CONTROL::BackspEdit ); append_row( CONTROL::UndoEdit ); append_row( CONTROL::EnterEdit ); append_row( CONTROL::InputAA ); append_comment_row( "" ); append_comment_row( "■ " + CONTROL::get_mode_label( CONTROL::MODE_BBSLIST ) ); append_row( CONTROL::OpenBoard ); append_row( CONTROL::OpenBoardTab ); append_comment_row( "" ); append_comment_row( "■ " + CONTROL::get_mode_label( CONTROL::MODE_BOARD ) ); append_row( CONTROL::OpenArticle ); append_row( CONTROL::OpenArticleTab ); append_row( CONTROL::NewArticle ); append_row( CONTROL::SearchCache ); append_row( CONTROL::ScrollRightBoard ); append_row( CONTROL::ScrollLeftBoard ); append_comment_row( "" ); append_comment_row( "■ " + CONTROL::get_mode_label( CONTROL::MODE_ARTICLE ) ); append_row( CONTROL::UpMid ); append_row( CONTROL::UpFast ); append_row( CONTROL::DownMid ); append_row( CONTROL::DownFast ); append_row( CONTROL::PrevRes ); append_row( CONTROL::NextRes ); append_row( CONTROL::PrePost ); append_row( CONTROL::NextPost ); append_row( CONTROL::GotoNew ); append_row( CONTROL::WriteMessage ); append_row( CONTROL::SearchNextArticle ); append_row( CONTROL::SearchWeb ); append_row( CONTROL::SearchCacheLocal ); append_row( CONTROL::SearchCacheAll ); append_row( CONTROL::LiveStartStop ); append_row( CONTROL::ShowSelectImage ); append_row( CONTROL::DeleteSelectImage, ITEM_NAME_SELECTDELIMG ); append_row( CONTROL::AboneSelectImage, ITEM_NAME_SELECTABONEIMG ); append_row( CONTROL::AboneSelectionRes ); append_comment_row( "" ); append_comment_row( "■ " + CONTROL::get_mode_label( CONTROL::MODE_IMAGEVIEW ) ); append_row( CONTROL::CancelMosaic ); append_row( CONTROL::ZoomFitImage ); append_row( CONTROL::ZoomInImage ); append_row( CONTROL::ZoomOutImage ); append_row( CONTROL::OrgSizeImage ); append_row( CONTROL::ScrollUpImage ); append_row( CONTROL::ScrollDownImage ); append_row( CONTROL::ScrollLeftImage ); append_row( CONTROL::ScrollRightImage ); append_comment_row( "" ); append_comment_row( "■ " + CONTROL::get_mode_label( CONTROL::MODE_MESSAGE ) ); append_row( CONTROL::CancelWrite ); append_row( CONTROL::ExecWrite ); append_row( CONTROL::FocusWrite ); append_row( CONTROL::ToggleSage ); append_comment_row( "" ); append_comment_row( "■ " + CONTROL::get_mode_label( CONTROL::MODE_JDGLOBALS ) ); append_row( CONTROL::JDExit ); append_row( CONTROL::JDHelp ); } MouseKeyDiag* KeyPref::create_setting_diag( const int id, const std::string& str_motions ) { return new KeyDiag( this, "", id, str_motions ); } const std::string KeyPref::get_str_motions( const int id ) { return CONTROL::get_str_keymotions( id ); } const std::string KeyPref::get_default_motions( const int id ) { return CONTROL::get_default_keymotions( id ); } void KeyPref::set_motions( const int id, const std::string& str_motions ) { if( id == CONTROL::JDExit && ! str_motions.empty() ){ // JDExitを設定したら、2.8.6以前との互換性オプションをオフにする CONFIG::set_disable_close( false ); } CONTROL::set_keymotions( id, str_motions ); } const bool KeyPref::remove_motions( const int id ) { return CONTROL::remove_keymotions( id ); } // // キャンセルボタンを押した // void KeyPref::slot_cancel_clicked() { #ifdef _DEBUG std::cout << "KeyPref::slot_cancel_clicked\n"; #endif // キー設定を戻す CONTROL::restore_keyconfig(); } jd-2.8.7-140104/src/control/keypref.h0000644000076400010400000000357212201405212013651 0ustar // ライセンス: GPL2 // キーボード設定ダイアログ // KeyPref が本体で、KeyPrefの各行をダブルクリックすると KeyDiag が開いて個別に操作の設定が出来る // KeyDiag の各行をダブルクリックすると KeyInputDiag が開いてキー入力が出来る #ifndef _KEYPREFPREF_H #define _KEYPREFPREF_H #include "mousekeypref.h" namespace CONTROL { // // キーボード入力をラベルに表示するダイアログ // class KeyInputDiag : public CONTROL::InputDiag { public: KeyInputDiag( Gtk::Window* parent, const std::string& url, const int id ); }; /////////////////////////////////////// // // 個別のショートカットキー設定ダイアログ // class KeyDiag : public CONTROL::MouseKeyDiag { public: KeyDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& str_motions ); protected: virtual InputDiag* create_inputdiag(); virtual const std::string get_default_motions( const int id ); virtual const std::vector< int > check_conflict( const int mode, const std::string& str_motion ); }; /////////////////////////////////// // // キーボード設定ダイアログ // class KeyPref : public CONTROL::MouseKeyPref { public: KeyPref( Gtk::Window* parent, const std::string& url ); protected: virtual MouseKeyDiag* create_setting_diag( const int id, const std::string& str_motions ); virtual const std::string get_str_motions( const int id ); virtual const std::string get_default_motions( const int id ); virtual void set_motions( const int id, const std::string& str_motions ); virtual const bool remove_motions( const int id ); private: virtual void slot_cancel_clicked(); }; } #endif jd-2.8.7-140104/src/control/keysyms.h0000644000076400010400000000375511070177641013732 0ustar // ライセンス: GPL2 // キー名 <-> keysym 変換テーブル #ifndef _KEYSYMS_H #define _KEYSYMS_H enum { MAX_KEYNAME = 64 }; struct KEYSYMS { char keyname[ MAX_KEYNAME ]; size_t keysym; }; namespace CONTROL { KEYSYMS keysyms[] ={ { "Space", GDK_space }, { "Escape", GDK_Escape }, { "Delete", GDK_Delete }, { "Enter", GDK_Return }, { "Up", GDK_Up }, { "Down", GDK_Down }, { "Left", GDK_Left }, { "Right", GDK_Right }, { "Page_Up", GDK_Page_Up }, { "Page_Down", GDK_Page_Down }, { "Tab", GDK_Tab }, { "Left_Tab", GDK_ISO_Left_Tab }, { "Home", GDK_Home }, { "End", GDK_End }, { "BackSpace", GDK_BackSpace }, { "F1", GDK_F1 }, { "F2", GDK_F2 }, { "F3", GDK_F3 }, { "F4", GDK_F4 }, { "F5", GDK_F5 }, { "F6", GDK_F6 }, { "F7", GDK_F7 }, { "F8", GDK_F8 }, { "F9", GDK_F9 }, { "F10", GDK_F10 }, { "F11", GDK_F11 }, { "F12", GDK_F12 }, { "Menu", GDK_Menu }, // テンキー { "KP_Divide", GDK_KP_Divide }, // "/" { "KP_Multiply", GDK_KP_Multiply }, // "*" { "KP_Subtract", GDK_KP_Subtract }, // "-" { "KP_Home", GDK_KP_Home }, // "Home(7)" { "KP_Up", GDK_KP_Up }, // "↑(8)" { "KP_Prior", GDK_KP_Prior }, // "Pg UP(9)" { "KP_Add", GDK_KP_Add }, // "+" { "KP_Left", GDK_KP_Left }, // "←(4)" //{ "KP_Begin", GDK_KP_Begin }, // "(5)" { "KP_Right", GDK_KP_Right }, // "→(6)" { "KP_End", GDK_KP_End }, // "End(1)" { "KP_Down", GDK_KP_Down }, // "↓(2)" { "KP_Next", GDK_KP_Next }, // "Pg Dn(3)" { "KP_Enter", GDK_KP_Enter }, // "Enter" { "KP_Insert", GDK_KP_Insert }, // "Ins(0)" { "KP_Delete", GDK_KP_Delete }, // "Del(.)" }; } #endif jd-2.8.7-140104/src/control/Makefile.am0000644000076400010400000000101012072045132014057 0ustar noinst_LIBRARIES = libcontrol.a libcontrol_a_SOURCES = \ control.cpp \ controlutil.cpp \ mousekeyconf.cpp keyconfig.cpp mouseconfig.cpp buttonconfig.cpp \ mousekeypref.cpp keypref.cpp mousepref.cpp buttonpref.cpp noinst_HEADERS = \ controlid.h \ controllabel.h \ keysyms.h \ control.h \ controlutil.h \ mousekeyconf.h mousekeyitem.h keyconfig.h mouseconfig.h buttonconfig.h \ mousekeypref.h keypref.h mousepref.h buttonpref.h \ defaultconf.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/control/mouseconfig.cpp0000644000076400010400000000773512201400541015062 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "mouseconfig.h" #include "defaultconf.h" #include "jdlib/miscutil.h" #include "jdlib/confloader.h" #include "cache.h" #ifdef _DEBUG #include "controlutil.h" #endif using namespace CONTROL; MouseConfig::MouseConfig() : MouseKeyConf() {} MouseConfig::~MouseConfig() {} // // 設定ファイル読み込み // void MouseConfig::load_conf() { JDLIB::ConfLoader cf( CACHE::path_mouseconf(), std::string() ); // 共通 load_motions( cf, "Right", MOUSECONF_Right ); load_motions( cf, "Left", MOUSECONF_Left ); load_motions( cf, "TabRight", MOUSECONF_TabRight ); load_motions( cf, "TabLeft", MOUSECONF_TabLeft ); load_motions( cf, "TabRightUpdated", MOUSECONF_TabRightUpdated ); load_motions( cf, "TabLeftUpdated", MOUSECONF_TabLeftUpdated ); load_motions( cf, "CloseAllTabs", MOUSECONF_CloseAllTabs ); load_motions( cf, "CloseOtherTabs", MOUSECONF_CloseOtherTabs ); load_motions( cf, "RestoreLastTab", MOUSECONF_RestoreLastTab ); load_motions( cf, "CheckUpdateTabs", MOUSECONF_CheckUpdateTabs ); load_motions( cf, "ToggleArticle", MOUSECONF_ToggleArticle ); load_motions( cf, "ShowSideBar", MOUSECONF_ShowSideBar ); load_motions( cf, "ShowMenuBar", MOUSECONF_ShowMenuBar ); load_motions( cf, "ShowToolBarMain", MOUSECONF_ShowToolBarMain ); load_motions( cf, "Home", MOUSECONF_Home ); load_motions( cf, "End", MOUSECONF_End ); load_motions( cf, "Quit", MOUSECONF_Quit ); load_motions( cf, "Reload", MOUSECONF_Reload ); load_motions( cf, "Delete", MOUSECONF_Delete ); load_motions( cf, "StopLoading", MOUSECONF_StopLoading ); load_motions( cf, "AppendFavorite", MOUSECONF_AppendFavorite ); load_motions( cf, "NewArticle", MOUSECONF_NewArticle ); load_motions( cf, "WriteMessage", MOUSECONF_WriteMessage ); load_motions( cf, "SearchTitle", MOUSECONF_SearchTitle ); load_motions( cf, "CheckUpdateRoot", MOUSECONF_CheckUpdateRoot ); load_motions( cf, "CheckUpdateOpenRoot", MOUSECONF_CheckUpdateOpenRoot ); load_motions( cf, "QuitJD", MOUSECONF_QuitJD ); load_motions( cf, "MaximizeMainWin", MOUSECONF_MaximizeMainWin ); load_motions( cf, "IconifyMainWin", MOUSECONF_IconifyMainWin ); // ARTICLE load_motions( cf, "GotoNew", MOUSECONF_GotoNew ); load_motions( cf, "SearchNextArticle", MOUSECONF_SearchNextArticle ); load_motions( cf, "SearchWeb", MOUSECONF_SearchWeb ); load_motions( cf, "LiveStartStop", MOUSECONF_LiveStartStop ); // IMAGE load_motions( cf, "CancelMosaicButton", MOUSECONF_CancelMosaicButton ); } // ひとつの操作をデータベースに登録 void MouseConfig::set_one_motion_impl( const int id, const int mode, const std::string& name, const std::string& str_motion ) { if( name.empty() || str_motion.empty() ) return; #ifdef _DEBUG std::cout << "MouseConfig::set_one_motion_impl " << name << std::endl; std::cout << "motion = " << str_motion << std::endl; std::cout << CONTROL::get_label( id ) << std::endl; #endif const bool ctrl = false; const bool shift = false; const bool alt = false; const guint motion = atoi( str_motion.c_str() ); const bool dblclick = false; const bool trpclick = false; vec_items().push_back( MouseKeyItem( id, mode, name, str_motion, motion, ctrl, shift, alt, dblclick, trpclick ) ); } // 操作文字列取得 const std::string MouseConfig::get_str_motions( const int id_ ) { int id = id_; // (注) この行が無いと画像ビューのコンテキストメニューにマウスジェスチャが表示されない if( id == CONTROL::CancelMosaic ) id = CONTROL::CancelMosaicButton; return MouseKeyConf::get_str_motions( id ); } // IDからデフォルトの操作文字列取得 const std::string MouseConfig::get_default_motions( const int id_ ) { int id = id_; if( id == CONTROL::CancelMosaic ) id = CONTROL::CancelMosaicButton; return MouseKeyConf::get_default_motions( id ); } jd-2.8.7-140104/src/control/mouseconfig.h0000644000076400010400000000140411101351617014521 0ustar // ライセンス: GPL2 // // マウスジェスチャ設定 // #ifndef _MOUSECONFIG_H #define _MOUSECONFIG_H #include "mousekeyconf.h" namespace CONTROL { class MouseConfig : public MouseKeyConf { public: MouseConfig(); virtual ~MouseConfig(); virtual void load_conf(); // 操作文字列取得 virtual const std::string get_str_motions( const int id ); // IDからデフォルトの操作文字列取得 virtual const std::string get_default_motions( const int id ); private: // ひとつの操作をデータベースに登録 virtual void set_one_motion_impl( const int id, const int mode, const std::string& name, const std::string& str_motion ); }; } #endif jd-2.8.7-140104/src/control/mousekeyconf.cpp0000644000076400010400000001577612201400541015257 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "mousekeyconf.h" #include "mousekeyitem.h" #include "controlutil.h" #include "jdlib/miscutil.h" #include "cache.h" using namespace CONTROL; MouseKeyConf::MouseKeyConf() {} MouseKeyConf::~MouseKeyConf() {} // 設定ファイル保存 void MouseKeyConf::save_conf( const std::string& savefile ) { #ifdef _DEBUG std::cout << "MouseKeyConf::save_conf " << savefile << std::endl; #endif JDLIB::ConfLoader cf( savefile, std::string() ); std::map< int, std::string >::iterator it_map = m_map_default_motions.begin(); for( ; it_map != m_map_default_motions.end(); ++it_map ){ const int id = ( *it_map ).first; const std::string name = CONTROL::get_name( id ); std::string motions; std::vector< MouseKeyItem >::iterator it = m_vec_items.begin(); for( ; it != m_vec_items.end(); ++it ){ if( (*it).get_id() == id ){ if( !motions.empty() ) motions += " "; motions += (*it).get_str_motion(); } } #ifdef _DEBUG std::cout << name << " = " << motions << std::endl; #endif cf.update( name, motions ); } cf.save(); } // 操作からID取得 const int MouseKeyConf::get_id( const int mode, const guint motion, const bool ctrl, const bool shift, const bool alt, const bool dblclick, const bool trpclick ) { int id = CONTROL::None;; std::vector< MouseKeyItem >::iterator it = m_vec_items.begin(); for( ; it != m_vec_items.end(); ++it ){ id = (*it).is_activated( mode, motion, ctrl, shift, alt, dblclick, trpclick ); if( id != CONTROL::None ) break; } #ifdef _DEBUG std::cout << "MouseKeyConf::get_id mode = " << mode << " id = " << id << " motion = " << motion << " ctrl = " << ctrl << " shift = " << shift << " alt = " << alt << " dblclick = " << dblclick << " trpclick = " << trpclick << std::endl; #endif return id; } // ID から操作を取得 // (注意) リストの一番上にあるものを出力 const bool MouseKeyConf::get_motion( const int id, guint& motion, bool& ctrl, bool& shift, bool& alt, bool& dblclick, bool& trpclick ) { std::vector< MouseKeyItem >::iterator it = m_vec_items.begin(); for( ; it != m_vec_items.end(); ++it ){ if( (*it).get_id() == id ){ motion = (*it).get_motion(); ctrl = (*it).get_ctrl(); shift = (*it).get_shift(); alt = (*it).get_alt(); dblclick = (*it).get_dblclick(); trpclick = (*it).get_trpclick(); return true; } } return false; } // ID が割り当てられているかチェック const bool MouseKeyConf::alloted( const int id, const guint motion, const bool ctrl, const bool shift, const bool alt, const bool dblclick, const bool trpclick ) { std::vector< MouseKeyItem >::iterator it = m_vec_items.begin(); for( ; it != m_vec_items.end(); ++it ){ if( (*it).equal( motion, ctrl, shift, alt, dblclick, trpclick ) == id ) return true; } return false; } // 同じモード内でモーションが重複していないかチェック const std::vector< int > MouseKeyConf::check_conflict( const int mode, const std::string& str_motion ) { std::vector< int > vec_ids; std::vector< MouseKeyItem >::iterator it = m_vec_items.begin(); for( ; it != m_vec_items.end(); ++it ){ const int id = (*it).is_activated( mode, str_motion ); if( id != CONTROL::None ) vec_ids.push_back( id ); } return vec_ids; } // IDから操作文字列取得 const std::string MouseKeyConf::get_str_motions( const int id ) { std::string motions; std::vector< MouseKeyItem >::iterator it = m_vec_items.begin(); for( ; it != m_vec_items.end(); ++it ){ if( (*it).get_id() == id ){ if( ! motions.empty() ) motions += " "; motions += (*it).get_str_motion(); } } return motions; } // IDからデフォルトの操作文字列取得 const std::string MouseKeyConf::get_default_motions( const int id ) { std::map< int, std::string >::iterator it = m_map_default_motions.find( id ); if( it != m_map_default_motions.end() ) return ( *it ).second; return std::string(); } // 設定ファイルから読み込んだモーションを登録 void MouseKeyConf::load_motions( JDLIB::ConfLoader& cf, const std::string& name, const std::string& default_motions ) { const int id = CONTROL::get_id( name ); const std::string str_motions = cf.get_option_str( name, default_motions, 256 ); set_motions( id, str_motions ); set_default_motions( id, default_motions ); } // 設定ファイルから読み込んだモーションを登録 // ver.2.0.2 以前との互換性のため Plus を + に置き換える void MouseKeyConf::load_keymotions( JDLIB::ConfLoader& cf, const std::string& name, const std::string& default_motions ) { const int id = CONTROL::get_id( name ); std::string str_motions = cf.get_option_str( name, default_motions, 256 ); if( str_motions.find( "Plus" ) != std::string::npos ) str_motions = MISC::replace_str( str_motions, "Plus", "+" ); set_motions( id, str_motions ); set_default_motions( id, default_motions ); } // スペースで区切られた複数の操作をデータベースに登録 void MouseKeyConf::set_motions( const int id, const std::string& str_motions ) { if( id == CONTROL::None ) return; const std::string name = CONTROL::get_name( id ); if( name.empty() ) return; const int mode = CONTROL::get_mode( id ); if( mode == CONTROL::MODE_ERROR ) return; std::list< std::string > list_motion = MISC::StringTokenizer( str_motions, ' ' ); std::list< std::string >::iterator it = list_motion.begin(); for( ; it != list_motion.end(); ++it ) set_one_motion_impl( id, mode, name, (*it) ); } // デフォルト操作を登録 void MouseKeyConf::set_default_motions( const int id, const std::string& default_motions ) { if( id == CONTROL::None ) return; m_map_default_motions.insert( make_pair( id, default_motions ) ); } // ひとつの操作をデータベースに登録 void MouseKeyConf::set_one_motion( const std::string& name, const std::string& str_motion ) { const int id = CONTROL::get_id( name ); if( id == CONTROL::None ) return; const int mode = CONTROL::get_mode( id ); if( mode == CONTROL::MODE_ERROR ) return; set_one_motion_impl( id, mode, name, str_motion ); } // 指定したIDの操作を全て削除 // 削除したら true を返す const bool MouseKeyConf::remove_motions( const int id ) { bool ret = false; std::vector< MouseKeyItem >::iterator it = m_vec_items.begin(); for( ; it != m_vec_items.end(); ++it ){ if( (*it).get_id() == id ){ m_vec_items.erase( it ); ret = true; break; } } if( ret ) remove_motions( id ); return ret; } jd-2.8.7-140104/src/control/mousekeyconf.h0000644000076400010400000000566512201400541014720 0ustar // ライセンス: GPL2 // // マウス、キーボード設定のベースクラス // #ifndef _MOUSEKEYCONF_H #define _MOUSEKEYCONF_H #include "mousekeyitem.h" #include "controlutil.h" #include "jdlib/confloader.h" #include #include #include namespace CONTROL { class MouseKeyConf { std::vector< MouseKeyItem > m_vec_items; std::map< int, std::string > m_map_default_motions; public: MouseKeyConf(); virtual ~MouseKeyConf(); // 設定ファイル読み込み virtual void load_conf() = 0; // 設定ファイル保存 void save_conf( const std::string& savefile ); // 操作からID取得 const int get_id( const int mode, const guint motion, const bool ctrl, const bool shift, const bool alt, const bool dblclick, const bool trpclick ); // ID から操作を取得 // (注意) リストの一番上にあるものを出力 const bool get_motion( const int id, guint& motion, bool& ctrl, bool& shift, bool& alt, bool& dblclick, bool& trpclick ); // ID が割り当てられているかチェック const bool alloted( const int id, const guint motion, const bool ctrl, const bool shift, const bool alt, const bool dblclick, const bool trpclick ); // IDから操作文字列取得 virtual const std::string get_str_motions( const int id ); // IDからデフォルトの操作文字列取得 virtual const std::string get_default_motions( const int id ); // 同じモード内でモーションが重複していないかチェック // 戻り値 : コントロールID const std::vector< int > check_conflict( const int mode, const std::string& str_motion ); // スペースで区切られた複数の操作をデータベースに登録 void set_motions( const int id, const std::string& str_motions ); // 指定したIDの操作を全て削除 const bool remove_motions( const int id ); protected: std::vector< MouseKeyItem >& vec_items(){ return m_vec_items; } // 設定ファイルから読み込んだモーションを登録 void load_motions( JDLIB::ConfLoader& cf, const std::string& name, const std::string& default_motions ); void load_keymotions( JDLIB::ConfLoader& cf, const std::string& name, const std::string& default_motions ); // デフォルト操作を登録 void set_default_motions( const int id, const std::string& default_motions ); // ひとつの操作をデータベースに登録 void set_one_motion( const std::string& name, const std::string& str_motion ); virtual void set_one_motion_impl( const int id, const int mode, const std::string& name, const std::string& str_motion ) = 0; }; } #endif jd-2.8.7-140104/src/control/mousekeyitem.h0000644000076400010400000000524611070177641014743 0ustar // ライセンス: GPL2 // // マウスやキー設定のデータ // #ifndef _MOUSEKEYITEM_H #define _MOUSEKEYITEM_H #include "controlid.h" #include #include namespace CONTROL { class MouseKeyItem { int m_id; int m_mode; std::string m_name; std::string m_str_motion; guint m_motion; bool m_ctrl; bool m_shift; bool m_alt; bool m_dblclick; bool m_trpclick; public: MouseKeyItem( const guint id, const int mode, const std::string& name, const std::string& str_motion, const guint motion, const bool ctrl, const bool shift, const bool alt, const bool dblclick, const bool trpclick ) : m_id( id ), m_mode( mode ), m_name( name ), m_str_motion( str_motion ), m_motion( motion ), m_ctrl( ctrl ), m_shift( shift ), m_alt( alt ), m_dblclick( dblclick ), m_trpclick( trpclick ) {} const int get_id() const { return m_id; } const int get_mode() const{ return m_mode; } const std::string& get_name() const { return m_name; } const std::string& get_str_motion() const { return m_str_motion; } const gint get_motion() const{ return m_motion; } const bool get_ctrl() const { return m_ctrl; } const bool get_shift() const { return m_shift; } const bool get_alt() const { return m_alt; } const bool get_dblclick() const { return m_dblclick; } const bool get_trpclick() const { return m_trpclick; } // モード無視 const int equal( const std::string& str_motion ) { if( str_motion == m_str_motion ) return m_id; return CONTROL::None; } // モード無視 const int equal( const guint motion, const bool ctrl, const bool shift, const bool alt, const bool dblclick, const bool trpclick ) { if( motion == m_motion && ctrl == m_ctrl && shift == m_shift && alt == m_alt && dblclick == m_dblclick && trpclick == m_trpclick ) return m_id; return CONTROL::None; } const int is_activated( const int mode, const std::string& str_motion ) { if( mode == m_mode ) return equal( str_motion ); return CONTROL::None; } const int is_activated( const int mode, const guint motion, const bool ctrl, const bool shift, const bool alt, const bool dblclick, const bool trpclick ) { if( mode == m_mode ) return equal( motion, ctrl, shift, alt, dblclick, trpclick ); return CONTROL::None; } }; } #endif jd-2.8.7-140104/src/control/mousekeypref.cpp0000644000076400010400000005074512201405212015261 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "mousekeypref.h" #include "controlutil.h" #include "controlid.h" #include "config/globalconf.h" #include "skeleton/msgdiag.h" #include "jdlib/miscutil.h" #include "colorid.h" using namespace CONTROL; // // キーやマウス入力ダイアログの基底クラス // InputDiag::InputDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& target, const int mode ) : SKELETON::PrefDiag( parent, url ), m_id( id ), m_mode( mode ), m_controlmode( CONTROL::get_mode( m_id ) ), m_label( target + "を入力して下さい。" ) { add_events( Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK ); m_control.add_mode( m_controlmode ); m_control.set_send_mg_info( false ); set_title( CONTROL::get_label( m_id ) + " ( " + CONTROL::get_mode_label( m_controlmode ) + " )" ); resize( 400, 400 ); get_vbox()->pack_start( m_label ); show_all_children(); } bool InputDiag::on_key_press_event( GdkEventKey* event ) { guint key = event->keyval; const bool ctrl = ( event->state ) & GDK_CONTROL_MASK; bool shift = ( event->state ) & GDK_SHIFT_MASK; const bool alt = ( event->state ) & GDK_MOD1_MASK; const bool caps = ( event->state ) & GDK_LOCK_MASK; // caps lock if( m_mode & INPUTDIAG_MODE_KEY ){ // caps lockされている場合は、アスキー文字を大文字小文字入れ替えて、capsを無視する // Control::key_press()も参照のこと if( caps ){ if( key >= 'A' && key <= 'Z' ){ key += 'a' - 'A'; } else if( key >= 'a' && key <= 'z' ){ key += 'A' - 'a'; } } // keyがアスキー文字の場合は shift を無視する // KeyConfig::set_one_motion()も参照せよ if( CONTROL::is_ascii( key ) ) shift = false; #ifdef _DEBUG std::cout << "InputDiag::on_key_press_event key = " << std::hex << key; if( ctrl ) std::cout << " ctrl"; if( shift ) std::cout << " shift"; if( alt ) std::cout << " alt"; std::cout << "\n"; #endif m_str_motion = std::string(); const std::string keyname = CONTROL::get_keyname( key ); std::string control_label; if( ! keyname.empty() ){ if( ctrl ) m_str_motion += "Ctrl+"; if( shift ) m_str_motion += "Shift+"; if( alt ) m_str_motion += "Alt+"; m_str_motion += keyname; // ラベルに被っている操作名を表示 control_label = get_key_label(); } m_label.set_label( m_str_motion + "\n" + control_label ); // エンターやスペースキーを押すとキャンセルボタンが押されてしまうのでキャンセルする if( keyname == "Space" || keyname == "Enter" ) return true; } return SKELETON::PrefDiag::on_key_press_event( event ); } bool InputDiag::on_button_press_event( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "InputDiag::on_button_press_event\n"; #endif const bool ret = SKELETON::PrefDiag::on_button_press_event( event ); if( m_mode & INPUTDIAG_MODE_MOUSE ){ m_control.MG_start( event ); m_str_motion = std::string(); m_label.set_label( "" ); } else if( m_mode & INPUTDIAG_MODE_BUTTON ){ const guint button = event->button; const bool ctrl = ( event->state ) & GDK_CONTROL_MASK; const bool shift = ( event->state ) & GDK_SHIFT_MASK; const bool alt = ( event->state ) & GDK_MOD1_MASK; const bool dblclick = ( event->type == GDK_2BUTTON_PRESS ); const bool trpclick = ( event->type == GDK_3BUTTON_PRESS ); m_str_motion = std::string(); std::string buttonname; std::string control_label; if( button == 1 ){ if( trpclick ) buttonname = "TrpLeft"; else if( dblclick ) buttonname = "DblLeft"; else buttonname = "Left"; } else if( button == 2 ){ if( trpclick ) buttonname = "TrpMid"; else if( dblclick ) buttonname = "DblMid"; else buttonname = "Mid"; } else if( button == 3 ){ if( trpclick ) buttonname = "TrpRight"; else if( dblclick ) buttonname = "DblRight"; else buttonname = "Right"; } else if( button == 6 ) buttonname = "Tilt_Left"; else if( button == 7 ) buttonname = "Tilt_Right"; else if( button == 8 ) buttonname = "Button4"; else if( button == 9 ) buttonname = "Button6"; if( ! buttonname.empty() ){ if( ctrl ) m_str_motion += "Ctrl+"; if( shift ) m_str_motion += "Shift+"; if( alt ) m_str_motion += "Alt+"; m_str_motion += buttonname; control_label = get_button_label(); } m_label.set_label( m_str_motion + "\n" + control_label ); } return ret; } bool InputDiag::on_button_release_event( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "InputDiag::on_button_release_event\n"; #endif const bool ret = SKELETON::PrefDiag::on_button_release_event( event ); if( m_mode & INPUTDIAG_MODE_MOUSE ){ m_control.MG_end( event ); } return ret; } bool InputDiag::on_motion_notify_event( GdkEventMotion* event ) { #ifdef _DEBUG // std::cout << "InputDiag::on_motion_notify_event\n"; #endif const bool ret = SKELETON::PrefDiag::on_motion_notify_event( event ); if( ( m_mode & INPUTDIAG_MODE_MOUSE ) && m_control.is_mg_mode() ){ m_control.MG_motion( event ); if( m_str_motion != m_control.get_mg_direction() ){ m_str_motion = m_control.get_mg_direction(); m_label.set_label( m_str_motion + "\n" + get_mouse_label() ); } } return ret; } const std::string InputDiag::get_key_label() { std::string label; for( int mode = CONTROL::MODE_START; mode <= CONTROL::MODE_END; ++mode ){ const std::vector< int > vec_ids = CONTROL::check_key_conflict( mode, m_str_motion ); std::vector< int >::const_iterator it = vec_ids.begin(); for( ; it != vec_ids.end(); ++it ){ const int id = *it; label += "\n" + CONTROL::get_label( id ) + " ( " + CONTROL::get_mode_label( mode ) + " )"; if( mode == m_controlmode && id != m_id ) label += " ×"; } } return label; } const std::string InputDiag::get_mouse_label() { std::string label; for( int mode = CONTROL::MODE_START; mode <= CONTROL::MODE_END; ++mode ){ const std::vector< int > vec_ids = CONTROL::check_mouse_conflict( mode, m_str_motion ); std::vector< int >::const_iterator it = vec_ids.begin(); for( ; it != vec_ids.end(); ++it ){ const int id = *it; label += "\n" + CONTROL::get_label( id ) + " ( " + CONTROL::get_mode_label( mode ) + " )"; if( mode == m_controlmode && id != m_id ) label += " ×"; } } return label; } const std::string InputDiag::get_button_label() { std::string label; for( int mode = CONTROL::MODE_START; mode <= CONTROL::MODE_END; ++mode ){ const std::vector< int > vec_ids = CONTROL::check_button_conflict( mode, m_str_motion ); std::vector< int >::const_iterator it = vec_ids.begin(); for( ; it != vec_ids.end(); ++it ){ const int id = *it; label += "\n" + CONTROL::get_label( id ) + " ( " + CONTROL::get_mode_label( mode ) + " )"; } } return label; } /////////////////////////////////// // // 個別のショートカットキー設定ダイアログ // MouseKeyDiag::MouseKeyDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& target, const std::string& str_motions ) : SKELETON::PrefDiag( parent, url ), m_id( id ), m_controlmode( CONTROL::get_mode( m_id ) ), m_single( false ), m_label( "編集したい" + target + "設定をダブルクリックして下さい。" ), m_button_delete( Gtk::Stock::DELETE ), m_button_add( Gtk::Stock::ADD ), m_button_reset( "デフォルト" ) { m_liststore = Gtk::ListStore::create( m_columns ); m_treeview.set_model( m_liststore ); m_treeview.set_size_request( 320, 200 ); m_treeview.signal_row_activated().connect( sigc::mem_fun( *this, &MouseKeyDiag::slot_row_activated ) ); Gtk::TreeViewColumn* column = Gtk::manage( new Gtk::TreeViewColumn( target, m_columns.m_col_motion ) ); column->set_resizable( true ); m_treeview.append_column( *column ); m_scrollwin.add( m_treeview ); m_scrollwin.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS ); m_button_delete.signal_clicked().connect( sigc::mem_fun( *this, &MouseKeyDiag::slot_delete ) ); m_button_add.signal_clicked().connect( sigc::mem_fun( *this, &MouseKeyDiag::slot_add ) ); m_button_reset.signal_clicked().connect( sigc::mem_fun( *this, &MouseKeyDiag::slot_reset ) ); m_vbuttonbox.pack_start( m_button_delete, Gtk::PACK_SHRINK ); m_vbuttonbox.pack_start( m_button_add, Gtk::PACK_SHRINK ); m_vbuttonbox.pack_start( m_button_reset, Gtk::PACK_SHRINK ); m_vbuttonbox.set_layout( Gtk::BUTTONBOX_START ); m_vbuttonbox.set_spacing( 4 ); m_hbox.pack_start( m_scrollwin, Gtk::PACK_SHRINK ); m_hbox.pack_start( m_vbuttonbox, Gtk::PACK_SHRINK ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_label ); get_vbox()->pack_start( m_hbox ); show_all_children(); set_title( CONTROL::get_label( m_id ) + " ( " + CONTROL::get_mode_label( m_controlmode ) + " )" ); // キー設定をスペース毎に区切って行を作成 std::list< std::string > list_motions = MISC::StringTokenizer( str_motions, ' ' ); if( list_motions.size() ){ std::list< std::string >::iterator it = list_motions.begin(); for( ; it != list_motions.end() ; ++it ) append_row( MISC::remove_space( *it ) ); // 先頭にカーソルセット Gtk::TreeModel::Children children = m_liststore->children(); Gtk::TreeModel::iterator it_row = children.begin(); if( *it_row ) m_treeview.set_cursor( m_liststore->get_path( *it_row ) ); } } Gtk::TreeModel::Row MouseKeyDiag::append_row( const std::string& motion ) { Gtk::TreeModel::Row row; row = *( m_liststore->append() ); if( row ) row[ m_columns.m_col_motion ] = motion; return row; } const std::string MouseKeyDiag::get_str_motions() { std::string str_motions; Gtk::TreeModel::Children children = m_liststore->children(); Gtk::TreeModel::iterator it = children.begin(); for( ; it != children.end(); ++it ){ if( it != children.begin() ) str_motions += " "; str_motions += ( *it )[ m_columns.m_col_motion ]; } #ifdef _DEBUG std::cout << "MouseKeyDiag::get_str_motions motions = " << str_motions << std::endl; #endif return str_motions; } // // 入力ダイアログを表示 // const std::string MouseKeyDiag::show_inputdiag( bool is_append ) { std::string str_motion; if( m_single ){ // 1つだけしか設定できない場合 const int count = get_count(); if( count > 1 || ( count == 1 && is_append ) ){ SKELETON::MsgDiag mdiag( NULL, "この項目には、1つだけ設定できます。" ); mdiag.run(); return std::string(); } } InputDiag* diag = create_inputdiag(); if( diag == NULL ) return std::string(); while( diag->run() == Gtk::RESPONSE_OK ){ // 設定が重複していないかチェック bool conflict = false; const std::vector< int > vec_ids = check_conflict( m_controlmode, diag->get_str_motion() ); std::vector< int >::const_iterator it = vec_ids.begin(); for( ; it != vec_ids.end(); ++it ){ const int id = *it; if( id != CONTROL::None && id != m_id ){ SKELETON::MsgDiag mdiag( NULL, diag->get_str_motion() + "\n\nは「" + CONTROL::get_label( id ) + "」で使用されています" ); mdiag.run(); conflict = true; break; } } if( ! conflict ){ str_motion = diag->get_str_motion(); break; } } delete diag; return str_motion; } // 行をダブルクリック void MouseKeyDiag::slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ) { #ifdef _DEBUG std::cout << "MouseKeyDiag::slot_row_activated path = " << path.to_string() << std::endl; #endif Gtk::TreeModel::Row row = *( m_liststore->get_iter( path ) ); if( ! row ) return; std::string str_motion = show_inputdiag( false ); if( ! str_motion.empty() ) row[ m_columns.m_col_motion ] = str_motion; } // 行削除 void MouseKeyDiag::slot_delete() { std::list< Gtk::TreeModel::Path > rows = m_treeview.get_selection()->get_selected_rows(); if( ! rows.size() ) return; Gtk::TreeModel::Path path = *rows.begin(); Gtk::TreeModel::iterator row = *( m_liststore->get_iter( path ) ); if( ! row ) return; // 削除する行の次の行にカーソルを移動 Gtk::TreeModel::Path path_next = path; path_next.next(); Gtk::TreeModel::iterator row_next = *( m_liststore->get_iter( path_next ) ); if( row_next ) m_treeview.set_cursor( path_next ); else{ // 次が無ければ前の行にカーソル移動 Gtk::TreeModel::Path path_prev = path; path_prev.prev(); Gtk::TreeModel::iterator row_prev = *( m_liststore->get_iter( path_prev ) ); if( row_prev ) m_treeview.set_cursor( path_prev ); } m_liststore->erase( row ); } // 行追加 void MouseKeyDiag::slot_add() { std::string str_motion = show_inputdiag( true ); if( str_motion.empty() ) return; // 既に登録済みか調べる Gtk::TreeModel::Children children = m_liststore->children(); Gtk::TreeModel::iterator it = children.begin(); for( ; it != children.end(); ++it ){ const std::string motion_tmp = ( *it )[ m_columns.m_col_motion ]; if( str_motion == motion_tmp ) return; } Gtk::TreeModel::iterator it_new = m_liststore->append(); ( *it_new )[ m_columns.m_col_motion ] = str_motion; } // デフォルトに戻す void MouseKeyDiag::slot_reset() { const std::string default_motions = get_default_motions( m_id ); #ifdef _DEBUG std::cout << "MouseKeyDiag::slot_reset default = " << default_motions << std::endl; #endif // デフォルト設定が既に使われていないか確認 std::list< std::string > list_motions = MISC::StringTokenizer( default_motions, ' ' ); std::list< std::string > list_defaults; std::list< std::string >::iterator it = list_motions.begin(); for( ; it != list_motions.end() ; ++it ){ const std::string motion = MISC::remove_space( *it ); bool conflict = false; const std::vector< int > vec_ids = check_conflict( m_controlmode, motion ); std::vector< int >::const_iterator it = vec_ids.begin(); for( ; it != vec_ids.end(); ++it ){ const int id = *it; if( id != CONTROL::None && id != m_id ){ SKELETON::MsgDiag mdiag( NULL, motion + "\n\nは「" + CONTROL::get_label( id ) + "」で使用されています" ); mdiag.run(); conflict = true; break; } } if( ! conflict ) list_defaults.push_back( motion ); } // クリアして再登録 m_liststore->clear(); it = list_defaults.begin(); for( ; it != list_defaults.end() ; ++it ) append_row( ( *it ) ); } /////////////////////////////////// // // マウスジェスチャ、キーボード設定ダイアログの基底クラス // MouseKeyPref::MouseKeyPref( Gtk::Window* parent, const std::string& url, const std::string& target ) : SKELETON::PrefDiag( parent, url ), m_button_reset( "全てデフォルト設定に戻す" ), m_label( "編集したい" + target + "設定をダブルクリックして下さい。" ) { m_liststore = Gtk::ListStore::create( m_columns ); m_treeview.set_model( m_liststore ); m_treeview.set_size_request( 640, 400 ); m_treeview.signal_row_activated().connect( sigc::mem_fun( *this, &MouseKeyPref::slot_row_activated ) ); Gtk::TreeViewColumn* column = Gtk::manage( new Gtk::TreeViewColumn( "コマンド", m_columns.m_col_label ) ); column->set_fixed_width( 220 ); column->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ); column->set_resizable( true ); m_treeview.append_column( *column ); column = Gtk::manage( new Gtk::TreeViewColumn( target, m_columns.m_col_motions ) ); column->set_resizable( true ); m_treeview.append_column( *column ); Gtk::CellRenderer *cell = column->get_first_cell_renderer(); if( cell ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &MouseKeyPref::slot_cell_data ) ); m_scrollwin.add( m_treeview ); m_scrollwin.set_policy( Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS ); m_button_reset.signal_clicked().connect( sigc::mem_fun( *this, &MouseKeyPref::slot_reset ) ); m_hbox.pack_start( m_button_reset, Gtk::PACK_SHRINK ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_label, Gtk::PACK_SHRINK ); get_vbox()->pack_start( m_scrollwin ); get_vbox()->pack_start( m_hbox, Gtk::PACK_SHRINK ); show_all_children(); set_title( target + "設定" ); } // 行追加 void MouseKeyPref::append_row( const int id, const std::string& label ) { Gtk::TreeModel::Row row; row = *( get_liststore()->append() ); if( row ){ const std::string motions = get_str_motions( id ); if( label.empty() ){ row[ get_colums().m_col_label ] = CONTROL::get_label( id ); }else{ row[ get_colums().m_col_label ] = label; } row[ get_colums().m_col_motions ] = motions; row[ get_colums().m_col_id ] = id; if( motions != get_default_motions( id ) ) row[ get_colums().m_col_drawbg ] = true; else row[ get_colums().m_col_drawbg ] = false; } } // // コメント行追加 // void MouseKeyPref::append_comment_row( const std::string& comment ) { Gtk::TreeModel::Row row; row = *( m_liststore->append() ); if( row ){ row[ m_columns.m_col_label ] = comment; row[ m_columns.m_col_motions ] = std::string(); row[ m_columns.m_col_id ] = CONTROL::None; row[ m_columns.m_col_drawbg ] = false; } } // // デフォルト設定に戻す // void MouseKeyPref::slot_reset() { const Gtk::TreeModel::Children children = get_liststore()->children(); Gtk::TreeModel::iterator it = children.begin(); for( ; it != children.end(); ++it ){ Gtk::TreeModel::Row row = ( *it ); if( row ){ const int id = row[ get_colums().m_col_id ]; if( id != CONTROL::None ){ const std::string str_motions = get_default_motions( id ); row[ get_colums().m_col_motions ] = str_motions; row[ get_colums().m_col_drawbg ] = false; remove_motions( id ); set_motions( id, str_motions ); } } } } // // 行をダブルクリック // void MouseKeyPref::slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ) { #ifdef _DEBUG std::cout << "MouseKeyPref::slot_row_activated path = " << path.to_string() << std::endl; #endif Gtk::TreeModel::Row row = *( get_liststore()->get_iter( path ) ); if( ! row ) return; const int id = row[ get_colums().m_col_id ]; if( id == CONTROL::None ) return; MouseKeyDiag* diag = create_setting_diag( id, row[ get_colums().m_col_motions ] ); if( diag->run() == Gtk::RESPONSE_OK ){ const std::string motions = diag->get_str_motions(); row[ get_colums().m_col_motions ] = motions; if( motions != get_default_motions( id ) ) row[ get_colums().m_col_drawbg ] = true; else row[ get_colums().m_col_drawbg ] = false; remove_motions( id ); set_motions( id, motions ); } delete diag; } // // 実際の描画の際に cellrendere のプロパティをセットするスロット関数 // void MouseKeyPref::slot_cell_data( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ) { Gtk::TreeModel::Row row = *it; if( row[ m_columns.m_col_drawbg ] ){ cell->property_cell_background() = CONFIG::get_color( COLOR_BACK_HIGHLIGHT_TREE ); cell->property_cell_background_set() = true; } else cell->property_cell_background_set() = false; } jd-2.8.7-140104/src/control/mousekeypref.h0000644000076400010400000001324712201405212014722 0ustar // ライセンス: GPL2 // // マウスジェスチャ、キーボード設定ダイアログの基底クラス // #ifndef _MOUSEKEYPREFPREF_H #define _MOUSEKEYPREFPREF_H #include "skeleton/prefdiag.h" #include "skeleton/treeviewbase.h" #include "control.h" namespace CONTROL { enum { INPUTDIAG_MODE_BUTTON = 1, INPUTDIAG_MODE_MOUSE = 2, INPUTDIAG_MODE_KEY = 4 }; // // キーやマウス入力ダイアログの基底クラス // class InputDiag : public SKELETON::PrefDiag { int m_id; int m_mode; int m_controlmode; std::string m_str_motion; Gtk::Label m_label; Gtk::HBox m_hbox; CONTROL::Control m_control; public: InputDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& target, const int mode ); const std::string& get_str_motion() const { return m_str_motion; } void set_str_motion( const std::string& motion ){ m_str_motion = motion; } protected: const int get_id() const { return m_id; } const std::string get_key_label(); const std::string get_mouse_label(); const std::string get_button_label(); private: virtual bool on_key_press_event (GdkEventKey* event); virtual bool on_button_press_event( GdkEventButton* event ); virtual bool on_button_release_event( GdkEventButton* event ); virtual bool on_motion_notify_event( GdkEventMotion* event ); }; /////////////////////////////////////// class MouseKeyDiagColumn : public Gtk::TreeModel::ColumnRecord { public: Gtk::TreeModelColumn< std::string > m_col_motion; MouseKeyDiagColumn() { add( m_col_motion ); } }; // // 個別のマウスジェスチャ、ショートカットキー設定ダイアログの基底クラス // class MouseKeyDiag : public SKELETON::PrefDiag { int m_id; int m_controlmode; bool m_single; SKELETON::JDTreeViewBase m_treeview; Glib::RefPtr< Gtk::ListStore > m_liststore; MouseKeyDiagColumn m_columns; Gtk::ScrolledWindow m_scrollwin; Gtk::Label m_label; Gtk::Button m_button_delete; Gtk::Button m_button_add; Gtk::Button m_button_reset; Gtk::VButtonBox m_vbuttonbox; Gtk::HBox m_hbox; public: MouseKeyDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& target, const std::string& str_motions ); const std::string get_str_motions(); protected: const int get_id() const { return m_id; } const int get_controlmode() const { return m_controlmode; } const int get_count() const { return m_liststore->children().size(); } const int get_single() const { return m_single; } const void set_single( bool single ){ m_single = single; } virtual InputDiag* create_inputdiag() = 0; virtual const std::string get_default_motions( const int id ) = 0; virtual const std::vector< int > check_conflict( const int mode, const std::string& str_motion ) = 0; private: Gtk::TreeModel::Row append_row( const std::string& motion ); // 入力ダイアログを表示 const std::string show_inputdiag( bool is_append ); // 行をダブルクリック void slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ); // 行削除 void slot_delete(); // 行追加 void slot_add(); // デフォルトに戻す void slot_reset(); }; /////////////////////////////////////// class MouseKeyTreeColumn : public Gtk::TreeModel::ColumnRecord { public: Gtk::TreeModelColumn< std::string > m_col_label; Gtk::TreeModelColumn< std::string > m_col_motions; Gtk::TreeModelColumn< int > m_col_id; Gtk::TreeModelColumn< bool > m_col_drawbg; MouseKeyTreeColumn() { add( m_col_label ); add( m_col_motions ); add( m_col_id ); add( m_col_drawbg ); } }; // // マウスジェスチャ、キーボード設定ダイアログの基底クラス // class MouseKeyPref : public SKELETON::PrefDiag { SKELETON::JDTreeViewBase m_treeview; Glib::RefPtr< Gtk::ListStore > m_liststore; MouseKeyTreeColumn m_columns; Gtk::ScrolledWindow m_scrollwin; Gtk::HBox m_hbox; Gtk::Button m_button_reset; Gtk::Label m_label; public: MouseKeyPref( Gtk::Window* parent, const std::string& url, const std::string& target ); protected: Glib::RefPtr< Gtk::ListStore >& get_liststore(){ return m_liststore; } MouseKeyTreeColumn& get_colums(){ return m_columns; } void append_row( const int id, const std::string& label = std::string() ); void append_comment_row( const std::string& comment ); virtual MouseKeyDiag* create_setting_diag( const int id, const std::string& str_motions ) = 0; virtual const std::string get_str_motions( const int id ) = 0; virtual const std::string get_default_motions( const int id ) = 0; virtual void set_motions( const int id, const std::string& str_motions ) = 0; virtual const bool remove_motions( const int id ) = 0; private: void slot_reset(); void slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ); void slot_cell_data( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ); }; } #endif jd-2.8.7-140104/src/control/mousepref.cpp0000644000076400010400000001007512201335554014553 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "mousepref.h" #include "controlid.h" #include "controlutil.h" using namespace CONTROL; // // マウスジェスチャ入力をラベルに表示するダイアログ // MouseInputDiag::MouseInputDiag( Gtk::Window* parent, const std::string& url, const int id ) : CONTROL::InputDiag( parent, url, id, "マウスジェスチャ", INPUTDIAG_MODE_MOUSE ) {} /////////////////////////////// // // 個別のマウスジェスチャ設定ダイアログ // MouseDiag::MouseDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& str_motions ) : CONTROL::MouseKeyDiag( parent, url, id, "マウスジェスチャ", str_motions ) {} InputDiag* MouseDiag::create_inputdiag() { return new MouseInputDiag( this, "", get_id() ); } const std::string MouseDiag::get_default_motions( const int id ) { return CONTROL::get_default_mousemotions( id ); } const std::vector< int > MouseDiag::check_conflict( const int mode, const std::string& str_motion ) { return CONTROL::check_mouse_conflict( mode, str_motion ); } /////////////////////////////////////////////// // // マウスジェスチャ設定ダイアログ // MousePref::MousePref( Gtk::Window* parent, const std::string& url ) : MouseKeyPref( parent, url, "マウスジェスチャ" ) { // マウスジェスチャのバックアップを取る // キャンセルを押したら戻す CONTROL::bkup_mouseconfig(); append_comment_row( "■ "+ CONTROL::get_mode_label( CONTROL::MODE_COMMON ) ); append_row( CONTROL::Right ); append_row( CONTROL::Left ); append_row( CONTROL::TabRight ); append_row( CONTROL::TabLeft ); append_row( CONTROL::TabRightUpdated ); append_row( CONTROL::TabLeftUpdated ); append_row( CONTROL::ToggleArticle ); append_row( CONTROL::ShowSideBar ); append_row( CONTROL::ShowMenuBar ); append_row( CONTROL::ShowToolBarMain ); append_row( CONTROL::Home ); append_row( CONTROL::End ); append_row( CONTROL::Quit ); append_row( CONTROL::CloseAllTabs ); append_row( CONTROL::CloseOtherTabs ); append_row( CONTROL::RestoreLastTab ); append_row( CONTROL::CheckUpdateTabs ); append_row( CONTROL::Reload ); append_row( CONTROL::Delete ); append_row( CONTROL::StopLoading ); append_row( CONTROL::AppendFavorite ); append_row( CONTROL::SearchTitle ); append_row( CONTROL::CheckUpdateRoot ); append_row( CONTROL::CheckUpdateOpenRoot ); append_row( CONTROL::QuitJD ); append_row( CONTROL::MaximizeMainWin ); append_row( CONTROL::IconifyMainWin ); append_comment_row( "" ); append_comment_row( "■ "+ CONTROL::get_mode_label( CONTROL::MODE_BOARD ) ); append_row( CONTROL::NewArticle ); append_comment_row( "" ); append_comment_row( "■ "+ CONTROL::get_mode_label( CONTROL::MODE_ARTICLE ) ); append_row( CONTROL::GotoNew ); append_row( CONTROL::WriteMessage ); append_row( CONTROL::SearchNextArticle ); append_row( CONTROL::SearchWeb ); append_row( CONTROL::LiveStartStop ); append_comment_row( "" ); append_comment_row( "■ "+ CONTROL::get_mode_label( CONTROL::MODE_IMAGEVIEW ) ); append_row( CONTROL::CancelMosaicButton ); } MouseKeyDiag* MousePref::create_setting_diag( const int id, const std::string& str_motions ) { return new MouseDiag( this, "", id, str_motions ); } const std::string MousePref::get_str_motions( const int id ) { return CONTROL::get_str_mousemotions( id ); } const std::string MousePref::get_default_motions( const int id ) { return CONTROL::get_default_mousemotions( id ); } void MousePref::set_motions( const int id, const std::string& str_motions ) { CONTROL::set_mousemotions( id, str_motions ); } const bool MousePref::remove_motions( const int id ) { return CONTROL::remove_mousemotions( id ); } // // キャンセルボタンを押した // void MousePref::slot_cancel_clicked() { #ifdef _DEBUG std::cout << "MousePref::slot_cancel_clicked\n"; #endif // 設定を戻す CONTROL::restore_mouseconfig(); } jd-2.8.7-140104/src/control/mousepref.h0000644000076400010400000000370612201335554014223 0ustar // ライセンス: GPL2 // マウスジェスチャ設定ダイアログ // MousePref が本体で、MousePrefの各行をダブルクリックすると MouseDiag が開いて個別に操作の設定が出来る // MouseDiag の各行をダブルクリックすると MouseInputDiag が開いてキー入力が出来る #ifndef _MOUSEPREFPREF_H #define _MOUSEPREFPREF_H #include "mousekeypref.h" #include "control.h" namespace CONTROL { // // マウスジェスチャ入力をラベルに表示するダイアログ // class MouseInputDiag : public CONTROL::InputDiag { public: MouseInputDiag( Gtk::Window* parent, const std::string& url, const int id ); }; /////////////////////////////////////// // // 個別のマウスジェスチャ設定ダイアログ // class MouseDiag : public CONTROL::MouseKeyDiag { public: MouseDiag( Gtk::Window* parent, const std::string& url, const int id, const std::string& str_motions ); protected: virtual InputDiag* create_inputdiag(); virtual const std::string get_default_motions( const int id ); virtual const std::vector< int > check_conflict( const int mode, const std::string& str_motion ); }; /////////////////////////////////////// // // マウスジェスチャ設定ダイアログ // class MousePref : public CONTROL::MouseKeyPref { public: MousePref( Gtk::Window* parent, const std::string& url ); protected: virtual MouseKeyDiag* create_setting_diag( const int id, const std::string& str_motions ); virtual const std::string get_str_motions( const int id ); virtual const std::string get_default_motions( const int id ); virtual void set_motions( const int id, const std::string& str_motions ); virtual const bool remove_motions( const int id ); private: virtual void slot_cancel_clicked(); }; } #endif jd-2.8.7-140104/src/core.cpp0000644000076400010400000051013212201335554012015 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "core.h" #include "maintoolbar.h" #include "command.h" #include "winmain.h" #include "session.h" #include "global.h" #include "type.h" #include "dndmanager.h" #include "usrcmdmanager.h" #include "linkfiltermanager.h" #include "compmanager.h" #include "searchmanager.h" #include "aamanager.h" #include "dispatchmanager.h" #include "cssmanager.h" #include "updatemanager.h" #include "login2ch.h" #include "loginbe.h" #include "loginp2.h" #include "environment.h" #include "setupwizard.h" #include "cache.h" #include "sharedbuffer.h" #include "control/controlutil.h" #include "control/controlid.h" #include "history/historymanager.h" #include "skeleton/msgdiag.h" #include "config/globalconf.h" #include "config/defaultconf.h" #include "jdlib/miscutil.h" #include "jdlib/miscgtk.h" #include "jdlib/misctime.h" #include "jdlib/loader.h" #include "jdlib/timeout.h" #include "dbtree/interface.h" #include "dbimg/imginterface.h" #include "bbslist/bbslistadmin.h" #include "board/boardadmin.h" #include "article/articleadmin.h" #include "image/imageadmin.h" #include "message/messageadmin.h" #include "message/logmanager.h" #include "sound/soundmanager.h" using namespace CORE; Core* instance_core; Core* CORE::get_instance() { return instance_core; } // 全ビューをフォーカスアウト #define FOCUS_OUT_ALL() do{ \ ARTICLE::get_admin()->set_command_immediately( "focus_out" ); \ BOARD::get_admin()->set_command_immediately( "focus_out" ); \ BBSLIST::get_admin()->set_command_immediately( "focus_out" ); \ IMAGE::get_admin()->set_command_immediately( "focus_out" ); \ MESSAGE::get_admin()->set_command_immediately( "focus_out" ); \ }while(0) ////////////////////////////////////////////////////// Core::Core( JDWinMain& win_main ) : m_win_main( win_main ), m_hpaned( SKELETON::PANE_FIXSIZE_PAGE1 ), m_vpaned_r( SKELETON::PANE_FIXSIZE_PAGE1 ), m_hpaned_r( SKELETON::PANE_FIXSIZE_PAGE1 ), m_imagetab_shown( 0 ), m_vpaned_message( SKELETON::PANE_FIXSIZE_PAGE2 ), m_toolbar( NULL ), m_enable_menuslot( true ), m_init( false ), m_count_savesession( 0 ) { // ディスパッチマネージャ作成 CORE::get_dispmanager(); instance_core = this; // データベースのルート作成 DBTREE::create_root(); DBIMG::create_root(); // 2chログインマネージャ作成 CORE::get_login2ch(); // BEログインマネージャ作成 CORE::get_loginbe(); // p2ログインマネージャ作成 CORE::get_loginp2(); // マウス、キー設定読み込み CONTROL::load_conf(); // 各管理クラス作成 BBSLIST::get_admin(); BOARD::get_admin(); ARTICLE::get_admin(); IMAGE::get_admin(); MESSAGE::get_admin(); // D&Dマネージャ作成 CORE::get_dnd_manager(); // ユーザコマンドマネージャ作成 CORE::get_usrcmd_manager(); // リンクフィルタマネージャ作成 CORE::get_linkfilter_manager(); // ログ検索マネージャ作成 CORE::get_search_manager(); m_vbox_article.signal_realize().connect( sigc::mem_fun(*this, &Core::slot_realize ) ); m_vbox_article.signal_style_changed().connect( sigc::mem_fun(*this, &Core::slot_style_changed ) ); } Core::~Core() { #ifdef _DEBUG std::cout << "Core::~Core\n"; #endif // デストラクタの中からdispatchを呼ぶと落ちるので dispatch不可にする set_dispatchable( false ); SESSION::set_quitting( true ); // ローダの起動待ちキューにあるスレッドを実行しない // アプリ終了時にこの関数を呼び出さないとキューに登録されたスレッドが起動してしまうので注意 JDLIB::disable_pop_loader_queue(); // 削除リストに登録されているスレを削除 ( 実況したスレなど ) const std::vector< std::string >& dellist = SESSION::get_delete_list(); if( dellist.size() ){ std::vector< std::string >::const_iterator it = dellist.begin(); for( ; it != dellist.end(); ++it ){ // しおりが付いている場合は削除しない if( ! DBTREE::is_bookmarked_thread( *it ) && ! DBTREE::get_num_bookmark( *it ) ){ DBTREE::delete_article( *it, false ); ARTICLE::get_admin()->set_command_immediately( "unlock_views", *it ); ARTICLE::get_admin()->set_command_immediately( "close_view", *it, "closeall" // command.url を含む全てのビューを閉じる ); } } } save_session(); // ログ検索マネージャ削除 CORE::delete_search_manager(); // ユーザコマンドマネージャ削除 CORE::delete_usrcmd_manager(); // リンクフィルタマネージャ削除 CORE::delete_linkfilter_manager(); // 補完マネージャ削除 CORE::delete_completion_manager(); // D&Dマネージャ削除 CORE::delete_dnd_manager(); // AA マネージャ削除 CORE::delete_aamanager(); // 更新チェックマネージャ削除 CORE::delete_checkupdate_manager(); // マウス、キーコンフィグ削除 CONTROL::delete_conf(); // ビューを削除する前にswitch_pageをdisconnectしておかないとエラーが出る if( m_sigc_switch_page.connected() ) m_sigc_switch_page.disconnect(); // 各管理クラスを削除 BBSLIST::delete_admin(); BOARD::delete_admin(); ARTICLE::delete_admin(); IMAGE::delete_admin(); MESSAGE::delete_admin(); // 履歴マネージャ削除 HISTORY::delete_history_manager(); // cssマネージャ削除 CORE::delete_css_manager(); // 2chログインマネージャ削除 CORE::delete_login2ch(); // BEログインマネージャ削除 CORE::delete_loginbe(); // p2ログインマネージャ削除 CORE::delete_loginp2(); // データベース削除 DBTREE::delete_root(); DBIMG::delete_root(); // サウンドマネージャ削除 SOUND::delete_sound_manager(); // 書き込みログマネージャ削除 MESSAGE::delete_log_manager(); // ディスパッチマネージャ削除 CORE::delete_dispatchmanager(); // ツールバー削除 if( m_toolbar ) delete m_toolbar; // 設定削除 CONFIG::delete_confitem(); } // // セッション保存 // void Core::save_session() { // 設定保存 CONFIG::save_conf(); // マウス、キーコンフィグ保存 CONTROL::save_conf(); // PANEの敷居の位置保存 SESSION::set_hpane_main_pos( m_hpaned.get_ctrl().get_position() ); SESSION::set_vpane_main_pos( m_vpaned_r.get_ctrl().get_position() ); SESSION::set_hpane_main_r_pos( m_hpaned_r.get_ctrl().get_position() ); SESSION::set_vpane_main_mes_pos( m_vpaned_message.get_ctrl().get_position() ); CORE::get_completion_manager()->save_session(); CORE::get_aamanager()->save_history(); BBSLIST::get_admin()->save_session(); BOARD::get_admin()->save_session(); ARTICLE::get_admin()->save_session(); IMAGE::get_admin()->save_session(); MESSAGE::get_admin()->save_session(); // 内部で SESSION::get_*_URLs() を使用しているので // ARTICLEやBOARDなどの管理クラスのセッションを保存してから呼び出すこと HISTORY::get_history_manager()->viewhistory2xml(); // 全スレ情報保存 // 板情報は BOARD::get_admin()->save_session() で保存される DBTREE::save_articleinfo_all(); SESSION::save_session(); } // 右ペーンのnotebookのparentであるvboxがrealizeしたらnotebookのstyleを変更する // テーマによっては notebook の中に notebook を配置すると背景色が正しく // 出ない問題があるため。開発スレ 493 参照 void Core::slot_realize() { #ifdef _DEBUG std::cout << "Core::slot_realize\n"; #endif slot_style_changed( m_vbox_article.get_style() ); } void Core::slot_style_changed( Glib::RefPtr< Gtk::Style > ) { m_notebook_right.set_style( m_vbox_article.get_style() ); } Gtk::Widget* Core::get_toplevel() { return m_win_main.get_toplevel(); } // // 実行 // // init = true なら初回起動 // skip_setupdiag = true なら初回起動時にセットアップダイアログ非表示 // void Core::run( const bool init, const bool skip_setupdiag ) { // 初回起動時の設定 if( init && ! skip_setupdiag ) first_setup(); // メインメニューの設定 m_action_group = Gtk::ActionGroup::create(); // File m_action_group->add( Gtk::Action::create( "Menu_File", "ファイル(_F)" ) ); m_action_group->add( Gtk::Action::create( "OpenURL", "OpenURL"), sigc::mem_fun( *this, &Core::slot_openurl ) ); m_action_group->add( Gtk::ToggleAction::create( "Online", "オフライン作業(_W)", std::string(), ! SESSION::is_online() ), sigc::mem_fun( *this, &Core::slot_toggle_online ) ); m_action_group->add( Gtk::ToggleAction::create( "Login2ch", "2chにログイン(_L)", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_login2ch ) ); m_action_group->add( Gtk::ToggleAction::create( "LoginBe", "BEにログイン(_B)", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_loginbe ) ); m_action_group->add( Gtk::ToggleAction::create( "LoginP2", "p2にログイン(_P)", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_loginp2 ) ); m_action_group->add( Gtk::Action::create( "ReloadList", "板一覧再読込(_R)"), sigc::mem_fun( *this, &Core::slot_reload_list ) ); m_action_group->add( Gtk::Action::create( "SaveSession", "セッション保存(_S)"), sigc::mem_fun( *this, &Core::save_session ) ); Gtk::AccelKey jdexitKey = CONTROL::get_accelkey( CONTROL::JDExit ); if( jdexitKey.is_null() ){ m_action_group->add( Gtk::Action::create( "Quit", "終了(_Q)" ), sigc::mem_fun(*this, &Core::slot_quit ) ); }else{ m_action_group->add( Gtk::Action::create( "Quit", "終了(_Q)" ), jdexitKey, sigc::mem_fun(*this, &Core::slot_quit ) ); } ////////////////////////////////////////////////////// // 表示 m_action_group->add( Gtk::Action::create( "Menu_View", "表示(_V)" ) ); m_action_group->add( Gtk::Action::create( "Show_Board", "スレ一覧(_B)" ), sigc::bind< bool >( sigc::mem_fun(*this, &Core::switch_board ), false ) ); m_action_group->add( Gtk::Action::create( "Show_Thread", "スレビュー(_T)" ), sigc::bind< bool >( sigc::mem_fun(*this, &Core::switch_article ), false ) ); m_action_group->add( Gtk::Action::create( "Show_Image", "画像ビュー(_I)" ), sigc::bind< bool >( sigc::mem_fun(*this, &Core::switch_image ), false ) ); // サイドバー m_action_group->add( Gtk::Action::create( "Sidebar_Menu", "サイドバー(_S)" ) ); m_action_group->add( Gtk::ToggleAction::create( "Show_BBS", "板一覧(_B)", std::string(), SESSION::show_sidebar() ), sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_BBSLISTVIEW, false ) ); m_action_group->add( Gtk::ToggleAction::create( "Show_FAVORITE", std::string( ITEM_NAME_FAVORITEVIEW ) + "(_F)", std::string(), SESSION::show_sidebar() ), sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_FAVORITEVIEW, false ) ); m_action_group->add( Gtk::ToggleAction::create( "Show_HISTTHREAD", std::string( ITEM_NAME_HISTVIEW ) + "(_T)", std::string(), SESSION::show_sidebar() ), sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTTHREADVIEW, false ) ); m_action_group->add( Gtk::ToggleAction::create( "Show_HISTBOARD", std::string( ITEM_NAME_HIST_BOARDVIEW ) + "(_B)", std::string(), SESSION::show_sidebar() ), sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTBOARDVIEW, false ) ); m_action_group->add( Gtk::ToggleAction::create( "Show_HISTCLOSE", std::string( ITEM_NAME_HIST_CLOSEVIEW ) + "(_M)", std::string(), SESSION::show_sidebar() ), sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTCLOSEVIEW, false ) ); m_action_group->add( Gtk::ToggleAction::create( "Show_HISTCLOSEBOARD", std::string( ITEM_NAME_HIST_CLOSEBOARDVIEW ) + "(_N)", std::string(), SESSION::show_sidebar() ), sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTCLOSEBOARDVIEW, false ) ); m_action_group->add( Gtk::ToggleAction::create( "Show_HISTCLOSEIMG", std::string( ITEM_NAME_HIST_CLOSEIMGVIEW ) + "(_I)", std::string(), SESSION::show_sidebar() ), sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTCLOSEIMGVIEW, false ) ); m_action_group->add( Gtk::Action::create( "View_Menu", "詳細設定(_D)" ) ); // 一般 m_action_group->add( Gtk::ToggleAction::create( "ShowMenuBar", "ShowMenuBar", std::string(), false ), sigc::mem_fun( *this, &Core::toggle_menubar ) ); m_action_group->add( Gtk::ToggleAction::create( "ShowStatBar", "ステータスバー表示(_S)", std::string(), false ), sigc::mem_fun( *this, &Core::toggle_statbar ) ); m_action_group->add( Gtk::ToggleAction::create( "ToggleFlatButton", "ボタンをフラット表示(_F)", std::string(), false ), sigc::mem_fun( *this, &Core::toggle_flat_button ) ); m_action_group->add( Gtk::ToggleAction::create( "ToggleDrawToolbarback", "ツールバーの背景を描画する(_T)", std::string(), false ), sigc::mem_fun( *this, &Core::toggle_draw_toolbarback ) ); m_action_group->add( Gtk::ToggleAction::create( "TogglePostMark", "自分が書き込んだレスにマークをつける(_W)", std::string(), CONFIG::get_show_post_mark() ), sigc::mem_fun( *this, &Core::toggle_post_mark ) ); // since Gtk::RadioButtonGroup radiogroup_since; m_action_group->add( Gtk::Action::create( "Since_Menu", "スレ一覧の since 表示(_N)" ) ); Glib::RefPtr< Gtk::RadioAction > raction_since0 = Gtk::RadioAction::create( radiogroup_since, "Since_Normal", "年/月/日 時:分" ); Glib::RefPtr< Gtk::RadioAction > raction_since1 = Gtk::RadioAction::create( radiogroup_since, "Since_NoYear", "月/日 時:分" ); Glib::RefPtr< Gtk::RadioAction > raction_since2 = Gtk::RadioAction::create( radiogroup_since, "Since_Week", "年/月/日(曜日) 時:分:秒" ); Glib::RefPtr< Gtk::RadioAction > raction_since3 = Gtk::RadioAction::create( radiogroup_since, "Since_Second", "年/月/日 時:分:秒" ); Glib::RefPtr< Gtk::RadioAction > raction_since4 = Gtk::RadioAction::create( radiogroup_since, "Since_Passed", "~前" ); switch( SESSION::get_col_since_time() ){ case MISC::TIME_NORMAL: raction_since0->set_active( true ); break; case MISC::TIME_NO_YEAR: raction_since1->set_active( true ); break; case MISC::TIME_WEEK: raction_since2->set_active( true ); break; case MISC::TIME_SECOND: raction_since3->set_active( true ); break; case MISC::TIME_PASSED: raction_since4->set_active( true ); break; } m_action_group->add( raction_since0, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_since ), MISC::TIME_NORMAL ) ); m_action_group->add( raction_since1, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_since ), MISC::TIME_NO_YEAR ) ); m_action_group->add( raction_since2, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_since ), MISC::TIME_WEEK ) ); m_action_group->add( raction_since3, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_since ), MISC::TIME_SECOND ) ); m_action_group->add( raction_since4, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_since ), MISC::TIME_PASSED ) ); // 最終書き込み Gtk::RadioButtonGroup radiogroup_write; m_action_group->add( Gtk::Action::create( "Write_Menu", "スレ一覧の最終書込表示(_N)" ) ); Glib::RefPtr< Gtk::RadioAction > raction_write0 = Gtk::RadioAction::create( radiogroup_write, "Write_Normal", "年/月/日 時:分" ); Glib::RefPtr< Gtk::RadioAction > raction_write1 = Gtk::RadioAction::create( radiogroup_write, "Write_NoYear", "月/日 時:分" ); Glib::RefPtr< Gtk::RadioAction > raction_write2 = Gtk::RadioAction::create( radiogroup_write, "Write_Week", "年/月/日(曜日) 時:分:秒" ); Glib::RefPtr< Gtk::RadioAction > raction_write3 = Gtk::RadioAction::create( radiogroup_write, "Write_Second", "年/月/日 時:分:秒" ); Glib::RefPtr< Gtk::RadioAction > raction_write4 = Gtk::RadioAction::create( radiogroup_write, "Write_Passed", "~前" ); switch( SESSION::get_col_write_time() ){ case MISC::TIME_NORMAL: raction_write0->set_active( true ); break; case MISC::TIME_NO_YEAR: raction_write1->set_active( true ); break; case MISC::TIME_WEEK: raction_write2->set_active( true ); break; case MISC::TIME_SECOND: raction_write3->set_active( true ); break; case MISC::TIME_PASSED: raction_write4->set_active( true ); break; } m_action_group->add( raction_write0, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_write ), MISC::TIME_NORMAL ) ); m_action_group->add( raction_write1, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_write ), MISC::TIME_NO_YEAR ) ); m_action_group->add( raction_write2, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_write ), MISC::TIME_WEEK ) ); m_action_group->add( raction_write3, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_write ), MISC::TIME_SECOND ) ); m_action_group->add( raction_write4, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_write ), MISC::TIME_PASSED ) ); // ツールバー表示 m_action_group->add( Gtk::Action::create( "Toolbar_Menu", "ツールバー表示(_T)" ) ); // メインツールバー m_action_group->add( Gtk::ToggleAction::create( "ShowToolBarMain", "ShowToolBarMain", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_toolbarmain ) ); Gtk::RadioButtonGroup radiogroup_toolbar; m_action_group->add( Gtk::Action::create( "Toolbar_Main_Menu", "メインツールバーの位置(_P)" ) ); Glib::RefPtr< Gtk::RadioAction > raction_toolbarpos0 = Gtk::RadioAction::create( radiogroup_toolbar, "ToolbarPos0", "メニューバーの下に表示する(_U)" ); Glib::RefPtr< Gtk::RadioAction > raction_toolbarpos1 = Gtk::RadioAction::create( radiogroup_toolbar, "ToolbarPos1", "サイドバーの右に表示する(_R)" ); switch( SESSION::get_toolbar_pos() ){ case SESSION::TOOLBAR_POS_NORMAL: raction_toolbarpos0->set_active( true ); break; case SESSION::TOOLBAR_POS_RIGHT: raction_toolbarpos1->set_active( true ); break; } m_action_group->add( raction_toolbarpos0, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_toolbarpos ), SESSION::TOOLBAR_POS_NORMAL ) ); m_action_group->add( raction_toolbarpos1, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_toolbarpos ), SESSION::TOOLBAR_POS_RIGHT ) ); // その他のツールバー m_action_group->add( Gtk::ToggleAction::create( "ShowToolBarBbslist", "サイドバーのツールバー表示(_S)", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_toolbarbbslist ) ); m_action_group->add( Gtk::ToggleAction::create( "ShowToolBarBoard", "スレ一覧のツールバー表示(_B)", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_toolbarboard ) ); m_action_group->add( Gtk::ToggleAction::create( "ShowToolBarArticle", "スレビューのツールバー表示(_A)", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_toolbararticle ) ); // タブ表示 m_action_group->add( Gtk::Action::create( "Tab_Menu", "タブ表示(_B)" ) ); m_action_group->add( Gtk::ToggleAction::create( "TabBoard", "スレ一覧(_B)", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_tabboard ) ); m_action_group->add( Gtk::ToggleAction::create( "TabArticle", "スレビュー(_A)", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_tabarticle ) ); // pane 設定 Gtk::RadioButtonGroup radiogroup; Glib::RefPtr< Gtk::RadioAction > raction0 = Gtk::RadioAction::create( radiogroup, "2Pane", "2ペイン表示(_2)" ); Glib::RefPtr< Gtk::RadioAction > raction1 = Gtk::RadioAction::create( radiogroup, "3Pane", "3ペイン表示(_3)" ); Glib::RefPtr< Gtk::RadioAction > raction2 = Gtk::RadioAction::create( radiogroup, "v3Pane", "縦3ペイン表示(_V)" ); switch( SESSION::get_mode_pane() ){ case SESSION::MODE_2PANE: raction0->set_active( true ); break; case SESSION::MODE_3PANE: raction1->set_active( true ); break; case SESSION::MODE_V3PANE: raction2->set_active( true ); break; } m_action_group->add( raction0, sigc::mem_fun( *this, &Core::slot_toggle_2pane ) ); m_action_group->add( raction1, sigc::mem_fun( *this, &Core::slot_toggle_3pane ) ); m_action_group->add( raction2, sigc::mem_fun( *this, &Core::slot_toggle_v3pane ) ); // フルスクリーン m_action_group->add( Gtk::ToggleAction::create( "FullScreen", "FullScreen", std::string(), false ), sigc::mem_fun( *this, &Core::slot_toggle_fullscreen ) ); // 書き込みビュー m_action_group->add( Gtk::Action::create( "MessageView_Menu", "書き込み設定(_M)" ) ); m_action_group->add( Gtk::Action::create( "ShowMsgView_Menu", "書き込みビュー(_M)" ) ); Gtk::RadioButtonGroup radiogroup_msg; Glib::RefPtr< Gtk::RadioAction > raction_msg0 = Gtk::RadioAction::create( radiogroup_msg, "UseWinMsg", "ウィンドウ表示する(_W)" ); Glib::RefPtr< Gtk::RadioAction > raction_msg1 = Gtk::RadioAction::create( radiogroup_msg, "UseEmbMsg", "埋め込み表示する(_E)" ); if( ! SESSION::get_embedded_mes() ) raction_msg0->set_active( true ); else raction_msg1->set_active( true ); m_action_group->add( raction_msg0, sigc::mem_fun( *this, &Core::slot_toggle_winmsg ) ); m_action_group->add( raction_msg1, sigc::mem_fun( *this, &Core::slot_toggle_embmsg ) ); m_action_group->add( Gtk::ToggleAction::create( "ToggleWrap", "テキストを折り返し表示する(_W)", std::string(), CONFIG::get_message_wrap() ), sigc::mem_fun( *this, &Core::slot_toggle_msg_wrap ) ); // 画像表示設定 m_action_group->add( Gtk::Action::create( "ImageView_Menu", "画像表示設定(_G)" ) ); m_action_group->add( Gtk::Action::create( "ShowImageView_Menu", "画像ビュー(_V)" ) ); Gtk::RadioButtonGroup radiogroup_img; Glib::RefPtr< Gtk::RadioAction > raction_img0 = Gtk::RadioAction::create( radiogroup_img, "UseWinImg", "ウィンドウ表示する(_W)" ); Glib::RefPtr< Gtk::RadioAction > raction_img1 = Gtk::RadioAction::create( radiogroup_img, "UseEmbImg", "埋め込み表示する(_E)" ); if( ! SESSION::get_embedded_img() ) raction_img0->set_active( true ); else raction_img1->set_active( true ); m_action_group->add( raction_img0, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_imgview ), IMGVIEW_WINDOW ) ); m_action_group->add( raction_img1, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_imgview ), IMGVIEW_EMB ) ); m_action_group->add( Gtk::ToggleAction::create( "UseImgPopup", "画像ポップアップを表示する(_P)", std::string(), CONFIG::get_use_image_popup() ), sigc::mem_fun( *this, &Core::slot_toggle_use_imgpopup ) ); m_action_group->add( Gtk::ToggleAction::create( "UseInlineImg", "インライン画像を表示する(_I)", std::string(), CONFIG::get_use_inline_image() ), sigc::mem_fun( *this, &Core::slot_toggle_use_inlineimg ) ); m_action_group->add( Gtk::ToggleAction::create( "ShowSsspIcon", "BEアイコンを表示する(_B)", std::string(), CONFIG::get_show_ssspicon() ), sigc::mem_fun( *this, &Core::slot_toggle_show_ssspicon ) ); // リスト表示項目設定 m_action_group->add( Gtk::Action::create( "ListItem_Menu", "リスト項目設定(_L)" ) ); m_action_group->add( Gtk::Action::create( "SetupBoardItemColumn", "スレ一覧(_T)..." ), sigc::mem_fun( *this, &Core::slot_setup_boarditem_column ) ); // ツールバー項目設定 m_action_group->add( Gtk::Action::create( "Item_Menu", "ツールバー項目設定(_I)" ) ); m_action_group->add( Gtk::Action::create( "SetupMainItem", "メイン(_M)..." ), sigc::mem_fun( *this, &Core::slot_setup_mainitem ) ); m_action_group->add( Gtk::Action::create( "SetupSidebarItem", "サイドバー(_S)..." ), sigc::mem_fun( *this, &Core::slot_setup_sidebaritem ) ); m_action_group->add( Gtk::Action::create( "SetupBoardItem", "スレ一覧(_B)..." ), sigc::mem_fun( *this, &Core::slot_setup_boarditem ) ); m_action_group->add( Gtk::Action::create( "SetupArticleItem", "スレビュー(_A)..." ), sigc::mem_fun( *this, &Core::slot_setup_articleitem ) ); m_action_group->add( Gtk::Action::create( "SetupSearchItem", "ログ/スレタイ検索(_L)..." ), sigc::mem_fun( *this, &Core::slot_setup_searchitem ) ); m_action_group->add( Gtk::Action::create( "SetupMsgItem", "書き込みビュー(_W)..." ), sigc::mem_fun( *this, &Core::slot_setup_msgitem ) ); // コンテキストメニュー項目設定 m_action_group->add( Gtk::Action::create( "MenuItem_Menu", "コンテキストメニュー項目設定(_C)" ) ); m_action_group->add( Gtk::Action::create( "SetupBoardItemMenu", "スレ一覧(_B)..." ), sigc::mem_fun( *this, &Core::slot_setup_boarditem_menu ) ); m_action_group->add( Gtk::Action::create( "SetupArticleItemMenu", "スレビュー(_A)..." ), sigc::mem_fun( *this, &Core::slot_setup_articleitem_menu ) ); ////////////////////////////////////////////////////// // 履歴 m_action_group->add( Gtk::Action::create( "Menu_History", "履歴(_S)" ) ); // 戻る、進む m_action_group->add( Gtk::Action::create( "PrevView", "PrevView"), sigc::mem_fun( *this, &Core::slot_prevview ) ); m_action_group->add( Gtk::Action::create( "NextView", "NextView"), sigc::mem_fun( *this, &Core::slot_nextview ) ); ////////////////////////////////////////////////////// // 設定 m_action_group->add( Gtk::Action::create( "Menu_Config", "設定(_C)" ) ); m_action_group->add( Gtk::Action::create( "Property_Menu", "プロパティ(_P)" ) ); m_action_group->add( Gtk::Action::create( "BbslistPref", "板一覧のプロパティ(_L)..." ), sigc::mem_fun( *this, &Core::slot_bbslist_pref ) ); m_action_group->add( Gtk::Action::create( "BoardPref", "表示中の板のプロパティ(_B)..." ), sigc::mem_fun( *this, &Core::slot_board_pref ) ); m_action_group->add( Gtk::Action::create( "ArticlePref", "表示中のスレのプロパティ(_T)..." ), sigc::mem_fun( *this, &Core::slot_article_pref ) ); m_action_group->add( Gtk::Action::create( "ImagePref", "表示中の画像のプロパティ(_I)..." ), sigc::mem_fun( *this, &Core::slot_image_pref ) ); // 一般 m_action_group->add( Gtk::Action::create( "General_Menu", "一般(_G)" ) ); m_action_group->add( Gtk::ToggleAction::create( "RestoreViews", "前回開いていた各ビューを起動時に復元する(_R)", std::string(), ( CONFIG::get_restore_board() & CONFIG::get_restore_article() & CONFIG::get_restore_image() ) ), sigc::mem_fun( *this, &Core::slot_toggle_restore_views ) ); m_action_group->add( Gtk::ToggleAction::create( "ToggleFoldMessage", "非アクティブ時に書き込みビューを折りたたむ(_C)", std::string(), CONFIG::get_fold_message() ), sigc::mem_fun( *this, &Core::slot_toggle_fold_message ) ); m_action_group->add( Gtk::ToggleAction::create( "SavePostLog", "書き込みログを保存する(_A)", std::string(), CONFIG::get_save_post_log() ), sigc::mem_fun( *this, &Core::slot_toggle_save_post_log ) ); m_action_group->add( Gtk::ToggleAction::create( "SavePostHist", "書き込み履歴(鉛筆マーク)を保存する(_P)", std::string(), CONFIG::get_save_post_history() ), sigc::mem_fun( *this, &Core::slot_toggle_save_post_history ) ); m_action_group->add( Gtk::ToggleAction::create( "UseMosaic", "画像にモザイクをかける(_M)", std::string(), CONFIG::get_use_mosaic() ), sigc::mem_fun( *this, &Core::slot_toggle_use_mosaic ) ); m_action_group->add( Gtk::ToggleAction::create( "UseMachiOfflaw", "まちBBSでofflaw.cgiを使用する(_O)", std::string(), CONFIG::get_use_machi_offlaw() ), sigc::mem_fun( *this, &Core::slot_toggle_use_machi_offlaw ) ); // マウス/キーボード m_action_group->add( Gtk::Action::create( "Mouse_Menu", "マウス/キーボード(_M)" ) ); const bool toggled = CONTROL::is_toggled_tab_button() && CONTROL::is_toggled_tab_key(); m_action_group->add( Gtk::ToggleAction::create( "ToggleTab", "スレ一覧/スレビューを開く時に常に新しいタブで開く(_T)", std::string(), toggled ), sigc::mem_fun( *this, &Core::slot_toggle_tabbutton ) ); m_action_group->add( Gtk::ToggleAction::create( "TogglePopupWarp", "スレビューでアンカーをクリックして多重ポップアップモードに移行する(_W)", std::string(), CONTROL::is_popup_warpmode() ), sigc::mem_fun( *this, &Core::slot_toggle_popupwarpmode ) ); m_action_group->add( Gtk::ToggleAction::create( "ShortMarginPopup", "スレビューでカーソルを移動して多重ポップアップモードに移行する(_M)", std::string(), ( CONFIG::get_margin_popup() != CONFIG::CONF_MARGIN_POPUP ) ), sigc::mem_fun( *this, &Core::slot_shortmargin_popup ) ); m_action_group->add( Gtk::ToggleAction::create( "ToggleEmacsMode", "書き込みビューのショートカットキーをEmacs風にする(_E)", std::string(), CONTROL::is_emacs_mode() ), sigc::mem_fun( *this, &Core::slot_toggle_emacsmode ) ); m_action_group->add( Gtk::Action::create( "MousePref", "マウスジェスチャ詳細設定(_G)..." ), sigc::mem_fun( *this, &Core::slot_setup_mouse ) ); m_action_group->add( Gtk::Action::create( "KeyPref", "ショートカットキー詳細設定(_R)..." ), sigc::mem_fun( *this, &Core::slot_setup_key ) ); m_action_group->add( Gtk::Action::create( "ButtonPref", "マウスボタン詳細設定(_B)..." ), sigc::mem_fun( *this, &Core::slot_setup_button ) ); // フォントと色 m_action_group->add( Gtk::Action::create( "FontColor_Menu", "フォントと色(_F)" ) ); m_action_group->add( Gtk::Action::create( "FontMain", "スレビューフォント(_T)..." ), sigc::mem_fun( *this, &Core::slot_changefont_main ) ); m_action_group->add( Gtk::Action::create( "FontPopup", "ポップアップフォント(_P)..." ), sigc::mem_fun( *this, &Core::slot_changefont_popup ) ); m_action_group->add( Gtk::Action::create( "FontTree", "板/スレ一覧フォント(_B)..." ), sigc::mem_fun( *this, &Core::slot_changefont_tree ) ); m_action_group->add( Gtk::Action::create( "ColorChar", "スレビュー文字色(_C)..." ), sigc::mem_fun( *this, &Core::slot_changecolor_char ) ); m_action_group->add( Gtk::Action::create( "ColorBack", "スレビュー背景色(_A)..." ), sigc::mem_fun( *this, &Core::slot_changecolor_back ) ); m_action_group->add( Gtk::Action::create( "ColorCharTree", "板/スレ一覧文字色(_H)..." ), sigc::mem_fun( *this, &Core::slot_changecolor_char_tree ) ); m_action_group->add( Gtk::Action::create( "ColorBackTree", "板/スレ一覧背景色(_K)..." ), sigc::mem_fun( *this, &Core::slot_changecolor_back_tree ) ); m_action_group->add( Gtk::Action::create( "FontColorPref", "詳細設定(_R)..." ), sigc::mem_fun( *this, &Core::slot_setup_fontcolor ) ); // ネットワーク m_action_group->add( Gtk::Action::create( "Net_Menu", "ネットワーク(_N)" ) ); m_action_group->add( Gtk::Action::create( "SetupProxy", "プロキシ(_X)..." ), sigc::mem_fun( *this, &Core::slot_setup_proxy ) ); m_action_group->add( Gtk::Action::create( "SetupBrowser", "Webブラウザ(_W)..." ), sigc::mem_fun( *this, &Core::slot_setup_browser ) ); m_action_group->add( Gtk::Action::create( "SetupPasswd", "パスワード(_P)..." ), sigc::mem_fun( *this, &Core::slot_setup_passwd ) ); m_action_group->add( Gtk::ToggleAction::create( "ToggleIPv6", "IPv6使用(_I)", std::string(), CONFIG::get_use_ipv6() ), sigc::mem_fun( *this, &Core::slot_toggle_ipv6 ) ); // あぼーん m_action_group->add( Gtk::Action::create( "Abone_Menu", "あぼ〜ん(_A)" ) ); m_action_group->add( Gtk::Action::create( "SetupAbone", "全体あぼ〜ん設定(対象: スレビュー)(_V)..." ), sigc::mem_fun( *this, &Core::slot_setup_abone ) ); m_action_group->add( Gtk::Action::create( "SetupAboneThread", "全体スレあぼ〜ん設定(対象: スレ一覧)(_L)..." ), sigc::mem_fun( *this, &Core::slot_setup_abone_thread ) ); m_action_group->add( Gtk::ToggleAction::create( "TranspChainAbone", "スレビューで透明/連鎖あぼ〜んをデフォルト設定にする(_T)", std::string(), ( CONFIG::get_abone_transparent() && CONFIG::get_abone_chain() ) ), sigc::mem_fun( *this, &Core::slot_toggle_abone_transp_chain ) ); m_action_group->add( Gtk::ToggleAction::create( "IcaseWcharAbone", "NG正規表現で大小と全半角文字の違いを無視する(_W)", std::string(), ( CONFIG::get_abone_icase() && CONFIG::get_abone_wchar() ) ), sigc::mem_fun( *this, &Core::slot_toggle_abone_icase_wchar ) ); // その他 m_action_group->add( Gtk::Action::create( "Etc_Menu", "その他(_O)" ) ); m_action_group->add( Gtk::Action::create( "LivePref", "実況設定(_L)..." ), sigc::mem_fun( *this, &Core::slot_setup_live ) ); m_action_group->add( Gtk::Action::create( "UsrCmdPref", "ユーザコマンドの編集(_U)..." ), sigc::mem_fun( *this, &Core::slot_usrcmd_pref ) ); m_action_group->add( Gtk::Action::create( "FilterPref", "リンクフィルタの編集(_F)..." ), sigc::mem_fun( *this, &Core::slot_filter_pref ) ); m_action_group->add( Gtk::Action::create( "AboutConfig", "about:config(_A)..." ), sigc::mem_fun( *this, &Core::slot_aboutconfig ) ); // プライバシー m_action_group->add( Gtk::Action::create( "Privacy_Menu", "プライバシー(_R)" ) ); m_action_group->add( Gtk::Action::create( "ClearAllPrivacy", "各履歴等の消去(_I)..." ), sigc::mem_fun( *this, &Core::slot_clear_privacy ) ); m_action_group->add( Gtk::Action::create( "ClearPostLog", "書き込みログの消去(_P)" ), sigc::mem_fun( *this, &Core::slot_clear_post_log ) ); m_action_group->add( Gtk::Action::create( "ClearPostHist", "書き込み履歴(鉛筆マーク)の消去(_H)" ), sigc::mem_fun( *this, &Core::slot_clear_post_history ) ); m_action_group->add( Gtk::Action::create( "DeleteImages", "画像キャッシュの消去(_D)..." ), sigc::mem_fun( *this, &Core::slot_delete_all_images ) ); ////////////////////////////////////////////////////// // ツール m_action_group->add( Gtk::Action::create( "Menu_Tool", "ツール(_T)" ) ); m_action_group->add( Gtk::Action::create( "LiveStartStop", "LiveStartStop"), sigc::mem_fun( *this, &Core::slot_live_start_stop ) ); m_action_group->add( Gtk::Action::create( "SearchCache_Menu", "キャッシュ内ログ検索(_C)" ) ); m_action_group->add( Gtk::Action::create( "SearchCacheBoard", "表示中の板のログを検索(_B)" ), sigc::mem_fun( *this, &Core::slot_search_cache_board ) ); m_action_group->add( Gtk::Action::create( "SearchCache", "キャッシュ内の全ログを検索(_A)" ), sigc::mem_fun( *this, &Core::slot_search_cache ) ); m_action_group->add( Gtk::Action::create( "ShowCache_Menu", "キャッシュ内ログ一覧(_H)" ) ); m_action_group->add( Gtk::Action::create( "ShowCacheBoard", "表示中の板のログをスレ一覧に表示(_B)" ), sigc::mem_fun( *this, &Core::slot_show_cache_board ) ); m_action_group->add( Gtk::Action::create( "ShowCache", "キャッシュ内の全ログをスレ一覧に表示(_A)" ), sigc::mem_fun( *this, &Core::slot_show_cache ) ); m_action_group->add( Gtk::Action::create( "SearchTitle", "SearchTitle" ), sigc::mem_fun( *this, &Core::slot_search_title ) ); m_action_group->add( Gtk::Action::create( "CheckUpdate_Menu", "サイドバーの更新チェック(_U)" ) ); m_action_group->add( Gtk::Action::create( "CheckUpdateRoot", "更新チェックのみ(_R)" ), sigc::mem_fun( *this, &Core::slot_check_update_root ) ); m_action_group->add( Gtk::Action::create( "CheckUpdateOpenRoot", "更新されたスレをタブで開く(_T)" ), sigc::mem_fun( *this, &Core::slot_check_update_open_root ) ); m_action_group->add( Gtk::Action::create( "CancelCheckUpdate", "キャンセル(_C)" ), sigc::mem_fun( *this, &Core::slot_cancel_check_update ) ); m_action_group->add( Gtk::Action::create( "EditFavorite", "お気に入りの編集(_E)"), sigc::mem_fun( *this, &Core::slot_edit_favorite ) ); m_action_group->add( Gtk::Action::create( "ShowPostlog", "書き込みログの表示(_P)" ), sigc::mem_fun( *this, &Core::slot_show_postlog ) ); m_action_group->add( Gtk::Action::create( "ImportDat", "表示中の板にdatをインポート(_I)" ), sigc::mem_fun( *this, &Core::slot_import_dat ) ); m_action_group->add( Gtk::Action::create( "ShowSidebarBoard", "サイドバーをスレ一覧に表示(_B)" ), sigc::mem_fun( *this, &Core::slot_show_sidebarboard ) ); m_action_group->add( Gtk::Action::create( "CreateVBoard", "サイドバーの仮想板を作成(_V)" ), sigc::mem_fun( *this, &Core::slot_create_vboard ) ); ////////////////////////////////////////////////////// // help m_action_group->add( Gtk::Action::create( "Menu_Help", "ヘルプ(_H)" ) ); m_action_group->add( Gtk::Action::create( "Bbs", "サポート掲示板(_B)" ), sigc::mem_fun( *this, &Core::slot_show_bbs ) ); m_action_group->add( Gtk::Action::create( "OldLog", "2chスレ過去ログ(_L)" ), sigc::mem_fun( *this, &Core::slot_show_old2ch ) ); Gtk::AccelKey jdhelpKey = CONTROL::get_accelkey( CONTROL::JDHelp ); if( jdhelpKey.is_null() ){ m_action_group->add( Gtk::Action::create( "Manual", "オンラインマニュアル(_M)..." ), sigc::mem_fun( *this, &Core::slot_show_manual ) ); }else{ m_action_group->add( Gtk::Action::create( "Manual", "オンラインマニュアル(_M)..." ), jdhelpKey, sigc::mem_fun( *this, &Core::slot_show_manual ) ); } m_action_group->add( Gtk::Action::create( "About", "JDについて(_A)..." ), sigc::mem_fun( *this, &Core::slot_show_about ) ); m_ui_manager = Gtk::UIManager::create(); m_ui_manager->insert_action_group( m_action_group ); // アクセラレータの追加 m_win_main.add_accel_group( m_ui_manager->get_accel_group() ); Glib::ustring menu_font = "" "" "" "" "" "" "" "" "" "" "" ""; Glib::ustring str_ui = "" "" // ファイル "" "" "" "" "" "" "" "" "" "" "" "" "" "" // 表示 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" // 詳細設定 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; str_ui += menu_font; str_ui += "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" // 履歴 "" "" "" "" // ツール "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" // 設定 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; str_ui += menu_font; str_ui += "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" // プライバシー "" "" "" "" "" "" "" "" "" // その他 "" "" "" "" "" "" "" "" // ヘルプ "" "" "" "" "" "" "" "" "" ""; m_ui_manager->add_ui_from_string( str_ui ); m_menubar = dynamic_cast< Gtk::MenuBar* >( m_ui_manager->get_widget("/menu_bar") ); assert( m_menubar ); m_menubar->set_size_request( 0 ); // 履歴メニュー追加 Gtk::Menu_Helpers::MenuList& items = m_menubar->items(); Gtk::Menu_Helpers::MenuList::iterator it_item = items.begin(); ++it_item; ++it_item; (*it_item).signal_activate().connect( sigc::mem_fun( *this, &Core::slot_activate_historymenu ) ); Gtk::Menu* submenu = dynamic_cast< Gtk::Menu* >( (*it_item).get_submenu() ); submenu->append( *Gtk::manage( new Gtk::SeparatorMenuItem() ) ); // スレ履歴 submenu->append( *HISTORY::get_history_manager()->get_menu_thread() ); // 板履歴 submenu->append( *HISTORY::get_history_manager()->get_menu_board() ); // 最近閉じたスレ履歴 submenu->append( *HISTORY::get_history_manager()->get_menu_close() ); // 最近閉じた板履歴 submenu->append( *HISTORY::get_history_manager()->get_menu_closeboard() ); // 最近閉じた画像履歴 submenu->append( *HISTORY::get_history_manager()->get_menu_closeimg() ); submenu->show_all_children(); // メニューにショートカットキーやマウスジェスチャを表示 items = m_menubar->items(); it_item = items.begin(); for( ; it_item != items.end(); ++it_item ){ submenu = dynamic_cast< Gtk::Menu* >( (*it_item).get_submenu() ); CONTROL::set_menu_motion( submenu ); ( *it_item ).signal_activate().connect( sigc::mem_fun( *this, &Core::slot_activate_menubar ) ); } // ツールバー作成 create_toolbar(); assert( m_toolbar ); // サイドバー m_sidebar = BBSLIST::get_admin()->get_widget(); assert( m_sidebar ); // その他設定とwidgetのパッキング m_notebook_right.set_show_tabs( false ); m_notebook_right.set_show_border( false ); m_notebook_right.get_style()->set_xthickness( 10 ); if( CONFIG::get_open_sidebar_by_click() ) m_hpaned.get_ctrl().set_click_fold( SKELETON::PANE_CLICK_FOLD_PAGE1 ); m_hpaned.get_ctrl().add_remove1( false, *m_sidebar ); pack_widget( false ); m_sigc_switch_page = m_notebook_right.signal_switch_page().connect( sigc::mem_fun( *this, &Core::slot_switch_page ) ); m_hpaned.get_ctrl().sig_pane_modechanged().connect( sigc::mem_fun( *this, &Core::slot_show_hide_leftpane ) ); m_win_main.signal_focus_out_event().connect( sigc::mem_fun(*this, &Core::slot_focus_out_event ) ); m_win_main.signal_focus_in_event().connect( sigc::mem_fun(*this, &Core::slot_focus_in_event ) ); m_win_main.show_all_children(); // 各管理クラスが開いていたURLを復元 core_set_command( "restore_views" ); } // // 3paneモードか // bool Core::is_3pane() { int mode_pane = SESSION::get_mode_pane(); return( mode_pane == SESSION::MODE_3PANE || mode_pane == SESSION::MODE_V3PANE ); } // (bbslistを除く)全adminがemptyか bool Core::is_all_admin_empty() { bool emp_img = ! ( SESSION::get_embedded_img() && ! IMAGE::get_admin()->empty() ); bool emp_mes = ! ( SESSION::get_embedded_mes() && ! MESSAGE::get_admin()->empty() ); return ( BOARD::get_admin()->empty() && ARTICLE::get_admin()->empty() && emp_mes && emp_img ); } // // 右側ペーン取得 // Gtk::Paned* Core::get_rpane() { Gtk::Paned* paned_r = &m_vpaned_r; if( SESSION::get_mode_pane() == SESSION::MODE_V3PANE ) paned_r = &m_hpaned_r; return paned_r; } // // 右側ペーンコントロール取得 // SKELETON::PaneControl* Core::get_rpctrl() { SKELETON::PaneControl* pctrl = &m_vpaned_r.get_ctrl(); if( SESSION::get_mode_pane() == SESSION::MODE_V3PANE ) pctrl = &m_hpaned_r.get_ctrl(); return pctrl; } // // widget のパック // void Core::pack_widget( bool unpack ) { m_enable_menuslot = false; int mode_pane = SESSION::get_mode_pane(); if( unpack ){ SESSION::set_hpane_main_pos( m_hpaned.get_ctrl().get_position() ); SESSION::set_vpane_main_pos( m_vpaned_r.get_ctrl().get_position() ); SESSION::set_hpane_main_r_pos( m_hpaned_r.get_ctrl().get_position() ); SESSION::set_vpane_main_mes_pos( m_vpaned_message.get_ctrl().get_position() ); } if( SESSION::get_embedded_mes() ){ // 埋め込みmessage // 書き込みウィンドウを閉じる MESSAGE::get_admin()->set_command_immediately( "close_window" ); m_vpaned_message.get_ctrl().add_remove1( unpack, *ARTICLE::get_admin()->get_widget() ); m_vpaned_message.get_ctrl().add_remove2( unpack, *MESSAGE::get_admin()->get_widget() ); m_notebook_right.append_remove_page( unpack, m_vpaned_message, "スレッド" ); } else{ // 書き込みウィンドウ表示 MESSAGE::get_admin()->set_command_immediately( "open_window" ); m_notebook_right.append_remove_page( unpack, *ARTICLE::get_admin()->get_widget(), "スレッド" ); } if( SESSION::get_embedded_img() ){ // 埋め込みimage // 画像ウィンドウを閉じる IMAGE::get_admin()->set_command_immediately( "close_window" ); m_notebook_right.append_remove_page( unpack, *IMAGE::get_admin()->get_widget(), "画像" ); } else{ // 画像ウィンドウ表示 IMAGE::get_admin()->set_command_immediately( "open_window" ); } // 画像インジケータ if( unpack ) hide_imagetab(); // 2ペーン if( mode_pane == SESSION::MODE_2PANE ){ m_notebook_right.append_remove_page( unpack, *BOARD::get_admin()->get_widget(), "スレ一覧" ); if( SESSION::get_show_main_toolbar() && SESSION::get_toolbar_pos() == SESSION::TOOLBAR_POS_RIGHT ) m_vbox_article.pack_remove_start( unpack, *m_toolbar, Gtk::PACK_SHRINK ); m_vbox_article.pack_remove_start( unpack, m_notebook_right ); m_hpaned.get_ctrl().add_remove2( unpack, m_vbox_article ); } // 3ペーン else if( is_3pane() ){ m_vbox_article.pack_remove_start( unpack, m_notebook_right ); get_rpctrl()->add_remove1( unpack, *BOARD::get_admin()->get_widget() ); get_rpctrl()->add_remove2( unpack, m_vbox_article ); if( SESSION::get_show_main_toolbar() && SESSION::get_toolbar_pos() == SESSION::TOOLBAR_POS_RIGHT ){ m_vbox_toolbar.pack_remove_start( unpack, *m_toolbar, Gtk::PACK_SHRINK ); m_vbox_toolbar.pack_remove_start( unpack, *get_rpane() ); m_hpaned.get_ctrl().add_remove2( unpack, m_vbox_toolbar ); } else m_hpaned.get_ctrl().add_remove2( unpack, *get_rpane() ); } // メインwindowのパッキング if( SESSION::get_show_main_statbar() ) m_win_main.pack_remove_end( unpack, m_win_main.get_statbar(), Gtk::PACK_SHRINK ); m_win_main.pack_remove_end( unpack, m_hpaned ); if( SESSION::get_show_main_toolbar() && SESSION::get_toolbar_pos() == SESSION::TOOLBAR_POS_NORMAL ) m_win_main.pack_remove_end( unpack, *m_toolbar, Gtk::PACK_SHRINK ); if( SESSION::show_menubar() ) m_win_main.pack_remove_end( unpack, *m_menubar, Gtk::PACK_SHRINK ); if( ! unpack ){ // ペーンの位置設定 m_vpaned_r.get_ctrl().set_position( SESSION::vpane_main_pos() ); m_hpaned_r.get_ctrl().set_position( SESSION::hpane_main_r_pos() ); m_vpaned_message.get_ctrl().set_position( SESSION::vpane_main_mes_pos() ); // 画像インジケータ if( ! IMAGE::get_admin()->empty() ) show_imagetab(); // サイドバーの位置設定 m_hpaned.get_ctrl().set_position( SESSION::hpane_main_pos() ); toggle_maximize_rightpane(); } m_enable_menuslot = true; } // // ツールバー作成 // void Core::create_toolbar() { if( m_toolbar ) return; m_toolbar = new MainToolBar(); m_toolbar->m_button_bbslist.signal_clicked().connect( sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_BBSLISTVIEW, false ) ); m_toolbar->m_button_favorite.signal_clicked().connect( sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_FAVORITEVIEW, false ) ); m_toolbar->m_button_hist.signal_clicked().connect( sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTTHREADVIEW, false ) ); m_toolbar->m_button_hist_board.signal_clicked().connect( sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTBOARDVIEW, false ) ); m_toolbar->m_button_hist_close.signal_clicked().connect( sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTCLOSEVIEW, false ) ); m_toolbar->m_button_hist_closeboard.signal_clicked().connect( sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTCLOSEBOARDVIEW, false ) ); m_toolbar->m_button_hist_closeimg.signal_clicked().connect( sigc::bind< std::string, bool >( sigc::mem_fun(*this, &Core::switch_sidebar ), URL_HISTCLOSEIMGVIEW, false ) ); m_toolbar->m_button_board.signal_clicked().connect( sigc::bind< bool >( sigc::mem_fun(*this, &Core::switch_board ), false ) ); m_toolbar->m_button_thread.signal_clicked().connect( sigc::bind< bool >( sigc::mem_fun(*this, &Core::switch_article ), false ) ); m_toolbar->m_button_image.signal_clicked().connect( sigc::bind< bool >( sigc::mem_fun(*this, &Core::switch_image ), false ) ); m_toolbar->m_entry_url.signal_activate().connect( sigc::mem_fun( *this, &Core::slot_active_url ) ); m_toolbar->m_button_go.signal_clicked().connect( sigc::mem_fun( *this, &Core::slot_active_url ) ); m_toolbar->open_buttonbar(); m_toolbar->show_toolbar(); } // // 初回起動時のセットアップ // void Core::first_setup() { m_init = true; SetupWizard wizard; wizard.run(); m_init = false; } // // メインタイトルセット // void Core::set_maintitle() { if( SESSION::is_booting() ) return; std::string title; if( m_title.empty() ) title = "JD - " + ENVIRONMENT::get_jdversion(); else title = "JD - " + m_title; if( CORE::get_login2ch()->login_now() ) title +=" [ ● ]"; if( CORE::get_loginbe()->login_now() ) title +=" [ BE ]"; if( CORE::get_loginp2()->login_now() ) title +=" [ p2 ]"; if( ! SESSION::is_online() ) title += " [ オフライン ]"; m_win_main.set_title( title ); } static inline void toggle_sidebar_action( Glib::RefPtr< Gtk::ActionGroup >& group, const std::string& action, const std::string url ) { Glib::RefPtr< Gtk::Action > act; Glib::RefPtr< Gtk::ToggleAction > tact; act = group->get_action( action ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::show_sidebar() && SESSION::get_sidebar_current_url() == url ) tact->set_active( true ); else tact->set_active( false ); } } // // メニューバーがアクティブになったときに呼ばれるスロット // void Core::slot_activate_menubar() { // toggle アクションを activeにするとスロット関数が呼ばれるので処理しないようにする m_enable_menuslot = false; Glib::RefPtr< Gtk::Action > act; Glib::RefPtr< Gtk::ToggleAction > tact; // サイドバー toggle_sidebar_action( m_action_group, "Show_BBS", URL_BBSLISTVIEW ); toggle_sidebar_action( m_action_group, "Show_FAVORITE", URL_FAVORITEVIEW ); toggle_sidebar_action( m_action_group, "Show_HISTTHREAD", URL_HISTTHREADVIEW ); toggle_sidebar_action( m_action_group, "Show_HISTBOARD", URL_HISTBOARDVIEW ); toggle_sidebar_action( m_action_group, "Show_HISTCLOSE", URL_HISTCLOSEVIEW ); toggle_sidebar_action( m_action_group, "Show_HISTCLOSEBOARD", URL_HISTCLOSEBOARDVIEW ); toggle_sidebar_action( m_action_group, "Show_HISTCLOSEIMG", URL_HISTCLOSEIMGVIEW ); // メニューバー act = m_action_group->get_action( "ShowMenuBar" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::show_menubar() ) tact->set_active( true ); else tact->set_active( false ); } // ボタンのrelief切り替え act = m_action_group->get_action( "ToggleFlatButton" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( CONFIG::get_flat_button() ) tact->set_active( true ); else tact->set_active( false ); } // ツールバー背景描画 act = m_action_group->get_action( "ToggleDrawToolbarback" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( CONFIG::get_draw_toolbarback() ) tact->set_active( true ); else tact->set_active( false ); } // ツールバー act = m_action_group->get_action( "ShowToolBarMain" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::get_show_main_toolbar() ) tact->set_active( true ); else tact->set_active( false ); } act = m_action_group->get_action( "ShowToolBarBbslist" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::get_show_bbslist_toolbar() ) tact->set_active( true ); else tact->set_active( false ); } act = m_action_group->get_action( "ShowToolBarBoard" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::get_show_board_toolbar() ) tact->set_active( true ); else tact->set_active( false ); } act = m_action_group->get_action( "ShowToolBarArticle" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::get_show_article_toolbar() ) tact->set_active( true ); else tact->set_active( false ); } // タブ act = m_action_group->get_action( "TabBoard" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::get_show_board_tab() ) tact->set_active( true ); else tact->set_active( false ); } act = m_action_group->get_action( "TabArticle" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::get_show_article_tab() ) tact->set_active( true ); else tact->set_active( false ); } // フルスクリーン act = m_action_group->get_action( "FullScreen" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::is_full_win_main() ) tact->set_active( true ); else tact->set_active( false ); } // ステータスバー act = m_action_group->get_action( "ShowStatBar" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( SESSION::get_show_main_statbar() ) tact->set_active( true ); else tact->set_active( false ); } // 2chログイン act = m_action_group->get_action( "Login2ch" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( CORE::get_login2ch()->login_now() ) tact->set_active( true ); else tact->set_active( false ); } // BEログイン act = m_action_group->get_action( "LoginBe" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( CORE::get_loginbe()->login_now() ) tact->set_active( true ); else tact->set_active( false ); } // P2ログイン act = m_action_group->get_action( "LoginP2" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( CORE::get_loginp2()->login_now() ) tact->set_active( true ); else tact->set_active( false ); } // 表示->スレ一覧に切替 (アクティブ状態を切り替える) act = m_action_group->get_action( "Show_Board" ); if( BOARD::get_admin()->empty() ) act->set_sensitive( false ); else act->set_sensitive( true ); // 表示->スレビューに切替 (アクティブ状態を切り替える) act = m_action_group->get_action( "Show_Thread" ); if( ARTICLE::get_admin()->empty() ) act->set_sensitive( false ); else act->set_sensitive( true ); // 表示->画像ビューに切替 (アクティブ状態を切り替える) act = m_action_group->get_action( "Show_Image" ); if( CONFIG::get_use_image_view() && ! IMAGE::get_admin()->empty() ) act->set_sensitive( true ); else act->set_sensitive( false ); // 画像ビュー表示切り替え act = m_action_group->get_action( "UseWinImg" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( ! CONFIG::get_use_image_view() ) tact->set_active( false ); else{ if( SESSION::get_embedded_img() ) tact->set_active( false ); else tact->set_active( true ); } } act = m_action_group->get_action( "UseEmbImg" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( ! CONFIG::get_use_image_view() ) tact->set_active( false ); else{ if( SESSION::get_embedded_img() ) tact->set_active( true ); else tact->set_active( false ); } } // 開いている板のログ検索 act = m_action_group->get_action( "SearchCacheBoard" ); if( BOARD::get_admin()->empty() || DBTREE::url_subject( BOARD::get_admin()->get_current_url() ).empty() ) act->set_sensitive( false ); else act->set_sensitive( true ); // 開いている板のログ一覧表示 act = m_action_group->get_action( "ShowCacheBoard" ); if( BOARD::get_admin()->empty() || DBTREE::url_subject( BOARD::get_admin()->get_current_url() ).empty() ) act->set_sensitive( false ); else act->set_sensitive( true ); // スレ一覧のプロパティ act = m_action_group->get_action( "BoardPref" ); if( BOARD::get_admin()->empty() || DBTREE::url_subject( BOARD::get_admin()->get_current_url() ).empty() ) act->set_sensitive( false ); else act->set_sensitive( true ); // スレのプロパティ act = m_action_group->get_action( "ArticlePref" ); if( ! ARTICLE::get_admin()->empty() ) act->set_sensitive( true ); else act->set_sensitive( false ); // 画像のプロパティ act = m_action_group->get_action( "ImagePref" ); if( ! IMAGE::get_admin()->empty() ) act->set_sensitive( true ); else act->set_sensitive( false ); // 実況 act = m_action_group->get_action( "LiveStartStop" ); if( ! ARTICLE::get_admin()->empty() ) act->set_sensitive( true ); else act->set_sensitive( false ); // emacsモード act = m_action_group->get_action( "ToggleEmacsMode" ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( CONTROL::is_emacs_mode() ) tact->set_active( true ); else tact->set_active( false ); } // datのインポート act = m_action_group->get_action( "ImportDat" ); if( ! BOARD::get_admin()->empty() ) act->set_sensitive( true ); else act->set_sensitive( false ); // サイドバーのスレ一覧表示 act = m_action_group->get_action( "ShowSidebarBoard" ); if( SESSION::get_sidebar_current_url() != URL_BBSLISTVIEW && SESSION::get_sidebar_current_url() != URL_HISTBOARDVIEW ) act->set_sensitive( true ); else act->set_sensitive( false ); // 仮想板作成 act = m_action_group->get_action( "CreateVBoard" ); if( SESSION::get_sidebar_current_url() != URL_BBSLISTVIEW && SESSION::get_sidebar_current_url() != URL_HISTBOARDVIEW ) act->set_sensitive( true ); else act->set_sensitive( false ); m_enable_menuslot = true; } // // 履歴メニューがアクティブになった // void Core::slot_activate_historymenu() { m_enable_menuslot = false; std::string view_url; switch( SESSION::focused_admin() ){ case SESSION::FOCUS_BOARD: view_url = BOARD::get_admin()->get_current_url(); break; case SESSION::FOCUS_ARTICLE: view_url = ARTICLE::get_admin()->get_current_url(); break; } bool enable_prev = false; bool enable_next = false; if( ! view_url.empty() ){ enable_prev = HISTORY::get_history_manager()->can_back_viewhistory( view_url, 1 ); enable_next = HISTORY::get_history_manager()->can_forward_viewhistory( view_url, 1 ); } #ifdef _DEBUG std::cout << "Core::slot_activate_historymenu\n" << "view_url = " << view_url << " prev = " << enable_prev << " next = " << enable_next << std::endl; #endif Glib::RefPtr< Gtk::Action > act; act = m_action_group->get_action( "PrevView" ); if( act ) act->set_sensitive( enable_prev ); act = m_action_group->get_action( "NextView" ); if( act ) act->set_sensitive( enable_next ); m_enable_menuslot = true; } // 戻る void Core::slot_prevview() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; if( SESSION::focused_admin() == SESSION::FOCUS_ARTICLE ){ ARTICLE::get_admin()->set_command( "back_viewhistory", ARTICLE::get_admin()->get_current_url(), "1" ); } else if( SESSION::focused_admin() == SESSION::FOCUS_BOARD ){ BOARD::get_admin()->set_command( "back_viewhistory", BOARD::get_admin()->get_current_url(), "1" ); } } // 進む void Core::slot_nextview() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; if( SESSION::focused_admin() == SESSION::FOCUS_ARTICLE ){ ARTICLE::get_admin()->set_command( "forward_viewhistory", ARTICLE::get_admin()->get_current_url(), "1" ); } else if( SESSION::focused_admin() == SESSION::FOCUS_BOARD ){ BOARD::get_admin()->set_command( "forward_viewhistory", BOARD::get_admin()->get_current_url(), "1" ); } } void Core::slot_clear_board() { HISTORY::remove_allhistories( URL_HISTBOARDVIEW ); BOARD::get_admin()->set_command( "clear_viewhistory" ); } void Core::slot_clear_thread() { HISTORY::remove_allhistories( URL_HISTTHREADVIEW ); ARTICLE::get_admin()->set_command( "clear_viewhistory" ); } void Core::slot_clear_close() { HISTORY::remove_allhistories( URL_HISTCLOSEVIEW ); } void Core::slot_clear_closeboard() { HISTORY::remove_allhistories( URL_HISTCLOSEBOARDVIEW ); } void Core::slot_clear_closeimg() { HISTORY::remove_allhistories( URL_HISTCLOSEIMGVIEW ); } void Core::slot_clear_search() { CORE::get_completion_manager()->clear( CORE::COMP_SEARCH_ARTICLE ); CORE::get_completion_manager()->clear( CORE::COMP_SEARCH_BBSLIST ); CORE::get_completion_manager()->clear( CORE::COMP_SEARCH_BOARD ); } void Core::slot_clear_name() { CORE::get_completion_manager()->clear( CORE::COMP_NAME ); } void Core::slot_clear_mail() { CORE::get_completion_manager()->clear( CORE::COMP_MAIL ); } // // 色選択ダイアログを開く // フォントと色の設定 // bool Core::open_color_diag( std::string title, int id ) { Gdk::Color color( CONFIG::get_color( id ) ); Gtk::ColorSelectionDialog diag( title ); diag.get_colorsel()->set_current_color( color ); diag.set_transient_for( *CORE::get_mainwindow() ); if( diag.run() == Gtk::RESPONSE_OK ){ CONFIG::set_color( id, MISC::color_to_str( diag.get_colorsel()->get_current_color() ) ); return true; } return false; } // // メニューバー表示切替え // void Core::toggle_menubar() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::toggle_menubar\n"; #endif pack_widget( true ); SESSION::set_show_menubar( ! SESSION::show_menubar() ); pack_widget( false ); restore_focus( true, false ); if( ! SESSION::show_menubar() && CONFIG::get_show_hide_menubar_diag() ){ SKELETON::MsgCheckDiag mdiag( NULL, "メニューバーを再表示するには\n\n" + CONTROL::get_str_motions( CONTROL::ShowMenuBar ) + "\n\nを押してください", "今後表示しない (_D)" ); mdiag.run(); if( mdiag.get_chkbutton().get_active() ) CONFIG::set_show_hide_menubar_diag( false ); } } // // ステータスバー表示切替え // void Core::toggle_statbar() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::toggle_statbar\n"; #endif pack_widget( true ); SESSION::set_show_main_statbar( ! SESSION::get_show_main_statbar() ); pack_widget( false ); restore_focus( true, false ); } // // ボタンのreliefの切り替え // void Core::toggle_flat_button() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::toggle_flat_button\n"; #endif CONFIG::set_flat_button( ! CONFIG::get_flat_button() ); ARTICLE::get_admin()->set_command( "update_toolbar_button" ); BOARD::get_admin()->set_command( "update_toolbar_button" ); BBSLIST::get_admin()->set_command( "update_toolbar_button" ); IMAGE::get_admin()->set_command( "update_toolbar_button" ); MESSAGE::get_admin()->set_command( "update_toolbar_button" ); m_toolbar->update_button(); } // // ツールバーの背景描画切り替え // void Core::toggle_draw_toolbarback() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::toggle_draw_toolbarback\n"; #endif CONFIG::set_draw_toolbarback( ! CONFIG::get_draw_toolbarback() ); SKELETON::MsgDiag mdiag( NULL, "正しく表示させるためにはJDを再起動してください。" ); mdiag.run(); } // // 書き込みマーク表示切り替え // void Core::toggle_post_mark() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; CONFIG::set_show_post_mark( ! CONFIG::get_show_post_mark() ); ARTICLE::get_admin()->set_command( "relayout_all" ); } // // サイドバー表示切替え // // url を開いているときは閉じる // 閉じているときは開く // // サイドバーの表示が切り替わったら slot_show_hide_leftpane()が呼び出される // void Core::toggle_sidebar() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::toggle_sidebar focus = " << SESSION::focused_admin() << " mode = " << m_hpaned.get_ctrl().get_mode() << " empty = " << is_all_admin_empty() << std::endl; #endif // 閉じていたらサイドバーを開く if( ! SESSION::show_sidebar() ){ // 右ペーンが空の時は常に最大化 if( CONFIG::get_expand_sidebar() && is_all_admin_empty() ) m_hpaned.get_ctrl().set_mode( SKELETON::PANE_MAX_PAGE1 ); // 通常 else m_hpaned.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); } // 開いていたら閉じる( 右ペーンが空の時は閉じない ) else if( ! is_all_admin_empty() ) m_hpaned.get_ctrl().set_mode( SKELETON::PANE_MAX_PAGE2 ); } // // サイドバーの表示が切り替わったときに呼ばれる // void Core::slot_show_hide_leftpane( int mode ) { const bool present = false; #ifdef _DEBUG std::cout << "slot_show_hide_leftpane mode = " << mode << std::endl; #endif if( mode == SKELETON::PANE_NORMAL ) SESSION::set_show_sidebar( true ); else SESSION::set_show_sidebar( false ); // 表示されたらサイドバーをフォーカス if( SESSION::focused_admin() != SESSION::FOCUS_SIDEBAR && SESSION::show_sidebar() ) switch_sidebar( std::string(), present ); // 非表示になったときは SESSION::focused_admin_sidebar() で指定されるadminにフォーカスを移す else{ #ifdef _DEBUG std::cout << "focused_admin = " << SESSION::focused_admin_sidebar() << std::endl; #endif if( SESSION::focused_admin_sidebar() == SESSION::FOCUS_BOARD ) switch_board( present ); else if( SESSION::focused_admin_sidebar() == SESSION::FOCUS_ARTICLE ) switch_article( present ); else if( SESSION::focused_admin_sidebar() == SESSION::FOCUS_IMAGE ) switch_image( present ); else if( SESSION::focused_admin_sidebar() == SESSION::FOCUS_MESSAGE ) switch_message( present ); else if( SESSION::focused_admin_sidebar() == SESSION::FOCUS_NOT ){ if( ! BOARD::get_admin()->empty() ) switch_board( present ); else if( ! ARTICLE::get_admin()->empty() ) switch_article( present ); else if( ! IMAGE::get_admin()->empty() ) switch_image( present ); } } } // // コマンドセット // // 他のadminクラスに委譲する場合はこの関数で、coreが実行するコマンドはexec_command()で処理 // void Core::set_command( const COMMAND_ARGS& command ) { if( SESSION::is_quitting() ) return; #ifdef _DEBUG std::cout << "Core::set_command : " << command.command << " " << command.url << " " << command.arg1 << " " << command.arg2 << " " << command.arg3 << " " << command.arg4 << std::endl; #endif bool emp_mes = ! ( SESSION::get_embedded_mes() && ! MESSAGE::get_admin()->empty() ); //////////////////////////// // article系のコマンド // メインビュー if( command.command == "open_article" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ command.arg1, // 開く位置 "false", // command.url を開いてるかチェックする command.arg2, // 開き方のモード "MAIN" // メインモードでarticleを開く ); // ジャンプ // command.arg3 がジャンプ先番号( empty ならジャンプしない )、arg4 がジャンプ元番号 if( ! command.arg3.empty() ) ARTICLE::get_admin()->set_command( "goto_num", command.url, command.arg3, command.arg4 ); return; } // メインビューを複数開く // if( command.command == "open_article_list" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_list", std::string(), // 以下 Admin::set_command() におけるCOMMAND_ARGS::arg1, arg2,.... command.arg1, // datファイルのURLを空白で区切って指定 command.arg2 // 開き方のモード ); return; } // レス抽出 else if( command.command == "open_article_res" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() におけるCOMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード "RES", // レス抽出モード command.arg1, // レス番号 ( from-to ) command.arg2 // ジャンプ番号( empty ならジャンプしない ) ); // 画像ウィンドウが開いている時にメインウィンドウを前面に出す switch_article( true ); return; } // 名前 で抽出 else if( command.command == "open_article_name" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード "NAME", // 名前抽出モード command.arg1 // 名前 ); return; } // ID で抽出 else if( command.command == "open_article_id" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード "ID", // ID 抽出モード command.arg1 // ユーザID ); return; } // ブックマークで抽出 else if( command.command == "open_article_bm" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード "BM" // ブックマーク抽出モード ); return; } // 自分の書き込みレスを抽出 else if( command.command == "open_article_post" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード "POST" // 書き込み抽出モード ); return; } // URL抽出 else if( command.command == "open_article_url" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード "URL" // URL抽出モード ); return; } // 参照抽出 else if( command.command == "open_article_refer" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード "REF", // 参照抽出モード command.arg1 // 対象レス番号 ); return; } // キーワードで抽出( AND/OR ) else if( command.command == "open_article_keyword" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); std::string mode_str = "KEYWORD"; if( command.arg2 == "true" ) mode_str = "KEYWORD_OR"; // OR 抽出 // 検索履歴更新 CORE::get_completion_manager()->set_query( CORE::COMP_SEARCH_ARTICLE, command.arg1 ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() におけるCOMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード mode_str, // キーワード抽出モード command.arg1 // query ); return; } // 書き込みログ表示 else if( command.command == "open_article_postlog" ) { if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", "postlog", // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード "POSTLOG", // モード command.arg1 // ログ番号 ); return; } // ログ検索 else if( command.command == "open_article_searchlog" ) { if( CORE::get_search_manager()->is_searching() ){ SKELETON::MsgDiag mdiag( NULL, "他の検索スレッドが実行中です" ); mdiag.run(); return; } if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); // URL_SEARCH_ALLBOARD の時は全ログ対象 std::string mode = "SEARCHLOG"; if( command.url == URL_SEARCH_ALLBOARD ) mode = "SEARCHALLLOG"; // 検索履歴更新 CORE::get_completion_manager()->set_query( CORE::COMP_SEARCH_ARTICLE, command.arg1 ); ARTICLE::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード mode, command.arg1, // query command.arg2, // "exec" ならViewを開いた直後に検索開始 command.arg3, // OR command.arg4 // BM ); return; } // スレタイ検索 else if( command.command == "open_article_searchtitle" ) { if( CORE::get_search_manager()->is_searching() ){ SKELETON::MsgDiag mdiag( NULL, "他の検索スレッドが実行中です" ); mdiag.run(); return; } if( ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); ARTICLE::get_admin()->set_command( "open_view", URL_SEARCH_TITLE, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // command.url を開いてるかチェックする "", // 開き方のモード "SEARCHTITLE", // モード command.arg1, // query command.arg2 // "exec" ならViewを開いた直後に検索開始 ); return; } // datが更新されたときにローダから呼ばれる else if( command.command == "update_article" ){ ARTICLE::get_admin()->set_command( "update_view", command.url ); return; } // datが更新が終わったときにローダから呼ばれる // "update_article" はdatロード時などの更新中でも呼び出されるが // "update_article_finish" は最後に一度だけ呼び出される else if( command.command == "update_article_finish" ){ ARTICLE::get_admin()->set_command( "update_finish", command.url ); return; } // articleの削除 // // command.arg1 == "reget" のときはキャッシュだけ再読み込み // command.arg2 再読み込み後にジャンプするレス番号 // else if( command.command == "delete_article" ){ bool locked = FALSE; int num_open = 0; std::string current_url; if( command.arg1 == "reget" ){ locked = ARTICLE::get_admin()->is_locked( command.url ); current_url = ARTICLE::get_admin()->get_current_url(); if( current_url.find( command.url ) == 0 ) current_url = command.url; // タブを開く位置を取得 const std::list list_urls = ARTICLE::get_admin()->get_URLs(); std::list< std::string >::const_iterator it = list_urls.begin(); for( ; it != list_urls.end(); ++it ){ if( *it == command.url ) break; if( ( *it ).find( command.url ) != std::string::npos ) continue; ++num_open; } } DBTREE::delete_article( command.url, ( command.arg1 == "reget" ) ); if( DBTREE::article_is_cached( command.url ) ) return; ARTICLE::get_admin()->set_command( "unlock_views", command.url ); ARTICLE::get_admin()->set_command( "close_view", command.url, "closeall" // command.url を含む全てのビューを閉じる ); BOARD::get_admin()->set_command( "unlock_views", command.url ); BOARD::get_admin()->set_command( "close_view", command.url, "closeall" // command.url を含む全てのビューを閉じる ); // ポップアップも削除して対象となるarticlebaseのロックを解除 (注) ポップアップは遅延してdeleteされる // そうしないと articlebase::unlock_impl()が呼び出されないためnotetreebaseが削除されない ARTICLE::get_admin()->set_command( "delete_all_popups" ); // もう一度開く if( command.arg1 == "reget" ){ const std::string str_num_open = "page" + MISC::itostr( num_open ); const std::string mode = std::string( "noswitch" ) + ( locked ? " lock" : "" ); const std::string str_num_jump = command.arg2; #ifdef _DEBUG std::cout << "reget tab = " << str_num_open << " mode = " << mode << " jump = " << str_num_jump << std::endl; #endif core_set_command( "open_article", command.url , str_num_open, mode, str_num_jump ); ARTICLE::get_admin()->set_command( "switch_view", current_url ); } return; } // 全articleviewの再レイアウト else if( command.command == "relayout_all_article" ){ ARTICLE::get_admin()->set_command( "relayout_all" ); } // 全articleviewのフォントの初期化 else if( command.command == "init_font_all_article" ){ ARTICLE::get_admin()->set_command( "init_font" ); } // スレビューのタブのアイコン表示を更新 else if( command.command == "toggle_article_icon" ){ ARTICLE::get_admin()->set_command( "toggle_icon", command.url ); return; } // ツールバー表示更新 else if( command.command == "redraw_article_toolbar" ){ ARTICLE::get_admin()->set_command( "redraw_toolbar" ); return; } // ツールバーボタン更新 else if( command.command == "update_article_toolbar_button" ){ ARTICLE::get_admin()->set_command( "update_toolbar_button" ); return; } // ポップアップメニュー再作成 else if( command.command == "reset_article_popupmenu" ){ ARTICLE::get_admin()->set_command( "reset_popupmenu" ); return; } //////////////////////////// // board系のコマンド // メインビュー else if( command.command == "open_board" ){ BOARD::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ command.arg1, // 開く位置 "false", // command.url を開いてるかチェック command.arg2, // 開き方のモード "MAIN" // モード ); return; } // 次スレ検索 else if( command.command == "open_board_next" ){ int tabpos = CONFIG::get_boardnexttab_pos(); std::string str_tab; std::string str_mode = ""; switch (tabpos) { case -1: // 2.8.5以前の動作 { // タブだらけになってしまうので実況中の場合はタブで開かない const bool live = SESSION::is_live( command.arg1 ); str_tab = (live) ? "false" : "newtab"; break; } case 1: // 新しいタブで開く str_tab = "newtab"; break; case 2: // アクティブなタブを置き換える str_tab = "false"; break; case 0: // 次スレ検索タブで開く default: str_tab = "replace"; str_mode = "boardnext"; break; } BOARD::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ str_tab, // 開く位置 "false", // 既にビューを開いてるかチェックする str_mode, // 開き方のモード "NEXT", // モード command.arg1 // スレのアドレス ); return; } // ログ一覧表示 else if( command.command == "open_board_showlog" || command.command == "open_board_showalllog" ){ if( CORE::get_search_manager()->is_searching() ){ SKELETON::MsgDiag mdiag( NULL, "他の検索スレッドが実行中です" ); mdiag.run(); return; } std::string url = command.url; if( command.command == "open_board_showalllog" ){ SKELETON::MsgDiag mdiag( NULL, "全ログの一覧表示はかなり時間がかかります。\n\n本当に表示しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; url = URL_ALLLOG; } BOARD::get_admin()->set_command( "open_view", url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ "newtab", // 開く位置 "false", // 既にビューを開いてるかチェックする "", // 開き方のモード "LOG" // モード ); return; } // サイドバーをスレ一覧に表示 else if( command.command == "open_sidebar_board" ) { BOARD::get_admin()->set_command( "open_view", command.url, // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... // 詳しくは Admin::open_view() を参照せよ command.arg1, // 開く位置 "false", // command.url を開いてるかチェック command.arg2, // 開き方のモード "SIDEBAR", // モード command.arg3, // お気に入りのディレクトリID、emptyでも可(その場合はcommand.urlにIDを含める) command.arg4 // "set_history" の時は板の履歴に登録する ); return; } // 複数開く // else if( command.command == "open_board_list" ) { BOARD::get_admin()->set_command( "open_list", std::string(), // 以下 Admin::set_command() における COMMAND_ARGS::arg1, arg2,.... command.arg1 // datファイルのURLを空白で区切って指定 ); return; } // 板を閉じる // その板に所属するスレも閉じる else if( command.command == "close_board" ){ std::string datbase = DBTREE::url_datbase( command.url ); ARTICLE::get_admin()->set_command_immediately( "close_view", datbase, "closeall" // datbase を含む全てのビューを閉じる ); BOARD::get_admin()->set_command_immediately( "close_view", command.url, "closeall" // command.url を含む全てのビューを閉じる ); } else if( command.command == "update_board" ){ BOARD::get_admin()->set_command( "update_view", command.url ); return; } else if( command.command == "update_board_item" ){ BOARD::get_admin()->set_command( "update_item", command.url, command.arg1 // スレID ); return; } // ツールバーボタン更新 else if( command.command == "update_board_toolbar_button" ){ BOARD::get_admin()->set_command( "update_toolbar_button" ); return; } // 列項目更新 else if( command.command == "update_board_columns" ){ BOARD::get_admin()->set_command( "update_columns" ); return; } // スレ一覧のタブのアイコン表示を更新 else if( command.command == "toggle_board_icon" ){ BOARD::get_admin()->set_command( "toggle_icon", command.url ); return; } // 表示中のスレ一覧のURLを選択 else if( command.command == "select_board_item" ){ BOARD::get_admin()->set_command_immediately( "select_item", command.url ); return; } // 全boardviewの再レイアウト else if( command.command == "relayout_all_board" ){ BOARD::get_admin()->set_command( "relayout_all" ); } // datのインポート else if( command.command == "import_dat" ){ if( command.arg1 == "show_diag" ){ SKELETON::MsgDiag mdiag( NULL, "「"+ DBTREE::board_name( command.url ) + "」\n\nにdatファイルをインポートしますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; } std::list< std::string > list_files; // ダイアログを開いてファイルのリストを取得 if( command.arg2.empty() ){ list_files = CACHE::open_load_diag( NULL, SESSION::get_dir_dat(), CACHE::FILE_TYPE_DAT, true ); } // 共有バッファからファイルのリストを取得 else if( CORE::SBUF_size() ){ const CORE::DATA_INFO_LIST list_info = CORE::SBUF_list_info(); CORE::DATA_INFO_LIST::const_iterator it = list_info.begin(); for( ; it != list_info.end(); ++it ){ if( ( *it ).type == TYPE_FILE ) list_files.push_back( ( *it ).url ); } } if( list_files.size() ){ SESSION::set_dir_dat( MISC::get_dir( *list_files.begin() ) ); import_dat( command.url, list_files ); } } //////////////////////////// // bbslist(サイドバー)系のコマンド // 板一覧の表示を更新 // 板一覧を更新したとき等に呼び出す else if( command.command == "update_bbslist" ){ CORE::core_set_command( "set_status","" ,"" ); // フォーカスされていなかったらサイドバーにフォーカス切り替え if( SESSION::focused_admin() != SESSION::FOCUS_SIDEBAR || SESSION::get_sidebar_current_url() != URL_BBSLISTVIEW ) CORE::core_set_command( "switch_sidebar", URL_BBSLISTVIEW ); BBSLIST::get_admin()->set_command( "update_view", URL_BBSLISTVIEW ); return; } // お気に入りに項目追加 // 共有バッファにコピーデータをセットしておくこと else if( command.command == "append_favorite" ){ BBSLIST::get_admin()->set_command( "append_item", URL_FAVORITEVIEW ); return; } // お気に入りから command.url で指定したスレを削除 else if( command.command == "remove_favorite" ){ BBSLIST::get_admin()->set_command( "remove_item", URL_FAVORITEVIEW, command.url ); return; } // 新スレ移行時等にお気に入りのスレの url と 名前を変更 else if( command.command == "replace_favorite_thread" ){ BBSLIST::get_admin()->set_command( "replace_thread", URL_FAVORITEVIEW, command.arg1, // 旧スレのURL command.arg2 // 新スレのURL ); return; } // サイドバーの表示中のビューの全体更新チェック else if( command.command == "check_update_root" ){ check_update( false ); return; } // サイドバーの表示中のビューの全体を更新チェックして開く else if( command.command == "check_update_open_root" ){ check_update( true ); return; } // サイドバーの全体の更新チェックのキャンセル else if( command.command == "cancel_check_update" ){ BBSLIST::get_admin()->set_command( "cancel_check_update", SESSION::get_sidebar_current_url() ); return; } // お気に入りの編集ウィンドウを開く else if( command.command == "edit_favorite" ){ BBSLIST::get_admin()->set_command( "edit_tree", URL_FAVORITEVIEW ); return; } // サイドバーのアイコン表示を更新 ( スレ ) else if( command.command == "toggle_sidebar_articleicon" ){ BBSLIST::get_admin()->set_command_immediately( "toggle_articleicon", URL_FAVORITEVIEW, command.url ); BBSLIST::get_admin()->set_command_immediately( "toggle_articleicon", URL_HISTTHREADVIEW, command.url ); BBSLIST::get_admin()->set_command_immediately( "toggle_articleicon", URL_HISTCLOSEVIEW, command.url ); // 履歴メニューを開いていたらメニューのアイコンも更新 HISTORY::get_history_manager()->set_menulabel( URL_HISTTHREADVIEW ); HISTORY::get_history_manager()->set_menulabel( URL_HISTCLOSEVIEW ); return; } // サイドバーのアイコン表示を更新 ( 板 ) else if( command.command == "toggle_sidebar_boardicon" ){ BBSLIST::get_admin()->set_command_immediately( "toggle_boardicon", URL_FAVORITEVIEW, command.url ); BBSLIST::get_admin()->set_command_immediately( "toggle_boardicon", URL_HISTBOARDVIEW, command.url ); // 履歴メニューを開いていたらメニューのアイコンも更新 HISTORY::get_history_manager()->set_menulabel( URL_HISTBOARDVIEW ); return; } // 表示中のサイドバーのURLを選択 else if( command.command == "select_sidebar_item" ){ BBSLIST::get_admin()->set_command_immediately( "select_item", SESSION::get_sidebar_current_url(), command.url ); return; } // 移転時にサイドバーに登録されているURLを新URLに更新 else if( command.command == "update_sidebar_item" ){ BBSLIST::get_admin()->set_command( "update_item", URL_BBSLISTVIEW ); BBSLIST::get_admin()->set_command( "update_item", URL_FAVORITEVIEW ); BBSLIST::get_admin()->set_command( "update_item", URL_HISTTHREADVIEW ); BBSLIST::get_admin()->set_command( "update_item", URL_HISTBOARDVIEW ); BBSLIST::get_admin()->set_command( "update_item", URL_HISTCLOSEVIEW ); BBSLIST::get_admin()->set_command( "update_item", URL_HISTCLOSEBOARDVIEW ); return; } // 各履歴の更新 // 共有バッファにデータをセットしておくこと else if( command.command == "append_history" ){ BBSLIST::get_admin()->set_command_immediately( "append_history", command.url ); return; } // 各履歴から command.arg1 で指定した項目を削除 else if( command.command == "remove_history" ){ BBSLIST::get_admin()->set_command( "remove_item", command.url, command.arg1 ); return; } // 各履歴から先頭にある項目を削除 else if( command.command == "remove_headhistory" ){ BBSLIST::get_admin()->set_command( "remove_headitem", command.url ); return; } // 各履歴から全項目を削除 else if( command.command == "remove_allhistories" ){ BBSLIST::get_admin()->set_command( "remove_allitems", command.url ); return; } // ツールバーボタン更新 else if( command.command == "update_bbslist_toolbar_button" ){ BBSLIST::get_admin()->set_command( "update_toolbar_button" ); return; } // 全bbslistviewの再レイアウト else if( command.command == "relayout_all_bbslist" ){ BBSLIST::get_admin()->set_command( "relayout_all" ); } //////////////////////////// // image系のコマンド else if( command.command == "open_image" ){ show_imagetab(); // キャッシュに無かったらロード if( ! DBIMG::is_cached( command.url ) && ! DBIMG::is_loading( command.url ) && ! DBIMG::is_wait( command.url ) ){ const bool mosaic = CONFIG::get_use_mosaic(); DBIMG::download_img( command.url, std::string(), mosaic ); } IMAGE::get_admin()->set_command( "open_view", command.url ); return; } else if( command.command == "delete_image" ){ DBIMG::delete_cache( command.url ); return; } else if( command.command == "close_image" ){ IMAGE::get_admin()->set_command( "close_view", command.url ); } // キャッシュに無い画像を閉じる else if( command.command == "close_nocached_image_views" ){ IMAGE::get_admin()->set_command( "close_nocached_views" ); return; } //////////////////////////// // message系 else if( command.command == "open_message" ){ if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( NULL, "オフラインです" ); mdiag.run(); } else{ const size_t max_lng = DBTREE::board_get_max_dat_lng( command.url ); if( max_lng > 0 && DBTREE::article_lng_dat( command.url ) > max_lng * 1000 ){ SKELETON::MsgDiag mdiag( NULL, "スレのサイズが" + MISC::itostr( max_lng ) + "Kバイトを越えています。\n\n本当に書き込みますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; } if( SESSION::get_embedded_mes() ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); MESSAGE::get_admin()->set_command( "open_view", command.url, command.arg1 ); } } else if( command.command == "close_message" ){ if( ! MESSAGE::get_admin()->empty() ) MESSAGE::get_admin()->set_command( "close_message", command.url ); } else if( command.command == "create_new_thread" ){ if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( NULL, "オフラインです" ); mdiag.run(); } else if( DBTREE::url_bbscgi_new( command.url ).empty() ){ SKELETON::MsgDiag mdiag( NULL, "この板では新スレを立てることは出来ません" ); mdiag.run(); } else{ if( SESSION::get_embedded_mes() ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); MESSAGE::get_admin()->set_command( "open_view", command.url, command.arg1, "new" ); } } // ツールバーボタン更新 else if( command.command == "update_message_toolbar_button" ){ MESSAGE::get_admin()->set_command( "update_toolbar_button" ); return; } // messageviewの再レイアウト else if( command.command == "relayout_all_message" ){ MESSAGE::get_admin()->set_command( "relayout_all" ); } // meesageview の wrap 切り替え else if( command.command == "toggle_message_wrap" ){ CONFIG::set_message_wrap( ! CONFIG::get_message_wrap() ); MESSAGE::get_admin()->set_command( "toggle_wrap" ); } //////////////////////////// // ダイアログボックスが表示/非表示状態になった else if( command.command == "dialog_shown" ){ // 表示された // フォーカスが外れて画像ウィンドウの開け閉めをしないようにする IMAGE::get_admin()->set_command_immediately( "disable_fold_win" ); MESSAGE::get_admin()->set_command_immediately( "disable_fold_win" ); return; } else if( command.command == "dialog_hidden" ){ // 非表示になった IMAGE::get_admin()->set_command_immediately( "enable_fold_win" ); MESSAGE::get_admin()->set_command_immediately( "enable_fold_win" ); return; } //////////////////////////// // 再描画系 // command.url を含むviewを全て再描画 else if( command.command == "redraw" ){ ARTICLE::get_admin()->set_command( "redraw", command.url ); BOARD::get_admin()->set_command( "redraw", command.url ); BBSLIST::get_admin()->set_command( "redraw", command.url ); IMAGE::get_admin()->set_command( "redraw", command.url ); MESSAGE::get_admin()->set_command( "redraw", command.url ); return; } // 表示中のbbslist viewを再描画 else if( command.command == "redraw_bbslist" ) { BBSLIST::get_admin()->set_command( "redraw_current_view" ); return; } // 表示中のboard viewを再描画 else if( command.command == "redraw_board" ) { BOARD::get_admin()->set_command( "redraw_current_view" ); return; } // 表示中のarticle viewを再描画 else if( command.command == "redraw_article" ) { ARTICLE::get_admin()->set_command( "redraw_current_view" ); return; } // 表示中のmessage viewを再描画 else if( command.command == "redraw_message" ) { MESSAGE::get_admin()->set_command( "redraw_current_view" ); return; } // command.url を含むarticle viewを全て再レイアウトして再描画 else if( command.command == "relayout_article" ){ ARTICLE::get_admin()->set_command( "relayout_views", command.url ); return; } // 表示中のimage viewを再描画 else if( command.command == "redraw_image" ) { IMAGE::get_admin()->set_command( "redraw_current_view" ); return; } // 表示中のviewを全部再描画 else if( command.command == "redraw_all" ) { ARTICLE::get_admin()->set_command( "redraw_current_view" ); BOARD::get_admin()->set_command( "redraw_current_view" ); BBSLIST::get_admin()->set_command( "redraw_current_view" ); IMAGE::get_admin()->set_command( "redraw_current_view" ); MESSAGE::get_admin()->set_command( "redraw_current_view" ); return; } /////////////////////////////// // 移転があった else if( command.command == "update_url" ){ ARTICLE::get_admin()->set_command( "update_url", command.url, command.arg1 ); BOARD::get_admin()->set_command( "update_url", command.url, command.arg1 ); BBSLIST::get_admin()->set_command( "update_url", command.url, command.arg1 ); IMAGE::get_admin()->set_command( "update_url", command.url, command.arg1 ); MESSAGE::get_admin()->set_command( "update_url", command.url, command.arg1 ); return; } /////////////////////////////// // 板名変更 else if( command.command == "update_boardname" ){ ARTICLE::get_admin()->set_command( "update_boardname", command.url ); BOARD::get_admin()->set_command( "update_boardname", command.url ); BBSLIST::get_admin()->set_command( "update_boardname", command.url ); IMAGE::get_admin()->set_command( "update_boardname", command.url ); MESSAGE::get_admin()->set_command( "update_boardname", command.url ); return; } /////////////////////////////// // フォーカス回復 else if( command.command == "restore_focus" ){ restore_focus( true, ( command.arg1 == "present" ) ); return; } /////////////////////////////// // タイトル、URL、ステータスなどの表示 else if( command.command == "set_title" ){ m_title = command.arg1; set_maintitle(); } else if( command.command == "set_url" ){ m_toolbar->m_entry_url.set_text( command.url ); } else if( command.command == "set_status" ){ m_win_main.set_status( command.arg1 ); } else if( command.command == "set_status_color" ){ if( CONFIG::get_change_stastatus_color() ) m_win_main.set_status_color( command.arg1 ); } // 一時的にステータスバーの表示を変える( マウスオーバーでのURL表示用 ) else if( command.command == "set_status_temporary" ){ m_win_main.set_status_temporary( command.arg1 ); } // 一時的に変えたステータスバーの表示を戻す else if( command.command == "restore_status" ){ m_win_main.restore_status(); } // ステータスバーのマウスジェスチャ欄にに一時的な情報を表示 // ダイアログを表示するまでも無い場合に使用する else if( command.command == "set_info" ){ m_win_main.set_mginfo( command.arg1 ); } // マウスジェスチャ else if( command.command == "set_mginfo" ){ // 画像ウィンドウが表示されている場合 if( ! SESSION::get_embedded_img() && SESSION::is_shown_win_img() && SESSION::is_focus_win_img() ){ IMAGE::get_admin()->set_command( "set_mginfo", "", command.arg1 ); } else m_win_main.set_mginfo( command.arg1 ); } //////////////////////////// // ポップアップを隠す else if( command.command == "hide_popup" ){ BBSLIST::get_admin()->set_command_immediately( "hide_popup" ); ARTICLE::get_admin()->set_command_immediately( "hide_popup" ); MESSAGE::get_admin()->set_command_immediately( "hide_popup" ); return; } //////////////////////////// // その他 Coreが自前で処理するコマンド( Core::exec_command() で処理 ) m_list_command.push_back( command ); dispatch(); // 一度メインループに戻った後にcallback_dispatch() が呼び戻される } // // ディスパッチャのコールバック関数 // void Core::callback_dispatch() { while( m_list_command.size() ) exec_command(); } // coreが自前でする処理 void Core::exec_command() { const bool present = false; if( m_list_command.size() == 0 ) return; COMMAND_ARGS command = m_list_command.front(); m_list_command.pop_front(); #ifdef _DEBUG std::cout << "Core::exec_command : " << command.command << " " << command.url << " " << command.arg1 << " " << command.arg2 << " " << command.arg3 << " " << command.arg4 << std::endl; #endif // 各管理クラスが開いていたURLを復元 if( command.command == "restore_views" ){ // bbslist は無条件でリストア // 板一覧がロードされてない時はここでロードされる BBSLIST::get_admin()->set_command( "restore" ); // 残りは CONFIG::get_restore_* で全てリストアするかロックされているタブだけリストアするか決定 BOARD::get_admin()->set_command( "restore", "", ( CONFIG::get_restore_board() ? "" : "only_locked" ) ); ARTICLE::get_admin()->set_command( "restore", "", ( CONFIG::get_restore_article() ? "" : "only_locked" ) ); // ロックされている画像があるか調べる bool img_locked = false; if( ! CONFIG::get_restore_image() ){ std::list< bool > list_locked = SESSION::get_image_locked(); std::list< bool >::iterator it_locked = list_locked.begin(); for( ; it_locked != list_locked.end(); ++it_locked ){ if( ( *it_locked ) ){ img_locked = true; break; } } } if( SESSION::image_URLs().size() && ( CONFIG::get_restore_image() || img_locked ) ){ show_imagetab(); IMAGE::get_admin()->set_command( "restore", "", ( CONFIG::get_restore_image() ? "" : "only_locked" ) ); } } // 各ビューのタブ幅調整 else if( command.command == "adjust_tabwidth" ){ BOARD::get_admin()->set_command( "adjust_tabwidth" ); ARTICLE::get_admin()->set_command( "adjust_tabwidth" ); } // メインツールバーのボタン表示更新 else if( command.command == "update_main_toolbar_button" ){ m_toolbar->update_button(); } // 履歴のクリア else if( command.command == "clear_board" ) slot_clear_board(); else if( command.command == "clear_thread" ) slot_clear_thread(); else if( command.command == "clear_closed_thread" ) slot_clear_close(); else if( command.command == "clear_search" ) slot_clear_search(); else if( command.command == "clear_name" ) slot_clear_name(); else if( command.command == "clear_mail" ) slot_clear_mail(); // ビューの切替え else if( command.command == "switch_article" ) switch_article( present ); else if( command.command == "switch_board" ) switch_board( present ); else if( command.command == "switch_sidebar" ) switch_sidebar( command.url, present ); else if( command.command == "switch_image" ) switch_image( present ); else if( command.command == "switch_message" ) switch_message( present ); else if( command.command == "toggle_article" ) toggle_article(); else if( command.command == "switch_leftview" ) switch_leftview(); else if( command.command == "switch_rightview" ) switch_rightview(); // メニューバー表示/非表示 else if( command.command == "toggle_menubar" ) toggle_menubar(); // メインツールバー表示/非表示 else if( command.command == "toggle_toolbarmain" ) slot_toggle_toolbarmain(); // サイドバー表示/非表示 else if( command.command == "toggle_sidebar" ) toggle_sidebar(); // 2chへのログイン処理が完了した else if( command.command == "login2ch_finished" ) set_maintitle(); // p2へのログイン処理が完了した else if( command.command == "loginp2_finished" ) set_maintitle(); // BEへのログイン処理が完了した else if( command.command == "loginbe_finished" ) set_maintitle(); // あるadminのnotebookが空になった else if( command.command == "empty_page" ) empty_page( command.url ); // あるadminのnotebookがswitchした else if( command.command == "page_switched" ){ set_toggle_view_button(); } // bbsmenu再読み込み else if( command.command == "reload_bbsmenu" ){ slot_reload_list(); } // グローバルあぼーん(名前) else if( command.command == "set_global_abone_name" ){ std::list< std::string >list_tmp = CONFIG::get_list_abone_name(); list_tmp.push_back( command.arg1 ); CONFIG::set_list_abone_name( list_tmp ); DBTREE::update_abone_all_article(); CORE::core_set_command( "relayout_all_article" ); } // グローバルあぼーん(ワード) else if( command.command == "set_global_abone_word" ){ std::list< std::string >list_tmp = CONFIG::get_list_abone_word(); list_tmp.push_back( command.arg1 ); CONFIG::set_list_abone_word( list_tmp ); DBTREE::update_abone_all_article(); CORE::core_set_command( "relayout_all_article" ); } // ユーザコマンド実行 else if( command.command == "exec_usr_cmd" ){ CORE::get_usrcmd_manager()->exec( atoi( command.arg1.c_str() ), // コマンド番号 command.url, // URL command.arg2, // Link command.arg3, // 選択文字 atoi( command.arg4.c_str() ) // レス番号 ); } // JD 終了 else if( command.command == "quit_jd" ) slot_quit(); // 最大化/最大化解除 else if( command.command == "maximize_mainwin" ){ if( ! SESSION::is_maximized_win_main() ) m_win_main.maximize_win(); else m_win_main.unmaximize_win(); } // 最小化 else if( command.command == "iconify_mainwin" ){ m_win_main.iconify_win(); } // 全画面表示 else if( command.command == "toggle_fullscreen" ){ slot_toggle_fullscreen(); } // URL のオープン関係 // URLを開くダイアログを表示 else if( command.command == "show_openurl_diag" ) slot_openurl(); // 常に外部ブラウザで開く場合 else if( command.command == "open_url_browser" ) open_by_browser( command.url ); // タイプによって判定する場合 else if( command.command == "open_url" ){ // プロトコルが指定されていない場合 command.url = MISC::remove_space( command.url ); if( command.url.find( "http://" ) != 0 && command.url.find( "https://" ) != 0 && command.url.find( "file://" ) != 0 && command.url.find( "ftp://" ) != 0 ){ // ローカルのファイルかチェック std::string path_real = CACHE::get_realpath( command.url ); if( ! path_real.empty() ) command.url = "file://" + path_real; // "http://"を仮定する else command.url = "http://" + command.url; } int num_from, num_to; std::string num_str; const std::string url_dat = DBTREE::url_dat( command.url, num_from, num_to, num_str ); const std::string url_subject = DBTREE::url_subject( command.url ); // datの場合ビューで開く if( ! url_dat.empty() ){ #ifdef _DEBUG std::cout << "exec : open_article url = " << url_dat << std::endl; #endif if( num_from ) CORE::core_set_command( "open_article" , url_dat, "newtab", "", MISC::itostr( num_from ) ); else CORE::core_set_command( "open_article" , url_dat, "newtab", "" ); } // 画像の場合 else if( DBIMG::get_type_ext( command.url ) != DBIMG::T_UNKNOWN ){ // 画像ビューを使用 if( CONFIG::get_use_image_view() ){ if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( NULL, "オフラインです" ); mdiag.run(); } else{ // キャッシュに無かったらロード if( ! DBIMG::is_cached( command.url ) ){ const bool mosaic = CONFIG::get_use_mosaic(); DBIMG::download_img( command.url, std::string(), mosaic ); } CORE::core_set_command( "open_image", command.url ); CORE::core_set_command( "switch_image" ); } } // 外部ビュアー使用 else open_by_browser( command.url ); } // 掲示板のベースURLの場合 else if( ! url_subject.empty() ){ #ifdef _DEBUG std::cout << "exec : open_board url = " << url_subject << std::endl; #endif CORE::core_set_command( "open_board" , url_subject, "true" ); } // その他 else open_by_browser( command.url ); } // ある admin クラスのコマンドが空になった else if( command.command == "empty_command" ){} // ある jdwindow クラスのブートが終わった else if( command.command == "window_boot_fin" ){} // 起動中 if( SESSION::is_booting() && ! m_init ){ // coreがコマンドを全て実行して、かつ全てのadminクラスがブートした if( m_list_command.size() == 0 && ! BBSLIST::get_admin()->is_booting() && ! BOARD::get_admin()->is_booting() && ! ARTICLE::get_admin()->is_booting() && ! IMAGE::get_admin()->is_booting() && ! MESSAGE::get_admin()->is_booting() ){ // 起動完了 SESSION::set_booting( false ); exec_command_after_boot(); } } } // // 起動処理完了後に実行する処理 // void Core::exec_command_after_boot() { #ifdef _DEBUG std::cout << "Core::exec_command_after_boot\n"; #endif // サイドバー表示状態変更 if( ! SESSION::show_sidebar() ) m_hpaned.get_ctrl().set_mode( SKELETON::PANE_MAX_PAGE2 ); // フォーカス回復 restore_focus( true, true ); // タイマーセット sigc::slot< bool > slot_timeout = sigc::bind( sigc::mem_fun(*this, &Core::slot_timeout), 0 ); JDLIB::Timeout::connect( slot_timeout, TIMER_TIMEOUT ); // 2chログイン if( SESSION::login2ch() ) slot_toggle_login2ch(); // BEログイン if( SESSION::loginbe() ) slot_toggle_loginbe(); // p2ログイン if( SESSION::loginp2() ) slot_toggle_loginp2(); // タイトル表示 set_maintitle(); // 画像ウィンドウが復元されると画面が表示されないので再レイアウト指定 ARTICLE::get_admin()->set_command( "relayout_current_view" ); // お気に入り更新チェック if( CONFIG::get_check_update_boot() && SESSION::is_online() ){ BBSLIST::get_admin()->set_command( "check_update_root", URL_FAVORITEVIEW ); } #ifdef _DEBUG std::cout << "\n\n----------- boot fin --------------\n\n"; #endif } // // フォーカス回復 // // force : true の時は強制的に回復(処理が重い) // present : フォーカス回復後にメインウィンドウをpresentする // void Core::restore_focus( const bool force, const bool present ) { int admin = SESSION::focused_admin(); // フォーカスするadminがemptyならリセット bool reset_focus = false; switch( admin ) { case SESSION::FOCUS_SIDEBAR: if( BBSLIST::get_admin()->empty() ) reset_focus = true; break; case SESSION::FOCUS_BOARD: if( BOARD::get_admin()->empty() ) reset_focus = true; break; case SESSION::FOCUS_ARTICLE: if( ARTICLE::get_admin()->empty() ) reset_focus = true; break; case SESSION::FOCUS_IMAGE: if( IMAGE::get_admin()->empty() ) reset_focus = true; break; case SESSION::FOCUS_MESSAGE: if( MESSAGE::get_admin()->empty() ) reset_focus = true; break; } if( reset_focus ){ SESSION::set_focused_admin( SESSION::FOCUS_NOT ); SESSION::set_focused_admin_sidebar( SESSION::FOCUS_NOT ); admin = SESSION::FOCUS_NOT; } #ifdef _DEBUG std::cout << "Core::restore_focus admin = " << admin << std::endl; #endif // ウィンドウが表示されているときはウィンドウのフォーカスを外す if( ! SESSION::get_embedded_img() ) IMAGE::get_admin()->set_command_immediately( "focus_out" ); if( ! SESSION::get_embedded_mes() ) MESSAGE::get_admin()->set_command_immediately( "focus_out" ); if( ! force ){ // 通常回復 // フォーカス状態回復 switch( admin ) { case SESSION::FOCUS_SIDEBAR: BBSLIST::get_admin()->set_command_immediately( "restore_focus" ); break; case SESSION::FOCUS_BOARD: BOARD::get_admin()->set_command_immediately( "restore_focus" ); break; case SESSION::FOCUS_ARTICLE: ARTICLE::get_admin()->set_command_immediately( "restore_focus" ); break; case SESSION::FOCUS_IMAGE: IMAGE::get_admin()->set_command_immediately( "restore_focus" ); break; case SESSION::FOCUS_MESSAGE: MESSAGE::get_admin()->set_command_immediately( "restore_focus" ); break; } } else { // 強制的に回復 int admin_sidebar = SESSION::focused_admin_sidebar(); if( admin == SESSION::FOCUS_NOT ){ if( ! ARTICLE::get_admin()->empty() ) admin = admin_sidebar = SESSION::FOCUS_ARTICLE; else if( ! BOARD::get_admin()->empty() ) admin = admin_sidebar = SESSION::FOCUS_BOARD; else if( ! BBSLIST::get_admin()->empty() ) admin = admin_sidebar = SESSION::FOCUS_SIDEBAR; } SESSION::set_focused_admin( SESSION::FOCUS_NOT ); SESSION::set_focused_admin_sidebar( SESSION::FOCUS_NOT ); // adminの表示状態回復 set_right_current_page( SESSION::notebook_main_page() ); // フォーカス状態回復 switch( admin ){ case SESSION::FOCUS_SIDEBAR: switch_sidebar( std::string(), present ); break; case SESSION::FOCUS_BOARD: switch_board( present ); break; case SESSION::FOCUS_ARTICLE: switch_article( present ); break; case SESSION::FOCUS_IMAGE: switch_image( present ); break; case SESSION::FOCUS_MESSAGE: switch_message( present ); break; } SESSION::set_focused_admin( admin ); SESSION::set_focused_admin_sidebar( admin_sidebar ); } } // // メインタイマー // // TIMER_TIMEOUT msec毎に呼び出される // bool Core::slot_timeout( int timer_number ) { // 各管理クラスにクロック入力する BBSLIST::get_admin()->clock_in(); BOARD::get_admin()->clock_in(); ARTICLE::get_admin()->clock_in(); IMAGE::get_admin()->clock_in(); MESSAGE::get_admin()->clock_in(); DBIMG::clock_in(); // Panedにクロック入力 m_hpaned.get_ctrl().clock_in(); m_vpaned_r.get_ctrl().clock_in(); m_hpaned_r.get_ctrl().clock_in(); m_vpaned_message.get_ctrl().clock_in(); // セッション保存 if( CONFIG::get_save_session() ){ ++m_count_savesession; if( m_count_savesession > ( CONFIG::get_save_session() * 60 * 1000 / TIMER_TIMEOUT )){ m_count_savesession = 0; save_session(); } } return true; } // // 右ペーンのnotebookのタブの切替え // void Core::slot_switch_page( GtkNotebookPage*, guint ) { const bool present = false; const int page = get_right_current_page(); #ifdef _DEBUG std::cout << "Core::slot_switch_page " << page << std::endl; #endif switch( page ){ case SESSION::PAGE_ARTICLE: switch_article( present ); break; case SESSION::PAGE_IMAGE: switch_image( present ); break; case SESSION::PAGE_BOARD: switch_board( present ); break; } } // 右ペーンのnotebookのページ番号 int Core::get_right_current_page() { const int mode = SESSION::get_mode_pane(); int page = m_notebook_right.get_current_page(); if( mode == SESSION::MODE_2PANE ){ // 2paneで画像ビューをウィンドウ表示している場合 // 1 ページ目はIMAGEではなくてBOARDになる if( ! SESSION::get_embedded_img() && page == 1 ) page = SESSION::PAGE_BOARD; } return page; } // 右ペーンのnotebookのページをセット void Core::set_right_current_page( int page ) { // page が empty でないか調べる if( page == SESSION::PAGE_ARTICLE && ARTICLE::get_admin()->empty() && ( SESSION::get_embedded_mes() && MESSAGE::get_admin()->empty() ) ){ if( SESSION::get_mode_pane() == SESSION::MODE_2PANE && ! BOARD::get_admin()->empty() ) page = SESSION::PAGE_BOARD; else if( ! IMAGE::get_admin()->empty() ) page = SESSION::PAGE_IMAGE; else return; } if( page == SESSION::PAGE_BOARD && BOARD::get_admin()->empty() ){ if( ! ARTICLE::get_admin()->empty() ) page = SESSION::PAGE_ARTICLE; else if( ! IMAGE::get_admin()->empty() ) page = SESSION::PAGE_IMAGE; else return; } if( page == SESSION::PAGE_IMAGE && IMAGE::get_admin()->empty() ){ if( ! ARTICLE::get_admin()->empty() ) page = SESSION::PAGE_ARTICLE; else if( SESSION::get_mode_pane() == SESSION::MODE_2PANE && ! BOARD::get_admin()->empty() ) page = SESSION::PAGE_BOARD; else return; } if( get_right_current_page() == page ) return; // 画像ビューをウィンドウ表示している場合 if( ! SESSION::get_embedded_img() && page == SESSION::PAGE_IMAGE ) return; if( SESSION::get_mode_pane() == SESSION::MODE_2PANE ){ // 2paneで画像ビューをウィンドウ表示している場合 // 1 ページ目はIMAGEではなくてBOARDになる if( ! SESSION::get_embedded_img() && page == SESSION::PAGE_BOARD ) page = 1; } else if( page == SESSION::PAGE_BOARD ) return; // 2pane以外ではboardはnotebookに含まれない m_notebook_right.set_current_page( page ); SESSION::set_notebook_main_page( get_right_current_page() ); } // // フォーカスアウトイベント // bool Core::slot_focus_out_event( GdkEventFocus* ) { #ifdef _DEBUG std::cout << "Core::slot_focus_out_event admin = " << SESSION::focused_admin() << std::endl; #endif if( SESSION::is_dialog_shown() ) return true; FOCUS_OUT_ALL(); return true; } // // フォーカスインイベント // bool Core::slot_focus_in_event( GdkEventFocus* ) { #ifdef _DEBUG std::cout << "Core::slot_focus_in_event admin = " << SESSION::focused_admin() << std::endl; #endif restore_focus( false, false ); return true; } // // URL entryでenterを押した // void Core::slot_active_url() { std::string url = m_toolbar->m_entry_url.get_text(); if( !url.empty() ){ if( url == "about:config" ) slot_aboutconfig(); else CORE::core_set_command( "open_url", url ); } } // // あるadminがemptyになったので他のadminにスイッチ // // url : empty になったadmin // void Core::empty_page( const std::string& url ) { #ifdef _DEBUG std::cout << "Core::empty_page url = " << url << std::endl; #endif const bool present = false; const bool emp_img = ! ( SESSION::get_embedded_img() && ! IMAGE::get_admin()->empty() ); const bool emp_mes = ! ( SESSION::get_embedded_mes() && ! MESSAGE::get_admin()->empty() ); int focused_admin = SESSION::FOCUS_NOT; // emptyになったadminとフォーカスされているadminが異なる場合は // フォーカスを移動しない if( SESSION::focused_admin() == SESSION::FOCUS_SIDEBAR ) focused_admin = SESSION::FOCUS_SIDEBAR; else if( SESSION::focused_admin() == SESSION::FOCUS_BOARD && ! BOARD::get_admin()->empty() ) focused_admin = SESSION::FOCUS_BOARD; else if( SESSION::focused_admin() == SESSION::FOCUS_ARTICLE && ! ARTICLE::get_admin()->empty() ) focused_admin = SESSION::FOCUS_ARTICLE; else if( SESSION::focused_admin() == SESSION::FOCUS_IMAGE && ! IMAGE::get_admin()->empty() ) focused_admin = SESSION::FOCUS_IMAGE; else if( SESSION::focused_admin() == SESSION::FOCUS_MESSAGE && ! MESSAGE::get_admin()->empty() ) focused_admin = SESSION::FOCUS_MESSAGE; // 埋め込み画像ビューが空になった if( url == URL_IMAGEADMIN && SESSION::get_embedded_img() ){ if( CONFIG::get_hide_imagetab() ) hide_imagetab(); // 空でないadminを前に出す if( SESSION::get_mode_pane() == SESSION::MODE_2PANE ){ if( get_right_current_page() == SESSION::PAGE_IMAGE ){ if( ! ARTICLE::get_admin()->empty() ) switch_article( present ); else if( ! BOARD::get_admin()->empty() ) switch_board( present ); } } else if( ! ARTICLE::get_admin()->empty() ) switch_article( present ); // フォーカス切り替え if( focused_admin == SESSION::FOCUS_NOT ){ if( ! ARTICLE::get_admin()->empty() ) focused_admin = SESSION::FOCUS_ARTICLE; else if( ! BOARD::get_admin()->empty() ) focused_admin = SESSION::FOCUS_BOARD; else{ focused_admin = SESSION::FOCUS_SIDEBAR; SESSION::set_focused_admin_sidebar( SESSION::FOCUS_NOT ); } } } // articleビューが空になった else if( url == URL_ARTICLEADMIN ){ // 空でないadminを前に出す if( SESSION::get_mode_pane() == SESSION::MODE_2PANE ){ if( get_right_current_page() == SESSION::PAGE_ARTICLE && emp_mes ) { if( BOARD::get_admin()->empty() && ! emp_img ) switch_image( present ); else if( ! BOARD::get_admin()->empty() ) switch_board( present ); } } else if( ! emp_img ) switch_image( present ); // フォーカス切り替え if( focused_admin == SESSION::FOCUS_NOT ){ if( ! emp_mes ) focused_admin = SESSION::FOCUS_MESSAGE; else if( ! BOARD::get_admin()->empty() ) focused_admin = SESSION::FOCUS_BOARD; else{ focused_admin = SESSION::FOCUS_SIDEBAR; SESSION::set_focused_admin_sidebar( SESSION::FOCUS_NOT ); } } } // boardビューが空になった else if( url == URL_BOARDADMIN ){ // 空でないadminを前に出す if( SESSION::get_mode_pane() == SESSION::MODE_2PANE ){ if( get_right_current_page() == SESSION::PAGE_BOARD ){ if( ! ARTICLE::get_admin()->empty() ) switch_article( present ); else if( ! emp_img ) switch_image( present ); } } // フォーカス切り替え if( focused_admin == SESSION::FOCUS_NOT ){ focused_admin = SESSION::FOCUS_SIDEBAR; SESSION::set_focused_admin_sidebar( SESSION::FOCUS_NOT ); } } // 埋め込みmessageビューが空になった else if( url == URL_MESSAGEADMIN && SESSION::get_embedded_mes() ){ // フォーカス切り替え if( focused_admin == SESSION::FOCUS_NOT ){ if( ! ARTICLE::get_admin()->empty() ) focused_admin = SESSION::FOCUS_ARTICLE; else if( ! BOARD::get_admin()->empty() ) focused_admin = SESSION::FOCUS_BOARD; else{ focused_admin = SESSION::FOCUS_SIDEBAR; SESSION::set_focused_admin_sidebar( SESSION::FOCUS_NOT ); } } } // 切り替え実行 switch( focused_admin ){ case SESSION::FOCUS_SIDEBAR: switch_sidebar( std::string(), present ); break; case SESSION::FOCUS_BOARD: switch_board( present ); break; case SESSION::FOCUS_ARTICLE: switch_article( present ); break; case SESSION::FOCUS_IMAGE: switch_image( present ); break; case SESSION::FOCUS_MESSAGE: switch_message( present ); break; } } // // ビューのトグルボタンを上げ下げする // void Core::set_toggle_view_button() { m_enable_menuslot = false; bool sidebar_state[ 7 ] = { false, false, false, false, false, false, false }; switch( SESSION::focused_admin() ){ case SESSION::FOCUS_SIDEBAR: sidebar_state[ SESSION::get_sidebar_current_page() ] = true; m_toolbar->m_button_bbslist.set_active( sidebar_state[ 0 ] ); m_toolbar->m_button_favorite.set_active( sidebar_state[ 1 ] ); m_toolbar->m_button_hist.set_active( sidebar_state[ 2 ] ); m_toolbar->m_button_hist_board.set_active( sidebar_state[ 3 ] ); m_toolbar->m_button_hist_close.set_active( sidebar_state[ 4 ] ); m_toolbar->m_button_hist_closeboard.set_active( sidebar_state[ 5 ] ); m_toolbar->m_button_hist_closeimg.set_active( sidebar_state[ 6 ] ); m_toolbar->m_button_board.set_active( false ); m_toolbar->m_button_thread.set_active( false ); m_toolbar->m_button_image.set_active( false ); break; case SESSION::FOCUS_BOARD: if( ! BOARD::get_admin()->empty() ){ m_toolbar->m_button_bbslist.set_active( sidebar_state[ 0 ] ); m_toolbar->m_button_favorite.set_active( sidebar_state[ 1 ] ); m_toolbar->m_button_hist.set_active( sidebar_state[ 2 ] ); m_toolbar->m_button_hist_board.set_active( sidebar_state[ 3 ] ); m_toolbar->m_button_hist_close.set_active( sidebar_state[ 4 ] ); m_toolbar->m_button_hist_closeboard.set_active( sidebar_state[ 5 ] ); m_toolbar->m_button_hist_closeimg.set_active( sidebar_state[ 6 ] ); m_toolbar->m_button_board.set_active( true ); m_toolbar->m_button_thread.set_active( false ); m_toolbar->m_button_image.set_active( false ); } else m_toolbar->m_button_board.set_active( false ); break; case SESSION::FOCUS_ARTICLE: if( ! ARTICLE::get_admin()->empty() ){ m_toolbar->m_button_bbslist.set_active( sidebar_state[ 0 ] ); m_toolbar->m_button_favorite.set_active( sidebar_state[ 1 ] ); m_toolbar->m_button_hist.set_active( sidebar_state[ 2 ] ); m_toolbar->m_button_hist_board.set_active( sidebar_state[ 3 ] ); m_toolbar->m_button_hist_close.set_active( sidebar_state[ 4 ] ); m_toolbar->m_button_hist_closeboard.set_active( sidebar_state[ 5 ] ); m_toolbar->m_button_hist_closeimg.set_active( sidebar_state[ 6 ] ); m_toolbar->m_button_board.set_active( false ); m_toolbar->m_button_thread.set_active( true ); m_toolbar->m_button_image.set_active( false ); } else m_toolbar->m_button_thread.set_active( false ); break; case SESSION::FOCUS_IMAGE: if( ! IMAGE::get_admin()->empty() ){ m_toolbar->m_button_bbslist.set_active( sidebar_state[ 0 ] ); m_toolbar->m_button_favorite.set_active( sidebar_state[ 1 ] ); m_toolbar->m_button_hist.set_active( sidebar_state[ 2 ] ); m_toolbar->m_button_hist_board.set_active( sidebar_state[ 3 ] ); m_toolbar->m_button_hist_close.set_active( sidebar_state[ 4 ] ); m_toolbar->m_button_hist_closeboard.set_active( sidebar_state[ 5 ] ); m_toolbar->m_button_hist_closeimg.set_active( sidebar_state[ 6 ] ); m_toolbar->m_button_board.set_active( false ); m_toolbar->m_button_thread.set_active( false ); m_toolbar->m_button_image.set_active( true ); } else m_toolbar->m_button_image.set_active( false ); break; case SESSION::FOCUS_MESSAGE: m_toolbar->m_button_bbslist.set_active( sidebar_state[ 0 ] ); m_toolbar->m_button_favorite.set_active( sidebar_state[ 1 ] ); m_toolbar->m_button_hist.set_active( sidebar_state[ 2 ] ); m_toolbar->m_button_hist_board.set_active( sidebar_state[ 3 ] ); m_toolbar->m_button_hist_close.set_active( sidebar_state[ 4 ] ); m_toolbar->m_button_hist_closeboard.set_active( sidebar_state[ 5 ] ); m_toolbar->m_button_hist_closeimg.set_active( sidebar_state[ 6 ] ); m_toolbar->m_button_board.set_active( false ); if( SESSION::get_embedded_mes() ) m_toolbar->m_button_thread.set_active( true ); else m_toolbar->m_button_thread.set_active( false ); m_toolbar->m_button_image.set_active( false ); break; } m_enable_menuslot = true; } // // ビューのトグルボタンのsensitive状態を切り替える // void Core::set_sensitive_view_button() { m_enable_menuslot = false; bool emp_mes = ! ( SESSION::get_embedded_mes() && ! MESSAGE::get_admin()->empty() ); // スレ一覧ボタンの切り替え if( BOARD::get_admin()->empty() ) m_toolbar->m_button_board.set_sensitive( false ); else m_toolbar->m_button_board.set_sensitive( true ); // スレビューボタンの切り替え if( ! ARTICLE::get_admin()->empty() || ! emp_mes ) m_toolbar->m_button_thread.set_sensitive( true ); else m_toolbar->m_button_thread.set_sensitive( false ); // 画像ビューボタンの切り替え if( IMAGE::get_admin()->empty() ) m_toolbar->m_button_image.set_sensitive( false ); else m_toolbar->m_button_image.set_sensitive( true ); m_enable_menuslot = true; } // // 右ペーンの最大化表示切り替え // void Core::toggle_maximize_rightpane() { bool emp_board = BOARD::get_admin()->empty(); bool emp_article = ARTICLE::get_admin()->empty(); bool emp_img = ! ( SESSION::get_embedded_img() && ! IMAGE::get_admin()->empty() ); bool emp_mes = ! ( SESSION::get_embedded_mes() && ! MESSAGE::get_admin()->empty() ); // 埋め込みmessage if( SESSION::get_embedded_mes() ){ if( ! emp_article && emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_MAX_PAGE1 ); else if( emp_article && ! emp_mes ) m_vpaned_message.get_ctrl().set_mode( SKELETON::PANE_MAX_PAGE2 ); } if( is_3pane() && CONFIG::get_expand_rpane() ){ // スレ一覧を最大化 if( ! emp_board && emp_article && emp_img && emp_mes ) get_rpctrl()->set_mode( SKELETON::PANE_MAX_PAGE1 ); // スレビューを最大化 else if( emp_board && ( ! emp_article || ! emp_img || ! emp_mes ) ) get_rpctrl()->set_mode( SKELETON::PANE_MAX_PAGE2 ); // 戻す else if( ! emp_board && ( ! emp_article || ! emp_img || ! emp_mes ) ) get_rpctrl()->set_mode( SKELETON::PANE_NORMAL ); } } // // 各viewにスイッチ // void Core::switch_article( const bool present ) { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::switch_article present = " << present << std::endl; #endif const bool emp_mes = ! ( SESSION::get_embedded_mes() && ! MESSAGE::get_admin()->empty() ); if( ! ARTICLE::get_admin()->empty() ){ if( m_hpaned.get_ctrl().get_mode() == SKELETON::PANE_MAX_PAGE1 ) m_hpaned.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); if( SESSION::focused_admin() != SESSION::FOCUS_ARTICLE ){ FOCUS_OUT_ALL(); ARTICLE::get_admin()->set_command( "delete_popup" ); set_right_current_page( SESSION::PAGE_ARTICLE ); } ARTICLE::get_admin()->set_command_immediately( "focus_current_view" ); SESSION::set_focused_admin( SESSION::FOCUS_ARTICLE ); SESSION::set_focused_admin_sidebar( SESSION::FOCUS_ARTICLE ); if( SESSION::get_embedded_img() ) SESSION::set_shown_win_img( false ); } // articleは空だが、埋め込みmessageが表示されている場合 else if( ! emp_mes ){ switch_message( present ); return; } set_sensitive_view_button(); set_toggle_view_button(); toggle_maximize_rightpane(); if( present ) m_win_main.present(); } void Core::switch_board( const bool present ) { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::switch_board\n"; #endif if( ! BOARD::get_admin()->empty() ){ if( m_hpaned.get_ctrl().get_mode() == SKELETON::PANE_MAX_PAGE1 ) m_hpaned.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); if( SESSION::focused_admin() != SESSION::FOCUS_BOARD ){ FOCUS_OUT_ALL(); ARTICLE::get_admin()->set_command( "delete_popup" ); set_right_current_page( SESSION::PAGE_BOARD ); } BOARD::get_admin()->set_command_immediately( "focus_current_view" ); SESSION::set_focused_admin( SESSION::FOCUS_BOARD ); SESSION::set_focused_admin_sidebar( SESSION::FOCUS_BOARD ); // 3paneの時はboardに切り替えても(フォーカスアウトしても) // 画像は表示されたままの時があることに注意 if( SESSION::get_embedded_img() && SESSION::get_mode_pane() == SESSION::MODE_2PANE ) SESSION::set_shown_win_img( false ); } set_sensitive_view_button(); set_toggle_view_button(); toggle_maximize_rightpane(); if( present ) m_win_main.present(); } // // url は表示するページ( URL_BBSLISTVIEW or URL_FAVORITEVIEW ) // urlが空の時はフォーカスを移すだけ // present が true の時はメインウィンドウを前面に出す // void Core::switch_sidebar( const std::string& url, const bool present ) { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::switch_sidebar url = " << url << " current = " << SESSION::get_sidebar_current_url() << std::endl; #endif if( ! BBSLIST::get_admin()->empty() ){ if( SESSION::focused_admin() != SESSION::FOCUS_SIDEBAR ){ FOCUS_OUT_ALL(); ARTICLE::get_admin()->set_command( "delete_popup" ); } // urlがフォーカスされていて、かつ他のadminがemptyで無いときは閉じる else if( SESSION::get_sidebar_current_url() == url && ! is_all_admin_empty() ){ toggle_sidebar(); return; } // 閉じていたら開く if( ! SESSION::show_sidebar() ) toggle_sidebar(); // 右ペーンがemptyなら最大化 else if( CONFIG::get_expand_sidebar() && is_all_admin_empty() ) m_hpaned.get_ctrl().set_mode( SKELETON::PANE_MAX_PAGE1 ); if( ! url.empty() ) BBSLIST::get_admin()->set_command( "switch_view", url ); BBSLIST::get_admin()->set_command_immediately( "focus_current_view" ); SESSION::set_focused_admin( SESSION::FOCUS_SIDEBAR ); } set_sensitive_view_button(); set_toggle_view_button(); toggle_maximize_rightpane(); if( present ) m_win_main.present(); } void Core::switch_image( const bool present ) { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::switch_image\n"; #endif if( ! IMAGE::get_admin()->empty() ){ if( SESSION::get_embedded_img() ){ // 埋め込み画像ビュー if( m_hpaned.get_ctrl().get_mode() == SKELETON::PANE_MAX_PAGE1 ) m_hpaned.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); if( SESSION::focused_admin() != SESSION::FOCUS_IMAGE ){ FOCUS_OUT_ALL(); ARTICLE::get_admin()->set_command( "delete_popup" ); set_right_current_page( SESSION::PAGE_IMAGE ); // 画像強制表示 IMAGE::get_admin()->set_command( "show_image" ); } SESSION::set_focused_admin( SESSION::FOCUS_IMAGE ); SESSION::set_focused_admin_sidebar( SESSION::FOCUS_IMAGE ); } IMAGE::get_admin()->set_command_immediately( "focus_current_view" ); if( SESSION::get_embedded_img() ) SESSION::set_shown_win_img( true ); } set_sensitive_view_button(); set_toggle_view_button(); toggle_maximize_rightpane(); if( present && SESSION::get_embedded_img() ) m_win_main.present(); } void Core::switch_message( const bool present ) { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::switch_message\n"; #endif // 埋め込み書き込みビュー使用 const bool emb_mes = SESSION::get_embedded_mes(); if( ! MESSAGE::get_admin()->empty() ){ if( emb_mes ){ if( m_hpaned.get_ctrl().get_mode() == SKELETON::PANE_MAX_PAGE1 ) m_hpaned.get_ctrl().set_mode( SKELETON::PANE_NORMAL ); if( SESSION::focused_admin() != SESSION::FOCUS_MESSAGE ){ FOCUS_OUT_ALL(); ARTICLE::get_admin()->set_command( "delete_popup" ); set_right_current_page( SESSION::PAGE_ARTICLE ); } SESSION::set_focused_admin( SESSION::FOCUS_MESSAGE ); SESSION::set_focused_admin_sidebar( SESSION::FOCUS_MESSAGE ); } MESSAGE::get_admin()->set_command_immediately( "focus_current_view" ); } set_sensitive_view_button(); set_toggle_view_button(); toggle_maximize_rightpane(); if( present && emb_mes ) m_win_main.present(); } // 2paneの時にboard <-> article 切替え void Core::toggle_article() { const bool present = true; // 画像ウィンドウが表示されている場合 if( ! SESSION::get_embedded_img() && SESSION::is_shown_win_img() && SESSION::is_focus_win_img() ){ if( SESSION::focused_admin() == SESSION::FOCUS_ARTICLE ) switch_article( present ); else switch_board( present ); } else if( SESSION::focused_admin() == SESSION::FOCUS_ARTICLE ) switch_board( present ); else switch_article( present ); } // 左移動 void Core::switch_leftview() { const bool present = true; int next_admin = SESSION::focused_admin(); // 画像ウィンドウが表示されている場合 if( ! SESSION::get_embedded_img() && SESSION::is_shown_win_img() && SESSION::is_focus_win_img() ){ next_admin = SESSION::FOCUS_IMAGE; } for(;;){ if( next_admin == SESSION::FOCUS_IMAGE ) next_admin = SESSION::FOCUS_ARTICLE; else if( next_admin == SESSION::FOCUS_ARTICLE ) next_admin = SESSION::FOCUS_BOARD; else if( next_admin == SESSION::FOCUS_BOARD ) next_admin = SESSION::FOCUS_SIDEBAR; else break; if( next_admin == SESSION::FOCUS_SIDEBAR && ! BBSLIST::get_admin()->empty() ){ switch_sidebar( std::string(), present ); break; } else if( next_admin == SESSION::FOCUS_BOARD && ! BOARD::get_admin()->empty() ){ switch_board( present ); break; } else if( next_admin == SESSION::FOCUS_ARTICLE && ! ARTICLE::get_admin()->empty() ){ switch_article( present ); break; } } } // 右移動 void Core::switch_rightview() { const bool present = true; int next_admin = SESSION::focused_admin(); for(;;){ if( next_admin == SESSION::FOCUS_SIDEBAR ) next_admin = SESSION::FOCUS_BOARD; else if( next_admin == SESSION::FOCUS_BOARD ) next_admin = SESSION::FOCUS_ARTICLE; else if( next_admin == SESSION::FOCUS_ARTICLE ) next_admin = SESSION::FOCUS_IMAGE; else break; if( next_admin == SESSION::FOCUS_BOARD && ! BOARD::get_admin()->empty() ){ switch_board( present ); break; } else if( next_admin == SESSION::FOCUS_ARTICLE && ( ! ARTICLE::get_admin()->empty() || ( SESSION::get_embedded_mes() && ! MESSAGE::get_admin()->empty() ) ) ){ switch_article( present ); break; } else if( next_admin == SESSION::FOCUS_IMAGE && ! IMAGE::get_admin()->empty() ){ switch_image( present ); break; } } } // ブラウザで開く void Core::open_by_browser( const std::string& url ) { if( url.empty() ) return; std::string command_openurl = CONFIG::get_command_openurl(); if( !command_openurl.empty() ){ std::string tmp_url = url; size_t tmp_url_length = tmp_url.length(); // urlの先頭と最後のの " を取る while( *tmp_url.c_str() == '\"' ) tmp_url = tmp_url.substr( 1 ); while( tmp_url.c_str()[ tmp_url_length - 1 ] == '\"' ) { tmp_url = tmp_url.substr( 0, tmp_url_length - 1 ); --tmp_url_length; } command_openurl = MISC::replace_str( command_openurl, "%LINK", tmp_url ); command_openurl = MISC::replace_str( command_openurl, "%s", tmp_url ); #ifdef _DEBUG std::cout << "spawn url = " << tmp_url << " command = " << command_openurl << std::endl; #endif Glib::spawn_command_line_async( command_openurl ); } } // // 画像インジケータ表示 // void Core::show_imagetab() { if( SESSION::get_embedded_img() && ! m_imagetab_shown ){ // ツールバーの位置がサイドバーの右側の時はツールバーの下に挿入する int pos = 0; if( SESSION::get_show_main_toolbar() && SESSION::get_toolbar_pos() == SESSION::TOOLBAR_POS_RIGHT && SESSION::get_mode_pane() == SESSION::MODE_2PANE ) pos = 1; m_vbox_article.pack_start( IMAGE::get_admin()->tab(), Gtk::PACK_SHRINK ); m_vbox_article.reorder_child( IMAGE::get_admin()->tab(), pos ); m_win_main.show_all_children(); m_imagetab_shown = true; } } // // 画像インジケータを隠す // void Core::hide_imagetab() { if( m_imagetab_shown ){ m_vbox_article.remove( IMAGE::get_admin()->tab() ); m_win_main.show_all_children(); m_imagetab_shown = false; } } // // 板にdatファイルをインポートする // void Core::import_dat( const std::string& url_board, const std::list< std::string > list_files ) { if( ! list_files.size() ) return; const std::string url_subject = DBTREE::url_subject( url_board ); #ifdef _DEBUG std::cout << "Core::import_dat url = " << url_subject << std::endl; #endif CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; info.type = TYPE_THREAD; std::list< std::string >::const_iterator it = list_files.begin(); for(; it != list_files.end(); ++it ){ const std::string& filename = ( *it ); #ifdef _DEBUG std::cout << filename << std::endl; #endif std::string url = DBTREE::board_import_dat( url_subject, filename ); if( ! url.empty() ){ info.url = url; list_info.push_back( info ); } } if( list_info.size() ){ CORE::core_set_command( "open_board" , url_subject, "true" , "auto" ); CORE::SBUF_set_list( list_info ); BOARD::get_admin()->set_command( "draw_bg_articles", url_subject ); } } // サイドバー更新チェック // open : 更新があったらタブで開く void Core::check_update( const bool open ) { if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( NULL, "オフラインです" ); mdiag.run(); return; } if( SESSION::get_sidebar_current_url() != URL_BBSLISTVIEW ){ // 閉じていたら開く if( ! SESSION::show_sidebar() ){ const int admin = SESSION::focused_admin(); toggle_sidebar(); switch( admin ){ case SESSION::FOCUS_BOARD: switch_board( false ); break; case SESSION::FOCUS_ARTICLE: switch_article( false ); break; } } if( ! open ) BBSLIST::get_admin()->set_command( "check_update_root", SESSION::get_sidebar_current_url() ); else BBSLIST::get_admin()->set_command( "check_update_open_root", SESSION::get_sidebar_current_url() ); } } jd-2.8.7-140104/src/core.h0000644000076400010400000002226511577662613011505 0ustar // ライセンス: GPL2 // // コアクラス // #ifndef _CORE_H #define _CORE_H #include #include #include #include "skeleton/dispatchable.h" #include "skeleton/imgbutton.h" #include "skeleton/hpaned.h" #include "skeleton/vpaned.h" #include "skeleton/notebook.h" #include "skeleton/vbox.h" #include "command_args.h" class JDWinMain; namespace BOARD { class BoardAdmin; } namespace BBSLIST { class BBSListAdmin; } namespace ARTICLE { class ArticleAdmin; } namespace IMAGE { class ImageAdmin; } namespace MESSAGE { class MessageAdmin; } enum { IMGVIEW_WINDOW = 0, IMGVIEW_EMB, IMGVIEW_NO }; namespace CORE { class MainToolBar; class DND_Manager; class Core : public SKELETON::Dispatchable { std::list< COMMAND_ARGS > m_list_command; sigc::connection m_sigc_switch_page; JDWinMain& m_win_main; SKELETON::JDHPaned m_hpaned; // サイドバー Gtk::Widget* m_sidebar; // (縦/横) 3ペーンモード時の右側ペーン SKELETON::JDVPaned m_vpaned_r; SKELETON::JDHPaned m_hpaned_r; // 右ペーンで使用するwidget SKELETON::JDVBox m_vbox_article; SKELETON::JDVBox m_vbox_toolbar; SKELETON::JDNotebook m_notebook_right; bool m_imagetab_shown; SKELETON::JDVPaned m_vpaned_message; // 埋め込み書き込みビュー用 // ツールバー MainToolBar* m_toolbar; // タイトルに表示する文字列 // set_maintitle() 参照 std::string m_title; Gtk::MenuBar* m_menubar; Gtk::MenuItem *m_menuitem_prevview; Gtk::MenuItem *m_menuitem_nextview; Glib::RefPtr< Gtk::ActionGroup > m_action_group; Glib::RefPtr< Gtk::UIManager > m_ui_manager; bool m_enable_menuslot; // 初期設定中 bool m_init; // セッション保存までのカウンタ int m_count_savesession; public: Core( JDWinMain& win_main ); virtual ~Core(); Gtk::Widget* get_toplevel(); // init = true なら初回起動 // skip_setupdiag = true なら初回起動時にセットアップダイアログ非表示 void run( const bool init, const bool skip_setupdiag ); void set_command( const COMMAND_ARGS& command ); // セッション保存 void save_session(); private: bool is_3pane(); bool is_all_admin_empty(); Gtk::Paned* get_rpane(); SKELETON::PaneControl* get_rpctrl(); void pack_widget( bool unpack ); void create_toolbar(); // 初回起動時のセットアップ void first_setup(); void set_maintitle(); void slot_realize(); void slot_style_changed( Glib::RefPtr< Gtk::Style > ); void slot_activate_menubar(); void slot_activate_historymenu(); void slot_prevview(); void slot_nextview(); void slot_clear_board(); void slot_clear_thread(); void slot_clear_close(); void slot_clear_closeboard(); void slot_clear_closeimg(); void slot_clear_search(); void slot_clear_name(); void slot_clear_mail(); bool open_color_diag( std::string title, int id ); void toggle_menubar(); void toggle_statbar(); void toggle_flat_button(); void toggle_draw_toolbarback(); void toggle_post_mark(); void toggle_sidebar(); void slot_show_hide_leftpane( int mode ); virtual void callback_dispatch(); // coreが自前でするコマンド処理 void exec_command(); // 起動完了直後に実行する処理 void exec_command_after_boot(); // フォーカス回復 void restore_focus( const bool force, const bool present ); // メインタイマー bool slot_timeout( int timer_number ); // 右ペーンのnotebookのタブの切替え void slot_switch_page( GtkNotebookPage*, guint page ); // 右ペーンのnotebookのページ番号 int get_right_current_page(); // 右ペーンのnotebookのページをセット void set_right_current_page( int page ); bool slot_focus_out_event( GdkEventFocus* ev ); bool slot_focus_in_event( GdkEventFocus* ev ); // URL entryでenterを押した void slot_active_url(); // あるadminがemptyになったので他のadminにスイッチ void empty_page( const std::string& url ); void set_toggle_view_button(); void set_sensitive_view_button(); void toggle_maximize_rightpane(); void switch_article( const bool present ); void switch_board( const bool present ); void switch_sidebar( const std::string& url, const bool present ); void switch_image( const bool present ); void switch_message( const bool present ); void toggle_article(); void switch_leftview(); void switch_rightview(); void open_by_browser( const std::string& url ); // 画像インジケータ表示/非表示 void show_imagetab(); void hide_imagetab(); // 板にdatファイルをインポートする void import_dat( const std::string& url_board, const std::list< std::string > list_files ); // サイドバー更新チェック // open : 更新があったらタブで開く void check_update( const bool open ); // // メニュー関係( menuslots.cpp の中に記述) // void slot_openurl(); void slot_toggle_online(); void slot_toggle_login2ch(); void slot_toggle_loginbe(); void slot_toggle_loginp2(); void slot_reload_list(); void slot_quit(); /// void slot_toggle_since( const int mode ); void slot_toggle_write( const int mode ); void slot_toggle_toolbarmain(); void slot_toggle_toolbarpos( const int pos ); void slot_toggle_toolbarbbslist(); void slot_toggle_toolbarboard(); void slot_toggle_toolbararticle(); void slot_toggle_tabboard(); void slot_toggle_tabarticle(); void slot_toggle_2pane(); void slot_toggle_3pane(); void slot_toggle_v3pane(); void slot_toggle_fullscreen(); void slot_toggle_winmsg(); void slot_toggle_embmsg(); void slot_toggle_msg_wrap(); void slot_toggle_imgview( const int mode ); void slot_toggle_use_imgpopup(); void slot_toggle_use_inlineimg(); void slot_toggle_show_ssspicon(); void slot_setup_boarditem_column(); void slot_setup_mainitem(); void slot_setup_sidebaritem(); void slot_setup_boarditem(); void slot_setup_articleitem(); void slot_setup_searchitem(); void slot_setup_msgitem(); void slot_setup_boarditem_menu(); void slot_setup_articleitem_menu(); // void slot_bbslist_pref(); void slot_board_pref(); void slot_article_pref(); void slot_image_pref(); void slot_toggle_restore_views(); void slot_toggle_fold_message(); void slot_toggle_save_post_log(); void slot_toggle_save_post_history(); void slot_toggle_use_mosaic(); void slot_toggle_use_machi_offlaw(); void slot_toggle_tabbutton(); void slot_toggle_popupwarpmode(); void slot_shortmargin_popup(); void slot_toggle_emacsmode(); void slot_setup_mouse(); void slot_setup_key(); void slot_setup_button(); void slot_changefont_main(); void slot_changefont_popup(); void slot_changefont_tree(); void slot_changecolor_char(); void slot_changecolor_back(); void slot_changecolor_char_tree(); void slot_changecolor_back_tree(); void slot_setup_fontcolor(); void slot_setup_proxy(); void slot_setup_browser(); void slot_setup_passwd(); void slot_toggle_ipv6(); void slot_setup_abone(); void slot_setup_abone_thread(); void slot_toggle_abone_transp_chain(); void slot_toggle_abone_icase_wchar(); void slot_setup_live(); void slot_usrcmd_pref(); void slot_filter_pref(); void slot_aboutconfig(); void slot_clear_privacy(); void slot_clear_post_log(); void slot_clear_post_history(); void slot_delete_all_images(); // void slot_live_start_stop(); void slot_search_cache_board(); void slot_search_cache(); void slot_show_cache_board(); void slot_show_cache(); void slot_search_title(); void slot_check_update_root(); void slot_check_update_open_root(); void slot_cancel_check_update(); void slot_edit_favorite(); void slot_show_postlog(); void slot_import_dat(); void slot_show_sidebarboard(); void slot_create_vboard(); // void slot_show_bbs(); void slot_show_old2ch(); void slot_show_manual(); void slot_show_about(); }; Core* get_instance(); } #endif jd-2.8.7-140104/src/cssmanager.cpp0000644000076400010400000005303311636104666013223 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "dbtree/node.h" #include "jdlib/miscutil.h" #include "jdlib/miscgtk.h" #include "jdlib/jdregex.h" #include "cssmanager.h" #include "colorid.h" #include "cache.h" #include enum { SIZE_OF_HEAP = 16 * 1024 }; CORE::Css_Manager* instance_css_manager = NULL; CORE::Css_Manager* CORE::get_css_manager() { if( ! instance_css_manager ) instance_css_manager = new Css_Manager(); assert( instance_css_manager ); return instance_css_manager; } void CORE::delete_css_manager() { if( instance_css_manager ) delete instance_css_manager; instance_css_manager = NULL; } /////////////////////////////////////////////// using namespace CORE; enum { SIZETYPE_PX = 0, SIZETYPE_EM }; Css_Manager::Css_Manager() : m_heap( SIZE_OF_HEAP ), m_last_dom( NULL ) { #ifdef _DEBUG std::cout << "Css_Manager::Css_Manager\n"; #endif set_default_css(); read_css(); if( ! read_html() ) set_default_html(); } void Css_Manager::clear_property( CSS_PROPERTY* css ) { memset( css, 0, sizeof( CSS_PROPERTY ) ); css->color = -1; css->bg_color = -1; css->border_left_color = -1; css->border_right_color = -1; css->border_top_color = -1; css->border_bottom_color = -1; css->align = ALIGN_LEFT; } // // ユーザ設定の色取得 // std::string Css_Manager::get_color( int colorid ) { colorid -= USRCOLOR_BASE; return m_colors[ colorid ]; } // // クラス名からID取得 // int Css_Manager::get_classid( const std::string& classname ) { int id = 0; std::list< std::string >::iterator it = m_css_class.begin(); for( ; it != m_css_class.end(); ++it, ++id ) if( ( *it ) == classname ) return id; return -1; } // // クラス名登録 // int Css_Manager::register_class( const std::string& classname ) { #ifdef _DEBUG std::cout << "Css_Manager::register_class name = " << classname << std::endl; #endif m_css_class.push_back( classname ); return get_classid( classname ); } // // デフォルトのcssをセット // void Css_Manager::set_default_css() { CSS_PROPERTY css; //////////////// // body clear_property( &css ); css.padding_bottom_em = 2; set_property( "body", css ); ///////////////// // res clear_property( &css ); css.mrg_left_em = 0.8; css.mrg_right_em = 0.8; css.mrg_bottom_em = 1; set_property( "res", css ); ///////////////// // separator clear_property( &css ); css.align = ALIGN_CENTER; css.color = COLOR_BACK; css.padding_top_px = 4; css.padding_bottom_px = 4; css.mrg_bottom_em = 1; set_property( "separator", css ); ///////////////// // comment clear_property( &css ); css.mrg_left_em = 0.8; css.mrg_right_em = 0.8; css.mrg_bottom_em = 1; set_property( "comment", css ); ///////////////// // title clear_property( &css ); set_property( "title", css ); ///////////////// // mes clear_property( &css ); css.padding_left_em = 1.5; set_property( "mes", css ); ///////////////// // imgpopup clear_property( &css ); css.border_left_width_px = 1; css.border_right_width_px = 1; css.border_top_width_px = 1; css.border_bottom_width_px = 1; set_property( "imgpopup", css ); } // // css 読み込み // bool Css_Manager::read_css() { const std::string css_file = CACHE::path_css(); #ifdef _DEBUG std::cout << "Css_Manager::read_css file = " << css_file << std::endl; #endif std::string css_data; if( ! CACHE::load_rawdata( css_file, css_data ) ){ // 旧バージョンとの互換性のため if( ! CACHE::load_rawdata( CACHE::path_css_old(), css_data ) ) return false; } #ifdef _DEBUG std::cout << "css : \n" << css_data << "--------------\n\n"; #endif // 改行を取り除く css_data = MISC::remove_str( css_data, "\n" ); // コメントを取り除く css_data = MISC::remove_str( css_data, "/*", "*/" ); size_t start_pos = 0, l_pos = 0, r_pos = 0; while( ( l_pos = css_data.find( "{", start_pos ) ) != std::string::npos && ( r_pos = css_data.find( "}", l_pos + 1 ) ) != std::string::npos ) { // セレクタ部分を取り出す std::string selector = MISC::remove_spaces( css_data.substr( start_pos, l_pos - start_pos ) ); start_pos = r_pos + 1; if( selector.find( "." ) == 0 ) selector.erase( 0, 1 ); if( selector.empty() ) break; // {中身}を取り出す std::string range = css_data.substr( l_pos + 1, r_pos - l_pos - 1 ); #ifdef _DEBUG std::cout << "selector = " << selector << std::endl; #endif // 中身を";"で分ける std::list< std::string > properties = MISC::StringTokenizer( range, ';' ); // プロパティペア(名前, 値)の作成 std::map< std::string, std::string > css_pair; std::list< std::string >::iterator it = properties.begin(); while( it != properties.end() ) { size_t colon = (*it).find( ":" ); std::string key = MISC::remove_spaces( (*it).substr( 0, colon ) ); std::string value = MISC::remove_spaces( (*it).substr( colon + 1 ) ); #ifdef _DEBUG std::cout << " key = " << key << " value = " << value << std::endl; #endif css_pair.insert( make_pair( key, value ) ); ++it; } // 各プロパティを作成 if( css_pair.size() ) set_property( selector, create_property( css_pair ) ); } return true; } // CSS_PROPERTY を作成 #define GET_PROPVAL() {\ std::string sizestr = value; \ size = atof( sizestr.c_str() ); \ type = SIZETYPE_PX; \ if( sizestr.find( "em" ) != std::string::npos ) type = SIZETYPE_EM; \ }while(0) CSS_PROPERTY Css_Manager::create_property( std::map< std::string, std::string >& css_pair ) { CSS_PROPERTY css; clear_property( &css ); JDLIB::Regex regex; const size_t offset = 0; const bool icase = true; // 大文字小文字区別しない const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::map< std::string, std::string >::iterator it = css_pair.begin(); for( ; it != css_pair.end(); ++it ) { const std::string key = (*it).first; const std::string value = (*it).second; // background-color if( key == "background-color" ) { #ifdef _DEBUG std::cout << "background-color = " << value << std::endl; #endif m_colors.push_back( MISC::htmlcolor_to_str( value ) ); css.bg_color = USRCOLOR_BASE + m_colors.size()-1; } // border-color else if( key == "border-color" ) { #ifdef _DEBUG std::cout << "border-color = " << value << std::endl; #endif m_colors.push_back( MISC::htmlcolor_to_str( value ) ); int colorid = USRCOLOR_BASE + m_colors.size()-1; css.border_left_color = colorid; css.border_right_color = colorid; css.border_top_color = colorid; css.border_bottom_color = colorid; } // border-*-color else if( regex.exec( "border-([a-z]+)-color", key, offset, icase, newline, usemigemo, wchar ) ) { std::string mode = regex.str( 1 ); #ifdef _DEBUG std::cout << "border-" << mode << "-color = " << value << std::endl; #endif m_colors.push_back( MISC::htmlcolor_to_str( value ) ); int colorid = USRCOLOR_BASE + m_colors.size()-1; if( mode == "left" ) css.border_left_color = colorid; else if( mode == "right" ) css.border_right_color = colorid; else if( mode == "top" ) css.border_top_color = colorid; else if( mode == "bottom" ) css.border_bottom_color = colorid; } // border-style else if( key == "border-style" ) { #ifdef _DEBUG std::cout << "border-style = " << value << std::endl; #endif if( value == "solid" ) css.border_style = BORDER_SOLID; } // border-width else if( key == "border-width" ) { int type; double size; GET_PROPVAL(); #ifdef _DEBUG std::cout << "border-width = " << size << std::endl; #endif if( type == SIZETYPE_EM ) { css.border_left_width_em = size; css.border_right_width_em = size; css.border_right_width_em = size; css.border_bottom_width_em = size; } else { css.border_left_width_px = (int)size; css.border_right_width_px = (int)size; css.border_top_width_px = (int)size; css.border_bottom_width_px = (int)size; } } // border-*-width else if( regex.exec( "border-([a-z]+)-width", key, offset, icase, newline, usemigemo, wchar ) ) { std::string mode = regex.str( 1 ); int type; double size; GET_PROPVAL(); #ifdef _DEBUG std::cout << "border-" << mode << "-width size = " << size << " type = " << type << std::endl; #endif if( mode == "left" ){ if( type == SIZETYPE_EM ) css.border_left_width_em = size; else css.border_left_width_px = (int)size; } else if( mode == "right" ){ if( type == SIZETYPE_EM ) css.border_right_width_em = size; else css.border_right_width_px = (int)size; } else if( mode == "top" ){ if( type == SIZETYPE_EM ) css.border_top_width_em = size; else css.border_top_width_px = (int)size; } else if( mode == "bottom" ){ if( type == SIZETYPE_EM ) css.border_bottom_width_em = size; else css.border_bottom_width_px = (int)size; } } // color else if( key == "color" ) { #ifdef _DEBUG std::cout << "color = " << value << std::endl; #endif m_colors.push_back( MISC::htmlcolor_to_str( value ) ); css.color = USRCOLOR_BASE + m_colors.size()-1; } // margin else if( key == "margin" ) { int type; double size; GET_PROPVAL(); #ifdef _DEBUG std::cout << "margin = " << size << std::endl; #endif if( type == SIZETYPE_EM ) { css.mrg_left_em = size; css.mrg_right_em = size; css.mrg_right_em = size; css.mrg_bottom_em = size; } else { css.mrg_left_px = (int)size; css.mrg_right_px = (int)size; css.mrg_top_px = (int)size; css.mrg_bottom_px = (int)size; } } // margin-* else if( regex.exec( "margin-([a-z]+)", key, offset, icase, newline, usemigemo, wchar ) ) { std::string mode = regex.str( 1 ); int type; double size; GET_PROPVAL(); #ifdef _DEBUG std::cout << "margin-" << mode << " size = " << size << " type = " << type << std::endl; #endif if( mode == "left" ){ if( type == SIZETYPE_EM ) css.mrg_left_em = size; else css.mrg_left_px = (int)size; } else if( mode == "right" ){ if( type == SIZETYPE_EM ) css.mrg_right_em = size; else css.mrg_right_px = (int)size; } else if( mode == "top" ){ if( type == SIZETYPE_EM ) css.mrg_top_em = size; else css.mrg_top_px = (int)size; } else if( mode == "bottom" ){ if( type == SIZETYPE_EM ) css.mrg_bottom_em = size; else css.mrg_bottom_px = (int)size; } } // padding else if( key == "padding" ) { int type; double size; GET_PROPVAL(); #ifdef _DEBUG std::cout << "padding = " << size << std::endl; #endif if( type == SIZETYPE_EM ) { css.padding_left_em = size; css.padding_right_em = size; css.padding_top_em = size; css.padding_bottom_em = size; } else { css.padding_left_px = (int)size; css.padding_right_px = (int)size; css.padding_top_px = (int)size; css.padding_bottom_px = (int)size; } } // padding-* else if( regex.exec( "padding-([a-z]+)", key, offset, icase, newline, usemigemo, wchar ) ) { std::string mode = regex.str( 1 ); int type; double size; GET_PROPVAL(); #ifdef _DEBUG std::cout << "padding-" << mode << " size = " << size << " type = " << type << std::endl; #endif if( mode == "left" ){ if( type == SIZETYPE_EM ) css.padding_left_em = size; else css.padding_left_px = (int)size; } else if( mode == "right" ){ if( type == SIZETYPE_EM ) css.padding_right_em = size; else css.padding_right_px = (int)size; } else if( mode == "top" ){ if( type == SIZETYPE_EM ) css.padding_top_em = size; else css.padding_top_px = (int)size; } else if( mode == "bottom" ){ if( type == SIZETYPE_EM ) css.padding_bottom_em = size; else css.padding_bottom_px = (int)size; } } // text-align else if( key == "text-align" ) { #ifdef _DEBUG std::cout << "text-align = " << value << std::endl; #endif if( value == "left" ) css.align = ALIGN_LEFT; else if( value == "center" ) css.align = ALIGN_CENTER; else if( value == "right" ) css.align = ALIGN_RIGHT; } } return css; } // // プロパティ取得 // CSS_PROPERTY Css_Manager::get_property( const int id ) { return m_css[ id ]; } // // プロパティをセット // void Css_Manager::set_property( const std::string& classname, const CSS_PROPERTY& css ) { if( classname.empty() ) return; #ifdef _DEBUG std::cout << "Css_Manager::set_property class = " << classname << std::endl; #endif int id = get_classid( classname ); if( id < 0 ) id = register_class( classname ); m_css.erase( id ); m_css.insert( std::pair< int, CSS_PROPERTY >( id, css ) ); } // // 文字の高さを与えてemをセット // void Css_Manager::set_size( CSS_PROPERTY* css, double height ) { if( ! css ) return; if( ! height ) return; css->padding_left = 0; css->padding_right = 0; css->padding_top = 0; css->padding_bottom = 0; if( css->padding_left_px > 0 ) css->padding_left = css->padding_left_px; if( css->padding_right_px > 0 ) css->padding_right = css->padding_right_px; if( css->padding_top_px > 0 ) css->padding_top = css->padding_top_px; if( css->padding_bottom_px > 0 ) css->padding_bottom = css->padding_bottom_px; if( css->padding_left_em > 0 ) css->padding_left = (int)(height * css->padding_left_em); if( css->padding_right_em > 0 ) css->padding_right = (int)(height * css->padding_right_em); if( css->padding_top_em > 0 ) css->padding_top = (int)(height * css->padding_top_em); if( css->padding_bottom_em > 0 ) css->padding_bottom = (int)(height * css->padding_bottom_em); /////////////////////////////////////// css->mrg_left = 0; css->mrg_right = 0; css->mrg_top = 0; css->mrg_bottom = 0; if( css->mrg_left_px > 0 ) css->mrg_left = css->mrg_left_px; if( css->mrg_right_px > 0 ) css->mrg_right = css->mrg_right_px; if( css->mrg_top_px > 0 ) css->mrg_top = css->mrg_top_px; if( css->mrg_bottom_px > 0 ) css->mrg_bottom = css->mrg_bottom_px; if( css->mrg_left_em > 0 ) css->mrg_left = (int)(height * css->mrg_left_em); if( css->mrg_right_em > 0 ) css->mrg_right = (int)(height * css->mrg_right_em); if( css->mrg_top_em > 0 ) css->mrg_top = (int)(height * css->mrg_top_em); if( css->mrg_bottom_em > 0 ) css->mrg_bottom = (int)(height * css->mrg_bottom_em); /////////////////////////////////////// css->border_left_width = 0; css->border_right_width = 0; css->border_top_width = 0; css->border_bottom_width = 0; if( css->border_left_width_px > 0 ) css->border_left_width = css->border_left_width_px; if( css->border_right_width_px > 0 ) css->border_right_width = css->border_right_width_px; if( css->border_top_width_px > 0 ) css->border_top_width = css->border_top_width_px; if( css->border_bottom_width_px > 0 ) css->border_bottom_width = css->border_bottom_width_px; if( css->border_left_width_em > 0 ) css->border_left_width = (int)(height * css->border_left_width_em); if( css->border_right_width_em > 0 ) css->border_right_width = (int)(height * css->border_right_width_em); if( css->border_top_width_em > 0 ) css->border_top_width = (int)( height * css->border_top_width_em); if( css->border_bottom_width_em > 0 ) css->border_bottom_width = (int)(height * css->border_bottom_width_em); /////////////////////////////////////// css->padding_left += css->border_left_width; css->padding_right += css->border_right_width; css->padding_top += css->border_top_width; css->padding_bottom += css->border_bottom_width; } // // DOM作成 // DOM* Css_Manager::create_domnode( int type ) { DOM* tmpdom = ( DOM* ) m_heap.heap_alloc( sizeof( DOM ) ); tmpdom->nodetype = type; if( m_last_dom ) m_last_dom->next_dom = tmpdom; else m_dom = tmpdom; m_last_dom = tmpdom; return tmpdom; } DOM* Css_Manager::create_divnode( const std::string& classname ) { int classid = get_classid( classname ); if( classid < 0 ) return NULL; #ifdef _DEBUG std::cout << "Css_Manager::create_divnode name = " << classname << std::endl; #endif DOM* tmpdom = create_domnode( DOMNODE_DIV ); tmpdom->dat = classid; return tmpdom; } DOM* Css_Manager::create_blocknode( int blockid ) { DOM* tmpdom = create_domnode( DOMNODE_BLOCK ); tmpdom->dat = blockid; #ifdef _DEBUG std::cout << "Css_Manager::create_blocknode id = " << blockid << std::endl; #endif return tmpdom; } DOM* Css_Manager::create_textnode( const char* text ) { int lng = strlen( text ); if( ! lng ) return NULL; #ifdef _DEBUG std::cout << "Css_Manager::create_textnode text = " << text << std::endl; #endif DOM* tmpdom = create_domnode( DOMNODE_TEXT ); tmpdom->chardat = ( char* ) m_heap.heap_alloc( lng ); strncpy( tmpdom->chardat, text, lng ); return tmpdom; } DOM* Css_Manager::create_imagenode() { #ifdef _DEBUG std::cout << "Css_Manager::create_imagenode\n"; #endif DOM* tmpdom = create_domnode( DOMNODE_IMAGE ); return tmpdom; } // // デフォルトのhtmlをセット // void Css_Manager::set_default_html() { create_divnode( "title" ); create_blocknode( DBTREE::BLOCK_NUMBER ); create_textnode( " " ); create_blocknode( DBTREE::BLOCK_NAMELINK ); create_textnode( ":" ); create_blocknode( DBTREE::BLOCK_NAME ); create_textnode( " " ); create_blocknode( DBTREE::BLOCK_MAIL ); create_textnode( ": " ); create_blocknode( DBTREE::BLOCK_DATE ); create_textnode( " " ); create_blocknode( DBTREE::BLOCK_ID_NAME ); create_divnode( "mes" ); create_blocknode( DBTREE::BLOCK_MES ); create_imagenode(); } // // html読み込み // bool Css_Manager::read_html() { const std::string htmlfile = CACHE::path_reshtml(); #ifdef _DEBUG std::cout << "Css_Manager::read_html file = " << htmlfile << std::endl; #endif std::string html; if( ! CACHE::load_rawdata( htmlfile, html ) ){ // 旧バージョンとの互換性のため if( ! CACHE::load_rawdata( CACHE::path_reshtml_old(), html ) ) return false; } #ifdef _DEBUG std::cout << "html : \n" << html << "--------------\n\n"; #endif // 改行を消した後に '>' でhtmlを分ける std::list< std::string > blocks = MISC::StringTokenizer( MISC::remove_str( html, "\n" ), '>' ); JDLIB::Regex regex; const size_t offset = 0; const bool icase = true; // 大文字小文字区別しない const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::list< std::string >::iterator it_block = blocks.begin(); for( ; it_block != blocks.end(); ++it_block ){ std::string block = ( *it_block ); #ifdef _DEBUG std::cout << "block = " << block << std::endl; #endif std::string::size_type pos = block.find( "<" ); if( pos == std::string::npos ){ create_textnode( block.c_str() ); continue; } else if( pos > 0 ){ create_textnode( block.substr( 0, pos ).c_str() ); block = block.substr( pos ); } block = MISC::remove_space( MISC::tolower_str( block.substr( 1 ) ) ); #ifdef _DEBUG std::cout << "tag = " << block << std::endl; #endif if( regex.exec( "div +class=\"([^\"]*)\"", block, offset, icase, newline, usemigemo, wchar ) ){ #ifdef _DEBUG std::cout << "name = " << regex.str( 1 ) << std::endl; #endif create_divnode( regex.str( 1 ) ); } else if( block.find( "number" ) == 0 ) create_blocknode( DBTREE::BLOCK_NUMBER ); else if( block.find( "namelink" ) == 0 ) create_blocknode( DBTREE::BLOCK_NAMELINK ); else if( block.find( "name" ) == 0 ) create_blocknode( DBTREE::BLOCK_NAME ); else if( block.find( "mail" ) == 0 ) create_blocknode( DBTREE::BLOCK_MAIL ); else if( block.find( "date" ) == 0 ) create_blocknode( DBTREE::BLOCK_DATE ); else if( block.find( "id" ) == 0 ) create_blocknode( DBTREE::BLOCK_ID_NAME ); else if( block.find( "message" ) == 0 ) create_blocknode( DBTREE::BLOCK_MES ); else if( block.find( "image" ) == 0 ) create_imagenode(); } return true; } jd-2.8.7-140104/src/cssmanager.h0000644000076400010400000000777611235621036012673 0ustar // ライセンス: GPL2 // // css 管理クラス // #ifndef _CSSMANAGER_H #define _CSSMANAGER_H #include #include #include #include #include "jdlib/heap.h" namespace CORE { // cssプロパティ struct CSS_PROPERTY { int align; // text-align int border_style; //////////////////// // 色 // >=0 のときは色を塗る int color; int bg_color; int border_left_color; int border_right_color; int border_top_color; int border_bottom_color; //////////////////// int padding_left; int padding_right; int padding_top; int padding_bottom; int padding_left_px; int padding_right_px; int padding_top_px; int padding_bottom_px; double padding_left_em; double padding_right_em; double padding_top_em; double padding_bottom_em; //////////////////// int mrg_left; int mrg_right; int mrg_top; int mrg_bottom; int mrg_left_px; int mrg_right_px; int mrg_top_px; int mrg_bottom_px; double mrg_left_em; double mrg_right_em; double mrg_top_em; double mrg_bottom_em; //////////////////// int border_left_width; int border_right_width; int border_top_width; int border_bottom_width; int border_left_width_px; int border_right_width_px; int border_top_width_px; int border_bottom_width_px; double border_left_width_em; double border_right_width_em; double border_top_width_em; double border_bottom_width_em; }; // text-align enum{ ALIGN_LEFT = 0, ALIGN_CENTER, ALIGN_RIGHT }; // border-style enum{ BORDER_NONE = 0, BORDER_SOLID }; ///////////////////////////////////////// // DOM構造 struct DOM { int nodetype; int dat; char* chardat; DOM* next_dom; }; // nodetype enum{ DOMNODE_DIV, DOMNODE_BLOCK, DOMNODE_TEXT, DOMNODE_IMAGE, }; ///////////////////////////////////////// class Css_Manager { JDLIB::HEAP m_heap; std::map< int, CSS_PROPERTY > m_css; std::vector< std::string > m_colors; std::list< std::string > m_css_class; DOM* m_dom; DOM* m_last_dom; public: Css_Manager(); virtual ~Css_Manager(){} // ユーザ設定の色取得 std::string get_color( int colorid ); // ユーザ設定の色( 先頭は黒 ) std::vector< std::string >& get_colors() { return m_colors; } // クラス名からID取得 int get_classid( const std::string& classname ); // プロパティ取得 CSS_PROPERTY get_property( const int id ); // 文字の高さを与えてemをセット void set_size( CSS_PROPERTY* css, double height ); // DOM 取得 const DOM* get_dom() const { return m_dom; } private: // クラス名登録 int register_class( const std::string& classname ); // cssプロパティ関係 CSS_PROPERTY create_property( std::map< std::string, std::string >& css_pair ); void set_property( const std::string& classname, const CSS_PROPERTY& css ); void clear_property( CSS_PROPERTY* css ); void set_default_css(); bool read_css(); // DOM関係 DOM* create_domnode( int type ); DOM* create_divnode( const std::string& classname ); DOM* create_blocknode( int blockid ); DOM* create_textnode( const char* text ); DOM* create_imagenode(); void set_default_html(); bool read_html(); }; /////////////////////////////////////// // インターフェース Css_Manager* get_css_manager(); void delete_css_manager(); } #endif jd-2.8.7-140104/src/data_info.h0000644000076400010400000000171611366570436012474 0ustar // データクラス // 関数の引数で使ったり、共有バッファ(sharedbuffer.h)と組み合わて使う #ifndef _DATA_INFO_H #define _DATA_INFO_H #include #include namespace Gtk { class Window; } namespace CORE { class DATA_INFO { public: int type; // type.h で定義されているタイプ Gtk::Window* parent; std::string url; std::string name; std::string path; // treeview の path std::string data; size_t dirid; // ディレクトリID、ディレクトリで無い場合は0 bool expanded; DATA_INFO() { type = 0; parent = NULL; url = std::string(); name = std::string(); path = std::string(); data = std::string(); dirid = 0; expanded = false; } }; typedef std::vector< CORE::DATA_INFO > DATA_INFO_LIST; } #endif jd-2.8.7-140104/src/dbimg/0000755000076400010400000000000012261751610011442 5ustar jd-2.8.7-140104/src/dbimg/delimgcachediag.cpp0000644000076400010400000001211211260143672015216 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "delimgcachediag.h" #ifdef _DEBUG #include "jdlib/misctime.h" #endif #include "cache.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include using namespace DBIMG; DelImgCacheDiag::DelImgCacheDiag() : m_label( "画像キャッシュ削除中・・・\n\nしばらくお待ち下さい" ) { add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ) ->signal_clicked().connect( sigc::mem_fun(*this, &DelImgCacheDiag::slot_cancel_clicked ) ); set_title( "JD 画像キャッシュ削除中" ); const int mrg = 8; get_vbox()->set_spacing( mrg ); set_border_width( mrg ); get_vbox()->pack_start( m_label, Gtk::PACK_SHRINK ); show_all_children(); } DelImgCacheDiag::~DelImgCacheDiag() { #ifdef _DEBUG std::cout << "DelImgCacheDiag::~DelImgCacheDiag\n"; #endif slot_cancel_clicked(); } bool DelImgCacheDiag::on_expose_event( GdkEventExpose* event ) { #ifdef _DEBUG std::cout << "DelImgCacheDiag::on_expose_event\n"; #endif // スレッドを起動してキャッシュ削除 if( ! m_thread.is_running() ){ m_stop = false; if( ! m_thread.create( ( STARTFUNC ) launcher, ( void * ) this, JDLIB::NODETACH ) ){ MISC::ERRMSG( "DelImgCacheDiag::on_expose_event : could not start thread" ); } } return Gtk::Dialog::on_expose_event( event ); } void* DelImgCacheDiag::launcher( void* dat ) { DelImgCacheDiag* tt = ( DelImgCacheDiag * ) dat; tt->main_thread(); return 0; } // 画像キャッシュ削除スレッド void DelImgCacheDiag::main_thread() { #ifdef _DEBUG std::cout << "DelImgCacheDiag::main_thread start\n"; #endif time_t days = 0; // info と 画像キャッシュ std::list< std::string >list_infofile; std::string path_info_root = CACHE::path_img_info_root(); list_infofile = CACHE::get_filelist( path_info_root ); std::list< std::string >::iterator it_info = list_infofile.begin(); for(; ! m_stop && it_info != list_infofile.end(); ++it_info ){ std::string path_info = path_info_root + ( *it_info ); // info ファイルの作成日時を調べて、設定した日時よりも古かったら消す if( CONFIG::get_del_img_day() > 0 ){ days = get_days( path_info ); if( days < CONFIG::get_del_img_day() ) continue; } // 画像ファイル名取得 std::string filename = MISC::get_filename( path_info ); std::string path_file = CACHE::path_img_root() + filename.substr( 0, filename.size() - 5 ); // ".info" を外す #ifdef _DEBUG std::cout << "\ninfo = " << path_info << std::endl; std::cout << "path = " << path_file << std::endl; std::cout << "days = " << days << std::endl; #endif // キャッシュ削除 if( CACHE::file_exists( path_file ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( path_file ) ); // info 削除 if( CACHE::file_exists( path_info ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( path_info ) ); } // あぼーん情報 #ifdef _DEBUG std::cout << "\ndelete abone info\n"; #endif path_info_root = CACHE::path_img_abone_root(); list_infofile = CACHE::get_filelist( path_info_root ); it_info = list_infofile.begin(); for(; ! m_stop && it_info != list_infofile.end(); ++it_info ){ std::string path_info = path_info_root + ( *it_info ); // info ファイルの作成日時を調べて、設定した日時よりも古かったら消す if( CONFIG::get_del_imgabone_day() > 0 ){ days = get_days( path_info ); if( days < CONFIG::get_del_imgabone_day() ) continue; } #ifdef _DEBUG std::cout << "\nabone info = " << path_info << std::endl; std::cout << "days = " << days << std::endl; #endif // info 削除 if( CACHE::file_exists( path_info ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( path_info ) ); } #ifdef _DEBUG std::cout << "DelImgCacheDiag::main_thread end\n"; #endif // アクセシビリティをonにした時に別スレッドでhide()すると // フリーズするので、dispatchしてメインスレッドでhide()する dispatch(); } void DelImgCacheDiag::callback_dispatch() { #ifdef _DEBUG std::cout << "DelImgCacheDiag::callback_dispatch\n"; #endif hide(); } // // ファイルの作成日からの経過日数を計算 // // エラーの時ははマイナスの値が戻る // time_t DelImgCacheDiag::get_days( const std::string& path ) { struct timeval tv; struct timezone tz; gettimeofday( &tv, &tz ); time_t mtime = CACHE::get_filemtime( path ); if( ! mtime ) return -1; return ( tv.tv_sec - mtime ) / ( 60 * 60 * 24 ); } void DelImgCacheDiag::wait() { #ifdef _DEBUG std::cout << "DelImgCacheDiag::wait\n"; #endif m_thread.join(); } void DelImgCacheDiag::slot_cancel_clicked() { #ifdef _DEBUG std::cout << "DelImgCacheDiag::slot_cancel_clicked\n"; #endif m_stop = true; wait(); } jd-2.8.7-140104/src/dbimg/delimgcachediag.h0000644000076400010400000000175011362077452014676 0ustar // ライセンス: GPL2 // 画像キャッシュ削除ダイアログ // // キャンセルボタンを押すとキャッシュの削除を中止する #ifndef _DELIMGCACHEDIAG_H #define _DELIMGCACHEDIAG_H #include "jdlib/jdthread.h" #include "skeleton/dispatchable.h" #include #include namespace DBIMG { class DelImgCacheDiag : public Gtk::Dialog, SKELETON::Dispatchable { Gtk::Label m_label; bool m_stop; // = true にするとスレッド停止 JDLIB::Thread m_thread; public: DelImgCacheDiag(); ~DelImgCacheDiag(); // 画像キャッシュ削除スレッド void main_thread(); static void* launcher( void* dat ); protected: virtual bool on_expose_event( GdkEventExpose* event ); private: virtual void callback_dispatch(); void wait(); void slot_cancel_clicked(); time_t get_days( const std::string& path ); }; } #endif jd-2.8.7-140104/src/dbimg/delimgdiag.h0000644000076400010400000000667611357364652013733 0ustar // ライセンス: GPL2 // 画像削除時の確認ダイアログ #ifndef _DELIMGDIAG_H #define _DELIMGDIAG_H #include "skeleton/prefdiag.h" #include "skeleton/spinbutton.h" #include "config/globalconf.h" #include "cache.h" #include namespace DBIMG { class ImgCacheFrame : public Gtk::Frame { Gtk::VBox m_vbox; Gtk::HBox m_hbox; Gtk::Label m_label; Gtk::Label m_spinlabel; SKELETON::SpinButton m_spin; public: SKELETON::SpinButton& get_spin(){ return m_spin; } ImgCacheFrame() { std::stringstream ss; ss << "現在の画像キャッシュサイズ : " << ( CACHE::get_dirsize( CACHE::path_img_root() ) / 1024 / 1024 ) << "M"; m_label.set_text( ss.str() ); m_spinlabel.set_text_with_mnemonic( "日より以前のキャッシュファイルを消去(_H)" ); m_spinlabel.set_mnemonic_widget( m_spin ); m_spin.set_range( 0, 360 ); m_spin.set_increments( 1, 1 ); m_spin.set_value( CONFIG::get_del_img_day() ); m_hbox.set_border_width( 8 ); m_hbox.set_spacing( 4 ); m_hbox.pack_start( m_spin, Gtk::PACK_SHRINK ); m_hbox.pack_start( m_spinlabel, Gtk::PACK_SHRINK ); m_vbox.set_spacing( 16 ); m_vbox.set_border_width( 8 ); m_vbox.pack_start( m_label, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox, Gtk::PACK_SHRINK ); set_border_width( 8 ); set_label( "画像キャッシュ" ); add( m_vbox ); } }; class ImgAboneFrame : public Gtk::Frame { Gtk::VBox m_vbox; Gtk::HBox m_hbox; Gtk::Label m_spinlabel; SKELETON::SpinButton m_spin; public: SKELETON::SpinButton& get_spin(){ return m_spin; } ImgAboneFrame() { m_spinlabel.set_text_with_mnemonic( "日より以前のあぼ〜ん情報を消去(_A)" ); m_spinlabel.set_mnemonic_widget( m_spin ); m_spin.set_range( 0, 360 ); m_spin.set_increments( 1, 1 ); m_spin.set_value( CONFIG::get_del_imgabone_day() ); m_hbox.set_border_width( 16 ); m_hbox.set_spacing( 4 ); m_hbox.pack_start( m_spin, Gtk::PACK_SHRINK ); m_hbox.pack_start( m_spinlabel, Gtk::PACK_SHRINK ); set_border_width( 8 ); set_label( "画像あぼ〜ん" ); add( m_hbox ); } }; class DelImgDiag : public SKELETON::PrefDiag { ImgCacheFrame m_frame_cache; ImgAboneFrame m_frame_abone; // OK押した virtual void slot_ok_clicked(){ CONFIG::set_del_img_day( m_frame_cache.get_spin().get_value_as_int() ); CONFIG::set_del_imgabone_day( m_frame_abone.get_spin().get_value_as_int() ); } public: DelImgDiag( Gtk::Window* parent, const std::string& url ): SKELETON::PrefDiag( parent, url ) { get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_frame_cache ); get_vbox()->pack_start( m_frame_abone ); set_activate_entry( m_frame_cache.get_spin() ); set_activate_entry( m_frame_abone.get_spin() ); set_title( "画像キャッシュの消去" ); show_all_children(); } virtual ~DelImgDiag(){} }; } #endif jd-2.8.7-140104/src/dbimg/img.cpp0000644000076400010400000005507012110716263012727 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "img.h" #include "imginterface.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/imgloader.h" #include "jdlib/confloader.h" #include "jdlib/loaderdata.h" #include "config/globalconf.h" #include "command.h" #include "httpcode.h" #include "cache.h" #include "session.h" #include "global.h" #include "urlreplacemanager.h" #include #include #ifndef MAX #define MAX( a, b ) ( a > b ? a : b ) #endif #ifndef MIN #define MIN( a, b ) ( a < b ? a : b ) #endif enum { MAX_REDIRECT = 5 // 最大リダイレクト回数 }; // 情報ファイルから値を読み込み // dbtree/articlebase.cpp からコピペ #define GET_INFOVALUE(target,targetname) \ do { \ target = std::string(); \ option = targetname; \ it2 = it; \ while( it2 != lines.end() && ( *it2 ).find( option ) != 0 ) ++it2; \ if( it2 != lines.end() ){ \ target = ( *it2 ).substr( option.length() ); \ it = ++it2; \ } } while( false ) using namespace DBIMG; Img::Img( const std::string& url ) : SKELETON::Loadable() ,m_url( url ) ,m_count_redirect( 0 ) ,m_fout( 0 ) { #ifdef _DEBUG std::cout << "Img::Img url = " << m_url << std::endl; #endif set_priority_low(); m_imgctrl = CORE::get_urlreplace_manager()->get_imgctrl( url ); reset(); } Img::~Img() { #ifdef _DEBUG std::cout << "Img::~Img url = " << m_url << std::endl; #endif if( m_fout ) fclose( m_fout ); m_fout = NULL; } void Img::clock_in() { // ロード待ち if( m_wait ){ --m_wait_counter; if( m_wait_counter <= 0 ) download_img( m_refurl, m_mosaic, 0 ); } } // // リセット( 情報をクリアしてinfoファイル再読み込み ) // void Img::reset() { clear(); read_info(); } // 情報クリア void Img::clear() { m_protect = false; m_refurl = std::string(); clear_load_data(); // HTTPコードのクリア m_mosaic = CONFIG::get_use_mosaic(); m_zoom_to_fit = CONFIG::get_zoom_to_fit(); m_size = 100; m_type = T_UNKNOWN; m_width = 0; m_height = 0; m_width_emb = 0; m_height_emb = 0; m_width_mosaic = 0; m_height_mosaic = 0; m_abone = false; m_wait = false; m_wait_counter = 0; } // // ロード待ち状態セット/リセット // const bool Img::set_wait( const std::string& refurl, const bool mosaic, const int waitsec ) { if( waitsec && ! m_wait ){ #ifdef _DEBUG std::cout << "Img::set_wait url = " << m_url << std::endl; #endif m_wait = true; m_wait_counter = (1000/TIMER_TIMEOUT) * waitsec; DBIMG::set_clock_in( this ); m_refurl = refurl; m_mosaic = mosaic; CORE::core_set_command( "redraw", m_url ); CORE::core_set_command( "redraw_article" ); CORE::core_set_command( "redraw_message" ); return true; } return false; } void Img::reset_wait() { if( m_wait ){ #ifdef _DEBUG std::cout << "Img::reset_wait url = " << m_url << std::endl; #endif m_wait = false; m_wait_counter = 0; DBIMG::reset_clock_in( this ); CORE::core_set_command( "redraw", m_url ); CORE::core_set_command( "redraw_article" ); CORE::core_set_command( "redraw_message" ); } } // スレ埋め込み画像の高さ、幅 const int Img::get_width_emb() { if( ! m_width_emb ) set_embedded_size(); return m_width_emb; } const int Img::get_height_emb() { if( ! m_height_emb ) set_embedded_size(); return m_height_emb; } // モザイク処理時に縮小するサイズ const int Img::get_width_mosaic() { if( ! m_width_mosaic ) set_mosaic_size(); return m_width_mosaic; } const int Img::get_height_mosaic() { if( ! m_height_mosaic ) set_mosaic_size(); return m_height_mosaic; } const bool Img::is_cached() { if( is_loading() ) return false; if( is_wait() ) return false; if( ! total_length() ) return false; return ( get_code() == HTTP_OK ); } // // あぼーん状態セット // // キャッシュに無くてもinfoを作るので is_cached() でチェックしない // void Img::set_abone( bool abone ) { if( m_abone == abone ) return; #ifdef _DEBUG std::cout << "Img::set_abone = " << abone << std::endl; #endif if( abone ) clear(); m_abone = abone; save_info(); } const std::string Img::get_cache_path() { if( m_protect ) return CACHE::path_img_protect( m_url ); return CACHE::path_img( m_url ); } // // ロード開始 // // receive_data() と receive_finish() がコールバックされる // // refurl : 参照元のスレのアドレス // mosaic : モザイク表示するか // waitsec: 指定した秒数経過後にロード開始 // void Img::download_img( const std::string refurl, const bool mosaic, const int waitsec ) { // ダウンロード初回(リダイレクトでは無い) if( ! m_count_redirect ) m_url_alt = std::string(); #ifdef _DEBUG std::cout << "Img::download_img url = "; if( ! m_url_alt.empty() ) std::cout << m_url_alt << " count = " << m_count_redirect << std::endl; else std::cout << m_url << std::endl; std::cout << "refurl = " << refurl << " wait = " << m_wait << " waitsec = " << waitsec << std::endl; #endif if( is_loading() ) return; if( is_cached() ) return; if( ! CACHE::mkdir_imgroot() ) return; if( get_type() == T_LARGE ) return; if( is_wait() && waitsec ) return; // ロード待ち状態にセット if( set_wait( refurl, mosaic, waitsec ) ) return; // ロード待ち状態解除 reset_wait(); #ifdef _DEBUG std::cout << "start...\n"; #endif // ダウンロード開始 std::string path = get_cache_path(); m_fout = fopen( to_locale_cstr( path ), "wb" ); if( m_fout == NULL ){ m_type = T_OPENFAILED; receive_finish(); return; } clear(); m_refurl = refurl; m_mosaic = mosaic; JDLIB::LOADERDATA data; data.init_for_data(); if( ! m_url_alt.empty() ) data.url = m_url_alt; else data.url = m_url; // Urlreplaceによるリファラ指定 std::string referer; if( CORE::get_urlreplace_manager()->referer( m_url, referer ) ) data.referer = referer; if( !start_load( data ) ) receive_finish(); else CORE::core_set_command( "redraw", m_url ); } // // ロード停止 // void Img::stop_load() { #ifdef _DEBUG std::cout << "Img::stop_load url = " << m_url << std::endl; #endif SKELETON::Loadable::stop_load(); if( m_wait ){ set_code( HTTP_TIMEOUT ); set_str_code( "stop loading" ); reset_wait(); } } // // キャッシュ保存 // // path_to はデフォルトのファイル名 // const bool Img::save( Gtk::Window* parent, const std::string& path_to ) { if( ! is_cached() ) return false; std::string dir = MISC::get_dir( path_to ); if( dir.empty() ) dir = SESSION::dir_img_save(); std::string name = MISC::get_filename( path_to ); if( name.empty() ) name = MISC::get_filename( m_url ); std::string save_to = CACHE::copy_file( parent, get_cache_path(), dir + name, CACHE::FILE_TYPE_ALL ); if( ! save_to.empty() ){ SESSION::set_dir_img_save( MISC::get_dir( save_to ) ); return true; } return false; } // // モザイクon/off // void Img::set_mosaic( const bool mosaic ) { if( ! is_cached() ) return; m_mosaic = mosaic; save_info(); // 再描画 CORE::core_set_command( "redraw_bbslist" ); CORE::core_set_command( "redraw_article" ); CORE::core_set_command( "redraw_message" ); } // // サイズの大きいファイルを表示 // void Img::show_large_img() { if( m_type != T_LARGE ) return; const int size = 256; char data[ size ]; CACHE::load_rawdata( get_cache_path(), data, size ); m_type = DBIMG::get_image_type( ( const unsigned char* ) data ); if( m_type != T_NOIMG ){ set_code( HTTP_OK ); set_str_code( "" ); CORE::core_set_command( "redraw", m_url ); CORE::core_set_command( "redraw_article" ); CORE::core_set_command( "redraw_message" ); } } // // 保護モード // void Img::set_protect( bool protect ) { if( ! is_cached() ) return; if( m_protect == protect ) return; if( protect ){ CACHE::jdmv( CACHE::path_img( m_url ), CACHE::path_img_protect( m_url ) ); CACHE::jdmv( CACHE::path_img_info( m_url ), CACHE::path_img_protect_info( m_url ) ); } else{ CACHE::jdmv( CACHE::path_img_protect( m_url ), CACHE::path_img( m_url ) ); CACHE::jdmv( CACHE::path_img_protect_info( m_url ), CACHE::path_img_info( m_url ) ); } m_protect = protect; } // 拡張子が偽装されているか const bool Img::is_fake() { if( ! is_cached() ) return false; if( m_imgctrl & CORE::IMGCTRL_GENUINE ) return false; bool ret = false; if( DBIMG::get_type_ext( m_url ) != m_type ) ret = true; else if( ! m_url_alt.empty() && DBIMG::get_type_ext( m_url_alt ) != m_type ) ret = true; #ifdef _DEBUG std::cout << "Img::is_fake url = " << m_url << " ret = " << ret << std::endl; #endif return ret; } // // データ受信 // void Img::receive_data( const char* data, size_t size ) { if( ! size ) return; #ifdef _DEBUG std::cout << "Img::receive_data code = " << get_code() << std::endl << "size / total = " << current_length() << " / " << total_length() << std::endl; #endif // Created は OK にしておく if( get_code() == HTTP_CREATED ) set_code( HTTP_OK ); // 先頭のシグネチャを見て画像かどうかをチェック if( m_type == T_UNKNOWN && get_code() == HTTP_OK ){ #ifdef _DEBUG assert( size > 8 ); #endif m_type = DBIMG::get_image_type( ( const unsigned char* ) data ); if( m_type == T_NOIMG ){ // リダイレクトしたら 404 を疑う // データに "404" "not" "found" という文字列が含まれていたら not found と仮定 if( ! m_url_alt.empty() ){ // std::stringにいきなりデータを入れるのはなんとなく恐いので strncasecmp() を使用 unsigned char notfound = 0; for( unsigned int i = 0; i < size; ++i ){ if( strncasecmp( data + i, "404", 3 ) == 0 ) notfound |= 1; if( strncasecmp( data + i, "not", 3 ) == 0 ) notfound |= 2; if( strncasecmp( data + i, "found", 5 ) == 0 ) notfound |= 4; } if( notfound == 7 ) m_type = T_NOT_FOUND; } stop_load(); #ifdef _DEBUG std::cout << "no image : size = " << size << std::endl; std::cout << data << std::endl; #endif } } if( m_fout && m_type != T_NOIMG && m_type != T_NOT_FOUND ){ if( fwrite( data, 1, size, m_fout ) != size ){ m_type = T_WRITEFAILED; // 書き込み失敗 stop_load(); } } #ifdef _DEBUG std::cout << "type = " << m_type << std::endl; #endif } // // ロード終了 // void Img::receive_finish() { #ifdef _DEBUG std::cout << "Img::receive_finish code = " << get_code() << std::endl << "strcode = " << get_str_code() << std::endl << "total byte = " << total_length() << std::endl << "contenttype = " << get_contenttype() << std::endl << "cookies : " << std::endl; // if( cookies().size() ){ // std::list< std::string >::iterator it = cookies().begin(); // for( ; it != cookies().end() ; ++it ) std::cout << *it << std::endl; // } #endif if( m_fout ) fclose( m_fout ); m_fout = NULL; // Created は OK にしておく if( get_code() == HTTP_CREATED ) set_code( HTTP_OK ); // データが無い if( get_code() == HTTP_OK && ! current_length() ) m_type = T_NODATA; // リダイレクト if( get_code() == HTTP_REDIRECT || get_code() == HTTP_MOVED_PERM ){ #ifdef _DEBUG std::cout << "301/302 redirect url = " << location() << std::endl; #endif // アドレスに "404", ".htm" が含まれていたら not found と仮定 std::string url_tmp = MISC::tolower_str( location() ); if( url_tmp.find( "404" ) != std::string::npos && url_tmp.find( ".htm" ) != std::string::npos ) m_type = T_NOT_FOUND; else if( ! location().empty() && m_count_redirect < MAX_REDIRECT ){ #ifdef _DEBUG std::cout << "exec redirect\n"; #endif ++m_count_redirect; m_url_alt = location(); download_img( m_refurl, m_mosaic, 0 ); return; } else m_type = T_NODATA; } m_count_redirect = 0; if( get_code() != HTTP_OK ) set_current_length( 0 ); // 画像サイズ取得 if( get_code() == HTTP_OK && current_length() ){ JDLIB::ImgLoader::get_loader( get_cache_path() )->get_size( m_width, m_height ); if( ! m_width || ! m_height ) m_type = T_NOSIZE; } ////////////////////////////////////////////////// // エラーメッセージのセット if( m_type == T_NOIMG ){ set_code( HTTP_ERR ); set_str_code( "画像ファイルではありません (" + get_contenttype() + ")" ); set_current_length( 0 ); } else if( m_type == T_NOT_FOUND ){ set_code( HTTP_NOT_FOUND ); set_str_code( "404 Not Found" ); set_current_length( 0 ); } else if( m_type == T_OPENFAILED ){ set_code( HTTP_ERR ); set_str_code( "ファイルのオープンに失敗しました" ); set_current_length( 0 ); } else if( m_type == T_WRITEFAILED ){ set_code( HTTP_ERR ); set_str_code( "ハードディスクへの書き込みに失敗しました" ); set_current_length( 0 ); } else if( m_type == T_NODATA ){ set_code( HTTP_ERR ); set_str_code( "サーバ上にファイルが存在しません" ); set_current_length( 0 ); } else if( m_type == T_NOSIZE ){ set_code( HTTP_ERR ); set_str_code( "画像サイズを取得出来ません" ); set_current_length( 0 ); } else if( get_code() == HTTP_OK && m_type == T_UNKNOWN ){ set_code( HTTP_ERR ); set_str_code( "未知の画像形式です" ); set_current_length( 0 ); } // 画像やファイルサイズが大きい else if( current_length() > (size_t) CONFIG::get_max_img_size() * 1024 * 1024 || m_width * m_height > CONFIG::get_max_img_pixel() * 1000 * 1000 ){ m_type = T_LARGE; set_code( HTTP_ERR ); std::stringstream ss; ss << "サイズが大きすぎます ( " << ( total_length() / 1024 / 1024 ) << " M, " << m_width << " x " << m_height << " ) ※コンテキストメニューから表示可能"; set_str_code( ss.str() ); } set_total_length( current_length() ); // 読み込み失敗の場合はファイルを消しておく if( ! total_length() ){ std::string path = get_cache_path(); if( CACHE::file_exists( path ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( path ) ); #ifdef _DEBUG std::cout << "unlink cache\n"; #endif } #ifdef _DEBUG std::cout << "type = " << m_type << std::endl << "refurl = " << m_refurl << std::endl; #endif // 画像が小さい場合はモザイクを解除 if( m_width && m_height ){ const int minsize = MAX( 1, CONFIG::get_mosaic_size() ); if( m_width >= m_height && m_width < minsize ) m_mosaic = false; else if( m_width < m_height && m_height < minsize ) m_mosaic = false; } // 拡張子が偽装されている時はモザイク表示にする if( is_fake() ) m_mosaic = true; // 読み込み失敗の場合でもエラーメッセージを残すので info は保存する save_info(); CORE::core_set_command( "redraw", m_url ); CORE::core_set_command( "redraw_article" ); CORE::core_set_command( "redraw_message" ); } // 埋め込み画像のサイズを計算 void Img::set_embedded_size() { if( ! m_width || ! m_height ) return; // 縮小比率を計算してサイズ取得 double scale; double scale_w = ( double ) CONFIG::get_embimg_width() / m_width; double scale_h = ( double ) CONFIG::get_embimg_height() / m_height; scale = MIN( scale_w, scale_h ); if( scale < 1.0 ){ m_width_emb = (int)( m_width * scale ); m_height_emb = (int)( m_height * scale ); } else{ m_width_emb = m_width; m_height_emb = m_height; } #ifdef _DEBUG std::cout << "Img::set_embedded_size w = " << m_width_emb << " h = " << m_height_emb << std::endl; #endif } // モザイク処理時に縮小するサイズを経産 void Img::set_mosaic_size() { if( ! m_width || ! m_height ) return; // 一旦元画像の横幅を mossize ピクセルまで縮めてから描画サイズに戻す const int mossize = MAX( 1, CONFIG::get_mosaic_size() ); int moswidth = m_width; int mosheight = m_height; if( moswidth >= mosheight ){ const int dev = MAX( 1, moswidth / mossize ); mosheight /= dev; moswidth = mossize; } else{ const int dev = MAX( 1, mosheight / mossize ); mosheight = mossize; moswidth /= dev; } m_width_mosaic = MAX( 1, moswidth ); m_height_mosaic = MAX( 1, mosheight ); } // // キャッシュ情報読み込み // void Img::read_info() { #ifdef _DEBUG std::cout << "Img::read_info\n"; #endif std::string filename = CACHE::filename_img_info( m_url ); std::string path_info = CACHE::path_img_info_root() + filename; bool exist = false; m_abone = false; do{ // 通常 if( CACHE::file_exists( path_info ) == CACHE::EXIST_FILE ){ m_protect = false; exist = true; break; } // 保護の場合 path_info = CACHE::path_img_protect_info_root() + filename; if( CACHE::file_exists( path_info ) == CACHE::EXIST_FILE ){ m_protect = true; exist = true; break; } // あぼーんの場合 path_info = CACHE::path_img_abone_root() + filename; if( CACHE::file_exists( path_info ) == CACHE::EXIST_FILE ){ m_abone = true; exist = false; break; } path_info = std::string(); }while( 0 ); if( exist ){ /* JDLIB::ConfLoader cf( path_info, std::string() ); m_refurl = cf.get_option( "refurl", "" ); set_code( cf.get_option( "code", HTTP_INIT ) ); set_str_code( cf.get_option( "str_code", "" ) ); set_total_length( cf.get_option( "byte", 0 ) ); m_mosaic = cf.get_option( "mosaic", CONFIG::get_use_mosaic() ); m_type = cf.get_option( "type", T_UNKNOWN ); m_width = cf.get_option( "width", 0 ); m_height = cf.get_option( "height", 0 ); */ // TODO : JDLIB::ConfLoaderFast を作る std::string str_info, str_tmp; std::list< std::string > list_tmp; std::list< std::string >::iterator it_tmp; CACHE::load_rawdata( path_info, str_info ); std::list< std::string > lines = MISC::get_lines( str_info ); std::list < std::string >::iterator it = lines.begin(), it2; std::string option; // GET_INFOVALUE で使用 GET_INFOVALUE( m_refurl, "refurl = " ); set_code( HTTP_INIT ); GET_INFOVALUE( str_tmp, "code = " ); if( ! str_tmp.empty() ) set_code( atoi( str_tmp.c_str() ) ); GET_INFOVALUE( str_tmp, "str_code = " ); set_str_code( str_tmp ); set_total_length( 0 ); GET_INFOVALUE( str_tmp, "byte = " ); if( ! str_tmp.empty() ) set_total_length( atoi( str_tmp.c_str() ) ); m_mosaic = CONFIG::get_use_mosaic(); GET_INFOVALUE( str_tmp, "mosaic = " ); if( ! str_tmp.empty() ) m_mosaic = atoi( str_tmp.c_str() ); m_type = T_UNKNOWN; GET_INFOVALUE( str_tmp, "type = " ); if( ! str_tmp.empty() ) m_type = atoi( str_tmp.c_str() ); m_width = 0; GET_INFOVALUE( str_tmp, "width = " ); if( ! str_tmp.empty() ) m_width = atoi( str_tmp.c_str() ); m_height = 0; GET_INFOVALUE( str_tmp, "height = " ); if( ! str_tmp.empty() ) m_height = atoi( str_tmp.c_str() ); if( ! total_length() ){ set_total_length( CACHE::get_filesize( get_cache_path() ) ); if( total_length() ) save_info(); } set_current_length( total_length() ); } #ifdef _DEBUG std::cout << "path_info = " << path_info << std::endl; std::cout << "exist = " << exist << std::endl; std::cout << "protect = " << m_protect << std::endl; std::cout << "refurl = " << m_refurl << std::endl; std::cout << "code = " << get_code() << std::endl; std::cout << "str_code = " << get_str_code() << std::endl; std::cout << "byte = " << total_length() << std::endl; std::cout << "mosaic = " << m_mosaic << std::endl; std::cout << "type = " << m_type << std::endl; std::cout << "width = " << m_width << std::endl; std::cout << "height = " << m_height << std::endl; std::cout << "abone = " << m_abone << std::endl; #endif } // // 情報保存 // void Img::save_info() { if( is_loading() ) return; if( ! CACHE::mkdir_imgroot() ) return; if( ! CACHE::mkdir_imgroot_favorite() ) return; std::string path_info; if( ! is_cached() && ! m_abone ){ // あぼーん情報ファイルがあったら消しておく path_info = CACHE::path_img_abone( m_url ); if( CACHE::file_exists( path_info ) == CACHE::EXIST_FILE ){ #ifdef _DEBUG std::cout << "unlink " << path_info << std::endl; #endif unlink( to_locale_cstr( path_info ) ); } if( get_code() == HTTP_INIT ) return; } if( m_protect ) path_info = CACHE::path_img_protect_info( m_url ); if( m_abone ) path_info = CACHE::path_img_abone( m_url ); else path_info = CACHE::path_img_info( m_url ); std::ostringstream oss; oss << "url = " << m_url << std::endl << "refurl = " << m_refurl << std::endl << "code = " << get_code() << std::endl << "str_code = " << get_str_code() << std::endl << "byte = " << total_length() << std::endl << "mosaic = " << m_mosaic << std::endl << "type = " << m_type << std::endl << "width = " << m_width << std::endl << "height = " << m_height << std::endl; #ifdef _DEBUG std::cout << "Img::save_info file = " << path_info << std::endl; std::cout << "protect = " << m_protect << std::endl; std::cout << oss.str() << std::endl; #endif CACHE::save_rawdata( path_info, oss.str() ); } jd-2.8.7-140104/src/dbimg/img.h0000644000076400010400000001006012110716263012362 0ustar // ライセンス: GPL2 // 画像データクラス #ifndef _IMG_H #define _IMG_H #include "skeleton/loadable.h" #include namespace Gtk { class Window; } namespace DBIMG { class Img : public SKELETON::Loadable { std::string m_url; std::string m_url_alt; // リダイレクトなどで使用するアドレス int m_count_redirect; // リダイレクト回数 int m_imgctrl; // 画像コントロール int m_type; // 画像タイプ // 幅、高さ int m_width; int m_height; // 埋め込み画像の幅、高さ int m_width_emb; int m_height_emb; // モザイク処理時に縮小するサイズ int m_width_mosaic; int m_height_mosaic; bool m_mosaic; // モザイクかける bool m_zoom_to_fit; // windowにサイズをあわせる int m_size; // 画像の大きさ(パーセントで) bool m_protect; // true ならキャッシュを保護する( delete_cache()で削除しない ) std::string m_refurl; // 参照元のスレのURL bool m_abone; // あぼーんされている // 読み込み待ち bool m_wait; int m_wait_counter; // 保存用ファイルハンドラ FILE* m_fout; public: Img( const std::string& url ); ~Img(); void clock_in(); void reset(); void clear(); const std::string& url() const { return m_url; } const std::string get_cache_path(); const bool is_wait() const{ return m_wait; } const int get_imgctrl() const { return m_imgctrl; } const int get_type() const { return m_type; } void set_type( const int type ){ m_type = type; } // 高さ、幅 const int get_width() const { return m_width; } const int get_height() const { return m_height; } // スレ埋め込み画像の高さ、幅 const int get_width_emb(); const int get_height_emb(); // モザイク処理時に縮小するサイズ const int get_width_mosaic(); const int get_height_mosaic(); const bool is_cached(); const bool get_abone() const { return m_abone; } void set_abone( bool abone ); const bool get_mosaic() const { return m_mosaic; } void set_mosaic( const bool mosaic ); void show_large_img(); const bool is_zoom_to_fit() const { return m_zoom_to_fit; } void set_zoom_to_fit( bool fit ) { m_zoom_to_fit = fit; } // 表示倍率 // ファイルサイズ(byte)は JDLIB::Loadable::total_length() で取得 const int get_size() const { return m_size; } void set_size( int size ) { m_size = size; } const std::string& get_refurl() const { return m_refurl; } const bool is_protected() const { return m_protect; } void set_protect( bool protect ); // 拡張子が偽装されているか const bool is_fake(); // ロード開始 // receive_data() と receive_finish() がコールバックされる // refurl : 参照元のスレのアドレス // mosaic : モザイク表示するか // waitsec: 指定した秒数経過後にロード開始 void download_img( const std::string refurl, const bool mosaic, const int waitsec ); // ロード停止 virtual void stop_load(); const bool save( Gtk::Window* parent, const std::string& path_to ); private: virtual void receive_data( const char* data, size_t size ); virtual void receive_finish(); // ロード待ち状態セット/リセット const bool set_wait( const std::string& refurl, const bool mosaic, const int waitsec ); void reset_wait(); // 埋め込み画像のサイズを計算 void set_embedded_size(); // モザイク処理時に縮小するサイズを経産 void set_mosaic_size(); void read_info(); void save_info(); }; } #endif jd-2.8.7-140104/src/dbimg/imginterface.cpp0000644000076400010400000001505611334022056014605 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imginterface.h" #include "imgroot.h" #include "img.h" #include "cache.h" #include "global.h" // インスタンスは Core でひとつだけ作って、Coreのデストラクタでdeleteする DBIMG::ImgRoot *instance_dbimg_root = NULL; void DBIMG::create_root() { if( ! instance_dbimg_root ) instance_dbimg_root = new DBIMG::ImgRoot(); } void DBIMG::delete_root() { if( instance_dbimg_root ) delete instance_dbimg_root; } void DBIMG::clock_in() { if( instance_dbimg_root ) instance_dbimg_root->clock_in(); } // 読み込み待ちのためクロックを回すImgクラスをセット/リセット void DBIMG::set_clock_in( Img* img ) { if( instance_dbimg_root ) instance_dbimg_root->set_clock_in( img ); } void DBIMG::reset_clock_in( Img* img ) { if( instance_dbimg_root ) instance_dbimg_root->reset_clock_in( img ); } const int DBIMG::get_type_ext( const std::string& url ) { if( instance_dbimg_root ) return instance_dbimg_root->get_type_ext( url ); return T_UNKNOWN; } const int DBIMG::get_image_type( const unsigned char *sign ) { if( instance_dbimg_root ) return instance_dbimg_root->get_image_type( sign ); return T_UNKNOWN; } const int DBIMG::get_type_ext( const char* url, int n ) { if( instance_dbimg_root ) return instance_dbimg_root->get_type_ext( url, n ); return T_UNKNOWN; } const int DBIMG::get_type_real( const std::string& url ) { int type = T_UNKNOWN; DBIMG::Img* img = DBIMG::get_img( url ); if( img ) type = img->get_type(); return type; } DBIMG::Img* DBIMG::get_img( const std::string& url ) { if( instance_dbimg_root ) return instance_dbimg_root->get_img( url ); return NULL; } const std::string DBIMG::get_cache_path( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->get_cache_path(); return std::string(); } void DBIMG::download_img( const std::string& url, const std::string& refurl, const bool mosaic ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) img->download_img( refurl, mosaic, 0 ); } void DBIMG::download_img_wait( const std::string& url, const std::string& refurl, const bool mosaic, const int first ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img && instance_dbimg_root ){ int wait = 0; if( ! first || instance_dbimg_root->get_wait_size() ) wait = ( instance_dbimg_root->get_wait_size() + 1 ) * WAITLOADIMG_SEC; img->download_img( refurl, mosaic, wait ); } } void DBIMG::stop_load( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) img->stop_load(); } const bool DBIMG::save( const std::string& url, Gtk::Window* parent, const std::string& path_to ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->save( parent, path_to ); return true; } void DBIMG::delete_cache( const std::string& url ) { if( instance_dbimg_root ) instance_dbimg_root->delete_cache( url ); } void DBIMG::delete_all_files() { if( instance_dbimg_root ) instance_dbimg_root->delete_all_files(); } const int DBIMG::get_width( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->get_width(); return 0; } const int DBIMG::get_height( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->get_height(); return 0; } const bool DBIMG::is_cached( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->is_cached(); return false; } const bool DBIMG::get_abone( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->get_abone(); return false; } void DBIMG::set_abone( const std::string& url, bool abone ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->set_abone( abone ); } const bool DBIMG::is_loading( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->is_loading(); return false; } const bool DBIMG::is_wait( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->is_wait(); return false; } const int DBIMG::get_code( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->get_code(); return 0; } const std::string DBIMG::get_str_code( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->get_str_code(); return std::string(); } const bool DBIMG::get_mosaic( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->get_mosaic(); return true; } void DBIMG::set_mosaic( const std::string& url, bool mosaic ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) img->set_mosaic( mosaic ); } void DBIMG::show_large_img( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) img->show_large_img(); } const bool DBIMG::is_zoom_to_fit( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->is_zoom_to_fit(); return true; } void DBIMG::set_zoom_to_fit( const std::string& url, bool fit ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) img->set_zoom_to_fit( fit ); } const int DBIMG::get_size( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->get_size(); return 100; } void DBIMG::set_size( const std::string& url, int size ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) img->set_size( size ); } const std::string DBIMG::get_refurl( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->get_refurl(); return std::string(); } const size_t DBIMG::byte( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->current_length(); return 0; } const size_t DBIMG::get_filesize( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->total_length(); return 0; } const bool DBIMG::is_protected( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->is_protected(); return true; } const bool DBIMG::is_fake( const std::string& url ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) return img->is_fake(); return false; } void DBIMG::set_protect( const std::string& url, bool protect ) { DBIMG::Img* img = DBIMG::get_img( url ); if( img ) img->set_protect( protect ); } jd-2.8.7-140104/src/dbimg/imginterface.h0000644000076400010400000000671712125473343014266 0ustar // ライセンス: GPL2 // // 画像データベースへのインターフェース関数 // #ifndef _IMGINTERFACE_H #define _IMGINTERFACE_H #include namespace Gtk { class Window; } namespace DBIMG { // DBIMG::get_type_*() で取得する画像タイプ enum{ T_NOIMG = 0, T_JPG, T_PNG, T_GIF, T_BMP, T_LARGE, T_NOSIZE, T_OPENFAILED, T_WRITEFAILED, T_NOT_FOUND, T_NODATA, T_UNKNOWN, // 画像ではない T_FORCEIMAGE, // 拡張子がなくても画像として扱う }; class Img; void create_root(); void delete_root(); void clock_in(); // 読み込み待ちのためクロックを回すImgクラスをセット/リセット void set_clock_in( Img* img ); void reset_clock_in( Img* img ); // 画像データの先頭のシグネチャを見て画像のタイプを取得 // 画像ではない場合は T_NOIMG を返す const int get_image_type( const unsigned char *sign ); // 拡張子だけをみて画像の種類を判断 // キャッシュに無くても判断可能 // 画像ではない場合は T_UNKNOWN を返す const int get_type_ext( const std::string& url ); const int get_type_ext( const char* url, int n ); // 実際の画像ファイルの種類を判断 // 画像がキャッシュに無いときは判断不能( T_UNKNOWN を返す ) const int get_type_real( const std::string& url ); DBIMG::Img* get_img( const std::string& url ); const std::string get_cache_path( const std::string& url ); // ロード開始 // refurl : 参照元のスレのアドレス // mosaic : モザイク表示するか void download_img( const std::string& url, const std::string& refurl, const bool mosaic ); // 時間差ロード // first : 一番最初の画像か void download_img_wait( const std::string& url, const std::string& refurl, const bool mosaic, const int first ); void stop_load( const std::string& url ); const bool save( const std::string& url, Gtk::Window* parent, const std::string& path_to ); void delete_cache( const std::string& url ); void delete_all_files(); const int get_width( const std::string& url ); const int get_height( const std::string& url ); const bool is_cached( const std::string& url ); const int get_type( const std::string& url ); const bool get_abone( const std::string& url ); void set_abone( const std::string& url, bool abone ); const bool is_loading( const std::string& url ); const bool is_wait( const std::string& url ); const int get_code( const std::string& url ); const std::string get_str_code( const std::string& url ); const bool get_mosaic( const std::string& url ); void set_mosaic( const std::string& url, bool mosaic ); void show_large_img( const std::string& url ); const bool is_zoom_to_fit( const std::string& url ); void set_zoom_to_fit( const std::string& url, bool fit ); const int get_size( const std::string& url ); void set_size( const std::string& url, int size ); const std::string get_refurl( const std::string& url ); const size_t byte( const std::string& url ); const size_t get_filesize( const std::string& url ); const bool is_protected( const std::string& url ); const bool is_fake( const std::string& url ); void set_protect( const std::string& url, bool protect ); } #endif jd-2.8.7-140104/src/dbimg/imgroot.cpp0000644000076400010400000001703212112057715013631 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imgroot.h" #include "img.h" #include "delimgcachediag.h" #include "imginterface.h" #include "jdlib/confloader.h" #ifdef _DEBUG #include "jdlib/misctime.h" #endif #include "cache.h" #include "command.h" #include "prefdiagfactory.h" #include "urlreplacemanager.h" #include #include using namespace DBIMG; ImgRoot::ImgRoot() { } ImgRoot::~ImgRoot() { std::map< std::string, Img* >::iterator it; for( it = m_map_img.begin(); it != m_map_img.end(); ++it ){ ( *it ).second->terminate_load(); delete ( *it ).second; } } void ImgRoot::clock_in() { if( m_list_wait.size() ){ std::list< Img* >::iterator it = m_list_wait.begin(); for( ; it != m_list_wait.end(); ++it ) ( *it )->clock_in(); remove_clock_in(); } } // 読み込み待ちのためクロックを回すImgクラスをセット/リセット void ImgRoot::set_clock_in( Img* img ) { m_list_wait.push_back( img ); } void ImgRoot::reset_clock_in( Img* img ) { // リストに登録しておいて remove_clock_in()で消す m_list_delwait.push_back( img ); } void ImgRoot::remove_clock_in() { if( m_list_delwait.size() ){ #ifdef _DEBUG std::cout << "ImgRoot::remove_clock_in\n"; #endif std::list< Img* >::iterator it = m_list_delwait.begin(); for( ; it != m_list_delwait.end(); ++it ){ #ifdef _DEBUG std::cout << ( *it )->url() << std::endl; #endif m_list_wait.remove( *it ); } m_list_delwait.clear(); } } // // Imgクラス取得 // データベースに無ければImgクラスを作る // Img* ImgRoot::get_img( const std::string& url ) { Img* img = search_img( url ); // 無ければ作る if( img == NULL ){ img = new Img( url ); m_map_img.insert( make_pair( url, img ) ); } return img; } // // 検索 // // DBになくてもImgクラスは作らない // Img* ImgRoot::search_img( const std::string& url ) { std::map< std::string, Img* >::iterator it = m_map_img.find( url ); if( it != m_map_img.end() ) return ( *it ).second; return NULL; } // // 画像データの先頭のシグネチャを見て画像のタイプを取得 // 画像ではない場合は T_NOIMG を返す // const int ImgRoot::get_image_type( const unsigned char *sign ) { int type = T_NOIMG; // jpeg は FF D8 if( sign[ 0 ] == 0xFF && sign[ 1 ] == 0xD8 ) type = T_JPG; // png は 0x89 0x50 0x4e 0x47 0xd 0xa 0x1a 0xa else if( sign[ 0 ] == 0x89 && sign[ 1 ] == 0x50 && sign[ 2 ] == 0x4e && sign[ 3 ] == 0x47 && sign[ 4 ] == 0x0d && sign[ 5 ] == 0x0a && sign[ 6 ] == 0x1a && sign[ 7 ] == 0x0a ) type = T_PNG; // gif else if( sign[ 0 ] == 'G' && sign[ 1 ] == 'I' && sign[ 2 ] == 'F' ) type = T_GIF; // bitmap if( sign[ 0 ] == 'B' && sign[ 1 ] == 'M' ) type = T_BMP; return type; } // // 拡張子からタイプを取得 // 画像ではない場合は T_UNKNOWN を返す // int ImgRoot::get_type_ext( const std::string& url ) { return get_type_ext( url.c_str(), url.length() ); } int ImgRoot::get_type_ext( const char* url, int n ) { // Urlreplaceによる画像コントロールを取得する int imgctrl = CORE::get_urlreplace_manager()->get_imgctrl( url ); // URLに拡張子があっても画像として扱わない if( imgctrl & CORE::IMGCTRL_FORCEBROWSER ) return T_UNKNOWN; if( is_jpg( url, n ) ) return T_JPG; if( is_png( url, n ) ) return T_PNG; if( is_gif( url, n ) ) return T_GIF; if( is_bmp( url, n ) ) return T_BMP; // URLに拡張子がない場合でも画像として扱うか if( imgctrl & CORE::IMGCTRL_FORCEIMAGE ) return T_FORCEIMAGE; return T_UNKNOWN; } // 今のところ拡張子だけを見る bool ImgRoot::is_jpg( const char* url, int n ) { // .jpg if( *( url + n -4 ) == '.' && *( url + n -3 ) == 'j' && *( url + n -2 ) == 'p' && *( url + n -1 ) == 'g' ) return true; if( *( url + n -4 ) == '.' && *( url + n -3 ) == 'J' && *( url + n -2 ) == 'P' && *( url + n -1 ) == 'G' ) return true; // .jpeg if( *( url + n -5 ) == '.' && *( url + n -4 ) == 'j' && *( url + n -3 ) == 'p' && *( url + n -2 ) == 'e' && *( url + n -1 ) == 'g' ) return true; if( *( url + n -5 ) == '.' && *( url + n -4 ) == 'J' && *( url + n -3 ) == 'P' && *( url + n -2 ) == 'E' && *( url + n -1 ) == 'G' ) return true; return false; } bool ImgRoot::is_png( const char* url, int n ) { // .png if( *( url + n -4 ) == '.' && *( url + n -3 ) == 'p' && *( url + n -2 ) == 'n' && *( url + n -1 ) == 'g' ) return true; if( *( url + n -4 ) == '.' && *( url + n -3 ) == 'P' && *( url + n -2 ) == 'N' && *( url + n -1 ) == 'G' ) return true; return false; } bool ImgRoot::is_gif( const char* url, int n ) { // .gif if( *( url + n -4 ) == '.' && *( url + n -3 ) == 'g' && *( url + n -2 ) == 'i' && *( url + n -1 ) == 'f' ) return true; if( *( url + n -4 ) == '.' && *( url + n -3 ) == 'G' && *( url + n -2 ) == 'I' && *( url + n -1 ) == 'F' ) return true; return false; } bool ImgRoot::is_bmp( const char* url, int n ) { // .bmp if( *( url + n -4 ) == '.' && *( url + n -3 ) == 'b' && *( url + n -2 ) == 'm' && *( url + n -1 ) == 'p' ) return true; if( *( url + n -4 ) == '.' && *( url + n -3 ) == 'B' && *( url + n -2 ) == 'M' && *( url + n -1 ) == 'P' ) return true; return false; } // // キャッシュ削除 // void ImgRoot::delete_cache( const std::string& url ) { #ifdef _DEBUG std::cout << "ImgRoot::delete_cache url = " << url << std::endl; #endif Img* img = get_img( url ); if( img && img->is_protected() ) return; // キャッシュ削除 std::string path = CACHE::path_img( url ); if( CACHE::file_exists( path ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( path ) ); // info 削除 path = CACHE::path_img_info( url ); if( CACHE::file_exists( path ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( path ) ); // 再描画 if( img ) img->reset(); CORE::core_set_command( "close_image", url ); CORE::core_set_command( "redraw_article" ); CORE::core_set_command( "redraw_message" ); } // // 全キャッシュ削除 // // image/info フォルダにあるファイルを全て取得して // 期限切れのファイルを削除 // void ImgRoot::delete_all_files() { #ifdef _DEBUG std::cout << "ImgRoot::delete_all_files\n"; #endif SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_DELIMG, "" ); int ret = pref->run(); delete pref; if( ret != Gtk::RESPONSE_OK ) return; // 画像キャッシュ削除ダイアログ表示 DelImgCacheDiag* deldiag = new DelImgCacheDiag(); deldiag->run(); delete deldiag; reset_imgs(); CORE::core_set_command( "close_nocached_image_views" ); CORE::core_set_command( "redraw_article" ); CORE::core_set_command( "redraw_message" ); } // // Img クラスの情報をリセット // void ImgRoot::reset_imgs() { std::map< std::string, Img* >::iterator it; for( it = m_map_img.begin(); it != m_map_img.end(); ++it ){ Img* img = ( *it ).second; if( img ) img->reset(); } } jd-2.8.7-140104/src/dbimg/imgroot.h0000644000076400010400000000346511542405531013302 0ustar // ライセンス: GPL2 // 画像データベースのルートクラス #ifndef _IMGROOT_H #define _IMGROOT_H #include #include #include namespace DBIMG { class Img; class ImgRoot { std::map< std::string, Img* > m_map_img; std::list< Img* > m_list_wait; // ロード待ち状態のImgクラス std::list< Img* > m_list_delwait; // ロード待ち状態のImgクラスを削除する時の一時変数 public: ImgRoot(); ~ImgRoot(); void clock_in(); // ロード待ちのためクロックを回すImgクラスをセット/リセット void set_clock_in( Img* img ); void reset_clock_in( Img* img ); void remove_clock_in(); const int get_wait_size(){ return m_list_wait.size(); } // Imgクラス取得(無ければ作成) Img* get_img( const std::string& url ); // 検索(無ければNULL) Img* search_img( const std::string& url ); // 画像データの先頭のシグネチャを見て画像のタイプを取得 // 画像ではない場合は T_NOIMG を返す const int get_image_type( const unsigned char *sign ); // 拡張子から画像タイプを取得 // 画像ではない場合は T_UNKNOWN を返す int get_type_ext( const std::string& url ); int get_type_ext( const char* url, int n ); // キャッシュ削除 void delete_cache( const std::string& url ); // 全キャッシュ削除 void delete_all_files(); private: bool is_jpg( const char* url, int n ); bool is_png( const char* url, int n ); bool is_gif( const char* url, int n ); bool is_bmp( const char* url, int n ); void reset_imgs(); }; } #endif jd-2.8.7-140104/src/dbimg/Makefile.am0000644000076400010400000000043012072045132013466 0ustar noinst_LIBRARIES = libdbimg.a libdbimg_a_SOURCES = \ imgroot.cpp \ img.cpp \ imginterface.cpp \ delimgcachediag.cpp noinst_HEADERS = \ imgroot.h \ img.h \ imginterface.h \ delimgdiag.h \ delimgcachediag.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/dbtree/0000755000076400010400000000000012261751610011625 5ustar jd-2.8.7-140104/src/dbtree/article2ch.cpp0000644000076400010400000000576511513340547014370 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "article2ch.h" #include "nodetree2ch.h" #include "interface.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "config/globalconf.h" #include "login2ch.h" #include "loginp2.h" #include using namespace DBTREE; Article2ch::Article2ch( const std::string& datbase, const std::string& id, bool cached ) : Article2chCompati( datbase, id, cached ) {} Article2ch::~Article2ch() {} // 書き込みメッセージ変換 const std::string Article2ch::create_write_message( const std::string& name, const std::string& mail, const std::string& msg ) { if( msg.empty() ) return std::string(); const std::string charset = DBTREE::board_charset( get_url() ); std::stringstream ss_post; ss_post.clear(); ss_post << "bbs=" << DBTREE::board_id( get_url() ) << "&key=" << get_key(); // キーワード( hana=mogera や suka=pontan など ) const std::string keyword = DBTREE::board_keyword_for_write( get_url() ); if( ! keyword.empty() ) ss_post << "&" << keyword; // ログイン中 if( CORE::get_login2ch()->login_now() ){ std::string sid = CORE::get_login2ch()->get_sessionid(); ss_post << "&sid=" << MISC::url_encode( sid.c_str(), sid.length() ); } ss_post << "&time=" << get_time_modified() << "&submit=" << MISC::charset_url_encode( "書き込む", charset ) << "&FROM=" << MISC::charset_url_encode( name, charset ) << "&mail=" << MISC::charset_url_encode( mail, charset ) << "&MESSAGE=" << MISC::charset_url_encode( msg, charset ); if( CORE::get_loginp2()->login_now() ){ ss_post << "&detect_hint=" << MISC::charset_url_encode( "◎◇", charset ) << "&host=" << MISC::url_encode( MISC::get_hostname( get_url(), false ) ) << "&popup=1" << "&rescount=" << get_number_load() << "&ttitle_en=" << MISC::url_encode( MISC::base64( MISC::Iconv( MISC::remove_space( get_subject() ), "UTF-8", charset ) ) ) << "&csrfid=" << MISC::url_encode( CORE::get_loginp2()->get_sessiondata() ); } #ifdef _DEBUG std::cout << "Article2chCompati::create_write_message " << ss_post.str() << std::endl; #endif return ss_post.str(); } // // bbscgi のURL // // (例) "http://www.hoge2ch.net/test/bbs.cgi" // // const std::string Article2ch::url_bbscgi() { if( CORE::get_loginp2()->login_now() ) return CONFIG::get_url_loginp2() + "post.php"; return Article2chCompati::url_bbscgi(); } // // subbbscgi のURL // // (例) "http://www.hoge2ch.net/test/subbbs.cgi" // const std::string Article2ch::url_subbbscgi() { if( CORE::get_loginp2()->login_now() ) return CONFIG::get_url_loginp2() + "post.php"; return Article2chCompati::url_subbbscgi(); } NodeTreeBase* Article2ch::create_nodetree() { return new NodeTree2ch( get_url(), get_org_url(), get_date_modified(), get_since_time() ); } jd-2.8.7-140104/src/dbtree/article2ch.h0000644000076400010400000000140111157077436014024 0ustar // ライセンス: GPL2 // // 2ch型スレ情報クラス // #ifndef _ARTICLE2ch_H #define _ARTICLE2ch_H #include "article2chcompati.h" namespace DBTREE { class Article2ch : public Article2chCompati { public: Article2ch( const std::string& datbase, const std::string& id, bool cached ); ~Article2ch(); // 書き込みメッセージ変換 virtual const std::string create_write_message( const std::string& name, const std::string& mail, const std::string& msg ); // bbscgi のURL virtual const std::string url_bbscgi(); // subbbscgi のURL virtual const std::string url_subbbscgi(); private: virtual NodeTreeBase* create_nodetree(); }; } #endif jd-2.8.7-140104/src/dbtree/article2chcompati.cpp0000644000076400010400000000502311314415543015726 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "article2chcompati.h" #include "nodetree2chcompati.h" #include "interface.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "config/globalconf.h" #include using namespace DBTREE; Article2chCompati::Article2chCompati( const std::string& datbase, const std::string& _id, bool cached ) : ArticleBase( datbase, _id, cached ) { assert( ! get_id().empty() ); // key (idから拡張子を除いたもの)を取得 size_t i = get_id().rfind( "." ); // 拡張子は取り除く if( i != std::string::npos ) set_key( get_id().substr( 0, i ) ); // key から since 計算 const char* ckey = get_key().c_str(); if( i != std::string::npos ) set_since_time( atol( ckey ) ); // スレッド924か if( ckey[ 0 ] == '9' && ckey[ 1 ] == '2' && ckey[ 2 ] == '4' ) set_is_924( true ); } Article2chCompati::~Article2chCompati() {} // 書き込みメッセージ変換 const std::string Article2chCompati::create_write_message( const std::string& name, const std::string& mail, const std::string& msg ) { if( msg.empty() ) return std::string(); std::string charset = DBTREE::board_charset( get_url() ); std::stringstream ss_post; ss_post.clear(); ss_post << "bbs=" << DBTREE::board_id( get_url() ) << "&key=" << get_key() << "&time=" << get_time_modified() << "&submit=" << MISC::charset_url_encode( "書き込む", charset ) << "&FROM=" << MISC::charset_url_encode( name, charset ) << "&mail=" << MISC::charset_url_encode( mail, charset ) << "&MESSAGE=" << MISC::charset_url_encode( msg, charset ); #ifdef _DEBUG std::cout << "Article2chCompati::create_write_message " << ss_post.str() << std::endl; #endif return ss_post.str(); } // // bbscgi のURL // // (例) "http://www.hoge2ch.net/test/bbs.cgi" // // const std::string Article2chCompati::url_bbscgi() { std::string cgibase = DBTREE::url_bbscgibase( get_url() ); return cgibase.substr( 0, cgibase.length() -1 ); // 最後の '/' を除く } // // subbbscgi のURL // // (例) "http://www.hoge2ch.net/test/subbbs.cgi" // const std::string Article2chCompati::url_subbbscgi() { std::string cgibase = DBTREE::url_subbbscgibase( get_url() ); return cgibase.substr( 0, cgibase.length() -1 ); // 最後の '/' を除く } NodeTreeBase* Article2chCompati::create_nodetree() { return new NodeTree2chCompati( get_url(), get_date_modified() ); } jd-2.8.7-140104/src/dbtree/article2chcompati.h0000644000076400010400000000144611203523242015371 0ustar // ライセンス: GPL2 // // 2ch互換型スレ情報クラス // #ifndef _ARTICLE2CHCOMPATI_H #define _ARTICLE2CHCOMPATI_H #include "articlebase.h" namespace DBTREE { class Article2chCompati : public ArticleBase { public: Article2chCompati( const std::string& datbase, const std::string& id, bool cached ); virtual ~Article2chCompati(); // 書き込みメッセージ変換 virtual const std::string create_write_message( const std::string& name, const std::string& mail, const std::string& msg ); // bbscgi のURL virtual const std::string url_bbscgi(); // subbbscgi のURL virtual const std::string url_subbbscgi(); private: virtual NodeTreeBase* create_nodetree(); }; } #endif jd-2.8.7-140104/src/dbtree/articlebase.cpp0000644000076400010400000020262512056574077014632 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articlebase.h" #include "nodetreebase.h" #include "interface.h" #include "skeleton/msgdiag.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "jdlib/miscmsg.h" #include "jdlib/jdregex.h" #include "jdlib/tfidf.h" #include "dbimg/imginterface.h" #include "config/globalconf.h" #include "httpcode.h" #include "command.h" #include "cache.h" #include "global.h" #include "login2ch.h" #include "session.h" #include "updatemanager.h" #include using namespace DBTREE; // 情報ファイルのパスをセット // デストラクタの中でCACHE::path_article_ext_info()などを呼ぶとabortするので // メンバ変数としてパスを取得しておく #define SET_INFOPATH() \ do{ \ m_path_article_info = CACHE::path_article_info( m_url, m_id ); \ m_path_article_ext_info = CACHE::path_article_ext_info( m_url, m_id ); \ } while( false ) // 情報ファイルから値を読み込み // JDLIB::ConfLoader では遅いので別に作成。オプションの順番に注意すること #define GET_INFOVALUE(target,targetname) \ do { \ target = std::string(); \ const int n = strlen( targetname ); \ it2 = it; \ while( it2 != lines.end() && ( ( *it2 ).c_str()[ 0 ] != targetname[ 0 ] || strncmp( ( *it2 ).c_str(), targetname, n ) != 0 ) ) ++it2; \ if( it2 != lines.end() ){ \ target = ( *it2 ).substr( n ); \ it = ++it2; \ } } while( false ) ArticleBase::ArticleBase( const std::string& datbase, const std::string& id, bool cached ) : SKELETON::Lockable(), m_id ( id ), m_key( std::string() ), m_since_time( 0 ), m_since_date( std::string() ), m_code( HTTP_INIT ), m_str_code( std::string() ), m_status( STATUS_UNKNOWN ), m_subject( std::string() ), m_number( 0 ), m_number_diff( 0 ), m_number_new( 0 ), m_number_load( 0 ), m_number_before_load( 0 ), m_number_seen( 0 ), m_number_max( 0 ), m_write_fixname( 0 ), m_write_fixmail( 0 ), m_abone_transparent( false ), m_abone_chain( false ), m_abone_age( false ), m_abone_board( true ), m_abone_global( true ), m_bookmarked_thread( false ), m_cached( cached ), m_read_info( 0 ), m_save_info( false ), m_924( false ) { #ifdef _DEBUG // std::cout << "ArticleBase::ArticleBase : " << m_id << std::endl; #endif memset( &m_access_time, 0, sizeof( struct timeval ) ); memset( &m_check_update_time, 0, sizeof( struct timeval ) ); memset( &m_write_time, 0, sizeof( struct timeval ) ); // m_url にURLセット update_datbase( datbase ); // この段階では移転前の旧ホスト名は分からないのでとりあえず現在のホスト名をセットしておく // あとで BoardBase::url_dat()でURLを変換する時に旧ホスト名を教えてもらってinfoファイルに保存しておく。 // BoardBase::url_dat()も参照せよ m_org_host = MISC::get_hostname( m_url ); } ArticleBase::~ArticleBase() { #ifdef _DEBUG // std::cout << "ArticleBase::~ArticleBase : " << m_id << std::endl; #endif // 参照ロックが外れていない assert( get_lock() == 0 ); // nodetreeのクリアと情報保存 unlock_impl(); } const bool ArticleBase::empty() { return m_url.empty(); } // ID がこのスレのものかどうか const bool ArticleBase::equal( const std::string& datbase, const std::string& id ) { return ( id == m_id ); } // // 移転する前のオリジナルのURL // const std::string ArticleBase::get_org_url() { std::string newhost = MISC::get_hostname( m_url ); return m_org_host + m_url.substr( newhost.length() ); } // スレ立て時刻( string型 ) const std::string& ArticleBase::get_since_date() { if( m_since_date.empty() || SESSION::get_col_since_time() == MISC::TIME_PASSED ){ m_since_date = MISC::timettostr( get_since_time(), SESSION::get_col_since_time() ); } return m_since_date; } // スレ速度 const int ArticleBase::get_speed() { time_t current_t = time( NULL ); return ( get_number() * 60 * 60 * 24 ) / MAX( 1, current_t - get_since_time() ); } // キャッシュにあるdatファイルのサイズ const size_t ArticleBase::get_lng_dat() { return get_nodetree()->get_lng_dat(); } // // nodetree の number 番のレスのヘッダノードのポインタを返す // NODE* ArticleBase::res_header( int number ) { return get_nodetree()->res_header( number ); } // // number番の名前 // const std::string ArticleBase::get_name( int number ) { return get_nodetree()->get_name( number ); } // // number番の名前の重複数( = 発言数 ) // int ArticleBase::get_num_name( int number ) { return get_nodetree()->get_num_name( number ); } // // 指定した発言者の名前のレス番号をリストにして取得 // std::list< int > ArticleBase::get_res_name( const std::string& name ) { return get_nodetree()->get_res_name( name ); } // // number番のレスの時刻を文字列で取得 // 内部で regex を使っているので遅い // const std::string ArticleBase::get_time_str( int number ) { return get_nodetree()->get_time_str( number ); } // // number番の発言者ID // const std::string ArticleBase::get_id_name( int number ) { return get_nodetree()->get_id_name( number ); } // 指定した発言者ID の重複数( = 発言数 ) // 下のnum_id_name( int number )と違って検索するので遅い int ArticleBase::get_num_id_name( const std::string& id ) { return get_nodetree()->get_num_id_name( id ); } // number番の発言者ID の重複数( = 発言数 ) int ArticleBase::get_num_id_name( int number ) { return get_nodetree()->get_num_id_name( number ); } // 指定した発言者IDを持つレス番号をリストにして取得 std::list< int > ArticleBase::get_res_id_name( const std::string& id_name ) { return get_nodetree()->get_res_id_name( id_name ); } // str_num で指定したレス番号をリストにして取得 // str_num は "from-to" の形式 (例) 3から10をセットしたいなら "3-10" // list_jointは出力で true のスレは前のスレに連結される (例) "3+4" なら 4が3に連結 std::list< int > ArticleBase::get_res_str_num( const std::string& str_num, std::list< bool >& list_joint ) { if( empty() ){ std::list< int > tmp; return tmp; } return get_nodetree()->get_res_str_num( str_num, list_joint ); } // ブックマークをつけたレス番号をリストにして取得 std::list< int > ArticleBase::get_res_bm() { std::list< int > list_resnum; for( int i = 1; i <= m_number_load ; ++i ){ if( is_bookmarked( i ) ) list_resnum.push_back( i ); } // あぼーんしていてもリストから取り除かない return list_resnum; } // 書き込みしたレス番号をリストにして取得 std::list< int > ArticleBase::get_res_posted() { std::list< int > list_resnum; for( int i = 1; i <= m_number_load ; ++i ){ if( is_posted( i ) ) list_resnum.push_back( i ); } // あぼーんしていてもリストから取り除かない return list_resnum; } // // number番のレスを参照しているレス番号をリストにして取得 // std::list< int > ArticleBase::get_res_reference( const int number ) { return get_nodetree()->get_res_reference( number ); } // // res_num に含まれるレスを参照しているレス番号をリストにして取得 // std::list< int > ArticleBase::get_res_reference( const std::list< int >& res_num ) { return get_nodetree()->get_res_reference( res_num ); } // // URL を含むレス番号をリストにして取得 // std::list< int > ArticleBase::get_res_with_url() { if( empty() ){ std::list< int > tmp; return tmp; } return get_nodetree()->get_res_with_url(); } // // query を含むレス番号をリストにして取得 // // mode_or == true なら OR抽出 // const std::list< int > ArticleBase::get_res_query( const std::string& query, const bool mode_or ) { if( empty() ){ std::list< int > tmp; return tmp; } return get_nodetree()->get_res_query( query, mode_or ); } // // number番のレスの文字列を返す // ref == true なら先頭に ">" を付ける // const std::string ArticleBase::get_res_str( int number, bool ref ) { return get_nodetree()->get_res_str( number, ref ); } // // number 番のレスの生文字列を返す // const std::string ArticleBase::get_raw_res_str( int number ) { return get_nodetree()->get_raw_res_str( number ); } // // 更新時刻 // time_t ArticleBase::get_time_modified() { time_t time_out; time_out = MISC::datetotime( m_date_modified ); if( time_out == 0 ) time_out = time( NULL ) - 600; return time_out; } // スレが立ってからの経過時間( 時間 ) const int ArticleBase::get_hour() { return ( time( NULL ) - get_since_time() ) / ( 60 * 60 ); } // // url の更新 // // 移転があったときなどに上位クラスのboardbaseから呼ばれる // void ArticleBase::update_datbase( const std::string& datbase ) { if( m_id.empty() ) return; #ifdef _DEBUG std::string old_url = m_url; #endif // URL 更新 m_datbase = datbase; m_url = datbase + m_id; // info ファイルのパスも更新 if( ! m_path_article_info.empty() ) SET_INFOPATH(); #ifdef _DEBUG if( !old_url.empty() ) std::cout << "ArticleBase::update_datbase from " << old_url << " to " << m_url << std::endl; #endif if( m_nodetree ) m_nodetree->update_url( m_url ); } // // 移転前のオリジナルのホスト名をセット // void ArticleBase::set_org_host( const std::string& host ) { if( host != m_org_host ){ #ifdef _DEBUG std::cout << "ArticleBase::set_org_host : " << m_id << std::endl << "m_url = " << m_url << std::endl << "org_host = " << m_org_host << " -> " << host << std::endl; #endif m_org_host = host; m_save_info = true; } } // // access_time を 文字列に変換して返す // const std::string ArticleBase::get_access_time_str() { return MISC::timevaltostr( m_access_time ); } // // ユーザが最後にロードした月日( string型 ) // const std::string& ArticleBase::get_access_date() { if( m_access_time.tv_sec ){ if( m_access_date.empty() || SESSION::get_col_write_time() == MISC::TIME_PASSED ){ m_access_date = MISC::timettostr( m_access_time.tv_sec, SESSION::get_col_write_time() ); } } return m_access_date; } void ArticleBase::reset_status() { #ifdef _DEBUG std::cout << "ArticleBase::reset_status\n"; #endif m_status = STATUS_UNKNOWN; } void ArticleBase::set_subject( const std::string& subject ) { if( subject.empty() ) return; // 特殊文字の置き換え if( subject.find( "&" ) != std::string::npos ){ std::string subject_tmp = MISC::html_unescape( subject ); if( subject_tmp != m_subject ){ m_subject = subject_tmp; m_save_info = true; } } else if( subject != m_subject ){ m_subject = subject; m_save_info = true; } } void ArticleBase::set_number( const int number, const bool is_online ) { if( ! number ) return; m_number_diff = 0; m_status &= ~STATUS_BROKEN_SUBJECT; if( number > m_number ){ m_number_diff = number - m_number; m_number = number; // キャッシュがあって更新可能になった場合は // お気に入りとスレビューのタブのアイコンに更新マークを表示 if( is_cached() && !( m_status & STATUS_UPDATE ) && m_number_load < m_number ) show_updateicon( true ); } // subject.txt に示されたレス数よりも実際の取得数の方が多い else if( is_online && number < m_number ){ #ifdef _DEBUG std::cout << "ArticleBase::set_number : broken_subject " << get_subject() << " " << number << " / " << m_number << std::endl; #endif m_status |= STATUS_BROKEN_SUBJECT; } } void ArticleBase::set_number_load( const int number_load ) { if( number_load && number_load != m_number_load ) m_number_load = number_load; } void ArticleBase::set_number_seen( const int number_seen ) { if( number_seen && number_seen != m_number_seen ){ m_number_seen = number_seen; m_save_info = true; } } // 最終書き込み時間( string型 ) const std::string& ArticleBase::get_write_date() { if( m_write_time.tv_sec ){ if( m_write_time_date.empty() || SESSION::get_col_write_time() == MISC::TIME_PASSED ){ m_write_time_date = MISC::timettostr( m_write_time.tv_sec, SESSION::get_col_write_time() ); } } return m_write_time_date; } // // 書き込み時間更新 // void ArticleBase::update_writetime() { struct timeval tv; struct timezone tz; if( CONFIG::get_save_post_history() && gettimeofday( &tv, &tz ) == 0 ){ m_write_time = tv; m_write_time_date = std::string(); #ifdef _DEBUG std::cout << "ArticleBase::update_writetime : " << m_write_time.tv_sec << " " << m_write_time_date << std::endl; #endif m_save_info = true; // BoardViewの行を更新 CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id ); } // 板の書き込み時間を更新 DBTREE::board_update_writetime( m_url ); } // // 書き込み数 // const int ArticleBase::get_num_posted() { if( ! m_vec_posted.size() ) return 0; int ret = 0; for( int i = 1; i < MAX_RESNUMBER; ++i ) if( is_posted( i ) ) ++ret; return ret; } // // スレ自体のスレ一覧でのブックマーク // void ArticleBase::set_bookmarked_thread( const bool bookmarked ) { m_bookmarked_thread = bookmarked; save_info( true ); // BoardViewの行を更新 CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id ); } // // キャッシュがあって、かつ新着の読み込みが可能 // const bool ArticleBase::enable_load() { return ( is_cached() && ( m_status & STATUS_UPDATE ) && ! ( m_status & STATUS_OLD ) ); } // // キャッシュはあるが規定のレス数を越えていて、かつ全てのレスが既読 // const bool ArticleBase::is_finished() { if( is_cached() && ! enable_load() && m_number_max && get_number_seen() >= m_number_max ){ #ifdef _DEBUG std::cout << "ArticleBase::is_finished : seen = " << get_number_seen() << " max = " << m_number_max << " : " << get_subject() << std::endl; #endif return true; } return false; } // // 透明あぼーん // const bool ArticleBase::get_abone_transparent() { if( CONFIG::get_abone_transparent() ) return true; return m_abone_transparent; } // // 連鎖あぼーん // const bool ArticleBase::get_abone_chain() { if( CONFIG::get_abone_chain() ) return true; return m_abone_chain; } // // あぼーんしてるか // const bool ArticleBase::get_abone( int number ) { return get_nodetree()->get_abone( number ); } // // 全レスのあぼーん状態の更新 // // あぼーん情報を変更したら呼び出す // // あぼーんしたスレの発言数や参照はカウントしないので、発言数や参照数も更新する // void ArticleBase::update_abone() { // nodetreeが作られていないときは更新しない if( ! m_nodetree ) return; get_nodetree()->copy_abone_info( m_list_abone_id, m_list_abone_name, m_list_abone_word, m_list_abone_regex, m_vec_abone_res, m_abone_transparent, m_abone_chain, m_abone_age, m_abone_board, m_abone_global ); get_nodetree()->update_abone_all(); } // // あぼーん状態のリセット(情報セットと状態更新) // void ArticleBase::reset_abone( const std::list< std::string >& ids, const std::list< std::string >& names, const std::list< std::string >& words, const std::list< std::string >& regexs, const std::vector< char >& vec_abone_res, const bool transparent, const bool chain, const bool age, const bool board, const bool global ) { if( empty() ) return; #ifdef _DEBUG std::cout << "ArticleBase::reset_abone\n"; #endif // 前後の空白と空白行を除く m_list_abone_id = MISC::remove_space_from_list( ids ); m_list_abone_id = MISC::remove_nullline_from_list( m_list_abone_id ); m_list_abone_name = MISC::remove_space_from_list( names ); m_list_abone_name = MISC::remove_nullline_from_list( m_list_abone_name ); m_list_abone_word = MISC::remove_space_from_list( words ); m_list_abone_word = MISC::remove_nullline_from_list( m_list_abone_word ); m_list_abone_regex = MISC::remove_space_from_list( regexs ); m_list_abone_regex = MISC::remove_nullline_from_list( m_list_abone_regex ); if( vec_abone_res.size() ){ if( ! m_vec_abone_res.size() ) m_vec_abone_res.resize( MAX_RESNUMBER ); for( int i = 1; i <= MIN( m_number_load, (int)vec_abone_res.size() ) ; ++i ){ if( vec_abone_res[ i ] ) m_vec_abone_res[ i ] = true; else m_vec_abone_res[ i ] = false; } } m_abone_transparent = transparent; m_abone_chain = chain; m_abone_age = age; m_abone_board = board; m_abone_global = global; update_abone(); m_save_info = true; } // // あぼーんID追加 // void ArticleBase::add_abone_id( const std::string& id ) { if( empty() ) return; if( id.empty() ) return; #ifdef _DEBUG std::cout << "ArticleBase::add_abone_id : " << id << std::endl; #endif std::string id_tmp = id.substr( strlen( PROTO_ID ) ); m_list_abone_id.push_back( id_tmp ); update_abone(); m_save_info = true; } // // あぼーん名前追加 // void ArticleBase::add_abone_name( const std::string& name ) { if( empty() ) return; if( name.empty() ) return; #ifdef _DEBUG std::cout << "ArticleBase::add_abone_name : " << name << std::endl; #endif m_list_abone_name.push_back( name ); update_abone(); m_save_info = true; } // // あぼーん文字列追加 // void ArticleBase::add_abone_word( const std::string& word ) { if( empty() ) return; if( word.empty() ) return; #ifdef _DEBUG std::cout << "ArticleBase::add_abone_word : " << word << std::endl; #endif m_list_abone_word.push_back( word ); update_abone(); m_save_info = true; } // // レスあぼーんのセット // void ArticleBase::set_abone_res( const int num_from, const int num_to, const bool set ) { if( empty() ) return; if( num_from > num_to ) return; if( num_from <= 0 || num_to >= MAX_RESNUMBER ) return; #ifdef _DEBUG std::cout << "ArticleBase::set_abone_res num_from = " << num_from << " num_to = " << num_to << " set = " << set << std::endl; #endif if( ! m_vec_abone_res.size() ) m_vec_abone_res.resize( MAX_RESNUMBER ); for( int i = num_from; i <= num_to; ++i ) m_vec_abone_res[ i ] = set; update_abone(); m_save_info = true; } // // 透明あぼーん更新 // void ArticleBase::set_abone_transparent( const bool set ) { if( empty() ) return; m_abone_transparent = set; update_abone(); m_save_info = true; } // // 連鎖あぼーん更新 // void ArticleBase::set_abone_chain( const bool set ) { if( empty() ) return; m_abone_chain = set; update_abone(); m_save_info = true; } // // ageあぼーん更新 // void ArticleBase::set_abone_age( const bool set ) { if( empty() ) return; m_abone_age = set; update_abone(); m_save_info = true; } // // 板レベルでのあぼーんを有効にする // void ArticleBase::set_abone_board( const bool set ) { if( empty() ) return; m_abone_board = set; update_abone(); m_save_info = true; } // // 全体レベルでのあぼーんを有効にする // void ArticleBase::set_abone_global( const bool set ) { if( empty() ) return; m_abone_global = set; update_abone(); m_save_info = true; } // // ブックマークの数 // const int ArticleBase::get_num_bookmark() { if( ! m_vec_bookmark.size() ) return 0; int ret = 0; for( int i = 1; i < MAX_RESNUMBER; ++i ) if( is_bookmarked( i ) ) ++ret; return ret; } // // ブックマークされているか // const bool ArticleBase::is_bookmarked( const int number ) { if( number <= 0 || number > m_number_load ) return false; // まだnodetreeが作られてなくてブックマークの情報が得られてないのでnodetreeを作って情報取得 if( ! m_vec_bookmark.size() ) get_nodetree(); if( ! m_vec_bookmark.size() ) return false; return ( m_vec_bookmark[ number ] ); } // // ブックマークセット // void ArticleBase::set_bookmark( const int number, const bool set ) { if( ! m_vec_bookmark.size() ) get_nodetree(); if( number <= 0 || number > MAX_RESNUMBER ) return; if( ! m_vec_bookmark.size() ) m_vec_bookmark.resize( MAX_RESNUMBER ); m_save_info = true; m_vec_bookmark[ number ] = set; } // // 自分が書き込んだレスか // const bool ArticleBase::is_posted( const int number ) { if( number <= 0 || number > m_number_load ) return false; // まだnodetreeが作られてなくて情報が得られてないのでnodetreeを作って情報取得 if( ! m_vec_posted.size() ) get_nodetree(); if( ! m_vec_posted.size() ) return false; return ( m_vec_posted[ number ] ); } // 自分の書き込みにレスしたか const bool ArticleBase::is_refer_posted( const int number ) { return get_nodetree()->is_refer_posted( number ); } // 書き込みマークセット void ArticleBase::set_posted( const int number, const bool set ) { if( number <= 0 || number > m_number_load ) return; // まだnodetreeが作られてなくて情報が得られてないのでnodetreeを作って情報取得 if( ! m_vec_posted.size() ) get_nodetree(); if( ! m_vec_posted.size() ) m_vec_posted.resize( MAX_RESNUMBER ); m_save_info = true; m_vec_posted[ number ] = set; // nodetreeに情報反映 m_nodetree->set_posted( number, set ); } // 書き込み履歴のリセット void ArticleBase::clear_post_history() { if( empty() ) return; if( ! is_cached() ) return; read_info(); if( m_vec_posted.size() || m_write_time.tv_sec || m_write_time.tv_usec ){ #ifdef _DEBUG std::cout << "ArticleBase::clear_post_history size = " << m_vec_posted.size() << " time = " << m_write_time_date << " subject = " << m_subject << std::endl; #endif m_vec_posted.clear(); memset( &m_write_time, 0, sizeof( struct timeval ) ); m_write_time_date = std::string(); // nodetreeが作られている時はnodetreeもリセット if( m_nodetree ) m_nodetree->clear_post_history(); m_write_name = std::string(); m_write_mail = std::string(); m_write_fixname = false; m_write_fixmail = false; save_info( true ); } } // // NodeTree作成 // // もしNodeTreeが作られていなかったらここでNewする // // this の参照が無くなったら ArticleBase::unlock_impl()が呼ばれて m_nodetree は自動クリアされる // JDLIB::ConstPtr< NodeTreeBase >& ArticleBase::get_nodetree() { assert( !empty() ); if( ! m_nodetree ){ #ifdef _DEBUG std::cout << "ArticleBase::get_nodetree create " << m_url << std::endl; #endif m_nodetree = create_nodetree(); assert( m_nodetree ); // あぼーん情報のコピー m_nodetree->copy_abone_info( m_list_abone_id, m_list_abone_name, m_list_abone_word, m_list_abone_regex, m_vec_abone_res, m_abone_transparent, m_abone_chain, m_abone_age, m_abone_board, m_abone_global ); // 書き込み情報のコピー m_nodetree->copy_post_info( m_vec_posted ); m_nodetree->sig_updated().connect( sigc::mem_fun( *this, &ArticleBase::slot_node_updated ) ); m_nodetree->sig_finished().connect( sigc::mem_fun( *this, &ArticleBase::slot_load_finished ) ); // キャッシュ読み込み m_number_load = 0; // 読み込み数リセット m_nodetree->load_cache(); } return m_nodetree; } // // this の参照ロックが外れたときに呼ばれる // // m_nodetree を deleteする // void ArticleBase::unlock_impl() { if( !m_nodetree ) return; #ifdef _DEBUG std::cout << "ArticleBase::unlock_impl url = " << m_url << std::endl; #endif m_nodetree->terminate_load(); // deleteする前にスレッド停止 // スレ情報保存 save_info( false ); m_nodetree.clear(); } // // ロード中か // const bool ArticleBase::is_loading() { if( ! m_nodetree ) return false; return m_nodetree->is_loading(); } // // 更新チェック中か // const bool ArticleBase::is_checking_update() { if( ! is_loading() ) return false; return m_nodetree->is_checking_update(); } // // ロード停止 // void ArticleBase::stop_load() { if( ! m_nodetree ) return; m_nodetree->stop_load(); } // // スレッドのロード開始 // // DAT落ちの場合はロードしないので、強制的にリロードしたいときは reset_status() で // ステータスをリセットしてからロードする // // check_update == true の時はHEADによる更新チェックをおこなう // void ArticleBase::download_dat( const bool check_update ) { if( empty() ) return; #ifdef _DEBUG std::cout << "ArticleBase::download_dat " << m_url << " status = " << m_status << " checkupdate = " << check_update << std::endl << "url_pre_article = " << m_url_pre_article << std::endl; #endif struct timeval tv; struct timezone tz; if( gettimeofday( &tv, &tz ) != 0 ) tv.tv_sec = 0; // 更新チェック可能か判定する if( check_update ){ // 一度更新チェックしたらしばらくは再チェックできないようにする time_t passed = 0; if( tv.tv_sec ) passed = MAX( 0, tv.tv_sec - m_check_update_time.tv_sec ); if( ! SESSION::is_online() || ! enable_check_update() || is_loading() || enable_load() // 既に新着あり状態の時はチェックしない || ( m_status & STATUS_OLD ) || ( passed <= CHECKUPDATE_MINSEC ) ) { #ifdef _DEBUG std::cout << "skipped : passed = " << passed << " enable_load = " << enable_load() << " loading = " << is_loading() << std::endl; #endif // スレビューのタブとサイドバーのアイコン表示を更新 // JDが異常終了すると、お気に入りに+が付いてないのにスレが更新可能状態になっていて // 更新チェックが行われてなくなるときがある。このバグは次の様にして再現出来た // (1) 端末からJDを起動する // (2) 適当な板のスレ一覧を開く // (3) お気に入りに適当なスレを登録 // (4) そのスレを読み込む。読み込んだらスレビューは閉じないままにしておく // (5) スレ一覧を更新してそのスレに + マークを付ける。お気に入りにも + が付く // (6) そのスレのスレビューを閉じる ( スレ情報を保存 ) // (7) 端末で Ctrl+c を押してJDを強制終了 // (8) 再起動してお気に入りの復元をしない // (9) お気に入りの + が消えている。以後更新チェックも行われない CORE::core_set_command( "toggle_article_icon", m_url); CORE::core_set_command( "toggle_sidebar_articleicon", m_url ); return; } } if( SESSION::is_online() && tv.tv_sec ) m_check_update_time = tv; // DAT落ちしていてログイン中で無い時はロードしない if( ( m_status & STATUS_OLD ) && ! CORE::get_login2ch()->login_now() ){ #ifdef _DEBUG std::cout << "old !\n"; #endif CORE::core_set_command( "toggle_sidebar_articleicon", m_url ); // update_article_finish コマンドを送らないとキャッシュが無くて // dat落ちしているスレのタブが空白になる CORE::core_set_command( "update_article_finish", m_url ); return; } #ifdef _DEBUG std::cout << "start\n"; #endif get_nodetree()->download_dat( check_update ); } // // 前スレのアドレスの指定 // // 前スレのアドレスをセットしてからdownload_dat()を呼び出すと // ロード終了時( slot_load_finished() )に次スレ移行チェックをする // void ArticleBase::set_url_pre_article( const std::string& url_pre_article ) { #ifdef _DEBUG std::cout << "ArticleBase::set_url_pre_article url = " << url_pre_article << std::endl; #endif m_url_pre_article = url_pre_article; if( ! m_url_pre_article.empty() ){ // 既読スレや板違いのスレに対しては移行チェックはしない if( m_number_load || m_datbase != DBTREE::url_datbase( m_url_pre_article ) || get_since_time() < DBTREE::article_since_time( m_url_pre_article ) ) m_url_pre_article = std::string(); } // TFIDFによる類似度判定のためオフラインに切り替えてからキャッシュにあるsubject.txtを読み込む if( ! m_url_pre_article.empty() && ! DBTREE::board_list_subject( m_url ).size() ){ #ifdef _DEBUG std::cout << "load subjects\n"; #endif const bool online = SESSION::is_online(); SESSION::set_online( false ); DBTREE::board_download_subject( m_url, std::string() ); SESSION::set_online( online ); } } // // url_src で示されるスレの情報をコピー // void ArticleBase::copy_article_info( const std::string& url_src ) { if( url_src.empty() ) return; if( ! DBTREE::article_is_cached( url_src ) ) return; // 名前、メール m_write_fixname = DBTREE::write_fixname( url_src ); m_write_name = DBTREE::write_name( url_src ); m_write_fixmail = DBTREE::write_fixmail( url_src ); m_write_mail = DBTREE::write_mail( url_src ); // あぼーん関係 std::list< std::string > ids; std::list< std::string > names = DBTREE::get_abone_list_name( url_src ); std::list< std::string > words = DBTREE::get_abone_list_word( url_src ); std::list< std::string > regexs = DBTREE::get_abone_list_regex( url_src ); std::vector< char > vec_abone_res; const bool transparent = DBTREE::get_abone_transparent( url_src ); const bool chain = DBTREE::get_abone_chain( url_src ); const bool age = DBTREE::get_abone_age( url_src ); const bool board = DBTREE::get_abone_board( url_src ); const bool global = DBTREE::get_abone_global( url_src ); reset_abone( ids, names ,words, regexs, vec_abone_res, transparent, chain, age, board, global ); } // // ロード中など nodetree の構造が変わったときにnodetreeから呼ばれる slot // void ArticleBase::slot_node_updated() { assert( m_nodetree ); // 更新チェック中 if( m_nodetree->is_checking_update() ) return; #ifdef _DEBUG std::cout << "ArticleBase::slot_node_updated" << std::endl; #endif // nodetreeから情報取得 if( ! m_nodetree->get_subject().empty() ) set_subject( m_nodetree->get_subject() ); // スレが更新している場合 if( m_number_load != m_nodetree->get_res_number() ){ // スレの読み込み数更新 m_number_load = m_nodetree->get_res_number(); // 対応するarticleビューを更新 CORE::core_set_command( "update_article", m_url ); } } // // ロード終了後に nodetree から呼ばれる slot // nodetree から情報を取得する // void ArticleBase::slot_load_finished() { assert( m_nodetree ); #ifdef _DEBUG std::cout << "ArticleBase::slot_load_finished" << std::endl; #endif slot_node_updated(); // HTTPコード取得 const int old_code = m_code; m_code = m_nodetree->get_code(); m_status &= ~STATUS_UPDATED; // 状態更新 const int old_status = m_status; if( m_code != HTTP_ERR ){ // DAT落ち if( m_code == HTTP_MOVED_PERM || m_code == HTTP_REDIRECT || m_code == HTTP_NOT_FOUND || m_code == HTTP_OLD ){ m_status &= ~STATUS_NORMAL; m_status |= STATUS_OLD; CORE::core_set_command( "toggle_sidebar_articleicon", m_url ); } // 既にDAT落ち状態では無いときは通常状態にする else if( ! (m_status & STATUS_OLD ) ){ m_status |= STATUS_NORMAL; m_status &= ~STATUS_OLD; } } // 壊れている if( m_nodetree->is_broken() ) m_status |= STATUS_BROKEN; // 状態が変わっていたら情報保存 if( old_status != m_status ) m_save_info = true; // 更新チェック if( m_nodetree->is_checking_update() ){ #ifdef _DEBUG std::cout << "check_update code = " << m_code << std::endl; #endif // スレタブとお気に入りとスレ一覧のアイコンに更新マークをつける if( m_code == HTTP_OK // まちBBSは206が返らない(200か304のみ) || m_code == HTTP_PARTIAL_CONTENT ){ show_updateicon( true ); // このスレが所属する板を更新可能状態にしてお気に入りやスレ一覧のタブのアイコンに更新マークを表示 DBTREE::board_show_updateicon( m_url, true ); // スレ一覧の ! 行のアイコンを更新マークにする CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id ); } // code と modified を戻しておく m_code = old_code; m_nodetree->set_date_modified( m_date_modified ); #ifdef _DEBUG std::cout << "check_update done\n"; #endif // 更新チェック時間を保存 save_info( true ); // 次のスレを更新チェック CORE::get_checkupdate_manager()->pop_front(); return; } // nodetreeから情報取得 m_str_code = m_nodetree->get_str_code(); std::string m_old_modified = m_date_modified; m_date_modified = m_nodetree->get_date_modified(); if( m_number_before_load < m_number_load ) m_number_new = m_number_load - m_number_before_load; else m_number_new = 0; // 書き込み情報 if( m_number_new && m_nodetree->get_vec_posted().size() ){ if( ! m_vec_posted.size() ) m_vec_posted.resize( MAX_RESNUMBER ); for( int i = m_number_before_load +1; i <= m_number_load; ++i ){ if( m_nodetree->get_vec_posted()[ i ] ) m_vec_posted[ i ] = true; else m_vec_posted[ i ] = false; #ifdef _DEBUG if( m_vec_posted[ i ] ) std::cout << "posted no = " << i << std::endl; #endif } } // 次スレチェック bool relayout = false; if( m_number_load && ! m_url_pre_article.empty() && ! m_subject.empty() ){ const std::string pre_subject = DBTREE::article_subject( m_url_pre_article ); if( ! pre_subject.empty() ){ #ifdef _DEBUG std::cout << "check next\n"; #endif int value = 0; const std::vector< DBTREE::ArticleBase* >& list_subject = DBTREE::board_list_subject( m_url ); // subjectがキャッシュにある場合は TFIDF を使って類似度チェック if( list_subject.size() ){ #ifdef _DEBUG std::cout << "use tfidf\n"; #endif // 単語ベクトル作成 MISC::VEC_WORDS vec_words; MISC::tfidf_create_vec_words( vec_words, pre_subject ); // IDFベクトル計算 MISC::VEC_IDF vec_idf; MISC::tfidf_create_vec_idf_from_board( vec_idf, pre_subject, list_subject, vec_words ); // TFIDFベクトル計算 MISC::VEC_TFIDF vec_tfidf_src; MISC::VEC_TFIDF vec_tfidf; vec_tfidf_src.resize( vec_words.size() ); vec_tfidf.resize( vec_words.size() ); MISC::tfidf_calc_vec_tfifd( vec_tfidf_src, pre_subject, vec_idf, vec_words ); MISC::tfidf_calc_vec_tfifd( vec_tfidf, m_subject, vec_idf, vec_words ); value = ( int )( MISC::tfidf_cos_similarity( vec_tfidf_src, vec_tfidf ) * 10 + .5 ); } // subject がキャッシュに無い場合はレーベンシュタイン距離を使って類似度チェック else{ #ifdef _DEBUG std::cout << "use leven\n"; #endif const int MAXSTR = 256; std::vector< std::vector< int > > dist( MAXSTR, std::vector< int >( MAXSTR ) ); value = 10 - ( int )( MISC::leven( dist, pre_subject, m_subject ) * 10 + .5 ); } #ifdef _DEBUG std::cout << "pre_subject = " << pre_subject << std::endl << "subject = " << m_subject << std::endl << "value = " << value << std::endl; #endif // このスレは m_url_pre_article の次スレとみなして情報をコピーする if( value >= CONFIG::get_threshold_next() ){ #ifdef _DEBUG std::cout << "hit!\n"; #endif copy_article_info( m_url_pre_article ); // お気に入りのアドレスと名前を自動更新 CORE::core_set_command( "replace_favorite_thread", "", m_url_pre_article, m_url ); // 前スレにしおりがセットされていたらしおりをつける if( DBTREE::is_bookmarked_thread( m_url_pre_article ) ){ set_bookmarked_thread( true ); } relayout = true; } #ifdef _DEBUG else std::cout << "not hit\n"; #endif } m_url_pre_article = std::string(); } m_number_before_load = m_number_load; m_ext_err = m_nodetree->get_ext_err(); // スレの数が0ならスレ情報はセーブしない if( ! m_number_load ) m_cached = false; else{ // スレ情報を更新 if( m_number_new // スレが更新している場合 || m_date_modified != m_old_modified // ときどき modified が誤って返るときがあるので最新の値を保存しておく || ( SESSION::is_online() && ( m_status & STATUS_UPDATE ) && ( m_code == HTTP_OK || m_code == HTTP_NOT_MODIFIED ) ) // 間違って更新可能マークが付いている場合はマークを消す ){ m_cached = true; m_read_info = true; m_save_info = true; struct timeval tv; struct timezone tz; if( gettimeofday( &tv, &tz ) == 0 ) { m_access_time = tv; m_access_date = std::string(); } if( m_number < m_number_load ) m_number = m_number_load; m_status |= STATUS_UPDATED; show_updateicon( false ); // 情報ファイルのパスをセット if( m_path_article_info.empty() ) SET_INFOPATH(); } } #ifdef _DEBUG std::cout << "ArticleBase::slot_load_finished " << std::endl << "subject = " << m_subject << std::endl << "load = " << m_number_load << std::endl << "number = " << m_number << std::endl << "new = " << m_number_new << std::endl << "date = " << m_date_modified << std::endl << "access-time = " << get_access_time_str() << std::endl << "code = " << m_code << std::endl << "status = " << m_status << std::endl ; #endif // 対応するBoardビューの行を更新 CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id ); // articleビューに終了を知らせる CORE::core_set_command( "update_article", m_url ); CORE::core_set_command( "update_article_finish", m_url ); // あぼーん情報が前スレよりコピーされたので再レイアウト指定 if( relayout ) CORE::core_set_command( "relayout_article", m_url ); } // // お気に入りのアイコンとスレビューのタブのアイコンに更新マークを表示 // // update == true の時に表示。falseなら戻す // void ArticleBase::show_updateicon( const bool update ) { #ifdef _DEBUG std::cout << "ArticleBase::show_updateicon url = " << m_url << " update = " << update << " status = " << ( m_status & STATUS_UPDATE ) << std::endl; #endif struct timeval tv; struct timezone tz; if( gettimeofday( &tv, &tz ) == 0 ) m_check_update_time = tv; if( update ){ if( ! ( m_status & STATUS_UPDATE ) ){ #ifdef _DEBUG std::cout << "toggle_icon on\n"; #endif m_save_info = true; m_status |= STATUS_UPDATE; // スレビューのタブとサイドバーのアイコン表示を更新 CORE::core_set_command( "toggle_article_icon", m_url); CORE::core_set_command( "toggle_sidebar_articleicon", m_url ); } } else{ // この if をコメントアウトしないと // // スレ一覧を開いてお気に入りにあるスレに更新マークを付ける → スレ一覧を閉じる // 更新マークを付けたスレを開かないでJD終了(※) → 再起動してお気に入りで更新マークを付けたスレをクリック // → お気に入りのアイコン表示が戻らない // // という問題が生じる( ※ の所でスレ情報が保存されていないので再起動すると STATUS_UPDATE が外れるため。 // 終了時にスレ情報を保存しようとすると終了処理が重くなる。) // if( m_status & STATUS_UPDATE ){ #ifdef _DEBUG std::cout << "toggle_icon off\n"; #endif m_save_info = true; m_status &= ~STATUS_UPDATE; // サイドバーのアイコン表示を戻す // スレビューのタブのアイコンはArticleViewがロード終了時に自動的に戻す CORE::core_set_command( "toggle_sidebar_articleicon", m_url ); // } } } // // キャッシュ削除 // // cache_only == true の時はキャッシュだけ削除してスレ情報は消さない // void ArticleBase::delete_cache( const bool cache_only ) { #ifdef _DEBUG std::cout << "ArticleBase::delete_cache url = " << m_url << std::endl; #endif if( empty() ) return; if( ! cache_only ){ if( m_bookmarked_thread ){ const std::string msg = "「" + get_subject() + "」にはしおりが付けられています。\n\nスレを削除しますか?\n\nしおりを解除するにはスレの上で右クリックしてしおり解除を選択してください。"; SKELETON::MsgDiag mdiag( NULL, msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_YES ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; } if( CONFIG::get_show_del_written_thread_diag() && m_write_time.tv_sec ){ const std::string msg = "「" + get_subject() + "」には書き込み履歴が残っています。\n\nスレを削除しますか?"; SKELETON::MsgCheckDiag mdiag( NULL, msg, "今後表示しない(常に削除)(_D)", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; if( mdiag.get_chkbutton().get_active() ) CONFIG::set_del_written_thread_diag( false ); } // スレ内の画像キャッシュ削除 if( CONFIG::get_delete_img_in_thread() != 2 ){ bool delete_img_cache = false; std::list< std::string > list_urls = get_nodetree()->get_urls(); std::list< std::string >::iterator it = list_urls.begin(); for( ; it != list_urls.end(); ++it ){ if( DBIMG::get_type_ext( *it ) != DBIMG::T_UNKNOWN && DBIMG::is_cached( *it ) ){ delete_img_cache = true; break; } } if( delete_img_cache ){ if( CONFIG::get_delete_img_in_thread() == 0 ){ const std::string msg = "「" + get_subject() + "」には画像が貼られています。\n\n画像のキャッシュも削除しますか?"; SKELETON::MsgCheckDiag mdiag( NULL, msg, "今後表示しない(常に削除しない)(_D)", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE ); mdiag.add_button( "スレ削除中止(_C)", Gtk::RESPONSE_CANCEL ); mdiag.add_button( Gtk::Stock::YES, Gtk::RESPONSE_YES ); Gtk::Button button( Gtk::Stock::NO ); mdiag.add_default_button( &button, Gtk::RESPONSE_NO ); const int ret = mdiag.run(); if( ret == Gtk::RESPONSE_CANCEL ) return; if( ret != Gtk::RESPONSE_YES ){ if( mdiag.get_chkbutton().get_active() ) CONFIG::set_delete_img_in_thread( 2 ); delete_img_cache = false; } } if( delete_img_cache ){ it = list_urls.begin(); for( ; it != list_urls.end(); ++it ){ if( DBIMG::get_type_ext( *it ) != DBIMG::T_UNKNOWN && DBIMG::is_cached( *it ) ){ #ifdef _DEBUG std::cout << "delete " << *it << std::endl; #endif DBIMG::delete_cache( *it ); } } } } } } m_number_load = m_number_seen = m_number_before_load = 0; m_cached = false; reset_status(); m_date_modified.clear(); memset( &m_access_time, 0, sizeof( struct timeval ) ); memset( &m_check_update_time, 0, sizeof( struct timeval ) ); if( ! cache_only ){ memset( &m_write_time, 0, sizeof( struct timeval ) ); m_write_time_date.clear(); m_code = HTTP_INIT; m_str_code = std::string(); m_write_name.clear(); m_write_mail.clear(); m_write_fixname = false; m_write_fixmail = false; m_vec_bookmark.clear(); m_vec_posted.clear(); m_list_abone_id.clear(); m_list_abone_name.clear(); m_list_abone_word.clear(); m_list_abone_regex.clear(); m_vec_abone_res.clear(); m_abone_transparent = false; m_abone_chain = false; m_abone_age = false; m_abone_board = true; m_abone_global = true; m_read_info = false; m_save_info = false; m_bookmarked_thread = false; // info 削除 if( CACHE::file_exists( m_path_article_info ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( m_path_article_info ) ); // 拡張info 削除 if( CACHE::file_exists( m_path_article_ext_info ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( m_path_article_ext_info ) ); // お気に入りから削除 CORE::core_set_command( "remove_favorite", m_url ); } // キャッシュ削除 std::string path_dat = CACHE::path_dat( m_url ); if( CACHE::file_exists( path_dat ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( path_dat ) ); // BoardViewの行を更新 CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id ); // サイドバーのアイコン表示を戻す CORE::core_set_command( "toggle_sidebar_articleicon", m_url ); } // // キャッシュを名前を付けて保存 // // path_to はデフォルトのファイル名 // bool ArticleBase::save_dat( const std::string& path_to ) { if( is_loading() ) return false; std::string dir = MISC::get_dir( path_to ); if( dir.empty() ) dir = SESSION::get_dir_dat(); std::string name = MISC::get_filename( path_to ); if( name.empty() ) name = get_id(); std::string save_to = CACHE::copy_file( NULL, CACHE::path_dat( m_url ), dir + name, CACHE::FILE_TYPE_DAT ); if( ! save_to.empty() ){ SESSION::set_dir_dat( MISC::get_dir( save_to ) ); return true; } return false; } // // infoファイル読み込み // // インスタンスが出来るたびに呼んでいると重くなるので、BoardBase::get_article_fromURL() // で初めて参照されたときや、Boardビューに表示するときに一回だけ読み込む // void ArticleBase::read_info() { if( m_read_info ) return; // 一度読んだら2度読みしない if( empty() ) return; if( ! is_cached() ) return; // キャッシュがないなら読まない #ifdef _DEBUG std::cout << "ArticleBase::read_info : url = " << m_url << std::endl; #endif m_read_info = true; const int status_old = m_status; bool saveinfo = false; // 情報ファイルのパスをセット if( m_path_article_info.empty() ) SET_INFOPATH(); int ret = CACHE::file_exists( m_path_article_ext_info ); if( ret == CACHE::EXIST_FILE ){ std::string str_info, str_tmp; std::list< std::string > list_tmp; std::list< std::string >::iterator it_tmp; CACHE::load_rawdata( m_path_article_ext_info, str_info ); std::list< std::string > lines = MISC::get_lines( str_info ); std::list < std::string >::iterator it = lines.begin(), it2; // subject GET_INFOVALUE( m_subject, "subject = " ); // 旧ホスト名 GET_INFOVALUE( m_org_host, "org_host = " ); if( m_org_host.empty() ) m_org_host = MISC::get_hostname( m_url ); // 取得数 m_number_load = 0; GET_INFOVALUE( str_tmp, "load = " ); if( ! str_tmp.empty() ) m_number_load = atoi( str_tmp.c_str() ); m_number_before_load = m_number_load; // 見た場所 m_number_seen = 0; GET_INFOVALUE( str_tmp, "seen = " ); if( ! str_tmp.empty() ) m_number_seen = atoi( str_tmp.c_str() ); // 更新時間 (time) GET_INFOVALUE( m_date_modified, "modified = " ); // access time GET_INFOVALUE( str_tmp, "access = " ); if( ! str_tmp.empty() ){ list_tmp = MISC::split_line( str_tmp ); if( list_tmp.size() == 3 ){ it_tmp = list_tmp.begin(); m_access_time.tv_sec = ( atoi( ( *(it_tmp++) ).c_str() ) << 16 ) + atoi( ( *(it_tmp++) ).c_str() ); m_access_time.tv_usec = atoi( ( *(it_tmp++) ).c_str() ); } } // write time GET_INFOVALUE( str_tmp, "writetime = " ); if( ! str_tmp.empty() ){ list_tmp = MISC::split_line( str_tmp ); if( list_tmp.size() == 3 ){ it_tmp = list_tmp.begin(); m_write_time.tv_sec = ( atoi( ( *(it_tmp++) ).c_str() ) << 16 ) + atoi( ( *(it_tmp++) ).c_str() ); m_write_time.tv_usec = atoi( ( *(it_tmp++) ).c_str() ); } } // write name m_write_name = std::string(); GET_INFOVALUE( m_write_name, "writename = " ); // write mail m_write_mail = std::string(); GET_INFOVALUE( m_write_mail, "writemail = " ); // name 固定 m_write_fixname = false; GET_INFOVALUE( str_tmp, "writefixname = " ); if( ! str_tmp.empty() ) m_write_fixname = atoi( str_tmp.c_str() ); // mail 固定 m_write_fixmail = false; GET_INFOVALUE( str_tmp, "writefixmail = " ); if( ! str_tmp.empty() ) m_write_fixmail = atoi( str_tmp.c_str() ); // 状態 reset_status(); GET_INFOVALUE( str_tmp, "status = " ); if( ! str_tmp.empty() ) m_status = atoi( str_tmp.c_str() ); // あぼーん ID GET_INFOVALUE( str_tmp, "aboneid = " ); if( ! str_tmp.empty() ) m_list_abone_id = MISC::strtolist( str_tmp ); // あぼーん name GET_INFOVALUE( str_tmp, "abonename = " ); if( ! str_tmp.empty() ) m_list_abone_name = MISC::strtolist( str_tmp ); // レスブックマーク GET_INFOVALUE( str_tmp, "bookmark = " ); if( ! str_tmp.empty() ){ if( ! m_vec_bookmark.size() ) m_vec_bookmark.resize( MAX_RESNUMBER ); list_tmp = MISC::split_line( str_tmp ); it_tmp = list_tmp.begin(); for( ; it_tmp != list_tmp.end(); ++it_tmp ){ int number = atoi( (*it_tmp).c_str() ); if( !(*it_tmp).empty() ) m_vec_bookmark[ number ] = true; else m_vec_bookmark[ number ] = false; } } // あぼーん word GET_INFOVALUE( str_tmp, "aboneword = " ); if( ! str_tmp.empty() ) m_list_abone_word = MISC::strtolist( str_tmp ); // あぼーん regex GET_INFOVALUE( str_tmp, "aboneregex = " ); if( ! str_tmp.empty() ) m_list_abone_regex = MISC::strtolist( str_tmp ); // 透明あぼーん m_abone_transparent = false; GET_INFOVALUE( str_tmp, "abonetrp = " ); if( ! str_tmp.empty() ) m_abone_transparent = atoi( str_tmp.c_str() ); // 連鎖あぼーん m_abone_chain = false; GET_INFOVALUE( str_tmp, "abonechain = " ); if( ! str_tmp.empty() ) m_abone_chain = atoi( str_tmp.c_str() ); // レス番号あぼーん m_vec_abone_res.clear(); GET_INFOVALUE( str_tmp, "aboneres = " ); if( ! str_tmp.empty() ){ if( ! m_vec_abone_res.size() ) m_vec_abone_res.resize( MAX_RESNUMBER ); list_tmp = MISC::split_line( str_tmp ); it_tmp = list_tmp.begin(); for( ; it_tmp != list_tmp.end(); ++it_tmp ){ int number = atoi( (*it_tmp).c_str() ); if( !(*it_tmp).empty() ) m_vec_abone_res[ number ] = true; else m_vec_abone_res[ number ] = false; } } // スレ一覧でブックマークされているか m_bookmarked_thread = false; GET_INFOVALUE( str_tmp, "bkmark_thread = " ); if( ! str_tmp.empty() ) m_bookmarked_thread = atoi( str_tmp.c_str() ); // 書き込みしたレス番号 GET_INFOVALUE( str_tmp, "posted = " ); if( ! str_tmp.empty() ){ if( ! m_vec_posted.size() ) m_vec_posted.resize( MAX_RESNUMBER ); list_tmp = MISC::split_line( str_tmp ); it_tmp = list_tmp.begin(); for( ; it_tmp != list_tmp.end(); ++it_tmp ){ int number = atoi( (*it_tmp).c_str() ); if( !(*it_tmp).empty() ) m_vec_posted[ number ] = true; else m_vec_posted[ number ] = false; } } // ageあぼーん m_abone_age = false; GET_INFOVALUE( str_tmp, "aboneage = " ); if( ! str_tmp.empty() ) m_abone_age = atoi( str_tmp.c_str() ); // 最終更新チェック時間 GET_INFOVALUE( str_tmp, "checktime = " ); if( ! str_tmp.empty() ){ list_tmp = MISC::split_line( str_tmp ); if( list_tmp.size() == 2 ){ it_tmp = list_tmp.begin(); m_check_update_time.tv_sec = ( atoi( ( *(it_tmp++) ).c_str() ) << 16 ) + atoi( ( *(it_tmp++) ).c_str() ); } } // 板レベルでのあぼーんを有効にする m_abone_board = true; GET_INFOVALUE( str_tmp, "aboneboard = " ); if( ! str_tmp.empty() ) m_abone_board = atoi( str_tmp.c_str() ); // 全体レベルでのあぼーんを有効にする m_abone_global = true; GET_INFOVALUE( str_tmp, "aboneglobal = " ); if( ! str_tmp.empty() ) m_abone_global = atoi( str_tmp.c_str() ); } // キャッシュはあるけど情報ファイルが無い場合 // 一時的にnodetreeを作って情報を取得して保存 else{ #ifdef _DEBUG std::cout << "ArticleBase::read_info : update info " << m_url << std::endl; std::cout << "load = " << m_number_load << " subject = " << m_subject << std::endl; std::cout << "ret = " << ret << std::endl; std::cout << "path = " << m_path_article_ext_info << std::endl; #endif CORE::core_set_command( "set_status","", "スレ情報更新中・・・しばらくお待ち下さい" ); MISC::MSG( "updating " + m_url ); reset_status(); set_subject( get_nodetree()->get_subject() ); m_number_load = get_nodetree()->get_res_number(); if( !m_number_load ){ m_number_load = 1; m_status |= STATUS_BROKEN; MISC::MSG( "updating failed" ); } m_number_before_load = m_number_load; saveinfo = true; unlock_impl(); #ifdef _DEBUG std::cout << "\nArticleBase::read_info : update done.\n\n"; #endif } if( m_number < m_number_load ) m_number = m_number_load; // infoファイル読み込み前に既にDAT落ち状態になっていた場合は // 状態を DAT 落ちに戻しておく if( ( status_old & STATUS_OLD ) && ( m_status & STATUS_NORMAL ) ){ m_status &= ~STATUS_NORMAL; m_status |= STATUS_OLD; saveinfo = true; } if( saveinfo ) save_info( true ); #ifdef _DEBUG std::cout << "ArticleBase::read_info file = " << m_path_article_ext_info << std::endl; std::cout << "subject = " << m_subject << std::endl << "org_host = " << m_org_host << std::endl << "load = " << m_number_load << std::endl << "seen = " << m_number_seen << std::endl << "modified = " << m_date_modified << std::endl << "writetime = " << m_write_time_date << std::endl << "writename = " << m_write_name << std::endl << "writemail = " << m_write_mail << std::endl << "writefixname = " << m_write_fixname << std::endl << "writefixmail = " << m_write_fixmail << std::endl << "status = " << m_status << std::endl << "transparent_abone = " << m_abone_transparent << std::endl << "bookmarked_thread = " << m_bookmarked_thread << std::endl ; std::cout << "abone-id\n"; std::list < std::string >::iterator it = m_list_abone_id.begin(); for( ; it != m_list_abone_id.end(); ++it ) std::cout << (*it) << std::endl; std::cout << "abone-name\n"; it = m_list_abone_name.begin(); for( ; it != m_list_abone_name.end(); ++it ) std::cout << (*it) << std::endl; std::cout << "abone-word\n"; it = m_list_abone_word.begin(); for( ; it != m_list_abone_word.end(); ++it ) std::cout << (*it) << std::endl; std::cout << "abone-regex\n"; it = m_list_abone_regex.begin(); for( ; it != m_list_abone_regex.end(); ++it ) std::cout << (*it) << std::endl; if( m_vec_abone_res.size() ){ std::cout << "abone-res ="; for( int i = 1; i <= m_number_load; ++i ) if( m_vec_abone_res[ i ] ) std::cout << " " << i; std::cout << std::endl; } if( m_vec_bookmark.size() ){ std::cout << "bookmark ="; for( int i = 1; i <= m_number_load; ++i ) if( m_vec_bookmark[ i ] ) std::cout << " " << i; std::cout << std::endl; } if( m_vec_posted.size() ){ std::cout << "posted ="; for( int i = 1; i <= m_number_load; ++i ) if( m_vec_posted[ i ] ) std::cout << " " << i; std::cout << std::endl; } #endif } // // infoファイル書き込み // // キャッシュがある( is_cached() == true ) かつ // m_save_info = true かつ nodetree が作られている時に保存。 // save_info()を呼ぶ前にm_save_infoをセットすること。 // // キャッシュがあって、force = true の時は強制書き込み void ArticleBase::save_info( const bool force ) { if( empty() ) return; if( ! is_cached() ) return; if( ! force ){ if( ! m_save_info ) return; if( ! m_nodetree ) return; } m_save_info = false; if( m_path_article_ext_info.empty() ) return; if( ! CACHE::mkdir_boardroot( m_url ) ) return; #ifdef _DEBUG std::cout << "ArticleBase::save_info force = " << force << std::endl; std::cout << "path_article_info = " << m_path_article_info << std::endl; std::cout << "path_article_ext_info = " << m_path_article_ext_info << std::endl; std::cout << "subject = " << m_subject << std::endl; #endif // 書き込み時間 std::ostringstream ss_write; if( m_write_time.tv_sec ) ss_write << ( m_write_time.tv_sec >> 16 ) << " " << ( m_write_time.tv_sec & 0xffff ) << " " << m_write_time.tv_usec; // 更新チェック時間 std::ostringstream ss_check; if( m_check_update_time.tv_sec ) ss_check << ( m_check_update_time.tv_sec >> 16 ) << " " << ( m_check_update_time.tv_sec & 0xffff ); // あぼーん情報 std::string str_abone_id = MISC::listtostr( m_list_abone_id ); std::string str_abone_name = MISC::listtostr( m_list_abone_name ); std::string str_abone_word = MISC::listtostr( m_list_abone_word ); std::string str_abone_regex = MISC::listtostr( m_list_abone_regex ); // レスあぼーん std::ostringstream ss_abone_res; if( m_vec_abone_res.size() ){ for( int i = 1; i <= m_number_load; ++i ) if( m_vec_abone_res[ i ] ) ss_abone_res << " " << i; } // レスのブックマーク std::ostringstream ss_bookmark; if( m_vec_bookmark.size() ){ for( int i = 1; i <= m_number_load; ++i ) if( m_vec_bookmark[ i ] ) ss_bookmark << " " << i; } // 書き込み std::ostringstream ss_posted; if( m_vec_posted.size() ){ for( int i = 1; i <= m_number_load; ++i ) if( m_vec_posted[ i ] ) ss_posted << " " << i; } std::ostringstream sstr; sstr << "subject = " << m_subject << std::endl << "org_host = " << m_org_host << std::endl << "load = " << m_number_load << std::endl << "seen = " << m_number_seen << std::endl << "modified = " << m_date_modified << std::endl << "access = " << get_access_time_str() << std::endl << "writetime = " << ss_write.str() << std::endl << "writename = " << m_write_name << std::endl << "writemail = " << m_write_mail << std::endl << "writefixname = " << m_write_fixname << std::endl << "writefixmail = " << m_write_fixmail << std::endl << "status = " << m_status << std::endl << "aboneid = " << str_abone_id << std::endl << "abonename = " << str_abone_name << std::endl << "bookmark = " << ss_bookmark.str() << std::endl << "aboneword = " << str_abone_word << std::endl << "aboneregex = " << str_abone_regex << std::endl << "abonetrp = " << m_abone_transparent << std::endl << "abonechain = " << m_abone_chain << std::endl << "aboneres = " << ss_abone_res.str() << std::endl << "bkmark_thread = " << m_bookmarked_thread << std::endl << "posted = " << ss_posted.str() << std::endl << "aboneage = " << m_abone_age << std::endl << "checktime = " << ss_check.str() << std::endl << "aboneboard = " << m_abone_board << std::endl << "aboneglobal = " << m_abone_global << std::endl ; #ifdef _DEBUG std::cout << "ArticleBase::save_info file = " << m_path_article_ext_info << std::endl; std::cout << sstr.str() << std::endl; #endif CACHE::save_rawdata( m_path_article_ext_info, sstr.str() ); // 互換性のため save_navi2ch_info(); } // // navi2ch互換情報ファイル書き込み // // 互換性のため書き出すだけで実際にはこの中の情報は使わない // void ArticleBase::save_navi2ch_info() { if( empty() ) return; if( ! is_cached() ) return; if( m_path_article_info.empty() ) return; std::string name = "nil"; std::string hide = "nil"; std::string important = "nil"; std::string unfilter = "nil"; std::string mail = "nil"; std::string kako = "nil"; // 保存してあるinfoから扱ってない情報をコピー if( CACHE::file_exists( m_path_article_info ) == CACHE::EXIST_FILE ){ std::string str_info; CACHE::load_rawdata( m_path_article_info, str_info ); #ifdef _DEBUG std::cout << "str_info " << str_info << std::endl; #endif std::list< std::string > lists = MISC::get_elisp_lists( str_info ); std::list< std::string >::iterator it = lists.begin(); do{ ++it; if( it == lists.end() ) break; name = *( it++ ); if( it == lists.end() ) break; ++it; if( it == lists.end() ) break; hide = *( it++ ); if( it == lists.end() ) break; important = *( it++ ); if( it == lists.end() ) break; unfilter = *( it++ ); if( it == lists.end() ) break; mail = *( it++ ); if( it == lists.end() ) break; kako = *( it++ ); } while(0); } std::ostringstream sstr; sstr << "(" << "(number . " << m_number_load << ")" << " " << name << " " << "(time . \"" << m_date_modified << "\")" << " " << hide << " " << important << " " << unfilter << " " << mail << " " << kako << ")"; #ifdef _DEBUG std::cout << "ArticleBase::save_navi2ch_info file = " << m_path_article_info << std::endl; std::cout << sstr.str() << std::endl; #endif CACHE::save_rawdata( m_path_article_info, sstr.str() ); } jd-2.8.7-140104/src/dbtree/articlebase.h0000644000076400010400000004453212056574077014300 0ustar // ライセンス: GPL2 // // スレ情報のベースクラス // // 新スレ用の id は 0000000000(.各板別の拡張子) とする。 // #ifndef _ARTICLEBASE_H #define _ARTICLEBASE_H #include #include #include #include #include #include "skeleton/lockable.h" #include "jdlib/constptr.h" namespace DBTREE { class NodeTreeBase; class NODE; class ArticleBase : public SKELETON::Lockable { // 情報ファイルのパス // デストラクタの中でCACHE::path_article_ext_info()を呼ぶとabortするので // ArticleBase::read_info()が呼ばれたときにパスを取得しておく std::string m_path_article_info; std::string m_path_article_ext_info; // m_nodetree は参照が外れたら自動でクリアされる JDLIB::ConstPtr< NodeTreeBase > m_nodetree; std::string m_url; // dat ファイルのURL std::string m_datbase; // ベースアドレス std::string m_id; // ID ( .datなどの拡張子付き (例) 1234567.dat ) std::string m_key; // ID から拡張子を取った物 std::string m_date_modified; // サーバのデータが更新された時間 time_t m_since_time; // スレが立った時刻 std::string m_since_date; // スレ立て月日( string型 ) int m_code; // HTTPコード std::string m_str_code; // HTTPコード(文字列) std::string m_ext_err; // HTTPコード以外のエラーメッセージ int m_status; // 状態 ( global.h で定義 ) // 移転する前にこのスレがあった旧ホスト名( 移転していないなら m_url に含まれているホスト名と同じ ) // 詳しくはコンストラクタの説明を参照せよ std::string m_org_host; std::string m_subject; // サブジェクト int m_number; // サーバ上にあるレスの数 int m_number_diff; // レス増分( subject.txt をロードした時の m_number の増分 ) int m_number_new; // 新着数( ロードした時の差分読み込み数) int m_number_load; // キャッシュにあるレスの数 int m_number_before_load; // ロード前のレスの数( m_number_new を計算するのに使う ) int m_number_seen; // どこまで読んだか int m_number_max; // 規定の最大レス数(0:未設定) struct timeval m_access_time; // ユーザが最後にロードした時間 std::string m_access_date; // ユーザが最後にロードした月日( string型 ) struct timeval m_check_update_time; // 最終更新チェック時間 struct timeval m_write_time; // 最終書き込み時間 std::string m_write_time_date; // 最終書き込み月日( string型 ) std::string m_write_name; // 書き込み時の名前 std::string m_write_mail; // 書き込み時のメアド bool m_write_fixname; // 書き込み時名前固定 bool m_write_fixmail; // 書き込み時メール固定 // あぼーん情報 std::list< std::string > m_list_abone_id; // あぼーんするID std::list< std::string > m_list_abone_name; // あぼーんする名前 std::list< std::string > m_list_abone_word; // あぼーんする文字列 std::list< std::string > m_list_abone_regex; // あぼーんする正規表現 std::vector< char > m_vec_abone_res; // レスあぼーん情報 bool m_abone_transparent; // 透明あぼーん bool m_abone_chain; // 連鎖あぼーん bool m_abone_age; // age ているレスをあぼーん bool m_abone_board; // 板レベルでのあぼーんを有効にする bool m_abone_global; // 全体レベルでのあぼーんを有効にする // 「スレ」がスレ一覧でブックマークされているか bool m_bookmarked_thread; // 「レス」のブックマーク std::vector< char > m_vec_bookmark; // ブックマーク判定キャッシュ // 自分が書き込んだレスか std::vector< char > m_vec_posted; // HDDにキャッシュされているか bool m_cached; // 情報ファイルを読みこんだらtrueにして2度読みしないようにする bool m_read_info; // true ならunlock_impl()がコールバックされたときに情報保存 bool m_save_info; // 前スレのアドレス // スレが未取得で、この変数がemptyで無いとき download_dat()を呼び出すと // ロード終了時に次スレ移行チェックと前スレの情報のコピーをする std::string m_url_pre_article; // スレッド924か bool m_924; protected: void set_key( const std::string& key ){ m_key = key; } void set_since_time( const time_t since ){ m_since_time = since; } void set_is_924( const bool is924 ){ m_924 = is924; } public: ArticleBase( const std::string& datbase, const std::string& id, bool cached ); virtual ~ArticleBase(); const bool empty(); const std::string& get_url() const { return m_url; } // ID がこのスレのものかどうか virtual const bool equal( const std::string& datbase, const std::string& id ); // 移転があったときなどにdatファイルのベースアドレスを更新 void update_datbase( const std::string& datbase ); // 移転する前のオリジナルのURL const std::string get_org_url(); // 移転する前のオリジナルのホスト名 const std::string& get_org_host() const { return m_org_host; } void set_org_host( const std::string& host ); const std::string& get_id() const { return m_id; } const std::string& get_key() const { return m_key; } const std::string& get_subject() const { return m_subject; } const int get_number() const { return m_number; } const int get_number_diff() const { return m_number_diff; } const int get_number_new() const { return m_number_new; } const int get_number_load() const { return m_number_load; } const int get_number_seen() const{ return m_number_seen; } void set_number_max( const int number ){ m_number_max = number; } // スレ速度 const int get_speed(); // キャッシュにあるdatファイルのサイズ const size_t get_lng_dat(); // nodetree の number 番のレスのヘッダノードのポインタを返す NODE* res_header( int number ); // number番のレスの発言者の名前 const std::string get_name( int number ); // number番の名前の重複数( = 発言数 ) int get_num_name( int number ); // 指定した発言者の名前のレス番号をリストにして取得 std::list< int > get_res_name( const std::string& name ); // number番のレスの時刻を文字列で取得 // 内部で regex を使っているので遅い const std::string get_time_str( int number ); // number番のレスの発言者ID( スレIDではなくて名前の横のID ) const std::string get_id_name( int number ); // 指定した発言者ID の重複数( = 発言数 ) // (注) 下の get_num_id_name( int number )と違って検索するので遅い int get_num_id_name( const std::string& id ); // number番の発言者ID の重複数( = 発言数 ) int get_num_id_name( int number ); // 指定した発言者IDを持つレス番号をリストにして取得 std::list< int > get_res_id_name( const std::string& id_name ); // str_num で指定したレス番号をリストにして取得 // str_num は "from-to" の形式 (例) 3から10をセットしたいなら "3-10" // list_jointは出力で true のスレは前のスレに連結される (例) "3+4" なら 4が3に連結 std::list< int > get_res_str_num( const std::string& str_num, std::list< bool >& list_joint ); // ブックマークをつけたレス番号をリストにして取得 std::list< int > get_res_bm(); // 書き込みしたレス番号をリストにして取得 std::list< int > get_res_posted(); // number番のレスを参照しているレス番号をリストにして取得 std::list< int > get_res_reference( const int number ); // res_num に含まれるレスを参照しているレス番号をリストにして取得 std::list< int > get_res_reference( const std::list< int >& res_num ); // URL を含むレス番号をリストにして取得 std::list< int > get_res_with_url(); // query を含むレス番号をリストにして取得 // mode_or == true なら OR抽出 const std::list< int > get_res_query( const std::string& query, const bool mode_or ); // number番のレスの文字列を返す // ref == true なら先頭に ">" を付ける const std::string get_res_str( int number, bool ref = false ); // number 番のレスの生文字列を返す const std::string get_raw_res_str( int number ); // 書き込み時の名前とメアド const std::string& get_write_name() const { return m_write_name; } void set_write_name( const std::string& str ){ m_save_info = true; m_write_name = str; } const bool get_write_fixname() const { return m_write_fixname; } void set_write_fixname( bool set ){ m_save_info = true; m_write_fixname = set; } const std::string& get_write_mail() const { return m_write_mail; } void set_write_mail( const std::string& str ){ m_save_info = true; m_write_mail = str; } const bool get_write_fixmail() const { return m_write_fixmail; } void set_write_fixmail( bool set ){ m_save_info = true; m_write_fixmail = set; } // 書き込みメッセージ作成 virtual const std::string create_write_message( const std::string& name, const std::string& mail, const std::string& msg ) { return std::string(); } // bbscgi のURL virtual const std::string url_bbscgi() { return std::string(); } // subbbscgi のURL virtual const std::string url_subbbscgi() { return std::string(); } // 最終アクセス時間 const std::string get_access_time_str(); const time_t& get_access_time() const { return m_access_time.tv_sec; } // 秒 const std::string& get_access_date(); // string型 // 最終書き込み時間 const time_t& get_write_time() const { return m_write_time.tv_sec; } // 秒 const std::string& get_write_date(); // string型 void reset_write_date(){ m_write_time_date = std::string(); } // 書き込み数 const int get_num_posted(); // 自分の書き込みか const bool is_posted( const int number ); // 自分の書き込みにレスしたか const bool is_refer_posted( const int number ); // 書き込みマークセット void set_posted( const int number, const bool set ); // 書き込み履歴のリセット void clear_post_history(); // スレ立て時刻 const time_t& get_since_time() const { return m_since_time; }; const std::string& get_since_date(); void reset_since_date(){ m_since_date = std::string(); } // 更新時間 time_t get_time_modified(); const std::string& get_date_modified() { return m_date_modified; } void set_date_modified( const std::string& date ){ m_date_modified = date; } // スレが立ってからの経過時間( 時間 ) const int get_hour(); // http コード const int get_code() const { return m_code; } const std::string& get_str_code() const { return m_str_code; } // エラーメッセージ const std::string& get_ext_err() const { return m_ext_err; } // DAT落ちかどうかなどの状態 ( global.hで定義 ) const int get_status() const{ return m_status; } void set_status( const int status ){ m_status = status; } void set_subject( const std::string& subject ); void set_number( const int number, const bool is_online ); void set_number_load( const int number_load ); void set_number_seen( const int number_seen ); void update_writetime(); // キャッシュ削除 // cache_only == true の時はキャッシュだけ削除してスレ情報は消さない virtual void delete_cache( const bool cache_only ); // キャッシュ保存 bool save_dat( const std::string& path_to ); // HDDにキャッシュされているか const bool is_cached() const { return m_cached; } void set_cached( const bool set ){ m_cached = set; } // キャッシュがarticlebaseに読み込まれている(nodetree!=NULL)か const bool is_cache_read() const { return ( m_nodetree ); } // キャッシュがあって、かつ新着の読み込みが可能 const bool enable_load(); // キャッシュはあるが規定のレス数を越えていて、かつ全てのレスが既読 const bool is_finished(); // あぼーん情報 const std::list< std::string >& get_abone_list_id(){ return m_list_abone_id; } const std::list< std::string >& get_abone_list_name(){ return m_list_abone_name; } const std::list< std::string >& get_abone_list_word(){ return m_list_abone_word; } const std::list< std::string >& get_abone_list_regex(){ return m_list_abone_regex; } const std::vector< char >& get_abone_vec_res(){ return m_vec_abone_res; } // 透明 const bool get_abone_transparent(); // 連鎖 const bool get_abone_chain(); // ageあぼーん const bool get_abone_age() const { return m_abone_age; } // 板レベルでのあぼーん const bool get_abone_board() const { return m_abone_board; } // 全体レベルでのあぼーん const bool get_abone_global() const { return m_abone_global; } // number番のレスがあぼーんされているか const bool get_abone( int number ); // 全レスのあぼーん状態の更新 void update_abone(); // あぼーん状態のリセット(情報セットと状態更新を同時におこなう) void reset_abone( const std::list< std::string >& ids, const std::list< std::string >& names, const std::list< std::string >& words, const std::list< std::string >& regexs, const std::vector< char >& vec_abone_res, const bool transparent, const bool chain, const bool age, const bool board, const bool global ); // あぼ〜ん状態更新(reset_abone()と違って各項目ごと個別におこなう) void add_abone_id( const std::string& id ); void add_abone_name( const std::string& name ); void add_abone_word( const std::string& word ); void set_abone_res( const int num_from, const int num_to, const bool set ); void set_abone_transparent( const bool set ); // 透明 void set_abone_chain( const bool set ); // 連鎖 void set_abone_age( const bool set ); // age void set_abone_board( const bool set ); // 板レベルでのあぼーん void set_abone_global( const bool set ); // 全体レベルでのあぼーん // 「スレ」のブックマーク void set_bookmarked_thread( const bool bookmarked ); const bool is_bookmarked_thread() const { return m_bookmarked_thread; } // 「レス」のブックマーク const int get_num_bookmark(); const bool is_bookmarked( const int number ); void set_bookmark( const int number, const bool set ); // 情報ファイル読み込み void read_info(); // 情報ファイル書き込み // キャッシュがあって、force = true の時は強制書き込み virtual void save_info( const bool force ); const bool is_loading(); // ロード中か const bool is_checking_update(); // 更新チェック中か // スレッドのロード停止 void stop_load(); // スレッドのロード開始 // DAT落ちの場合はロードしないので、強制的にリロードしたいときは reset_status() で // ステータスをリセットしてからロードする // check_update : true の時はHEADによる更新チェックをおこなう virtual void download_dat( const bool check_update ); // 前スレのアドレスを指定 // 前スレのアドレスをセットしてからdownload_dat()を呼び出すと // ロード終了時( slot_load_finished() )に次スレ移行チェックをする void set_url_pre_article( const std::string& url_pre_article ); // url_src で示されるスレの情報をコピー void copy_article_info( const std::string& url_src ); // スレッド924か const bool is_924() const{ return m_924; } private: // 更新チェック可能 virtual const bool enable_check_update(){ return true; } // NodeTree作成 // もしNodeTreeが作られていなかったら作成 JDLIB::ConstPtr< NodeTreeBase >& get_nodetree(); virtual NodeTreeBase* create_nodetree(){ return NULL; } void reset_status(); void slot_node_updated(); void slot_load_finished(); virtual void unlock_impl(); // お気に入りのアイコンとスレビューのタブのアイコンに更新マークを表示 // update == true の時に表示。falseなら戻す void show_updateicon( const bool update ); // navi2ch互換情報ファイル書き込み void save_navi2ch_info(); }; } #endif jd-2.8.7-140104/src/dbtree/articlehash.cpp0000644000076400010400000000562611322351043014622 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articlehash.h" #include "articlebase.h" #include // atoi using namespace DBTREE; enum { HASH_TBLSIZE = 1024 }; ArticleHash::ArticleHash() : m_size( 0 ), m_min_hash( HASH_TBLSIZE + 1 ) { m_iterator = new ArticleHashIterator( this ); } ArticleHash::~ArticleHash() { #ifdef _DEBUG if( size() ){ std::cout << "ArticleHash::~ArticleHash\n"; const size_t tblsize = m_table.size(); for( size_t hash = 0; hash < tblsize; ++hash ){ if( m_table[ hash ].size()) std::cout << hash << " : size = " << m_table[ hash ].size() << std::endl; } } #endif if( m_iterator ) delete m_iterator; m_iterator = NULL; } const int ArticleHash::get_hash( const std::string& id ) { const size_t hash = atoi( id.c_str() ) & ( HASH_TBLSIZE -1 ); #ifdef _DEBUG std::cout << id << " -> " << hash << std::endl; #endif return hash; } void ArticleHash::push( ArticleBase* article ) { if( ! m_table.size() ){ m_table.resize( HASH_TBLSIZE ); } const size_t hash = get_hash( article->get_id() ); if( hash < m_min_hash ) m_min_hash = hash; ++m_size; m_table[ hash ].push_back( article ); } ArticleBase* ArticleHash::find( const std::string& datbase, const std::string& id ) { if( ! m_table.size() ) return NULL; const size_t hash = get_hash( id ); std::vector< ArticleBase* >::iterator it = m_table[ hash ].begin(); for( ; it != m_table[ hash ].end(); ++it ) if( ( *it )->equal( datbase, id ) ) return *it; return NULL; } const ArticleHashIterator ArticleHash::begin() { m_it_hash = m_min_hash; m_it_pos = 0; m_it_size = 0; return *m_iterator; } ArticleBase* ArticleHash::it_get() { if( m_it_hash >= m_table.size() ) return NULL; return m_table[ m_it_hash ][ m_it_pos ]; } void ArticleHash::it_inc() { #ifdef _DEBUG std::cout << "ArticleHash::it_inc hash = " << m_it_hash << " pos = " << m_it_pos; #endif ++m_it_size; if( m_it_size < size() ){ ++m_it_pos; if( m_it_pos == m_table[ m_it_hash ].size() ){ m_it_pos = 0; while( ! m_table[ ++m_it_hash ].size() ); } } #ifdef _DEBUG std::cout << " -> hash = " << m_it_hash << " tablesize = " << m_table[ m_it_hash ].size() << " pos = " << m_it_pos << " size = " << m_it_size << " / " << size() << std::endl; #endif } ///////////////////////////////////////////////////// ArticleHashIterator::ArticleHashIterator( ArticleHash* hashtable ) : m_hashtable( hashtable ) {} ArticleBase* ArticleHashIterator::operator * () { return m_hashtable->it_get(); } ArticleBase* ArticleHashIterator::operator ++ () { m_hashtable->it_inc(); return m_hashtable->it_get(); } bool ArticleHashIterator::operator != ( const size_t size ) { return ( m_hashtable->it_size() != size ); } jd-2.8.7-140104/src/dbtree/articlehash.h0000644000076400010400000000311411177206361014267 0ustar // ライセンス: GPL2 // // ArticleBaseのチェーン式ハッシュテーブルとイテレータ // // コンパイルが遅くなるのでテンプレートを使用しないでArticleBase専用にした #ifndef _ARTICLEHASH_H #define _ARTICLEHASH_H #include #include namespace DBTREE { class ArticleBase; class ArticleHashIterator; class ArticleHash { friend class ArticleHashIterator; size_t m_size; size_t m_min_hash; ArticleHashIterator* m_iterator; std::vector< std::vector< ArticleBase* > > m_table; // iterator 用変数 size_t m_it_hash; size_t m_it_pos; size_t m_it_size; public: ArticleHash(); virtual ~ArticleHash(); const size_t size() const { return m_size; } void push( ArticleBase* article ); ArticleBase* find( const std::string& datbase, const std::string& id ); const ArticleHashIterator begin(); const size_t end() const{ return size(); } private: const int get_hash( const std::string& id ); // iterator 用関数 ArticleBase* it_get(); void it_inc(); const size_t it_size() const { return m_it_size; } }; ///////////////////////////////////////////////////// class ArticleHashIterator { ArticleHash* m_hashtable; public: ArticleHashIterator( ArticleHash* hashtable ); ArticleBase* operator * (); ArticleBase* operator ++ (); bool operator != ( const size_t size ); }; } #endif jd-2.8.7-140104/src/dbtree/articlejbbs.cpp0000644000076400010400000000465312260002463014617 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articlejbbs.h" #include "nodetreejbbs.h" #include "interface.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include using namespace DBTREE; ArticleJBBS::ArticleJBBS( const std::string& datbase, const std::string& _id, bool cached ) : ArticleBase( datbase, _id, cached ) { assert( ! get_id().empty() ); // JBBS の場合は拡張子が無いので key = id set_key( get_id() ); // key から since 計算 set_since_time( atol( get_key().c_str() ) ); } ArticleJBBS::~ArticleJBBS() {} const std::string ArticleJBBS::create_write_message( const std::string& name, const std::string& mail, const std::string& msg ) { if( msg.empty() ) return std::string(); std::string charset = DBTREE::board_charset( get_url() ); // DIR と BBS を分離する( ID = DIR/BBS ) std::string boardid = DBTREE::board_id( get_url() ); int i = boardid.find( "/" ); std::string dir = boardid.substr( 0, i ); std::string bbs = boardid.substr( i + 1 ); std::stringstream ss_post; ss_post.clear(); ss_post << "BBS=" << bbs << "&KEY=" << get_key() << "&DIR=" << dir << "&TIME=" << get_time_modified() << "&submit=" << MISC::charset_url_encode( "書き込む", charset ) << "&NAME=" << MISC::charset_url_encode( name, charset ) << "&MAIL=" << MISC::charset_url_encode( mail, charset ) << "&MESSAGE=" << MISC::charset_url_encode( msg, charset ); #ifdef _DEBUG std::cout << "Articlejbbs::create_write_message " << ss_post.str() << std::endl; #endif return ss_post.str(); } // // bbscgi(write.cgi) のURL // // (例) "http://jbbs.shitaraba.net/bbs/write.cgi/computer/123/1234567/" // // const std::string ArticleJBBS::url_bbscgi() { return DBTREE::url_bbscgibase( get_url() ) + DBTREE::board_id( get_url() ) + "/" + get_key() + "/"; } // // subbbscgi のURL // // (例) "http://jbbs.shitaraba.net/bbs/write.cgi/computer/123/1234567/" // const std::string ArticleJBBS::url_subbbscgi() { return DBTREE::url_subbbscgibase( get_url() ) + DBTREE::board_id( get_url() ) + "/" + get_key() + "/"; } NodeTreeBase* ArticleJBBS::create_nodetree() { #ifdef _DEBUG std::cout << "ArticleJBBS::create_nodetree " << get_url() << std::endl; #endif return new NodeTreeJBBS( get_url(), get_date_modified() ); } jd-2.8.7-140104/src/dbtree/articlejbbs.h0000644000076400010400000000157611340000342014255 0ustar // ライセンス: GPL2 // // JBBS型スレ情報クラス // #ifndef _ARTICLEJBBS_H #define _ARTICLEJBBS_H #include "articlebase.h" namespace DBTREE { class NodeTreeBase; class ArticleJBBS : public ArticleBase { public: ArticleJBBS( const std::string& datbase, const std::string& id, bool cached ); ~ArticleJBBS(); // 書き込みメッセージ変換 virtual const std::string create_write_message( const std::string& name, const std::string& mail, const std::string& msg ); // bbscgi のURL virtual const std::string url_bbscgi(); // subbbscgi のURL virtual const std::string url_subbbscgi(); private: // 更新チェック不可能 virtual const bool enable_check_update(){ return false; } virtual NodeTreeBase* create_nodetree(); }; } #endif jd-2.8.7-140104/src/dbtree/articlelocal.cpp0000644000076400010400000000153411176055047014777 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articlelocal.h" #include "nodetreelocal.h" using namespace DBTREE; ArticleLocal::ArticleLocal( const std::string& datbase, const std::string& id ) : Article2chCompati( datbase, id, true ) { #ifdef _DEBUG std::cout << "ArticleLocal::ArticleLocal datbase = " << datbase << ", id = " << id << ", url = " << get_url() << std::endl; #endif } ArticleLocal::~ArticleLocal() { #ifdef _DEBUG std::cout << "ArticleLocal::~ArticleLocal url = " << get_url() << std::endl; #endif } // ID がこのスレのものかどうか const bool ArticleLocal::equal( const std::string& datbase, const std::string& id ) { return ( get_url() == datbase + id ); } NodeTreeBase* ArticleLocal::create_nodetree() { return new NodeTreeLocal( get_url() ); } jd-2.8.7-140104/src/dbtree/articlelocal.h0000644000076400010400000000160511160730160014430 0ustar // ライセンス: GPL2 // // ローカルファイル用スレ情報クラス // #ifndef _ARTICLELOCAL_H #define _ARTICLELOCAL_H #include "article2chcompati.h" namespace DBTREE { class ArticleLocal : public Article2chCompati { public: ArticleLocal( const std::string& datbase, const std::string& id ); ~ArticleLocal(); // ID がこのスレのものかどうか virtual const bool equal( const std::string& datbase, const std::string& id ); // キャッシュの削除をしない virtual void delete_cache( const bool cache_only ){} // 情報ファイルを保存しない virtual void save_info( const bool force ){} // ダウンロードしない virtual void download_dat( const bool check_update ){} private: virtual NodeTreeBase* create_nodetree(); }; } #endif jd-2.8.7-140104/src/dbtree/articlemachi.cpp0000644000076400010400000000460211340000342014742 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "articlemachi.h" #include "nodetreemachi.h" #include "interface.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "config/globalconf.h" #include using namespace DBTREE; ArticleMachi::ArticleMachi( const std::string& datbase, const std::string& _id, bool cached ) : ArticleBase( datbase, _id, cached ) { assert( !get_id().empty() ); // Machi の場合は拡張子が無いので key = id set_key( get_id() ); // key から since 計算 set_since_time( atol( get_key().c_str() ) ); } ArticleMachi::~ArticleMachi() {} const std::string ArticleMachi::create_write_message( const std::string& name, const std::string& mail, const std::string& msg ) { if( msg.empty() ) return std::string(); std::string charset = DBTREE::board_charset( get_url() ); std::stringstream ss_post; ss_post.clear(); ss_post << "BBS=" << DBTREE::board_id( get_url() ) << "&KEY=" << get_key() << "&TIME=" << get_time_modified() << "&submit=" << MISC::charset_url_encode( "書き込む", charset ) << "&NAME=" << MISC::charset_url_encode( name, charset ) << "&MAIL=" << MISC::charset_url_encode( mail, charset ) << "&MESSAGE=" << MISC::charset_url_encode( msg, charset ); #ifdef _DEBUG std::cout << "ArticleMachi::create_write_message " << ss_post.str() << std::endl; #endif return ss_post.str(); } // // bbscgi のURL // // (例) "http://www.machi.to/bbs/write.cgi" // // const std::string ArticleMachi::url_bbscgi() { std::string cgibase = DBTREE::url_bbscgibase( get_url() ); return cgibase.substr( 0, cgibase.length() -1 ); // 最後の '/' を除く } // // subbbscgi のURL // // (例) "http://www.machi.to/bbs/write.cgi" // const std::string ArticleMachi::url_subbbscgi() { std::string cgibase = DBTREE::url_subbbscgibase( get_url() ); return cgibase.substr( 0, cgibase.length() -1 ); // 最後の '/' を除く } // offlawモードなら更新チェック可能 const bool ArticleMachi::enable_check_update() { return CONFIG::get_use_machi_offlaw(); } NodeTreeBase* ArticleMachi::create_nodetree() { #ifdef _DEBUG std::cout << "ArticleMachi::create_nodetree " << get_url() << std::endl; #endif return new NodeTreeMachi( get_url(), get_date_modified() ); } jd-2.8.7-140104/src/dbtree/articlemachi.h0000644000076400010400000000161111340000342014404 0ustar // ライセンス: GPL2 // // まち型スレ情報クラス // #ifndef _ARTICLEMACHI_H #define _ARTICLEMACHI_H_H #include "articlebase.h" namespace DBTREE { class NodeTreeBase; class ArticleMachi : public ArticleBase { public: ArticleMachi( const std::string& datbase, const std::string& id, bool cached ); ~ArticleMachi(); // 書き込みメッセージ変換 virtual const std::string create_write_message( const std::string& name, const std::string& mail, const std::string& msg ); // bbscgi のURL virtual const std::string url_bbscgi(); // subbbscgi のURL virtual const std::string url_subbbscgi(); private: // offlawモードなら更新チェック可能 virtual const bool enable_check_update(); virtual NodeTreeBase* create_nodetree(); }; } #endif jd-2.8.7-140104/src/dbtree/board2ch.cpp0000644000076400010400000002147511533727427014040 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "board2ch.h" #include "article2ch.h" #include "articlehash.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "jdlib/jdregex.h" #include "login2ch.h" #include "loginbe.h" #include "loginp2.h" #include using namespace DBTREE; Board2ch::Board2ch( const std::string& root, const std::string& path_board, const std::string& name ) : Board2chCompati( root, path_board, name, std::string() ) { #ifdef _DEBUG std::cout << "Board2ch::Board2ch\n"; #endif } Board2ch::~Board2ch() {} // ユーザエージェント // ダウンロード用 const std::string& Board2ch::get_agent() { return CONFIG::get_agent_for2ch(); } // 書き込み用 const std::string& Board2ch::get_agent_w() { if( CORE::get_loginp2()->login_now() ) return CONFIG::get_agent_for_data(); return CONFIG::get_agent_for2ch(); } // 読み込み用プロキシ const std::string Board2ch::get_proxy_host() { const int mode = get_mode_local_proxy(); if( mode == DBTREE::PROXY_GLOBAL ){ if( CONFIG::get_use_proxy_for2ch() ) return CONFIG::get_proxy_for2ch(); } else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy(); return std::string(); } const int Board2ch::get_proxy_port() { const int mode = get_mode_local_proxy(); if( mode == DBTREE::PROXY_GLOBAL ) return CONFIG::get_proxy_port_for2ch(); else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_port(); return 0; } const std::string Board2ch::get_proxy_basicauth() { const int mode = get_mode_local_proxy(); if( mode == DBTREE::PROXY_GLOBAL ) return CONFIG::get_proxy_basicauth_for2ch(); else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_basicauth(); return std::string(); } // 書き込み用プロキシ const std::string Board2ch::get_proxy_host_w() { if( CORE::get_loginp2()->login_now() ){ if( CONFIG::get_use_proxy_for_data() ) return CONFIG::get_proxy_for_data(); else return std::string(); } const int mode = get_mode_local_proxy_w(); if( mode == DBTREE::PROXY_GLOBAL ){ if( CONFIG::get_use_proxy_for2ch_w() ) return CONFIG::get_proxy_for2ch_w(); } else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_w(); return std::string(); } const int Board2ch::get_proxy_port_w() { if( CORE::get_loginp2()->login_now() ) return CONFIG::get_proxy_port_for_data(); const int mode = get_mode_local_proxy_w(); if( mode == DBTREE::PROXY_GLOBAL ) return CONFIG::get_proxy_port_for2ch_w(); else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_port_w(); return 0; } const std::string Board2ch::get_proxy_basicauth_w() { if( CORE::get_loginp2()->login_now() ) return CONFIG::get_proxy_basicauth_for_data(); const int mode = get_mode_local_proxy_w(); if( mode == DBTREE::PROXY_GLOBAL ) return CONFIG::get_proxy_basicauth_for2ch_w(); else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_basicauth_w(); return std::string(); } //書き込み用クッキー作成 const std::string Board2ch::cookie_for_write() { #ifdef _DEBUG std::cout << "Board2ch::cookie_for_write\n"; #endif std::string cookie = Board2chCompati::cookie_for_write(); // p2 ログイン中 if( CORE::get_loginp2()->login_now() ){ if( ! cookie.empty() ) cookie += "; "; cookie += "cid=" + CORE::get_loginp2()->get_sessionid(); } // BE ログイン中 else if( CORE::get_loginbe()->login_now() ){ if( ! cookie.empty() ) cookie += "; "; cookie += "DMDM=" + CORE::get_loginbe()->get_sessionid() + "; MDMD=" + CORE::get_loginbe()->get_sessiondata(); } #ifdef _DEBUG std::cout << "cookie = " << cookie << std::endl; #endif return cookie; } const std::string Board2ch::get_write_referer() { // p2ログインの場合はとりあえず空文字 if( CORE::get_loginp2()->login_now() ) return std::string(); return Board2chCompati::get_write_referer(); } // 新スレ作成時の書き込みメッセージ作成 const std::string Board2ch::create_newarticle_message( const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ) { if( subject.empty() ) return std::string(); if( msg.empty() ) return std::string(); std::stringstream ss_post; ss_post.clear(); ss_post << "bbs=" << get_id() << "&subject=" << MISC::charset_url_encode( subject, get_charset() ); // キーワード( hana=mogera や suka=pontan など ) const std::string keyword = get_keyword_for_write(); if( ! keyword.empty() ) ss_post << "&" << keyword; // 2chログイン中 // sidを送る if( ! CORE::get_loginp2()->login_now() && CORE::get_login2ch()->login_now() ){ std::string sid = CORE::get_login2ch()->get_sessionid(); ss_post << "&sid=" << MISC::url_encode( sid.c_str(), sid.length() ); } ss_post << "&time=" << get_time_modified() << "&submit=" << MISC::charset_url_encode( "新規スレッド作成", get_charset() ) << "&FROM=" << MISC::charset_url_encode( name, get_charset() ) << "&mail=" << MISC::charset_url_encode( mail, get_charset() ) << "&MESSAGE=" << MISC::charset_url_encode( msg, get_charset() ); if( CORE::get_loginp2()->login_now() ){ ss_post << "&detect_hint=" << MISC::charset_url_encode( "◎◇", get_charset() ) << "&host=" << MISC::url_encode( MISC::get_hostname( get_root(), false ) ) << "&key=" << "&popup=1" << "&rescount=1" << "&ttitle_en=" << "&csrfid=" << MISC::url_encode( CORE::get_loginp2()->get_sessiondata() ) << "&newthread=1"; } #ifdef _DEBUG std::cout << "Board2ch::create_newarticle_message " << ss_post.str() << std::endl; #endif return ss_post.str(); } // // 新スレ作成時のbbscgi のURL // // (例) "http://www.hoge2ch.net/test/bbs.cgi" // // const std::string Board2ch::url_bbscgi_new() { if( CORE::get_loginp2()->login_now() ) return CONFIG::get_url_loginp2() + "post.php"; return Board2chCompati::url_bbscgi_new(); } // // 新スレ作成時のsubbbscgi のURL // // (例) "http://www.hoge2ch.net/test/subbbs.cgi" // const std::string Board2ch::url_subbbscgi_new() { if( CORE::get_loginp2()->login_now() ) return CONFIG::get_url_loginp2() + "post.php"; return Board2chCompati::url_subbbscgi_new(); } // // 新しくArticleBaseクラスを追加してそのポインタを返す // // cached : HDD にキャッシュがあるならtrue // ArticleBase* Board2ch::append_article( const std::string& datbase, const std::string& id, const bool cached ) { if( empty() ) return get_article_null(); ArticleBase* article = new DBTREE::Article2ch( datbase, id, cached ); if( article ){ get_hash_article()->push( article ); // 最大レス数セット article->set_number_max( get_number_max_res() ); } else return get_article_null(); return article; } // 2chのクッキー:HAP const std::string Board2ch::get_hap() { if( ! CONFIG::get_use_cookie_hap() ) return std::string(); if( get_root().find( ".bbspink.com" ) != std::string::npos ) return CONFIG::get_cookie_hap_bbspink(); return CONFIG::get_cookie_hap(); } void Board2ch::set_hap( const std::string& hap ) { if( ! CONFIG::get_use_cookie_hap() ) return; if( get_root().find( ".bbspink.com" ) != std::string::npos ) CONFIG::set_cookie_hap_bbspink( hap ); else CONFIG::set_cookie_hap( hap ); } // // 2chのクッキー:HAPの更新 // void Board2ch::update_hap() { if( ! CONFIG::get_use_cookie_hap() ) return; const std::list< std::string > list_cookies = BoardBase::list_cookies_for_write(); if( list_cookies.empty() ) return; #ifdef _DEBUG std::cout << "Board2ch::update_hap\n"; #endif JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; const std::string query_hap = "HAP=([^;]*)?"; std::list< std::string >::const_iterator it = list_cookies.begin(); for( ; it != list_cookies.end(); ++it ){ const std::string cookie = (*it); #ifdef _DEBUG std::cout << cookie << std::endl; #endif if( regex.exec( query_hap, cookie, offset, icase, newline, usemigemo, wchar ) ){ const std::string tmp_hap = regex.str( 1 ); if( ! tmp_hap.empty() && tmp_hap != get_hap() ){ #ifdef _DEBUG std::cout << "old = " << get_hap() << std::endl; std::cout << "new = " << tmp_hap << std::endl; #endif set_hap( tmp_hap ); return; } } } } jd-2.8.7-140104/src/dbtree/board2ch.h0000644000076400010400000000462311533727427013501 0ustar // ライセンス: GPL2 // // 2ch // #ifndef _BOARD2CH_H #define _BOARD2CH_H #include "board2chcompati.h" namespace DBTREE { enum { DEFAULT_NUMBER_MAX_2CH = 1000, // デフォルト最大レス数 DEFAULT_MAX_DAT_LNG = 512 // デフォルトのdatの最大サイズ(Kバイト) }; class Board2ch : public Board2chCompati { public: Board2ch( const std::string& root, const std::string& path_board,const std::string& name ); virtual ~Board2ch(); // ユーザーエージェント virtual const std::string& get_agent(); // ダウンロード用 virtual const std::string& get_agent_w(); // 書き込み用 // 読み込み用プロキシ virtual const std::string get_proxy_host(); virtual const int get_proxy_port(); virtual const std::string get_proxy_basicauth(); // 書き込み用プロキシ virtual const std::string get_proxy_host_w(); virtual const int get_proxy_port_w(); virtual const std::string get_proxy_basicauth_w(); // 書き込み用クッキー virtual const std::string cookie_for_write(); // 書き込み時のリファラ virtual const std::string get_write_referer(); // 新スレ作成用のメッセージ変換 virtual const std::string create_newarticle_message( const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ); // 新スレ作成用のbbscgi のURL virtual const std::string url_bbscgi_new(); // 新スレ作成用のsubbbscgi のURL virtual const std::string url_subbbscgi_new(); // datの最大サイズ(Kバイト) virtual const int get_max_dat_lng() const { return DEFAULT_MAX_DAT_LNG; } protected: // クッキー:HAP virtual const std::string get_hap(); virtual void set_hap( const std::string& hap ); // クッキー:HAPの更新 (クッキーをセットした時に実行) virtual void update_hap(); private: // デフォルト最大レス数 virtual const int get_default_number_max_res() { return DEFAULT_NUMBER_MAX_2CH; } virtual ArticleBase* append_article( const std::string& datbase, const std::string& id, const bool cached ); }; } #endif jd-2.8.7-140104/src/dbtree/board2chcompati.cpp0000644000076400010400000004372612074275756015424 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "board2chcompati.h" #include "article2chcompati.h" #include "articlehash.h" #include "settingloader.h" #include "ruleloader.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/jdregex.h" #include "config/globalconf.h" #include "httpcode.h" #include "global.h" #include #include using namespace DBTREE; #ifndef MAX #define MAX( a, b ) ( a > b ? a : b ) #endif #ifndef MIN #define MIN( a, b ) ( a < b ? a : b ) #endif Board2chCompati::Board2chCompati( const std::string& root, const std::string& path_board, const std::string& name, const std::string& basicauth) : BoardBase( root, path_board, name ), m_settingloader( NULL ), m_ruleloader( NULL ) { set_path_dat( "/dat" ); set_path_readcgi( "/test/read.cgi" ); set_path_bbscgi( "/test/bbs.cgi" ); set_path_subbbscgi( "/test/subbbs.cgi" ); set_subjecttxt( "subject.txt" ); set_ext( ".dat" ); set_id( path_board.substr( 1 ) ); // 先頭の '/' を除く set_charset( "MS932" ); BoardBase::set_basicauth( basicauth ); } Board2chCompati::~Board2chCompati() { if( m_settingloader ){ m_settingloader->terminate_load(); delete m_settingloader; } m_settingloader = NULL; if( m_ruleloader ){ m_ruleloader->terminate_load(); delete m_ruleloader; } m_ruleloader = NULL; } // // キャッシュのファイル名が正しいか // const bool Board2chCompati::is_valid( const std::string& filename ) { if( filename.find( get_ext() ) == std::string::npos ) return false; if( filename.length() - filename.rfind( get_ext() ) != get_ext().length() ) return false; size_t dig, n; MISC::str_to_uint( filename.c_str(), dig, n ); if( dig != n ) return false; if( dig == 0 ) return false; return true; } //書き込み用クッキー作成 const std::string Board2chCompati::cookie_for_write() { const std::list< std::string > list_cookies = BoardBase::list_cookies_for_write(); if( list_cookies.empty() ) return std::string(); #ifdef _DEBUG std::cout << "Board2chCompati::cookie_for_write\n"; #endif JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string cookie_expire; std::string cookie_path; std::string cookie_pon; std::string cookie_hap = get_hap(); std::string cookie_name; std::string cookie_mail; const std::string query_expire = "expires=([^;]*)"; const std::string query_path = "path=([^;]*)"; const std::string query_pon = "PON=([^;]*)?"; const std::string query_hap = "HAP=([^;]*)?"; const std::string query_name = "NAME=([^;]*)?"; const std::string query_mail = "MAIL=([^;]*)?"; bool use_pon = false; bool use_hap = ! cookie_hap.empty(); bool use_name = false; bool use_mail = false; std::list< std::string >::const_iterator it = list_cookies.begin(); // expire と path は一つ目のcookieから取得 if( regex.exec( query_expire, (*it), offset, icase, newline, usemigemo, wchar ) ) cookie_expire = regex.str( 1 ); if( regex.exec( query_path, (*it), offset, icase, newline, usemigemo, wchar ) ) cookie_path = regex.str( 1 ); for( ; it != list_cookies.end(); ++it ){ const std::string tmp_cookie = MISC::Iconv( (*it), get_charset(), "UTF-8" ); #ifdef _DEBUG std::cout << tmp_cookie << std::endl; #endif if( regex.exec( query_pon, tmp_cookie, offset, icase, newline, usemigemo, wchar ) ){ use_pon = true; cookie_pon = regex.str( 1 ); } if( ! use_hap && regex.exec( query_hap, tmp_cookie, offset, icase, newline, usemigemo, wchar ) ){ use_hap = true; cookie_hap = regex.str( 1 ); } if( regex.exec( query_name, tmp_cookie, offset, icase, newline, usemigemo, wchar ) ){ use_name = true; cookie_name = MISC::charset_url_encode( regex.str( 1 ), get_charset() ); } if( regex.exec( query_mail, tmp_cookie, offset, icase, newline, usemigemo, wchar ) ){ use_mail = true; cookie_mail = MISC::charset_url_encode( regex.str( 1 ), get_charset() ); } } // PONを取得していないときはHAPを送らない if( ! use_pon || cookie_pon.empty() ){ use_hap = false; cookie_hap = std::string(); } #ifdef _DEBUG std::cout << "expire = " << cookie_expire << std::endl << "path = " << cookie_path << std::endl << "pon = " << cookie_pon << " " << use_pon << std::endl << "hap = " << cookie_hap << " " << use_hap << std::endl << "name = " << cookie_name << " " << use_name << std::endl << "mail = " << cookie_mail << " " << use_mail << std::endl; #endif std::string cookie; if( use_pon ) cookie += "PON=" + cookie_pon + "; "; if( use_hap ) cookie += "HAP=" + cookie_hap + "; "; if( use_name ) cookie += "NAME=" + cookie_name + "; "; if( use_mail ) cookie += "MAIL=" + cookie_mail + "; "; if( cookie.empty() ) return std::string(); cookie += "expires=" + cookie_expire + "; path=" + cookie_path; #ifdef _DEBUG std::cout << "cookie = " << cookie << std::endl; #endif return cookie; } // 書き込み時に必要なキーワード( hana=mogera や suka=pontan など )を // 確認画面のhtmlから解析する void Board2chCompati::analyze_keyword_for_write( const std::string& html ) { std::string keyword; #ifdef _DEBUG std::cout << "Board2chCompati::analyze_keyword_for_write\n"; std::cout << html << std::endl << "--------------------\n"; #endif JDLIB::Regex regex; size_t offset = 0; const bool icase = true; // 大文字小文字区別しない const bool newline = false; // . に改行をマッチさせる const bool usemigemo = false; const bool wchar = false; for(;;){ // のタグを解析して name と value を取得 if( ! regex.exec( "]*)>", html, offset, icase, newline, usemigemo, wchar ) ) break; offset = html.find( regex.str( 0 ) ); std::string name = MISC::remove_space( regex.str( 1 ) ); if( name[ 0 ] == '\"' ) name = MISC::cut_str( name, "\"", "\"" ); std::string value = MISC::remove_space( regex.str( 2 ) ); if( value[ 0 ] == '\"' ) value = MISC::cut_str( value, "\"", "\"" ); #ifdef _DEBUG std::cout << "offset = " << offset << " " << regex.str( 0 ) << std::endl << "name = " << name << " value = " << value << std::endl; #endif ++offset; // 除外する name の判定 // 2ch の仕様が変わったら項目を追加すること const std::string lowname = MISC::tolower_str( name ); if( lowname == "subject" || lowname == "from" || lowname == "mail" || lowname == "message" || lowname == "bbs" || lowname == "time" || lowname == "key" ) continue; // キーワード取得 if( ! keyword.empty() ) keyword += "&"; keyword += MISC::charset_url_encode( name, get_charset() ) + "=" + MISC::charset_url_encode( value, get_charset() ); } #ifdef _DEBUG std::cout << "keyword = " << keyword << std::endl; #endif set_keyword_for_write( keyword ); } // 新スレ作成時の書き込みメッセージ作成 const std::string Board2chCompati::create_newarticle_message( const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ) { if( subject.empty() ) return std::string(); if( msg.empty() ) return std::string(); std::stringstream ss_post; ss_post.clear(); ss_post << "bbs=" << get_id() << "&subject=" << MISC::charset_url_encode( subject, get_charset() ) << "&time=" << get_time_modified() << "&submit=" << MISC::charset_url_encode( "新規スレッド作成", get_charset() ) << "&FROM=" << MISC::charset_url_encode( name, get_charset() ) << "&mail=" << MISC::charset_url_encode( mail, get_charset() ) << "&MESSAGE=" << MISC::charset_url_encode( msg, get_charset() ); #ifdef _DEBUG std::cout << "Board2chCompati::create_newarticle_message " << ss_post.str() << std::endl; #endif return ss_post.str(); } // // 新スレ作成時のbbscgi のURL // // (例) "http://www.hoge2ch.net/test/bbs.cgi" // // const std::string Board2chCompati::url_bbscgi_new() { std::string cgibase = url_bbscgibase(); return cgibase.substr( 0, cgibase.length() -1 ); // 最後の '/' を除く } // // 新スレ作成時のsubbbscgi のURL // // (例) "http://www.hoge2ch.net/test/subbbs.cgi" // const std::string Board2chCompati::url_subbbscgi_new() { std::string cgibase = url_subbbscgibase(); return cgibase.substr( 0, cgibase.length() -1 ); // 最後の '/' を除く } // // 新しくArticleBaseクラスを追加してそのポインタを返す // // cached : HDD にキャッシュがあるならtrue // ArticleBase* Board2chCompati::append_article( const std::string& datbase, const std::string& id, const bool cached ) { if( empty() ) return get_article_null(); ArticleBase* article = new DBTREE::Article2chCompati( datbase, id, cached ); if( article ){ get_hash_article()->push( article ); // 最大レス数セット article->set_number_max( get_number_max_res() ); } else return get_article_null(); return article; } // // subject.txt から Aarticle のリストにアイテムを追加・更新 // void Board2chCompati::parse_subject( const char* str_subject_txt ) { #ifdef _DEBUG std::cout << "Board2chCompati::parse_subject\n"; #endif // 半角で 1024 文字を越えると Pango-WARNING **: Invalid UTF-8 string passed to pango_layout_set_text() が表示されるので注意 const int max_subject = 1024; const char* pos = str_subject_txt; while( *pos != '\0' ){ const char* str_id_dat; int lng_id_dat = 0; const char* str_subject; int lng_subject = 0; char str_num[ 16 ]; while( *pos == ' ' ) ++pos; // datのID取得 str_id_dat = pos; while( *pos != ' ' && *pos != '<' && *pos != '\0' && *pos != '\n' ) { ++pos; ++lng_id_dat; } // 壊れてる if( *pos == '\0' ){ MISC::ERRMSG( "subject.txt is broken" ); break; } if( *pos == '\n' ) { ++pos; continue; } while( *pos != '<' ) ++pos; ++pos; if( *pos != '>' ){ MISC::ERRMSG( "subject.txt is broken" ); break; } // subject取得 bool exist_amp = false; ++pos; str_subject = pos; while( *pos != '\0' && *pos != '\n' ){ if( *pos == '&' ) exist_amp = true; ++pos; } --pos; while( *pos != '(' && *pos != '\n' && pos != str_subject ) --pos; // 壊れてる if( *pos == '\n' || pos == str_subject ){ MISC::ERRMSG( "subject.txt is broken" ); break; } lng_subject = MIN( ( int )( pos - str_subject ), max_subject ); // レス数取得 ++pos; int i = 0; while( '0' <= *pos && *pos <= '9' && i < 16 ) str_num[ i++ ] = *( pos++ ); // 壊れてる if( i == 0 ){ MISC::ERRMSG( "subject.txt is broken (res)" ); break; } if( *pos == '\0' ) break; if( *pos == '\n' ) { ++pos; continue; } str_num[ i ] = '\0'; ++pos; // id, subject, number 取得 ARTICLE_INFO artinfo; artinfo.id.assign( str_id_dat, lng_id_dat ); if( str_subject[ lng_subject-1 ] == ' ' ){ lng_subject--; // 2chのsubject.txtは()の前に空白が一つ入る } artinfo.subject.assign( str_subject, lng_subject ); if( exist_amp ){ artinfo.subject = MISC::replace_str( artinfo.subject, "<", "<" ); artinfo.subject = MISC::replace_str( artinfo.subject, ">", ">" ); } artinfo.number = atol( str_num ); get_list_artinfo().push_back( artinfo ); #ifdef _DEBUG std::cout << "pos = " << ( pos - str_subject_txt ) << " lng = " << lng_subject << " id = " << artinfo.id << " num = " << artinfo.number; std::cout << " : " << artinfo.subject << std::endl; #endif } } void Board2chCompati::regist_article( const bool is_online ) { if( ! get_list_artinfo().size() ) return; #ifdef _DEBUG std::cout << "Board2chCompati::regist_article size = " << get_list_artinfo().size() << std::endl; #endif const std::string datbase = url_datbase(); for( unsigned int i = 0; i < get_list_artinfo().size(); ++i ){ const ARTICLE_INFO& artinfo = get_list_artinfo()[ i ]; // DBに登録されてるならarticle クラスの情報更新 ArticleBase* article = get_article( datbase, artinfo.id ); // DBにないなら新規に article クラスをDBに登録 // // なお BoardBase::receive_finish() のなかで append_all_article_in_cache() が既に呼び出されているため // DBに無いということはキャッシュに無いということ。よって append_article()の呼出に cached = false を指定する if( article->empty() ) article = append_article( datbase, artinfo.id, false // キャッシュ無し ); // スレ情報更新 if( article ){ // ステータスをDAT落ち状態から通常状態に変更 int status = article->get_status(); status |= STATUS_NORMAL; status &= ~STATUS_OLD; article->set_status( status ); // 情報ファイル読み込み article->read_info(); // 情報ファイルが無い場合もあるのでsubject.txtから取得したサブジェクト、レス数を指定しておく article->set_subject( artinfo.subject ); article->set_number( artinfo.number, is_online ); // 情報ファイル読み込み後にステータスが変わることがあるので、もう一度 // ステータスをDAT落ち状態から通常状態に変更 status = article->get_status(); status |= STATUS_NORMAL; status &= ~STATUS_OLD; article->set_status( status ); // boardビューに表示するリスト更新 if( ! BoardBase::is_abone_thread( article ) ) get_list_subject().push_back( article ); } } } const std::string Board2chCompati::localrule() { if( m_ruleloader ){ if( m_ruleloader->is_loading() ) return "ロード中です"; else if( m_ruleloader->get_code() == HTTP_OK || m_ruleloader->get_code() == HTTP_REDIRECT || m_ruleloader->get_code() == HTTP_MOVED_PERM ){ if( m_ruleloader->get_data().empty() ) return "ローカルルールはありません"; else return m_ruleloader->get_data(); } else return "ロードに失敗しました : " + m_ruleloader->get_str_code(); } return BoardBase::localrule(); } const std::string Board2chCompati::settingtxt() { if( m_settingloader ){ if( m_settingloader->is_loading() ) return "ロード中です"; else if( m_settingloader->get_code() == HTTP_OK || m_settingloader->get_code() == HTTP_REDIRECT || m_settingloader->get_code() == HTTP_MOVED_PERM ){ if( m_settingloader->get_data().empty() ) return "SETTING.TXTはありません"; else return m_settingloader->get_data(); } else return "ロードに失敗しました : " + m_settingloader->get_str_code(); } return BoardBase::settingtxt(); } const std::string Board2chCompati::default_noname() { if( m_settingloader && m_settingloader->get_code() == HTTP_OK ) return m_settingloader->default_noname(); return BoardBase::default_noname(); } const int Board2chCompati::line_number() { if( m_settingloader && m_settingloader->get_code() == HTTP_OK ) return m_settingloader->line_number(); return BoardBase::line_number(); } const int Board2chCompati::message_count() { if( m_settingloader && m_settingloader->get_code() == HTTP_OK ) return m_settingloader->message_count(); return BoardBase::message_count(); } const std::string Board2chCompati::get_unicode() { if( m_settingloader && m_settingloader->get_code() == HTTP_OK ) return m_settingloader->get_unicode(); return BoardBase::get_unicode(); } // // ローカルルールとSETTING.TXTをキャッシュから読み込む // // BoardBase::read_info()で呼び出す // void Board2chCompati::load_rule_setting() { #ifdef _DEBUG std::cout << "Board2chCompati::load_rule_setting\n"; #endif if( ! m_ruleloader ) m_ruleloader = new RuleLoader( url_boardbase() ); m_ruleloader->load_text(); if( ! m_settingloader ) m_settingloader = new SettingLoader( url_boardbase() ); m_settingloader->load_text(); } // // ローカルルールとSETTING.TXTをサーバからダウンロード // // 読み込むタイミングはsubject.txtを読み終わった直後( BoardBase::receive_finish() ) // void Board2chCompati::download_rule_setting() { #ifdef _DEBUG std::cout << "Board2chCompati::download_rule_setting\n"; #endif if( ! m_ruleloader ) m_ruleloader = new RuleLoader( url_boardbase() ); m_ruleloader->download_text(); if( ! m_settingloader ) m_settingloader = new SettingLoader( url_boardbase() ); m_settingloader->download_text(); } // // レス数であぼーん(グローバル) // const int Board2chCompati::get_abone_number_global() { return CONFIG::get_abone_number_thread(); } jd-2.8.7-140104/src/dbtree/board2chcompati.h0000644000076400010400000000424111525537616015052 0ustar // ライセンス: GPL2 // // 2ch 互換型板 // #ifndef _BOARD2CHCOMPATI_H #define _BOARD2CHCOMPATI_H #include "boardbase.h" namespace DBTREE { class SettingLoader; class RuleLoader; class Board2chCompati : public BoardBase { SettingLoader* m_settingloader; RuleLoader* m_ruleloader; public: Board2chCompati( const std::string& root, const std::string& path_board, const std::string& name, const std::string& basicauth ); virtual ~Board2chCompati(); // 書き込み用クッキー virtual const std::string cookie_for_write(); // 書き込み時に必要なキーワード( hana=mogera や suka=pontan など )を // 確認画面のhtmlから解析する virtual void analyze_keyword_for_write( const std::string& html ); // 新スレ作成用のメッセージ変換 virtual const std::string create_newarticle_message( const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ); // 新スレ作成用のbbscgi のURL virtual const std::string url_bbscgi_new(); // 新スレ作成用のsubbbscgi のURL virtual const std::string url_subbbscgi_new(); // ローカルルール virtual const std::string localrule(); // SETTING.TXT virtual const std::string settingtxt(); virtual const std::string default_noname(); virtual const int line_number(); virtual const int message_count(); virtual const std::string get_unicode(); private: virtual const bool is_valid( const std::string& filename ); virtual ArticleBase* append_article( const std::string& datbase, const std::string& id, const bool cached ); virtual void parse_subject( const char* str_subject_txt ); virtual void regist_article( const bool is_online ); virtual void load_rule_setting(); virtual void download_rule_setting(); // レス数であぼーん(グローバル) virtual const int get_abone_number_global(); }; } #endif jd-2.8.7-140104/src/dbtree/boardbase.cpp0000644000076400010400000021675311573436400014273 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _TEST_CACHE #include "jddebug.h" #include "boardbase.h" #include "articlebase.h" #include "articlehash.h" #include "interface.h" #include "skeleton/msgdiag.h" #include "jdlib/jdiconv.h" #include "jdlib/jdregex.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/loaderdata.h" #include "jdlib/confloader.h" #include "global.h" #include "httpcode.h" #include "command.h" #include "cache.h" #include "config/globalconf.h" #include "session.h" #include "boardcolumnsid.h" #include #include #ifdef _TEST_CACHE int cache_hit_art = 0; int cache_nohit_art = 0; #endif enum { SIZE_OF_RAWDATA = 2 * 1024 * 1024 }; using namespace DBTREE; BoardBase::BoardBase( const std::string& root, const std::string& path_board, const std::string& name ) : SKELETON::Loadable() , m_status( STATUS_UNKNOWN ) , m_list_subject_created( false ) , m_view_sort_column( -1 ) , m_view_sort_mode( -1 ) , m_view_sort_pre_column( -1 ) , m_view_sort_pre_mode( -1 ) , m_root( root ) , m_path_board( path_board ) , m_name( name ) , m_samba_sec( 0 ) , m_live_sec( 0 ) , m_last_access_time( 0 ) , m_number_max_res( 0 ) , m_iconv( NULL ) , m_rawdata( NULL ) , m_rawdata_left( NULL ) , m_read_info( 0 ) , m_append_articles( false ) , m_get_article( NULL ) , m_cancel_remove_abone_thread( false ) , m_article_null( 0 ) { clear(); clear_load_data(); memset( &m_write_time, 0, sizeof( struct timeval ) ); m_hash_article = new ArticleHash(); // 板情報はクラスが作られた時点ではまだ読まない // BoardBase::read_info() の説明を見ること } // // デストラクタで子ArticleBaseクラスを全部削除 // BoardBase::~BoardBase() { #ifdef _DEBUG if( m_hash_article->size() ) std::cout << "BoardBase::~BoardBase : " << url_boardbase() << std::endl; #endif clear(); ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ) delete ( *it ); if( m_article_null ) delete m_article_null; delete m_hash_article; #ifdef _TEST_CACHE if( m_hash_article->size() ){ std::cout << "article cache\n" << "hit = " << cache_hit_art << std::endl << "nohit = " << cache_nohit_art << std::endl << "hit/total*100 = " << (double)(cache_hit_art)/(cache_hit_art+cache_nohit_art)*100. << std::endl; } #endif } ArticleBase* BoardBase::get_article_null() { if( ! m_article_null ) m_article_null = new DBTREE::ArticleBase( "", "", false ); return m_article_null; } bool BoardBase::empty() { return m_root.empty(); } // // url がこの板のものかどうか // bool BoardBase::equal( const std::string& url ) { if( url.find( get_root() ) == 0 && url.find( get_path_board() + "/" ) != std::string::npos ) return true; return false; } // // 名前を変更 // void BoardBase::update_name( const std::string& name ) { if( m_name != name ){ m_name = name; // 表示中のviewの板名表示更新 CORE::core_set_command( "update_boardname", url_boardbase() ); } } // ユーザエージェント // ダウンロード用 const std::string& BoardBase::get_agent() { return CONFIG::get_agent_for_data(); } // 書き込み用 const std::string& BoardBase::get_agent_w() { return get_agent(); } // 読み込み用プロキシ const std::string BoardBase::get_proxy_host() { const int mode = get_mode_local_proxy(); if( mode == DBTREE::PROXY_GLOBAL ){ if( CONFIG::get_use_proxy_for_data() ) return CONFIG::get_proxy_for_data(); } else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy(); return std::string(); } const int BoardBase::get_proxy_port() { const int mode = get_mode_local_proxy(); if( mode == DBTREE::PROXY_GLOBAL ) return CONFIG::get_proxy_port_for_data(); else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_port(); return 0; } const std::string BoardBase::get_proxy_basicauth() { const int mode = get_mode_local_proxy(); if( mode == DBTREE::PROXY_GLOBAL ) return CONFIG::get_proxy_basicauth_for_data(); else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_basicauth(); return std::string(); } // 書き込み用プロキシ const std::string BoardBase::get_proxy_host_w() { const int mode = get_mode_local_proxy_w(); if( mode == DBTREE::PROXY_GLOBAL ){ if( CONFIG::get_use_proxy_for_data() ) return CONFIG::get_proxy_for_data(); } else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_w(); return std::string(); } const int BoardBase::get_proxy_port_w() { const int mode = get_mode_local_proxy_w(); if( mode == DBTREE::PROXY_GLOBAL ) return CONFIG::get_proxy_port_for_data(); else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_port_w(); return 0; } const std::string BoardBase::get_proxy_basicauth_w() { const int mode = get_mode_local_proxy_w(); if( mode == DBTREE::PROXY_GLOBAL ) return CONFIG::get_proxy_basicauth_for_data(); else if( mode == DBTREE::PROXY_LOCAL ) return get_local_proxy_basicauth_w(); return std::string(); } // ローカルルール const std::string BoardBase::localrule() { return "利用できません"; } // setting.txt const std::string BoardBase::settingtxt() { return "利用できません"; } // デフォルトの名無し名 const std::string BoardBase::default_noname() { return "???"; } // 最大改行数/2 const int BoardBase::line_number() { return 0; } // 最大書き込みバイト数 const int BoardBase::message_count() { return 0; } // 特殊文字書き込み可能か( pass なら可能、 change なら不可 ) const std::string BoardBase::get_unicode() { return ""; } //書き込み用クッキー const std::string BoardBase::cookie_for_write() { if( m_list_cookies_for_write.empty() ) return std::string(); return *(m_list_cookies_for_write.begin() ); } //書き込み用クッキーのセット void BoardBase::set_list_cookies_for_write( const std::list< std::string >& list_cookies ) { #ifdef _DEBUG std::cout << "BoardBase::set_list_cookies_for_write\n"; #endif std::list< std::string >::const_iterator it = list_cookies.begin(); for( ; it != list_cookies.end(); ++it ){ const std::string cookie = MISC::remove_space( *it ); #ifdef _DEBUG std::cout << "cookie = " << cookie << std::endl; #endif std::string key; const size_t n = cookie.find( "=" ); if( n != std::string::npos ) key = cookie.substr( 0, n+1 ); // 更新 // クッキーの削除は未実装 if( ! key.empty() && key.find( ";" ) == std::string::npos ){ #ifdef _DEBUG std::cout << "key = " << key << std::endl; #endif std::list< std::string >::iterator it2 = m_list_cookies_for_write.begin(); for( ; it2 != m_list_cookies_for_write.end(); ++it2 ){ if( (*it2).find( key ) == 0 ){ #ifdef _DEBUG std::cout << "found\n"; #endif (*it2) = cookie; break; } } if( it2 == m_list_cookies_for_write.end() ) m_list_cookies_for_write.push_back( cookie ); } } #ifdef _DEBUG std::cout << "result:\n"; it = m_list_cookies_for_write.begin(); for( ; it != m_list_cookies_for_write.end(); ++it ) std::cout << (*it) << std::endl; #endif update_hap(); } void BoardBase::clear() { if( m_rawdata ) free( m_rawdata ); m_rawdata = NULL; if( m_rawdata_left ) free( m_rawdata_left ); m_rawdata_left = NULL; m_lng_rawdata = 0; m_lng_rawdata_left = 0; m_get_article_url = std::string(); if( m_iconv ) delete m_iconv; m_iconv = NULL; m_list_artinfo.clear(); } // // m_url_update_views に登録されている view に update_board コマンドを送る // void BoardBase::send_update_board() { #ifdef _DEBUG std::cout << "BoardBase::send_update_board\n"; #endif // ダウンロードを開始したビュー以外のビューの内容を更新する // // "update_board" コマンドの後に"update_board_item"を送ると // ローディングが終了しているため行を二回更新してしまうので注意 // 詳しくは BoardViewBase::update_item() を参照 CORE::core_set_command( "update_board_item", url_subject(), std::string() // IDとして空文字を送る ); // ダウンロードを開始したビューの内容を更新する std::list< std::string >::iterator it = m_url_update_views.begin(); for( ; it != m_url_update_views.end(); ++it ){ #ifdef _DEBUG std::cout << "update : " << *it << std::endl; #endif CORE::core_set_command( "update_board", *it ); } m_url_update_views.clear(); } // // 新しくArticleBaseクラスを追加してそのポインタを返す // ArticleBase* BoardBase::append_article( const std::string& datbase, const std::string& id, const bool cached ) { // ベースクラスでは何もしない return get_article_null(); } // // 書き込み時間更新 // void BoardBase::update_writetime() { struct timeval tv; struct timezone tz; if( gettimeofday( &tv, &tz ) == 0 ){ m_write_time = tv; #ifdef _DEBUG std::cout << "BoardBase::update_writetime : " << m_write_time.tv_sec << std::endl; #endif } } // // 経過時間(秒) // const time_t BoardBase::get_write_pass() { time_t ret = 0; struct timeval tv; struct timezone tz; if( m_write_time.tv_sec && gettimeofday( &tv, &tz ) == 0 ) ret = MAX( 0, tv.tv_sec - m_write_time.tv_sec ); return ret; } // // 書き込み可能までの残り秒 // time_t BoardBase::get_write_leftsec() { const time_t mrg = 2; if( ! m_samba_sec ) return 0; if( ! get_write_pass() ) return 0; // ログイン中は書き込み規制無し if( SESSION::login2ch() ) return 0; return MAX( 0, m_samba_sec + mrg - get_write_pass() ); } // // 全書き込み履歴クリア // void BoardBase::clear_all_post_history() { // キャッシュにあるレスをデータベースに登録 append_all_article_in_cache(); if( m_hash_article->size() == 0 ) return; ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ) ( *it )->clear_post_history(); } // // 全スレの書き込み時間とスレ立て時間の文字列をリセット // void BoardBase::reset_all_write_date() { ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ) ( *it )->reset_write_date(); } void BoardBase::reset_all_since_date() { ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ) ( *it )->reset_since_date(); } // // 最大レス数をセット // void BoardBase::set_number_max_res( const int number ) { #ifdef _DEBUG std::cout << "BoardBase::set_number_max_res " << m_number_max_res << " -> " << number << std::endl; #endif m_number_max_res = MAX( 0, MIN( MAX_RESNUMBER, number ) ); ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ) ( *it )->set_number_max( m_number_max_res ); } // // 板情報の取得 // // コンストラクタで呼ぶと起動時に全ての板の情報を読まなければならなくなるので、 // Root::get_board()で初めて参照されたときに一度だけ実行 // void BoardBase::read_info() { if( empty() ) return; if( ! m_read_info ){ // 一度読んだらもう処理しない #ifdef _DEBUG std::cout << "BoardBase::read_info : " << m_id << std::endl; #endif m_read_info = true; // 板の情報ファイル読み込み read_board_info(); // キャッシュからローカルルールとSETTING.TXT のロード load_rule_setting(); } } // // 移転などで板のルートやパスを変更する // void BoardBase::update_url( const std::string& root, const std::string& path_board ) { #ifdef _DEBUG std::cout << "BoardBase::update_url\n" << m_root << " -> " << root << std::endl << m_path_board << " -> " << path_board << std::endl; #endif m_root = root; m_path_board = path_board; m_query_dat = std::string(); m_query_cgi = std::string(); m_query_kako = std::string(); // modified 時刻をリセット // 自動移転処理後に bbsmenu.html を読み込んだときに、bbsmenu.html の // アドレスが古いと二度と自動移転処理しなくなる set_date_modified( std::string() ); // 配下の ArticleBase にも知らせてあげる const std::string datbase = url_datbase(); ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ) ( *it )->update_datbase( datbase ); } // // スレの urlをdat型のurlに変換 // // url がスレッドのURLで無い時はempty()が返る // もしurlが移転前の旧ホストのものだったら対応するarticlebaseクラスに旧ホスト名を知らせる // // (例) url = "http://www.hoge2ch.net/test/read.cgi/hogeboard/12345/12-15"のとき、 // // 戻り値 : "http://www.hoge2ch.net/hogeboard/dat/12345.dat", num_from = 12, num_to = 15, num_str = "12-15" // const std::string BoardBase::url_dat( const std::string& url, int& num_from, int& num_to, std::string& num_str ) { if( empty() ) return std::string(); JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string id; // スレッドのID #ifdef _DEBUG std::cout << "BoardBase::url_dat : url = " << url << std::endl; #endif num_from = num_to = 0; if( m_query_dat.empty() ){ // dat 型 const std::string datpath = MISC::replace_str( url_datpath(), "?", "\\?" ); m_query_dat = "^ *(http://.+" + datpath + ")([1234567890]+" + get_ext() + ") *$"; // read.cgi型 const std::string cgipath = MISC::replace_str( url_readcgipath(), "?", "\\?" ); m_query_cgi = "^ *(http://.+" + cgipath + ")([1234567890]+)/?r?(l50)?([1234567890]+)?(-)?([1234567890]+)?.*$"; // 過去ログかどうか const std::string pathboard = MISC::replace_str( m_path_board, "?", "\\?" ); m_query_kako = "^ *(http://.+)" + pathboard + "/kako(/[1234567890]+)?/[1234567890]+/([1234567890]+).html *$"; #ifdef _DEBUG std::cout << "query_dat = " << m_query_dat << std::endl; std::cout << "query_cgi = " << m_query_cgi << std::endl; std::cout << "query_kako = " << m_query_kako << std::endl; #endif } if( regex.exec( m_query_dat , url, offset, icase, newline, usemigemo, wchar ) ) id = regex.str( 2 ); else if( regex.exec( m_query_cgi , url, offset, icase, newline, usemigemo, wchar ) ){ id = regex.str( 2 ) + get_ext(); if( !regex.str( 3 ).empty() ){ // l50 num_from = 1; num_to = 50; } else{ num_from = atoi( regex.str( 4 ).c_str() ); num_to = atoi( regex.str( 6 ).c_str() ); } if( num_from != 0 ){ num_from = MAX( 1, num_from ); // 12- みたいな場合はとりあえず大きい数字を入れとく if( !regex.str( 5 ).empty() && !num_to ) num_to = MAX_RESNUMBER + 1; } // -15 みたいな場合 else if( num_to != 0 ) num_from = 1; num_to = MAX( num_from, num_to ); num_str = MISC::get_filename( url ); } // どちらでもない(スレのURLでない)場合 else{ #ifdef _DEBUG std::cout << "query_kako = " << query_kako << std::endl; #endif if( regex.exec( m_query_kako , url, offset, icase, newline, usemigemo, wchar ) ){ std::string url_tmp = regex.str( 1 ) + url_datpath() + regex.str( 3 ) + get_ext(); #ifdef _DEBUG std::cout << "kako log -> " << url_tmp << std::endl; #endif return url_dat( url_tmp, num_from, num_to, num_str ); } // 外部板の移転の場合は path_board も変わるときがあるので // 移転した場合はurlを置換してからもう一度試す std::string old_root; std::string old_path_board; std::string new_root; std::string new_path_board; std::string new_url = DBTREE::is_board_moved( url, old_root, old_path_board, new_root, new_path_board ); #ifdef _DEBUG std::cout << "old_root = " << old_root << " new_root = " << new_root << std::endl; std::cout << "old_path_board = " << old_path_board << " new_path_board = " << new_path_board << std::endl; #endif if( ! new_url.empty() ){ std::string url_tmp = MISC::replace_str( url, old_root, new_root ); url_tmp = MISC::replace_str( url_tmp, old_path_board + "/", new_path_board + "/" ); #ifdef _DEBUG std::cout << "moved -> " << url_tmp << std::endl; #endif return url_dat( url_tmp, num_from, num_to, num_str ); } #ifdef _DEBUG std::cout << "not found\n"; #endif return std::string(); } const std::string datbase = url_datbase(); #ifdef _DEBUG std::cout << "BoardBase::url_dat result : " << url << " ->\n"; std::cout << "datbase = " << datbase << " id = " << id << " from " << num_from << " to " << num_to << " num = " << num_str << std::endl; #endif // もしurl(スレッドのURL)が移転前の旧URLのものだったら対応するarticlebaseクラスに旧ホスト名を教えてあげる // ( offlaw による dat落ちスレの読み込み時に使用する ) if( m_root.find( MISC::get_hostname( url ) ) != 0 ){ #ifdef _DEBUG std::cout << "org_host : " << MISC::get_hostname( url ) << std::endl; #endif get_article_create( datbase, id )->set_org_host( MISC::get_hostname( url ) ); } return datbase + id; } // // スレの url を read.cgi型のurlに変換 // // url がスレッドのURLで無い時はempty()が返る // num_from と num_to が 0 で無い時はスレ番号を付ける // // (例) "http://www.hoge2ch.net/hogeboard/dat/12345.dat", num_from = 12, num_to = 15 のとき // // 戻り値 : "http://www.hoge2ch.net/test/read.cgi/hogeboard/12345/12-15" // const std::string BoardBase::url_readcgi( const std::string& url, int num_from, int num_to ) { if( empty() ) return std::string(); #ifdef _DEBUG std::cout << "BoardBase::url_readcgi : " << url << " from " << num_from << " to " << num_to << std::endl; #endif ArticleBase* article = get_article_fromURL( url ); if( !article ) return std::string(); if( article->empty() ) return std::string(); std::string readcgi = url_readcgibase() + article->get_key() + "/"; #ifdef _DEBUG std::cout << "BoardBase::::url_readcgi : to " << readcgi << std::endl; #endif if( num_from > 0 || num_to > 0 ){ std::ostringstream ss; ss << readcgi; if( num_from ) ss << num_from; if( num_to > num_from ) ss << "-" << num_to; return ss.str(); } return readcgi; } // // subject.txt の URLを取得 // // (例) "http://www.hoge2ch.net/hogeboard/subject.txt" // const std::string BoardBase::url_subject() { if( empty() ) return std::string(); return url_boardbase() + m_subjecttxt; } // // ルートアドレス // // (例) "http://www.hoge2ch.net/" (最後に '/' がつく) // const std::string BoardBase::url_root() { if( empty() ) return std::string(); return m_root + "/"; } // // 板のベースアドレス // // (例) "http://www.hoge2ch.net/hogeboard/" (最後に '/' がつく) // const std::string BoardBase::url_boardbase() { if( empty() ) return std::string(); return m_root + m_path_board + "/"; } // // dat ファイルのURLのベースアドレスを返す // // (例) "http://www.hoge2ch.net/hogeboard/dat/" (最後に '/' がつく) // const std::string BoardBase::url_datbase() { if( empty() ) return std::string(); return m_root + url_datpath(); } // // dat ファイルのURLのパスを返す // // (例) "/hogeboard/dat/" (最初と最後に '/' がつく) // const std::string BoardBase::url_datpath() { if( empty() ) return std::string(); return m_path_board + m_path_dat + "/"; } // // read.cgi のURLのベースアドレスを返す // // (例) "http://www.hoge2ch.net/test/read.cgi/hogeboard/" (最後に '/' がつく) // const std::string BoardBase::url_readcgibase() { if( empty() ) return std::string(); return m_root + url_readcgipath(); } // // read.cgi のURLのパスを返す // // (例) "/test/read.cgi/hogeboard/" (最初と最後に '/' がつく) // const std::string BoardBase::url_readcgipath() { if( empty() ) return std::string(); return m_path_readcgi + m_path_board + "/"; } // // bbscgi のURLのベースアドレス // // (例) "http://www.hoge2ch.net/test/bbs.cgi/" ( 最後に '/' がつく ) // // const std::string BoardBase::url_bbscgibase() { if( empty() ) return std::string(); return m_root + m_path_bbscgi + "/"; } // // subbbscgi のURLのベースアドレス // // (例) "http://www.hoge2ch.net/test/subbbs.cgi/" ( 最後に '/' がつく ) // const std::string BoardBase::url_subbbscgibase() { if( empty() ) return std::string(); return m_root + m_path_subbbscgi + "/"; } // // article のID を渡してハッシュから article のポインタを検索して返すだけ // // 無ければNULLクラスを返す // ArticleBase* BoardBase::get_article( const std::string& datbase, const std::string& id ) { if( id.empty() ) return get_article_null(); // キャッシュにあるレスをデータベースに登録 append_all_article_in_cache(); ArticleBase* art = m_hash_article->find( datbase, id ); if( art ) return art; return get_article_null(); } // // articleの IDを渡して ハッシュから article のポインタを検索して返す // // ポインタがあった場合は情報ファイルを読み込む // さらにデータベースにArticleBaseクラスが登録されてない場合はクラスを作成して登録する // ArticleBase* BoardBase::get_article_create( const std::string& datbase, const std::string& id ) { #ifdef _DEBUG std::cout << "BoardBase::get_article_create id = " << id << std::endl; #endif ArticleBase* art = get_article( datbase, id ); // データベースに無いので新規登録 // get_article() の中で append_all_article_in_cache() を // 呼び出しているので、スレがキャッシュ内にない場合 art->empty() == TRUE になる if( art->empty() ){ #ifdef _DEBUG std::cout << "BoardBase::get_article_create : append_article id = " << id << std::endl; #endif art = append_article( datbase, id, false // キャッシュ無し ); assert( art ); } if( art->is_cached() ) art->read_info(); return art; } // // article の URL を渡してハッシュから article のポインタを検索して返す // // さらにデータベースにArticleBaseクラスが登録されてない場合はクラスを作成して登録する // ArticleBase* BoardBase::get_article_fromURL( const std::string& url ) { if( empty() ) return get_article_null(); // キャッシュ if( url == m_get_article_url ){ #ifdef _TEST_CACHE ++cache_hit_art; #endif return m_get_article; } m_get_article_url = url; m_get_article = get_article_null(); #ifdef _DEBUG std::cout << "BoardBase::get_article_fromURL url = " << url << std::endl; #endif // dat型のURLにしてdatbaseとidを取得 int num_from, num_to; std::string num_str; const std::string urldat = url_dat( url, num_from, num_to, num_str ); if( urldat.empty() ) return m_get_article; const std::string datbase = url_datbase(); const std::string id = urldat.substr( datbase.length() ); if( id.empty() ) return m_get_article; #ifdef _DEBUG std::cout << "datbase = " << datbase << std::endl << "id = " << id << std::endl; #endif #ifdef _TEST_CACHE ++cache_nohit_art; #endif // get_article_create() 経由で ArticleBase::read_info() から get_article_fromURL()が // 再帰呼び出しされることもあるので m_get_article_url を空にしておく m_get_article_url = std::string(); m_get_article = get_article_create( datbase, id ); m_get_article_url = url; return m_get_article; } // // subject.txt ダウンロード // // url_update_view : CORE::core_set_command( "update_board" ) を送信するビューのアドレス // read_from_cache : まだスレ一覧を開いていないときにキャッシュのsubject.txtを読み込む // void BoardBase::download_subject( const std::string& url_update_view, const bool read_from_cache ) { #ifdef _DEBUG std::cout << "BoardBase::download_subject " << url_subject() << std::endl << "url_update_view = " << url_update_view << std::endl << "read_from_cache = " << read_from_cache << std::endl << "empty = " << empty() << std::endl << "loading = " << is_loading() << std::endl << "views = " << m_url_update_views.size() << std::endl; #endif // ダウンロード中に他のビューから再びダウンロード依頼が来たら // ダウンロード終了時にまとめてビューにupdateコマンドを送る if( ! url_update_view.empty() ) m_url_update_views.push_back( url_update_view ); if( m_url_update_views.size() >= 2 ) return; if( empty() ) return; if( is_loading() ) return; if( read_from_cache && m_list_subject_created ) return; clear(); m_read_url_boardbase = false; if( read_from_cache ) m_is_online = false; else m_is_online = SESSION::is_online(); m_is_booting = SESSION::is_booting(); // オフライン if( ! m_is_online ){ // まだスレ一覧を開いていないときはディスパッチャを通さないで直接subject.txtを読み込む if( read_from_cache ) receive_finish(); // 一度でもスレ一覧を開いている場合はディスパッチャ経由で receive_finish() を呼び出す else{ // HTTP コードは Loadable::callback_dispatch() の中で HTTP_INIT にセットされる set_str_code( "" ); finish(); } return; } // オンライン // subject.txtのキャッシュが無かったら modified をリセット std::string path_subject = CACHE::path_board_root_fast( url_boardbase() ) + m_subjecttxt; if( CACHE::file_exists( path_subject ) != CACHE::EXIST_FILE ) set_date_modified( std::string() ); JDLIB::LOADERDATA data; create_loaderdata( data ); if( ! start_load( data ) ){ send_update_board(); clear(); } } // // ロード用データ作成 // void BoardBase::create_loaderdata( JDLIB::LOADERDATA& data ) { data.url = url_subject(); data.agent = get_agent(); data.host_proxy = get_proxy_host(); data.port_proxy = get_proxy_port(); data.basicauth_proxy = get_proxy_basicauth(); data.size_buf = CONFIG::get_loader_bufsize_board(); data.timeout = CONFIG::get_loader_timeout(); data.basicauth = get_basicauth(); data.modified = get_date_modified(); } // // ローダよりsubject.txt受信 // void BoardBase::receive_data( const char* data, size_t size ) { if( ! size ) return; if( ! m_rawdata ) m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA ); memcpy( m_rawdata + m_lng_rawdata , data, size ); m_lng_rawdata += size; m_rawdata[ m_lng_rawdata ] = '\0'; if( m_read_url_boardbase ) return; // url_boardbase をロードして移転が起きたかチェック中 // // 改行ごとに区切ってUTF8に文字コード変換して解析 // if( ! m_rawdata_left ) m_rawdata_left = ( char* )malloc( SIZE_OF_RAWDATA ); if( ! m_iconv ) m_iconv = new JDLIB::Iconv( m_charset, "UTF-8" ); memcpy( m_rawdata_left + m_lng_rawdata_left, data, size ); size_t byte_in = size + m_lng_rawdata_left; m_lng_rawdata_left = byte_in; while( byte_in && m_rawdata_left[ byte_in -1 ] != '\n' ) --byte_in; if( byte_in ){ int byte_out; const char* rawdata_utf8 = m_iconv->convert( m_rawdata_left, byte_in, byte_out ); parse_subject( rawdata_utf8 ); // 残りを先頭に移動 m_lng_rawdata_left -= byte_in; memmove( m_rawdata_left, m_rawdata_left + byte_in, m_lng_rawdata_left ); #ifdef _DEBUG std::cout << "BoardBase::receive_data lng_rawdata = " << m_lng_rawdata << " size = " << size << " byte_in = " << byte_in << " byte_out = " << byte_out << " lng_rawdata_left = " << m_lng_rawdata_left << std::endl; #endif } } // // ロード完了 // void BoardBase::receive_finish() { // 別スレッドでローカルルールとSETTING.TXT のダウンロード開始 if( m_is_online ) download_rule_setting(); m_list_subject.clear(); m_list_abone_thread_remove.clear(); m_status &= ~STATUS_UPDATED; bool read_from_cache = false; const std::string path_subject = CACHE::path_board_root_fast( url_boardbase() ) + m_subjecttxt; const std::string path_oldsubject = CACHE::path_board_root_fast( url_boardbase() ) + "old-" + m_subjecttxt; #ifdef _DEBUG std::cout << "----------------------------------\nBoardBase::receive_finish code = " << get_str_code() << std::endl; std::cout << "lng_rawdata = " << m_lng_rawdata << std::endl; #endif /////////////////////////////////////////////////////// // // url_boardbase をロードして移転が起きたかチェック if( m_read_url_boardbase ){ #ifdef _DEBUG std::cout << "move check\n"; #endif set_date_modified( std::string() ); send_update_board(); if( m_lng_rawdata && get_code() == HTTP_OK && std::string( m_rawdata ).find( "window.location.href" ) != std::string::npos ){ #ifdef _DEBUG std::cout << m_rawdata << std::endl; #endif JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string query = ".*window.location.href=\"([^\"]*)\".*"; if( regex.exec( query, m_rawdata, offset, icase, newline, usemigemo, wchar ) ){ const std::string new_url = regex.str( 1 ); int ret = Gtk::RESPONSE_YES; if( CONFIG::get_show_movediag() ){ const std::string msg = "「" + get_name() + "」は\n\n" + new_url + " に移転しました。\n\nデータベースを更新しますか?"; SKELETON::MsgCheckDiag mdiag( NULL, msg, "今後表示しない(常に更新)(_D)", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_title( "更新確認" ); ret = mdiag.run(); if( ret == Gtk::RESPONSE_YES && mdiag.get_chkbutton().get_active() ) CONFIG::set_show_movediag( false ); } if( ret == Gtk::RESPONSE_YES ){ if( DBTREE::move_board( url_boardbase(), new_url ) ){ // 再読み込み const std::string str_tab = "false"; CORE::core_set_command( "open_board", url_subject(), str_tab ); } } } } else{ SKELETON::MsgDiag mdiag( NULL, "移転しました\n\n板一覧を更新しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_YES ); if( mdiag.run() == Gtk::RESPONSE_YES ) CORE::core_set_command( "reload_bbsmenu" ); } clear(); return; } // 移転チェック終わり // /////////////////////////////////////////////////////// // サーバーからtimeoutなどのエラーが返った or 移転 if( get_code() != HTTP_ERR // HTTP_ERR はローダでの内部のエラー && get_code() != HTTP_OK && get_code() != HTTP_NOT_MODIFIED ){ // // リダイレクト(302)の場合は移転確認 // // ちなみにdatの読み込みでリダイレクト(302)が返ってきたときは、移転かdat落ちか判断出来ないので注意 // NodeTree2ch::receive_finish()も参照せよ // if( get_code() == HTTP_REDIRECT || get_code() == HTTP_MOVED_PERM ){ set_date_modified( std::string() ); if( start_checkking_if_board_moved() ) return; send_update_board(); clear(); return; } // サーバからエラーが返ったらキャッシュからデータをロード read_from_cache = true; } // ローダがエラーを返した 又は not modified 又はオフラインならキャッシュからデータをロード if( get_code() == HTTP_ERR || get_code() == HTTP_NOT_MODIFIED || ! m_is_online ) read_from_cache = true; // キャッシュから読み込み if( read_from_cache ){ #ifdef _DEBUG std::cout << "read from cache " << path_subject << std::endl; #endif m_lng_rawdata = 0; m_lng_rawdata_left = 0; char* rawdata = ( char* )malloc( SIZE_OF_RAWDATA ); size_t lng = CACHE::load_rawdata( path_subject, rawdata, SIZE_OF_RAWDATA ); receive_data( rawdata, lng ); free( rawdata ); } #ifdef _DEBUG std::cout << "size = " << m_list_artinfo.size() << " lng_rawdata = " << m_lng_rawdata << " left = " << m_lng_rawdata_left << std::endl; #endif // データが無い if( ! m_list_artinfo.size() ){ set_date_modified( std::string() ); // 移転した可能性があるので url_boardbase をロードして解析 if( m_is_online && get_code() == HTTP_OK ){ if( start_checkking_if_board_moved() ) return; } send_update_board(); clear(); return; } ////////////////////////////// // データベース更新 // subject.txtを解析して現行スレだけsubjectリスト(m_list_subject)に加える // キャッシュにあるレスをデータベースに登録 append_all_article_in_cache(); // 一度全てのarticleをdat落ち状態にして subject.txt に // 含まれているものだけ regist_article()の中で通常状態にする if( m_is_online || m_is_booting // ブート中の時も状態を変えないと起動直後にスレ一覧を復元した時にdat落ちしたスレが表示されない ){ ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ){ int status = ( *it )->get_status(); status &= ~STATUS_NORMAL; status |= STATUS_OLD; ( *it )->set_status( status ); } } m_is_booting = false; regist_article( m_is_online ); // list_subject 更新 if( ! m_list_subject.empty() ){ #ifdef _DEBUG std::cout << "list_subject was updated\n"; #endif if( m_is_online ){ // 既読スレに更新があったかチェック std::vector< ArticleBase* >::iterator it_art; for( it_art = m_list_subject.begin(); it_art != m_list_subject.end(); ++it_art ){ if( ( *it_art )->is_cached() && ( *it_art )->get_number() > ( *it_art )->get_number_load() ){ m_status |= STATUS_UPDATED; break; } } show_updateicon( false ); } // DAT落ちなどでsubject.txtに無いスレもsubjectリストに加える if( CONFIG::get_show_oldarticle() || m_show_oldlog ){ ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ){ if( ( *it )->is_cached() && ( ( *it )->get_status() & STATUS_OLD ) ){ // サブジェクトやロード数などの情報が無いのでスレのinfoファイルから // 取得する必要がある // TODO : 数が多いとboardビューを開くまで時間がかかるのをなんとかする #ifdef _DEBUG std::cout << "read article_info : " << ( *it )->get_url() << std::endl; #endif ( *it )->read_info(); if( ! is_abone_thread( *it ) ) m_list_subject.push_back( *it ); } } } // オンライン、かつcodeが200か304なら最終アクセス時刻を更新 if( m_is_online && ( get_code() == HTTP_OK || get_code() == HTTP_NOT_MODIFIED ) ){ m_last_access_time = time( NULL ); #ifdef _DEBUG std::cout << "access time " << m_last_access_time << std::endl; #endif } // オンライン、かつcodeが200なら情報を更新・保存して subject.txt をキャッシュに保存 if( m_is_online && get_code() == HTTP_OK ){ m_last_access_time = time( NULL ); #ifdef _DEBUG std::cout << "save info and subject.txt\n"; std::cout << "rename " << path_subject << " " << path_oldsubject << std::endl; std::cout << "save " << path_subject << std::endl; #endif save_info(); // subject.txtをキャッシュ if( CACHE::mkdir_boardroot( url_boardbase() ) ){ // 古いファイルをrename if( CACHE::file_exists( path_subject ) == CACHE::EXIST_FILE ){ #ifdef _WIN32 // not overwrite by rename() on windows if (CACHE::file_exists( path_oldsubject ) == CACHE::EXIST_FILE ){ remove( path_oldsubject.c_str() ); } #endif if( rename( path_subject.c_str(), path_oldsubject.c_str() ) != 0 ){ MISC::ERRMSG( "rename failed " + path_subject ); } } // subject.txt セーブ CACHE::save_rawdata( path_subject, m_rawdata, m_lng_rawdata ); } } m_list_subject_created = true; } // if( ! m_list_subject.empty() ) // list_subject が更新されなかった else{ #ifdef _DEBUG std::cout << "list_subject was NOT updated\n"; #endif set_date_modified( std::string() ); } // コアにデータベース更新を知らせる send_update_board(); clear(); } // // url_boardbase をロードして移転したかどうか解析開始 // // 移転するとコード200で // // // // の様なHTML本文が送られて来るので移転先が分かる // bool BoardBase::start_checkking_if_board_moved() { #ifdef _DEBUG std::cout << "BoardBase::start_checkking_if_board_moved " << url_boardbase() << std::endl; #endif m_lng_rawdata = 0; JDLIB::LOADERDATA data; data.init_for_data(); data.url = url_boardbase(); if( start_load( data ) ){ m_read_url_boardbase = true; return true; } return false; } // // キャッシュのディレクトリ内にあるスレのファイル名のリストを取得 // std::list< std::string > BoardBase::get_filelist_in_cache() { std::list< std::string >list_out; if( empty() ) return list_out; std::list< std::string >list_file; std::string path_board_root = CACHE::path_board_root_fast( url_boardbase() ); list_file = CACHE::get_filelist( path_board_root ); if( ! list_file.size() ) return list_out; std::list< std::string >::iterator it = list_file.begin(); for(; it != list_file.end(); ++it ){ std::string& file = ( *it ); if( is_valid( file ) ) list_out.push_back( file ); } return list_out; } // // キャッシュのディレクトリ内にあるスレのファイル名を取得してDBにすべてを登録 // // 全てのスレのinfoファイルを読むと遅くなるのでこの段階では読まない(DBへの登録のみ) // // boardビューに一覧表示するためBoardBaseの派生クラスのparse_subject()を呼び出したり、 // BoardBase::get_article_fromURL()で参照されたときに初めてスレのinfoファイルを読み込む // void BoardBase::append_all_article_in_cache() { if( m_append_articles ) return; m_append_articles = true; const std::string datbase = url_datbase(); #ifdef _DEBUG std::cout << "BoardBase::append_all_article_in_cache url = " << datbase << std::endl; #endif std::list< std::string >list_file = get_filelist_in_cache(); std::list< std::string >::iterator it = list_file.begin(); for(; it != list_file.end(); ++it ){ #ifdef _DEBUG std::cout << "append id = " << ( *it ) << std::endl; #endif // キャッシュあり( cached = true ) 指定でDBに登録 // キャッシュに無いスレはsubject.txtを読み込んだ時に // 派生クラスのparse_subject()で登録する。 append_article( datbase, ( *it ), true // キャッシュあり ); } } // // 配下の全articlebaseクラスのあぼーん状態の更新 // void BoardBase::update_abone_all_article() { ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ) ( *it )->update_abone(); } // // スレあぼーん判定 // const bool BoardBase::is_abone_thread( ArticleBase* article ) { if( ! article ) return false; if( article->empty() ) return false; const int check_number = article->get_number_load() ? 0: ( m_abone_number_thread ? m_abone_number_thread : get_abone_number_global() ); const int check_hour = article->get_number_load() ? 0: ( m_abone_hour_thread ? m_abone_hour_thread : CONFIG::get_abone_hour_thread() ); const bool check_thread = ! m_list_abone_thread.empty(); const bool check_word = ! m_list_abone_word_thread.empty(); const bool check_regex = ! m_list_abone_regex_thread.empty(); const bool check_word_global = ! CONFIG::get_list_abone_word_thread().empty(); const bool check_regex_global = ! CONFIG::get_list_abone_regex_thread().empty(); if( !check_number && !check_hour && !check_thread && !check_word && !check_regex && !check_word_global && !check_regex_global ) return false; JDLIB::Regex regex; const size_t offset = 0; const bool icase = CONFIG::get_abone_icase(); const bool newline = true; const bool usemigemo = false; const bool wchar = CONFIG::get_abone_wchar(); // レスの数であぼーん if( check_number ) if( article->get_number() >= check_number ) return true; // スレ立てからの時間であぼーん if( check_hour ) if( article->get_hour() >= check_hour ) return true; // スレあぼーん if( check_thread ){ std::list< std::string >::iterator it = m_list_abone_thread.begin(); for( ; it != m_list_abone_thread.end(); ++it ){ if( MISC::remove_space( article->get_subject() ) == MISC::remove_space(*it) ){ // 対象スレがDat落ちした場合はあぼーんしなかったスレ名をリストから消去する // remove_old_abone_thread() も参照 m_list_abone_thread_remove.push_back( *it ); return true; } } } // ローカル NG word if( check_word ){ std::list< std::string >::iterator it = m_list_abone_word_thread.begin(); for( ; it != m_list_abone_word_thread.end(); ++it ){ if( article->get_subject().find( *it ) != std::string::npos ) return true; } } // ローカル NG regex if( check_regex ){ std::list< std::string >::iterator it = m_list_abone_regex_thread.begin(); for( ; it != m_list_abone_regex_thread.end(); ++it ){ if( regex.exec( *it, article->get_subject(), offset, icase, newline, usemigemo, wchar ) ) return true; } } // 全体 NG word if( check_word_global ){ std::list< std::string >::iterator it = CONFIG::get_list_abone_word_thread().begin(); for( ; it != CONFIG::get_list_abone_word_thread().end(); ++it ){ if( article->get_subject().find( *it ) != std::string::npos ) return true; } } // 全体 NG regex if( check_regex_global ){ std::list< std::string >::iterator it = CONFIG::get_list_abone_regex_thread().begin(); for( ; it != CONFIG::get_list_abone_regex_thread().end(); ++it ){ if( regex.exec( *it, article->get_subject(), offset, icase, newline, usemigemo, wchar ) ) return true; } } return false; } // // subject.txtのロード後にdat落ちしたスレッドをスレあぼーんのリストから取り除く // // is_abone_thread() も参照せよ // void BoardBase::remove_old_abone_thread() { if( m_cancel_remove_abone_thread ) return; if( CONFIG::get_remove_old_abone_thread() == 2 ) return; if( m_list_abone_thread.empty() ) return; if( m_list_abone_thread.size() == m_list_abone_thread_remove.size() ) return; #ifdef _DEBUG std::cout << "BoardBase::remove_old_abone_thread\n"; std::list< std::string >::const_iterator it = m_list_abone_thread.begin(); for( ; it != m_list_abone_thread.end(); ++it ) std::cout << ( *it ) << std::endl; std::cout << "->\n"; std::list< std::string >::const_iterator it2 = m_list_abone_thread_remove.begin(); for( ; it2 != m_list_abone_thread_remove.end(); ++it2 ) std::cout << ( *it2 ) << std::endl; #endif if( CONFIG::get_remove_old_abone_thread() == 0 ){ SKELETON::MsgCheckDiag mdiag( NULL, "NGスレタイトルに登録したスレがdat落ちしました。\n\nNGスレタイトルから除外しますか?\n後で板のプロパティから削除する事も可能です。", "今後表示しない(_D)", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE ); mdiag.add_default_button( Gtk::Stock::NO, Gtk::RESPONSE_NO ); mdiag.add_button( Gtk::Stock::YES, Gtk::RESPONSE_YES ); const int ret = mdiag.run(); // 一度いいえを選択したらあとは再起動するまでダイアログを表示しない if( ret != Gtk::RESPONSE_YES ) m_cancel_remove_abone_thread = true; if( mdiag.get_chkbutton().get_active() ){ if( ret == Gtk::RESPONSE_YES ) CONFIG::set_remove_old_abone_thread( 1 ); else CONFIG::set_remove_old_abone_thread( 2 ); } if( ret != Gtk::RESPONSE_YES ) return; } std::list< std::string >::iterator it = m_list_abone_thread.begin(); for( ; it != m_list_abone_thread.end(); ++it ){ if( std::find( m_list_abone_thread_remove.begin(), m_list_abone_thread_remove.end(), *it ) == m_list_abone_thread_remove.end() ){ m_list_abone_thread.erase( it ); it = m_list_abone_thread.begin(); continue; } } } // // スレあぼーん情報を更新した時に対応するスレ一覧の表示を更新する // // CONFIG::set_abone_number_thread() などでグローバル設定をした後などに呼び出す // // redraw : スレ一覧の表示更新を行う // void BoardBase::update_abone_thread( const bool redraw ) { #ifdef _DEBUG std::cout << "BoardBase::update_abone_thread\n"; #endif // まだスレ一覧にスレを表示していないBoardBaseクラスは更新しない if( ! m_list_subject_created ) return; // オフラインに切り替えてからキャッシュにあるsubject.txtを再読み込みする const bool online = SESSION::is_online(); SESSION::set_online( false ); download_subject( ( redraw ? url_subject() : std::string() ), false ); SESSION::set_online( online ); } // // 板レベルでのあぼーん状態のリセット(情報セットとスレビューの表示更新を同時におこなう) // void BoardBase::reset_abone_board( const std::list< std::string >& ids, const std::list< std::string >& names, const std::list< std::string >& words, const std::list< std::string >& regexs ) { if( empty() ) return; // 前後の空白と空白行を除く m_list_abone_id = MISC::remove_space_from_list( ids ); m_list_abone_id = MISC::remove_nullline_from_list( m_list_abone_id ); m_list_abone_name = MISC::remove_space_from_list( names ); m_list_abone_name = MISC::remove_nullline_from_list( m_list_abone_name ); m_list_abone_word = MISC::remove_space_from_list( words ); m_list_abone_word = MISC::remove_nullline_from_list( m_list_abone_word ); m_list_abone_regex = MISC::remove_space_from_list( regexs ); m_list_abone_regex = MISC::remove_nullline_from_list( m_list_abone_regex ); update_abone_all_article(); CORE::core_set_command( "relayout_all_article" ); } // 板レベルでのあぼ〜ん状態更新(reset_abone()と違って各項目ごと個別におこなう。スレビューの表示更新も同時におこなう) void BoardBase::add_abone_id_board( const std::string& id ) { if( empty() ) return; if( id.empty() ) return; std::string id_tmp = id.substr( strlen( PROTO_ID ) ); m_list_abone_id.push_back( id_tmp ); update_abone_all_article(); CORE::core_set_command( "relayout_all_article" ); } void BoardBase::add_abone_name_board( const std::string& name ) { if( empty() ) return; if( name.empty() ) return; m_list_abone_name.push_back( name ); update_abone_all_article(); CORE::core_set_command( "relayout_all_article" ); } void BoardBase::add_abone_word_board( const std::string& word ) { if( empty() ) return; if( word.empty() ) return; m_list_abone_word.push_back( word ); update_abone_all_article(); CORE::core_set_command( "relayout_all_article" ); } // // スレあぼーん状態のリセット // // redraw : スレ一覧の表示更新を行う // void BoardBase::reset_abone_thread( const std::list< std::string >& threads, const std::list< std::string >& words, const std::list< std::string >& regexs, const int number, const int hour, const bool redraw ) { if( empty() ) return; #ifdef _DEBUG std::cout << "BoardBase::reset_abone_thread\n"; #endif // 前後の空白と空白行を除く m_list_abone_thread = MISC::remove_space_from_list( threads ); m_list_abone_thread = MISC::remove_nullline_from_list( m_list_abone_thread ); m_list_abone_word_thread = MISC::remove_space_from_list( words ); m_list_abone_word_thread = MISC::remove_nullline_from_list( m_list_abone_word_thread ); m_list_abone_regex_thread = MISC::remove_space_from_list( regexs ); m_list_abone_regex_thread = MISC::remove_nullline_from_list( m_list_abone_regex_thread ); m_abone_number_thread = number; m_abone_hour_thread = hour; update_abone_thread( redraw ); } // // 読み込み用ローカルプロキシ設定 // void BoardBase::set_local_proxy( const std::string& proxy ) { m_local_proxy = proxy; m_local_proxy_basicauth = std::string(); if( proxy.empty() ) return; // basic認証 JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "([^/]+:[^/]+@)(.+)$" , proxy, offset, icase, newline, usemigemo, wchar ) ) { m_local_proxy_basicauth = regex.str( 1 ).substr( 0, regex.str( 1 ).length() - 1 ); m_local_proxy = regex.str( 2 ); } } // // 書き込み用ローカルプロキシ設定 // void BoardBase::set_local_proxy_w( const std::string& proxy ) { m_local_proxy_w = proxy; m_local_proxy_basicauth_w = std::string(); if( proxy.empty() ) return; // basic認証 JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "([^/]+:[^/]+@)(.+)$" , proxy, offset, icase, newline, usemigemo, wchar ) ) { m_local_proxy_basicauth_w = regex.str( 1 ).substr( 0, regex.str( 1 ).length() - 1 ); m_local_proxy_w = regex.str( 2 ); } } // // キャッシュ内のログ検索 // // ArticleBase のアドレスをリスト(list_article)にセットして返す // query が空の時はキャッシュにあるログを全てヒットさせる // bm がtrueの時、しおりが付いている(スレ一覧でしおりを付けた or レスに一つでもしおりが付いている)スレのみを対象に検索する // void BoardBase::search_cache( std::vector< DBTREE::ArticleBase* >& list_article, const std::string& query, const bool mode_or, // 今のところ無視 const bool bm, const bool& stop // 呼出元のスレッドで true にセットすると検索を停止する ) { #ifdef _DEBUG std::cout << "BoardBase::search_cache " << url_subject() << std::endl; #endif if( empty() ) return; // キャッシュにあるレスをデータベースに登録 append_all_article_in_cache(); if( m_hash_article->size() == 0 ) return; const bool append_all = query.empty(); const std::string query_local = MISC::Iconv( query, "UTF-8", get_charset() ); const std::list< std::string > list_query = MISC::split_line( query_local ); const std::string path_board_root = CACHE::path_board_root_fast( url_boardbase() ); ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ){ if( stop ) break; ArticleBase* article = ( *it ); if( ! article->is_cached() ) continue; // しおりがついているスレだけ追加 if( bm ){ article->read_info(); if( ! article->is_bookmarked_thread() && ! article->get_num_bookmark() ) continue; } // 全て追加 if( append_all ){ article->read_info(); #ifdef _DEBUG std::cout << "append " << article->get_subject() << " bm = " << article->get_num_bookmark() << std::endl; #endif list_article.push_back( article ); continue; } const std::string path = path_board_root + article->get_id(); std::string rawdata; if( CACHE::load_rawdata( path, rawdata ) > 0 ){ bool apnd = true; #ifdef _DEBUG std::cout << "load " << path << " size = " << rawdata.size() << " byte" << std::endl; #endif std::list< std::string >::const_iterator it_query = list_query.begin(); for( ; it_query != list_query.end(); ++it_query ){ // 今の所 AND だけ対応 if( rawdata.find( *it_query ) == std::string::npos ){ apnd = false; break; } } if( apnd ){ article->read_info(); #ifdef _DEBUG std::cout << "found word in " << url_readcgi( article->get_url(), 0, 0 ) << std::endl << article->get_subject() << std::endl; #endif list_article.push_back( article ); } } } } // datファイルのインポート // 成功したらdat型のurlを返す const std::string BoardBase::import_dat( const std::string& filename ) { if( empty() ) return std::string(); if( CACHE::file_exists( filename ) != CACHE::EXIST_FILE ){ SKELETON::MsgDiag mdiag( NULL, "datファイルが存在しません" ); mdiag.run(); return std::string(); } const std::string dir = MISC::get_dir( filename ); const std::string id = MISC::get_filename( filename ); if( id.empty() || ! is_valid( id ) ){ SKELETON::MsgDiag mdiag( NULL, "ファイル名が正しくありません" ); mdiag.run(); return std::string(); } const std::string file_to = CACHE::path_board_root_fast( url_boardbase() ) + id; #ifdef _DEBUG std::cout << "BoardBase::import_dat cp " << filename << " " << file_to << std::endl; #endif const std::string datbase = url_datbase(); ArticleBase* art = get_article_create( datbase, id ); if( ! art->is_cached() ){ CACHE::jdcopy( filename, file_to ); if( CACHE::file_exists( file_to ) == CACHE::EXIST_FILE ){ art->set_cached( true ); art->read_info(); } else{ SKELETON::MsgDiag mdiag( NULL, "datファイルのコピーに失敗しました" ); mdiag.run(); return std::string(); } } return art->get_url(); } // // board.info( jd用 ) を読む // BoardBase::read_info() も参照すること // void BoardBase::read_board_info() { if( empty() ) return; std::string path_info = CACHE::path_jdboard_info( url_boardbase() ); #ifdef _DEBUG std::cout << "BoardBase::read_board_info " << path_info << std::endl; #endif JDLIB::ConfLoader cf( path_info, std::string() ); std::string modified = cf.get_option_str( "modified", "" ); set_date_modified( modified ); m_modified_localrule = cf.get_option_str( "modified_localrule", std::string() ); m_modified_setting = cf.get_option_str( "modified_setting", std::string() ); m_view_sort_column = cf.get_option_int( "view_sort_column", -1, -1, COL_VISIBLE_END-1 ); m_view_sort_mode = cf.get_option_int( "view_sort_mode", SORTMODE_ASCEND, 0, SORTMODE_NUM -1 ); m_view_sort_pre_column = cf.get_option_int( "view_sort_pre_column", -1, -1, COL_VISIBLE_END-1 ); m_view_sort_pre_mode = cf.get_option_int( "view_sort_pre_mode", SORTMODE_ASCEND, 0, SORTMODE_NUM -1 ); m_check_noname = cf.get_option_bool( "check_noname", false ); m_show_oldlog = cf.get_option_bool( "show_oldlog", false ); std::string str_tmp; // あぼーん id は再起動ごとにリセット // str_tmp = cf.get_option( "aboneid", std::string() ); // if( ! str_tmp.empty() ) m_list_abone_id = MISC::strtolist( str_tmp ); // あぼーん name str_tmp = cf.get_option_str( "abonename", "" ); if( ! str_tmp.empty() ) m_list_abone_name = MISC::strtolist( str_tmp ); // あぼーん word str_tmp = cf.get_option_str( "aboneword", "" ); if( ! str_tmp.empty() ) m_list_abone_word = MISC::strtolist( str_tmp ); // あぼーん regex str_tmp = cf.get_option_str( "aboneregex", "" ); if( ! str_tmp.empty() ) m_list_abone_regex = MISC::strtolist( str_tmp ); // スレ あぼーん str_tmp = cf.get_option_str( "abonethread", "" ); if( ! str_tmp.empty() ) m_list_abone_thread = MISC::strtolist( str_tmp ); // スレ あぼーん word str_tmp = cf.get_option_str( "abonewordthread", "" ); if( ! str_tmp.empty() ) m_list_abone_word_thread = MISC::strtolist( str_tmp ); // スレ あぼーん regex str_tmp = cf.get_option_str( "aboneregexthread", "" ); if( ! str_tmp.empty() ) m_list_abone_regex_thread = MISC::strtolist( str_tmp ); // レス数であぼーん m_abone_number_thread = cf.get_option_int( "abonenumberthread", 0, 0, 9999 ); // スレ立てからの経過時間であぼーん m_abone_hour_thread = cf.get_option_int( "abonehourthread", 0, 0, 9999 ); // ローカルプロキシ m_mode_local_proxy = cf.get_option_int( "mode_local_proxy", PROXY_GLOBAL, 0, PROXY_NUM -1 ); str_tmp = cf.get_option_str( "local_proxy", "" ); set_local_proxy( str_tmp ); m_local_proxy_port = cf.get_option_int( "local_proxy_port", 8080, 1, 65535 ); m_mode_local_proxy_w = cf.get_option_int( "mode_local_proxy_w", PROXY_GLOBAL, 0, PROXY_NUM -1 ); str_tmp = cf.get_option_str( "local_proxy_w", "" ); set_local_proxy_w( str_tmp ); m_local_proxy_port_w = cf.get_option_int( "local_proxy_port_w", 8080, 1, 65535 ); // 書き込み時のデフォルトの名前とメアド m_write_name = cf.get_option_str( "write_name", "" ); m_write_mail = cf.get_option_str( "write_mail", "" ); if( ! m_write_name.empty() && ( m_write_name == CONFIG::get_write_name() || ( m_write_name == JD_NAME_BLANK && CONFIG::get_write_name().empty() ) ) ){ #ifdef _DEBUG std::cout << "reset name = " << m_write_name << std::endl; #endif m_write_name = std::string(); } if( ! m_write_mail.empty() && ( m_write_mail == CONFIG::get_write_mail() || ( m_write_mail == JD_MAIL_BLANK && CONFIG::get_write_mail().empty() ) ) ){ #ifdef _DEBUG std::cout << "reset mail = " << m_write_mail << std::endl; #endif m_write_mail = std::string(); } // samba24 m_samba_sec = cf.get_option_int( "samba_sec", 0, 0, 65535 ); // 実況の秒数 m_live_sec = cf.get_option_int( "live_sec", 0, 0, 65535 ); // 最終アクセス時刻 m_last_access_time = cf.get_option_int( "last_access_time", 0, 0, 2147483647 ); // ステータス m_status = cf.get_option_int( "status", STATUS_UNKNOWN, 0, 8192 ); // 最大レス数 m_number_max_res = cf.get_option_int( "max_res", get_default_number_max_res(), 0, MAX_RESNUMBER ); #ifdef _DEBUG std::cout << "modified = " << get_date_modified() << std::endl; #endif } // // 情報保存 // void BoardBase::save_info() { if( empty() ) return; if( ! CACHE::mkdir_boardroot( url_boardbase() ) ) return; save_jdboard_info(); save_summary(); save_board_info(); } // // board.info( jd用 ) セーブ // void BoardBase::save_jdboard_info() { std::string path_info = CACHE::path_jdboard_info( url_boardbase() ); #ifdef _DEBUG std::cout << "BoardBase::save_jdboard_info file = " << path_info << std::endl; #endif // あぼーん情報 std::string str_abone_id = MISC::listtostr( m_list_abone_id ); std::string str_abone_name = MISC::listtostr( m_list_abone_name ); std::string str_abone_word = MISC::listtostr( m_list_abone_word ); std::string str_abone_regex = MISC::listtostr( m_list_abone_regex ); // スレあぼーん情報 std::string str_abone_thread = MISC::listtostr( m_list_abone_thread ); std::string str_abone_word_thread = MISC::listtostr( m_list_abone_word_thread ); std::string str_abone_regex_thread = MISC::listtostr( m_list_abone_regex_thread ); // ローカルプロキシ std::string local_proxy; if( m_local_proxy_basicauth.empty() ) local_proxy = m_local_proxy; else local_proxy = m_local_proxy_basicauth + "@" + m_local_proxy; std::string local_proxy_w; if( m_local_proxy_basicauth_w.empty() ) local_proxy_w = m_local_proxy_w; else local_proxy_w = m_local_proxy_basicauth_w + "@" + m_local_proxy_w; std::ostringstream sstr; sstr << "modified = " << get_date_modified() << std::endl << "modified_localrule = " << m_modified_localrule << std::endl << "modified_setting = " << m_modified_setting << std::endl << "view_sort_column = " << m_view_sort_column << std::endl << "view_sort_mode = " << m_view_sort_mode << std::endl << "view_sort_pre_column = " << m_view_sort_pre_column << std::endl << "view_sort_pre_mode = " << m_view_sort_pre_mode << std::endl << "check_noname = " << m_check_noname << std::endl << "show_oldlog = " << m_show_oldlog << std::endl // IDは再起動ごとにリセット // << "aboneid = " << str_abone_id << std::endl << "abonename = " << str_abone_name << std::endl << "aboneword = " << str_abone_word << std::endl << "aboneregex = " << str_abone_regex << std::endl << "abonethread = " << str_abone_thread << std::endl << "abonewordthread = " << str_abone_word_thread << std::endl << "aboneregexthread = " << str_abone_regex_thread << std::endl << "abonenumberthread = " << m_abone_number_thread << std::endl << "abonehourthread = " << m_abone_hour_thread << std::endl << "mode_local_proxy = " << m_mode_local_proxy << std::endl << "local_proxy = " << local_proxy << std::endl << "local_proxy_port = " << m_local_proxy_port << std::endl << "mode_local_proxy_w = " << m_mode_local_proxy_w << std::endl << "local_proxy_w = " << local_proxy_w << std::endl << "local_proxy_port_w = " << m_local_proxy_port_w << std::endl << "write_name = " << m_write_name << std::endl << "write_mail = " << m_write_mail << std::endl << "samba_sec = " << m_samba_sec << std::endl << "live_sec = " << m_live_sec << std::endl << "last_access_time = " << m_last_access_time << std::endl << "status = " << m_status << std::endl << "max_res = " << m_number_max_res << std::endl ; CACHE::save_rawdata( path_info, sstr.str() ); } // // article-summary( navi2ch互換 )保存 // // navi2chとの互換性のために保存しているだけで article-summary の情報は使わない // void BoardBase::save_summary() { std::string path_summary = CACHE::path_article_summary( url_boardbase() ); #ifdef _DEBUG std::cout << "BoardBase::save_summary file = " << path_summary << std::endl; #endif int count = 0; std::ostringstream sstr_out; sstr_out << "("; std::vector< ArticleBase* >::iterator it; for( it = m_list_subject.begin(); it != m_list_subject.end(); ++it ){ ArticleBase* art = *( it ); if( art->is_cached() && ( art->get_status() & STATUS_NORMAL ) ){ if( count ) sstr_out << " "; ++count; // key sstr_out << "(\"" << art->get_key() << "\""; // 読んだ位置 sstr_out << " :seen " << art->get_number_seen(); // access-time sstr_out << " :access-time (" << art->get_access_time_str() << "))"; } } sstr_out << ")"; #ifdef _DEBUG // std::cout << sstr_out.str() << std::endl; #endif if( count ) CACHE::save_rawdata( path_summary, sstr_out.str() ); } // // board.info( navi2ch 互換 ) セーブ // // navi2chとの互換性のために保存しているだけで情報は使わない // void BoardBase::save_board_info() { std::string path_info = CACHE::path_board_info( url_boardbase() ); #ifdef _DEBUG std::cout << "BoardBase::save_board_info file = " << path_info << std::endl; #endif // time だけ更新する(他の情報は使わない) std::string bookmark = "nil"; std::string hide = "nil"; std::string time = "(time . \"" + get_date_modified() + "\")"; std::string logo = "nil"; // board.info 読み込み if( CACHE::file_exists( path_info ) == CACHE::EXIST_FILE ){ std::string str_info; CACHE::load_rawdata( path_info, str_info ); #ifdef _DEBUG std::cout << "str_info " << str_info << std::endl; #endif std::list< std::string > lists = MISC::get_elisp_lists( str_info ); std::list< std::string >::iterator it = lists.begin(); for( ; it != lists.end(); ++it ){ if( ( *it ).find( "bookmark" ) != std::string::npos ) bookmark = *it; if( ( *it ).find( "hide" ) != std::string::npos ) hide = *it; if( ( *it ).find( "logo" ) != std::string::npos ) logo = *it; } } std::string str_out = "(" + bookmark + " " + hide + " " + time + " " + logo + ")"; #ifdef _DEBUG std::cout << "info = " << str_out << std::endl; #endif CACHE::save_rawdata( path_info, str_out ); } // // 配下の全articlebaseクラスの情報保存 // void BoardBase::save_articleinfo_all() { ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ) ( *it )->save_info( false ); } // 更新可能状態にしてお気に入りやスレ一覧のタブのアイコンに更新マークを表示 // update == true の時に表示。falseなら戻す void BoardBase::show_updateicon( const bool update ) { #ifdef _DEBUG std::cout << "BoardBase::show_updateicon url = " << url_boardbase() << " update = " << update << " status = " << ( m_status & STATUS_UPDATE ) << std::endl; #endif if( update ){ if( ! ( m_status & STATUS_UPDATE ) ){ #ifdef _DEBUG std::cout << "toggle_icon on\n"; #endif m_status |= STATUS_UPDATE; // スレ一覧のタブのアイコン表示を更新 CORE::core_set_command( "toggle_board_icon", url_subject() ); // サイドバーのアイコン表示を更新 CORE::core_set_command( "toggle_sidebar_boardicon", url_datbase() ); save_info(); } } else{ if( m_status & STATUS_UPDATE ){ #ifdef _DEBUG std::cout << "toggle_icon off\n"; #endif m_status &= ~STATUS_UPDATE; // サイドバーのアイコン表示を戻す // スレ一覧のタブのアイコンはBoardViewがロード終了時に自動的に戻す CORE::core_set_command( "toggle_sidebar_boardicon", url_subject() ); save_info(); } } } // 板の更新チェック時に、更新チェックを行うスレのアドレスのリスト // キャッシュが存在し、かつdat落ちしていないで新着数が0のスレを速度の順でソートして返す const std::list< std::string > BoardBase::get_check_update_articles() { std::list< std::string > list_url; if( empty() ) return list_url; if( is_loading() ) return list_url; if( m_status & STATUS_UPDATE ) return list_url; if( ! m_list_subject_created ) download_subject( std::string(), true ); if( ! m_list_subject_created ) return list_url; #ifdef _DEBUG std::cout << "BoardBase::get_check_update_articles url = " << url_boardbase() << std::endl; #endif std::list< int > list_speed; ArticleHashIterator it = m_hash_article->begin(); for( ; it != m_hash_article->end(); ++it ){ if( ( *it )->is_cached() && ( *it )->get_number() && ! ( ( *it )->get_status() & STATUS_UPDATE ) && ! ( ( *it )->get_status() & STATUS_OLD ) && ( *it )->get_number() == ( *it )->get_number_load() ){ const std::string& url = ( *it )->get_url(); const int speed = ( *it )->get_speed(); #ifdef _DEBUG std::cout << "added " << url << " number = " << ( *it )->get_number() << " load = " << ( *it )->get_number_load() << " speed = " << speed << " " << ( *it )->get_subject() << std::endl; #endif // 挿入ソート std::list< std::string >::iterator it_url = list_url.begin(); std::list< int >::iterator it_speed = list_speed.begin(); for( ; it_url != list_url.end(); ++it_url, ++it_speed ) if( ( *it_speed ) < speed ) break; list_url.insert( it_url, url ); list_speed.insert( it_speed, speed ); } } #ifdef _DEBUG std::cout << "result of insert sorting\n"; std::list< std::string >::const_iterator it_url = list_url.begin(); std::list< int >::const_iterator it_speed = list_speed.begin(); for( ; it_url != list_url.end(); ++it_url, ++it_speed ) std::cout << ( *it_speed ) << " / " << ( *it_url ) << std::endl; #endif return list_url; } jd-2.8.7-140104/src/dbtree/boardbase.h0000644000076400010400000006425411533727427013745 0ustar // ライセンス: GPL2 // // 板情報クラスのベース // #ifndef _BOARDBASE_H #define _BOARDBASE_H #include "skeleton/loadable.h" #include #include #include #include #ifdef _WIN32 #include #endif namespace JDLIB { class LOADERDATA; class Iconv; } namespace DBTREE { // ローカルプロキシ設定 enum { PROXY_GLOBAL = 0, // 全体設定使用 PROXY_DISABLE, // 全体設定無効 PROXY_LOCAL, // ローカル設定使用 PROXY_NUM }; struct ARTICLE_INFO { std::string id; std::string subject; int number; }; typedef std::vector< ARTICLE_INFO > ARTICLE_INFO_LIST; class Root; class ArticleBase; class ArticleHash; class BoardBase : public SKELETON::Loadable { // ArticleBaseクラス のキャッシュ // ArticleBaseクラスは一度作ったら~BoardBase()以外ではdeleteしないこと ArticleHash* m_hash_article; // subject.txt から作ったArticleBaseクラスのポインタのリスト // subject.txt と同じ順番で、ロードされるたびに更新される std::vector< ArticleBase* > m_list_subject; // ダウンロード中に parse_subject() でsubject.txtを解析して結果を入れておく // ダウンロード終了後に regist_article() でスレを登録する ARTICLE_INFO_LIST m_list_artinfo; // 状態 ( global.h で定義 ) int m_status; // 一度でも m_list_subject が作られた(=subject.txtを開いた)らtrue bool m_list_subject_created; // ローカルルールのmodified 時刻 std::string m_modified_localrule; // setting.txtの modified 時刻 std::string m_modified_setting; // subjectダウンロード指示時(BoardBase::download_subject)にオンラインだったか bool m_is_online; // subjectダウンロード指示時(BoardBase::download_subject)にブート中だったか bool m_is_booting; // ビュワーでソートをする列番号、ソード順 int m_view_sort_column; int m_view_sort_mode; int m_view_sort_pre_column; int m_view_sort_pre_mode; // 名無し書き込み不可 bool m_check_noname; // 過去ログも表示する bool m_show_oldlog; // // subjectファイルのURLが "http://www.hoge2ch.net/hogeboard/subject.txt" // datファイルのURLが "http://www.hoge2ch.net/hogeboard/dat/12345.dat" // スレのURLが "http://www.hoge2ch.net/test/read.cgi/hogeboard/12345" のとき、 // // m_root = "http://www.hoge2ch.net" // m_path_board = "/hogeboard" // m_path_dat = "/dat" // m_path_readcgi = "/test/read.cgi" // m_path_bbscgi = "/test/bbs.cgi" // m_path_subbbscgi = "/test/subbbs.cgi" // m_subjecttxt = "subject.txt" // m_ext = ".dat" // m_id = "hogeboard" // m_charset = "MS932" // // 先頭に'/'を付けて最後に '/' は付けないことにフォーマットを統一 // std::string m_root; std::string m_path_board; std::string m_path_dat; std::string m_path_readcgi; std::string m_path_bbscgi; std::string m_path_subbbscgi; std::string m_subjecttxt; std::string m_ext; std::string m_id; std::string m_charset; std::string m_name; // 板名 // dat型のurlに変換する時のquery ( url_dat()で使用する ) std::string m_query_dat; std::string m_query_cgi; std::string m_query_kako; // ローカルあぼーん情報(板内の全レス対象) std::list< std::string > m_list_abone_id; // あぼーんするID std::list< std::string > m_list_abone_name; // あぼーんする名前 std::list< std::string > m_list_abone_word; // あぼーんする文字列 std::list< std::string > m_list_abone_regex; // あぼーんする正規表現 // ローカルスレあぼーん情報 std::list< std::string > m_list_abone_thread; // あぼーんするスレのタイトル std::list< std::string > m_list_abone_thread_remove; // あぼーんするスレのタイトル( dat 落ち判定用、remove_old_abone_thread()を参照せよ ) std::list< std::string > m_list_abone_word_thread; // あぼーんする文字列 std::list< std::string > m_list_abone_regex_thread; // あぼーんする正規表現 int m_abone_number_thread; // レスの数 int m_abone_hour_thread; // スレ立てからの経過時間 // 読み込み用ローカルプロキシ設定 int m_mode_local_proxy; std::string m_local_proxy; int m_local_proxy_port; std::string m_local_proxy_basicauth; // basic 認証用の「ユーザID:パスワード」の組 // 書き込み用ローカルプロキシ設定 int m_mode_local_proxy_w; std::string m_local_proxy_w; int m_local_proxy_port_w; std::string m_local_proxy_basicauth_w; // basic 認証用の「ユーザID:パスワード」の組 // 書き込み時のデフォルトの名前とメアド std::string m_write_name; std::string m_write_mail; // 最終書き込み時間 struct timeval m_write_time; // samba(秒) time_t m_samba_sec; // 実況時の更新間隔(秒) time_t m_live_sec; // 最終アクセス時刻 time_t m_last_access_time; // 最大レス数 int m_number_max_res; // ダウンロード用変数 std::list< std::string > m_url_update_views; // CORE::core_set_command( "update_board" ) を送信するビューのアドレス JDLIB::Iconv* m_iconv; char* m_rawdata; char* m_rawdata_left; size_t m_lng_rawdata; size_t m_lng_rawdata_left; // 情報ファイルを読みこんだらtrueにして2度読みしないようにする bool m_read_info; // キャッシュにあるこの板に属するスレをデータベースに登録したか bool m_append_articles; // 移転を調査するために url_boardbase を読んでいる bool m_read_url_boardbase; // クッキー, 書き込み時に必要 std::list< std::string > m_list_cookies_for_write; // 書き込み時に必要なキーワード( hana=mogera や suka=pontan など ) // 書き込み時のメッセージに付加する std::string m_keyword_for_write; // basic 認証用の「ユーザID:パスワード」の組 std::string m_basicauth; // get_article_fromURL()のキャッシュ std::string m_get_article_url; ArticleBase* m_get_article; // remove_old_abone_thread() をキャンセルするか bool m_cancel_remove_abone_thread; // NULL artice クラス ArticleBase* m_article_null; protected: ARTICLE_INFO_LIST& get_list_artinfo(){ return m_list_artinfo; } ArticleHash* get_hash_article(){ return m_hash_article; } std::list< std::string >& get_url_update_views(){ return m_url_update_views; } ArticleBase* get_article_null(); ArticleBase* get_article( const std::string& datbase, const std::string& id ); ArticleBase* get_article_create( const std::string& datbase, const std::string& id ); void set_path_dat( const std::string& str ){ m_path_dat = str; } void set_path_readcgi( const std::string& str ){ m_path_readcgi = str; } void set_path_bbscgi( const std::string& str ){ m_path_bbscgi = str; } void set_path_subbbscgi( const std::string& str ){ m_path_subbbscgi = str; } void set_subjecttxt( const std::string& str ){ m_subjecttxt = str; } void set_ext( const std::string& str ){ m_ext = str; } void set_id( const std::string& str ){ m_id = str; } void set_charset( const std::string& str ){ m_charset = str; } // articleがスレあぼーんされているか const bool is_abone_thread( ArticleBase* article ); // m_url_update_views に登録されている view に update_board コマンドを送る void send_update_board(); // クッキー:HAP virtual const std::string get_hap(){ return std::string(); } virtual void set_hap( const std::string& hap ){} // クッキー:HAPの更新 (クッキーをセットした時に実行) virtual void update_hap(){} public: BoardBase( const std::string& root, const std::string& path_board, const std::string& name ); virtual ~BoardBase(); bool empty(); // 状態 ( global.hで定義 ) const int get_status() const{ return m_status; } // boardviewに表示するスレッドのリストを取得 std::vector< ArticleBase* >& get_list_subject(){ return m_list_subject; } // ローカルルールの modified 時刻 const std::string& get_modified_localrule() const { return m_modified_localrule; } void set_modified_localrule( const std::string& modified ){ m_modified_localrule = modified; } // setting.txtの modified 時刻 const std::string& get_modified_setting() const { return m_modified_setting; } void set_modified_setting( const std::string& modified ){ m_modified_setting = modified; } // boardviewでソートする列番号とソート順 const int get_view_sort_column() const { return m_view_sort_column; } void set_view_sort_column( int column ){ m_view_sort_column = column; } const int get_view_sort_mode() const { return m_view_sort_mode; } void set_view_sort_mode( int mode ){ m_view_sort_mode = mode; } const int get_view_sort_pre_column() const { return m_view_sort_pre_column; } void set_view_sort_pre_column( int column ) { m_view_sort_pre_column = column; } const int get_view_sort_pre_mode() const { return m_view_sort_pre_mode; } void set_view_sort_pre_mode( int mode ){ m_view_sort_pre_mode = mode; } // 名無し書き込み不可 const bool get_check_noname() const { return m_check_noname; } void set_check_noname( const bool check ){ m_check_noname = check; } // 過去ログも表示する const bool get_show_oldlog() const { return m_show_oldlog; } void set_show_oldlog( const bool show ){ m_show_oldlog = show; } // url がこの板のものかどうか virtual bool equal( const std::string& url ); // 移転などで板のルートやパスを変更する void update_url( const std::string& root, const std::string& path_board ); const std::string& get_root() const{ return m_root; } const std::string& get_path_board() const { return m_path_board; } const std::string& get_ext() const { return m_ext; } const std::string& get_id() const { return m_id; } const std::string& get_charset() const { return m_charset; } const std::string& get_name() const { return m_name; } void update_name( const std::string& name ); const std::string& get_subjecttxt() const { return m_subjecttxt; } // ユーザーエージェント virtual const std::string& get_agent(); // ダウンロード用 virtual const std::string& get_agent_w(); // 書き込み用 // ダウンロード時のプロキシ virtual const std::string get_proxy_host(); virtual const int get_proxy_port(); virtual const std::string get_proxy_basicauth(); // 書き込み時のプロキシ virtual const std::string get_proxy_host_w(); virtual const int get_proxy_port_w(); virtual const std::string get_proxy_basicauth_w(); // ローカルルール virtual const std::string localrule(); // SETTING.TXT virtual const std::string settingtxt(); // 書き込みの時のデフォルト名 virtual const std::string default_noname(); // 最大改行数/2 virtual const int line_number(); // 最大書き込みバイト数 virtual const int message_count(); // 特殊文字書き込み可能か( pass なら可能、 change なら不可 ) virtual const std::string get_unicode(); // 書き込み用クッキー virtual const std::string cookie_for_write(); const std::list< std::string >& list_cookies_for_write() { return m_list_cookies_for_write; } void set_list_cookies_for_write( const std::list< std::string >& list_cookies ); void reset_list_cookies_for_write(){ m_list_cookies_for_write.clear(); } // 書き込み時に必要なキーワード( hana=mogera や suka=pontan など ) // 書き込み時のメッセージに付加する const std::string& get_keyword_for_write() const { return m_keyword_for_write; } void set_keyword_for_write( const std::string& keyword ){ m_keyword_for_write = keyword; } // 書き込み時に必要なキーワード( hana=mogera や suka=pontan など )を // 確認画面のhtmlから解析する virtual void analyze_keyword_for_write( const std::string& html ){} // 書き込み時のリファラ virtual const std::string get_write_referer(){ return url_boardbase(); } // basic認証 const std::string& get_basicauth() const { return m_basicauth; } void set_basicauth( const std::string& basicauth ){ m_basicauth = basicauth; } // スレの url を dat型のurlに変換して出力 // url がスレッドのURLで無い時はempty()が返る // もしurlが移転前の旧ホストのものだったら対応するarticlebaseクラスに旧ホスト名を知らせる // (例) url = "http://www.hoge2ch.net/test/read.cgi/hogeboard/12345/12-15"のとき、 // "http://www.hoge2ch.net/hogeboard/dat/12345.dat", num_from = 12, num_to = 15, num_str = "12-15" virtual const std::string url_dat( const std::string& url, int& num_from, int& num_to, std::string& num_str ); // スレの url を read.cgi型のurlに変換 // url がスレッドのURLで無い時はempty()が返る // num_from と num_to が 0 で無い時はスレ番号を付ける // (例) "http://www.hoge2ch.net/hogeboard/dat/12345.dat", num_from = 12, num_to = 15 のとき // "http://www.hoge2ch.net/test/read.cgi/hogeboard/12345/12-15" virtual const std::string url_readcgi( const std::string& url, int num_from, int num_to ); // subject.txt の URLを取得 // (例) "http://www.hoge2ch.net/hogeboard/subject.txt" const std::string url_subject(); // ルートアドレス // (例) "http://www.hoge2ch.net/hogeboard/" なら "http://www.hoge2ch.net/" const std::string url_root(); // 板のベースアドレス // (例) "http://www.hoge2ch.net/hogeboard/" const std::string url_boardbase(); // dat ファイルのURLのベースアドレスを返す // (例) "http://www.hoge2ch.net/hogeboard/dat/12345.dat" なら "http://www.hoge2ch.net/hogeboard/dat/" const std::string url_datbase(); // dat ファイルのURLのパスを返す // (例) "http://www.hoge2ch.net/hogeboard/dat/12345.dat" なら "/hogeboard/dat/" virtual const std::string url_datpath(); // read.cgi のURLのベースアドレスを返す // (例) "http://www.hoge2ch.net/test/read.cgi/hogeboard/12345" なら "http://www.hoge2ch.net/test/read.cgi/hogeboard/" const std::string url_readcgibase(); // read.cgi のURLのパスを返す // (例) "http://www.hoge2ch.net/test/read.cgi/hogeboard/12345" なら "/test/read.cgi/hogeboard/" const std::string url_readcgipath(); // bbscgi のURLのベースアドレス // (例) "http://www.hoge2ch.net/test/bbs.cgi/" ( 最後に '/' がつく ) const std::string url_bbscgibase(); // subbbscgi のURLのベースアドレス // (例) "http://www.hoge2ch.net/test/subbbs.cgi/" ( 最後に '/' がつく ) const std::string url_subbbscgibase(); // article クラスのポインタ取得 ArticleBase* get_article_fromURL( const std::string& url ); // subject.txt ダウンロード // url_update_view : CORE::core_set_command( "update_board" ) を送信するビューのアドレス // read_from_cache : まだスレ一覧を開いていないときにキャッシュのsubject.txtを読み込む virtual void download_subject( const std::string& url_update_view, const bool read_from_cache ); // 新スレ作成用のメッセージ変換 virtual const std::string create_newarticle_message( const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ) { return std::string(); } // 新スレ作成用のbbscgi のURL virtual const std::string url_bbscgi_new() { return std::string(); } // 新スレ作成用のsubbbscgi のURL virtual const std::string url_subbbscgi_new() { return std::string(); } // 配下の全articlebaseクラスのあぼーん状態の更新 void update_abone_all_article(); // 板レベルでのあぼーん情報 const std::list< std::string >& get_abone_list_id_board(){ return m_list_abone_id; } const std::list< std::string >& get_abone_list_name_board(){ return m_list_abone_name; } const std::list< std::string >& get_abone_list_word_board(){ return m_list_abone_word; } const std::list< std::string >& get_abone_list_regex_board(){ return m_list_abone_regex; } // 板レベルでのあぼーん状態のリセット(情報セットとスレビューの表示更新を同時におこなう) void reset_abone_board( const std::list< std::string >& ids, const std::list< std::string >& names, const std::list< std::string >& words, const std::list< std::string >& regexs ); // 板レベルでのあぼ〜ん状態更新(reset_abone()と違って各項目ごと個別におこなう。スレビューの表示更新も同時におこなう) void add_abone_id_board( const std::string& id ); void add_abone_name_board( const std::string& name ); void add_abone_word_board( const std::string& word ); // スレあぼーん情報 const std::list< std::string >& get_abone_list_thread(){ return m_list_abone_thread; } const std::list< std::string >& get_abone_list_thread_remove(){ return m_list_abone_thread_remove; } const std::list< std::string >& get_abone_list_word_thread(){ return m_list_abone_word_thread; } const std::list< std::string >& get_abone_list_regex_thread(){ return m_list_abone_regex_thread; } const int get_abone_number_thread(){ return m_abone_number_thread; } const int get_abone_hour_thread(){ return m_abone_hour_thread; } // subject.txtのロード後にdat落ちしたスレッドをスレあぼーんのリストから取り除く void remove_old_abone_thread(); // スレあぼーん情報を更新した時に対応するスレ一覧の表示を更新する // CONFIG::set_abone_number_thread() などでグローバル設定をした後などに呼び出す // redraw : スレ一覧の表示更新を行う void update_abone_thread( const bool redraw ); // スレあぼーん状態のリセット(情報セットとスレ一覧の表示更新を同時におこなう) // redraw : スレ一覧の表示更新を行う void reset_abone_thread( const std::list< std::string >& threads, const std::list< std::string >& words, const std::list< std::string >& regexs, const int number, const int hour, const bool redraw ); // ローカルプロキシ設定 const int get_mode_local_proxy() const { return m_mode_local_proxy; } const std::string& get_local_proxy() const { return m_local_proxy; } const int get_local_proxy_port() const { return m_local_proxy_port; } const std::string& get_local_proxy_basicauth() const { return m_local_proxy_basicauth; } void set_mode_local_proxy( int mode ){ m_mode_local_proxy = mode; } void set_local_proxy( const std::string& proxy ); void set_local_proxy_port( int port ){ m_local_proxy_port = port; } const int get_mode_local_proxy_w() const { return m_mode_local_proxy_w; } const std::string& get_local_proxy_w() const { return m_local_proxy_w; } const int get_local_proxy_port_w() const { return m_local_proxy_port_w; } const std::string& get_local_proxy_basicauth_w() const { return m_local_proxy_basicauth_w; } void set_mode_local_proxy_w( int mode ){ m_mode_local_proxy_w = mode; } void set_local_proxy_w( const std::string& proxy ); void set_local_proxy_port_w( int port ){ m_local_proxy_port_w = port; } // 書き込み時のデフォルトの名前とメアド const std::string& get_write_name() const { return m_write_name; } const std::string& get_write_mail() const { return m_write_mail; } void set_write_name( const std::string& name ){ m_write_name = name; } void set_write_mail( const std::string& mail ){ m_write_mail = mail; } // 最終書き込み時間 void update_writetime(); const time_t& get_write_time() const { return m_write_time.tv_sec; } // 秒 const time_t get_write_pass(); // 経過時間(秒) const time_t get_samba_sec() const { return m_samba_sec; } // samba(秒) void set_samba_sec( time_t sec ){ m_samba_sec = sec; } time_t get_write_leftsec(); // 書き込み可能までの残り秒 // 全書き込み履歴クリア void clear_all_post_history(); // 全スレの書き込み時間とスレ立て時間の文字列をリセット void reset_all_write_date(); void reset_all_since_date(); // 実況の秒数 const time_t get_live_sec() const{ return m_live_sec; } void set_live_sec( time_t sec ){ m_live_sec = sec; } // 最終アクセス時刻 const time_t get_last_access_time() const{ return m_last_access_time; } // 最大レス数 const int get_number_max_res() const{ return m_number_max_res; } void set_number_max_res( const int number ); // datの最大サイズ(Kバイト) virtual const int get_max_dat_lng() const { return 0; } // 板情報の取得 virtual void read_info(); // 情報保存 virtual void save_info(); // 配下の全articlebaseクラスの情報保存 void save_articleinfo_all(); // キャッシュ内のログ検索 // ArticleBase のアドレスをリスト(list_article)にセットして返す // query が空の時はキャッシュにあるログを全てヒットさせる // bm がtrueの時、しおりが付いている(スレ一覧でしおりを付けた or レスに一つでもしおりが付いている)スレのみを対象に検索する virtual void search_cache( std::vector< ArticleBase* >& list_article, const std::string& query, const bool mode_or, // 今のところ無視 const bool bm, const bool& stop // 呼出元のスレッドで true にセットすると検索を停止する ); // datファイルのインポート // 成功したらdat型のurlを返す virtual const std::string import_dat( const std::string& filename ); // 更新可能状態にしてお気に入りやスレ一覧のタブのアイコンに更新マークを表示 // update == true の時に表示。falseなら戻す void show_updateicon( const bool update ); // 板の更新チェック時に、更新チェックを行うスレのアドレスのリスト // キャッシュが存在し、かつdat落ちしていないで新着数が0のスレを速度の順でソートして返す const std::list< std::string > get_check_update_articles(); private: void clear(); // デフォルト最大レス数( 0 : 未設定 ) virtual const int get_default_number_max_res(){ return 0; } // キャッシュのファイル名が正しいかどうか virtual const bool is_valid( const std::string& filename ){ return false; } virtual void create_loaderdata( JDLIB::LOADERDATA& data ); virtual void receive_data( const char* data, size_t size ); virtual void receive_finish(); // url_boardbase をロードして移転したかどうか解析開始 bool start_checkking_if_board_moved(); virtual ArticleBase* append_article( const std::string& datbase, const std::string& id, const bool cached ); virtual void parse_subject( const char* str_subject_txt ){} virtual void regist_article( const bool is_online ){} std::list< std::string > get_filelist_in_cache(); void read_board_info(); virtual void append_all_article_in_cache(); void save_summary(); void save_board_info(); void save_jdboard_info(); // ローカルルールとsetting.txtの読み込み及びダウンロード virtual void load_rule_setting(){} virtual void download_rule_setting(){} // レス数であぼーん(グローバル) // 2ch以外の板ではキャンセルする virtual const int get_abone_number_global(){ return 0; } }; } #endif jd-2.8.7-140104/src/dbtree/boardfactory.cpp0000644000076400010400000000163411160730160015006 0ustar // ライセンス: GPL2 #include "boardfactory.h" #include "board2ch.h" #include "board2chcompati.h" #include "boardlocal.h" #include "boardjbbs.h" #include "boardmachi.h" #include "type.h" DBTREE::BoardBase* DBTREE::BoardFactory( int type, const std::string& root, const std::string& path_board, const std::string& name, const std::string& basicauth ) { switch( type ) { case TYPE_BOARD_2CH: return new DBTREE::Board2ch( root, path_board, name ); case TYPE_BOARD_2CH_COMPATI: return new DBTREE::Board2chCompati( root, path_board, name, basicauth ); case TYPE_BOARD_LOCAL: return new DBTREE::BoardLocal( root, path_board, name ); case TYPE_BOARD_JBBS:return new DBTREE::BoardJBBS( root, path_board, name ); case TYPE_BOARD_MACHI:return new DBTREE::BoardMachi( root, path_board, name ); default: return NULL; } } jd-2.8.7-140104/src/dbtree/boardfactory.h0000644000076400010400000000060010540252733014451 0ustar // ライセンス: GPL2 // // BoardBaseのファクトリー // #ifndef _BOARDFACTORY_H #define _BOARDFACTORY_H #include namespace DBTREE { class BoardBase; DBTREE::BoardBase* BoardFactory( int type, const std::string& root, const std::string& path_board, const std::string& name, const std::string& basicauth ); } #endif jd-2.8.7-140104/src/dbtree/boardjbbs.cpp0000644000076400010400000002101012260002463014245 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boardjbbs.h" #include "articlejbbs.h" #include "articlehash.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/loaderdata.h" #include "global.h" #include #include using namespace DBTREE; BoardJBBS::BoardJBBS( const std::string& root, const std::string& path_board, const std::string& name ) : BoardBase( root, path_board, name ) { // dat のURLは特殊なので url_datpath()をオーバライドする set_path_dat( "" ); set_path_readcgi( "/bbs/read.cgi" ); set_path_bbscgi( "/bbs/write.cgi" ); set_path_subbbscgi( "/bbs/write.cgi" ); set_subjecttxt( "subject.txt" ); set_ext( "" ); set_id( path_board.substr( 1 ) ); // 先頭の '/' を除く set_charset( "EUCJP-WIN" ); } // // キャッシュのファイル名が正しいか // const bool BoardJBBS::is_valid( const std::string& filename ) { if( filename.length() != 10 ) return false; size_t dig, n; MISC::str_to_uint( filename.c_str(), dig, n ); if( dig != n ) return false; if( dig != 10 ) return false; return true; } // // 新しくArticleBaseクラスを追加してそのポインタを返す // // cached : HDD にキャッシュがあるならtrue // ArticleBase* BoardJBBS::append_article( const std::string& datbase, const std::string& id, const bool cached ) { if( empty() ) return get_article_null(); ArticleBase* article = new DBTREE::ArticleJBBS( datbase, id, cached ); if( article ){ get_hash_article()->push( article ); // 最大レス数セット article->set_number_max( get_number_max_res() ); } else return get_article_null(); return article; } // // rawmode のURLのパスを返す // // (例) "/bbs/rawmode.cgi/board/" (最初と最後に '/' がつく) // const std::string BoardJBBS::url_datpath() { if( empty() ) return std::string(); return "/bbs/rawmode.cgi" + get_path_board() + "/"; } const std::string BoardJBBS::create_newarticle_message( const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ) { if( subject.empty() ) return std::string(); if( msg.empty() ) return std::string(); // DIR と BBS を分離する( ID = DIR/BBS ) std::string boardid = get_id(); int i = boardid.find( "/" ); std::string dir = boardid.substr( 0, i ); std::string bbs = boardid.substr( i + 1 ); std::stringstream ss_post; ss_post.clear(); ss_post << "SUBJECT=" << MISC::charset_url_encode( subject, get_charset() ) << "&submit=" << MISC::charset_url_encode( "新規書き込み", get_charset() ) << "&NAME=" << MISC::charset_url_encode( name, get_charset() ) << "&MAIL=" << MISC::charset_url_encode( mail, get_charset() ) << "&MESSAGE=" << MISC::charset_url_encode( msg, get_charset() ) << "&DIR=" << dir << "&BBS=" << bbs << "&TIME=" << get_time_modified(); #ifdef _DEBUG std::cout << "BoardJBBS::create_newarticle_message " << ss_post.str() << std::endl; #endif return ss_post.str(); } // // 新スレ作成時のbbscgi(write.cgi) のURL // // (例) "http://jbbs.shitaraba.net/bbs/write.cgi/computer/123/new/" // // const std::string BoardJBBS::url_bbscgi_new() { return url_bbscgibase() + get_id() + "/new/"; } // // 新スレ作成時のsubbbscgi のURL // // (例) "http://jbbs.shitaraba.net/bbs/write.cgi/computer/123/new/" // const std::string BoardJBBS::url_subbbscgi_new() { return url_subbbscgibase() + get_id() + "/new/"; } // // subject.txt から Aarticle のリストにアイテムを追加・更新 // void BoardJBBS::parse_subject( const char* str_subject_txt ) { #ifdef _DEBUG std::cout << "BoardJBBS::parse_subject\n"; #endif const char* pos = str_subject_txt; while( *pos != '\0' ){ const char* str_id_dat; int lng_id_dat = 0; const char* str_subject; int lng_subject = 0; char str_num[ 16 ]; // datのID取得 // ".cgi" は除く str_id_dat = pos; while( *pos != '.' && *pos != '\0' && *pos != '\n' ) { ++pos; ++lng_id_dat; } // 壊れてる if( *pos == '\0' ) break; if( *pos == '\n' ) { ++pos; continue; } // subject取得 pos += 5; // ' ".cgi," str_subject = pos; while( *pos != '\0' && *pos != '\n' ) ++pos; --pos; while( *pos != '(' && *pos != '\n' && pos != str_subject_txt ) --pos; // 壊れてる if( *pos == '\n' || pos == str_subject_txt ){ MISC::ERRMSG( "subject.txt is broken" ); break; } lng_subject = ( int )( pos - str_subject ); // レス数取得 ++pos; int i = 0; while( '0' <= *pos && *pos <= '9' && i < 16 ) str_num[ i++ ] = *( pos++ ); // 壊れてる if( i == 0 ){ MISC::ERRMSG( "subject.txt is broken (res)" ); break; } if( *pos == '\0' ) break; if( *pos == '\n' ) { ++pos; continue; } str_num[ i ] = '\0'; ++pos; // id, subject, number 取得 ARTICLE_INFO artinfo; artinfo.id.assign( str_id_dat, lng_id_dat ); artinfo.id = MISC::remove_space( artinfo.id ); artinfo.subject.assign( str_subject, lng_subject ); artinfo.subject = MISC::remove_space( artinfo.subject ); artinfo.subject = MISC::replace_str( artinfo.subject, "<", "<" ); artinfo.subject = MISC::replace_str( artinfo.subject, ">", ">" ); artinfo.number = atol( str_num ); get_list_artinfo().push_back( artinfo ); #ifdef _DEBUG std::cout << "pos = " << ( pos - str_subject_txt ) << " lng = " << lng_subject << " id = " << artinfo.id << " num = " << artinfo.number; std::cout << " : " << artinfo.subject << std::endl; #endif } } void BoardJBBS::regist_article( const bool is_online ) { if( ! get_list_artinfo().size() ) return; #ifdef _DEBUG std::cout << "BoardJBBS::regist_article size = " << get_list_artinfo().size() << std::endl; #endif ArticleBase* article_first = NULL; const std::string datbase = url_datbase(); for( unsigned int i = 0; i < get_list_artinfo().size(); ++i ){ const ARTICLE_INFO& artinfo = get_list_artinfo()[ i ]; // DBに登録されてるならarticle クラスの情報更新 ArticleBase* article = get_article( datbase, artinfo.id ); // DBにないなら新規に article クラスを追加 // // なお BoardBase::receive_finish() のなかで append_all_article_in_cache() が既に呼び出されているため // DBに無いということはキャッシュにも無いということ。よって append_article()で cached = false if( article->empty() ) article = append_article( datbase, artinfo.id, false ); // スレ情報更新 if( article ){ // ステータスをDAT落ち状態から通常状態に変更 int status = article->get_status(); status |= STATUS_NORMAL; status &= ~STATUS_OLD; article->set_status( status ); // 情報ファイル読み込み article->read_info(); // 情報ファイルが無い場合もあるのでsubject.txtから取得したサブジェクト、レス数を指定しておく article->set_subject( artinfo.subject ); article->set_number( artinfo.number, is_online ); // boardビューに表示するリスト更新 // JBBSは最初と最後の行が同じになる仕様があるので最後の行を除く bool pushback = true; if( ! article_first ) article_first = article; else if( article == article_first ) pushback = false; if( pushback ){ // 情報ファイル読み込み後にステータスが変わることがあるので、もう一度 // ステータスをDAT落ち状態から通常状態に変更 status = article->get_status(); status |= STATUS_NORMAL; status &= ~STATUS_OLD; article->set_status( status ); // boardビューに表示するリスト更新 if( ! BoardBase::is_abone_thread( article ) ) get_list_subject().push_back( article ); } } } } jd-2.8.7-140104/src/dbtree/boardjbbs.h0000644000076400010400000000224011355145520013724 0ustar // ライセンス: GPL2 // // JBBS 型板 // #ifndef _BOARDJBBS_H #define _BOARDJBBS_H #include "boardbase.h" namespace DBTREE { class BoardJBBS : public BoardBase { public: BoardJBBS( const std::string& root, const std::string& path_board,const std::string& name ); virtual const std::string url_datpath(); // 新スレ作成用のメッセージ変換 virtual const std::string create_newarticle_message( const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ); // 新スレ作成用のbbscgi のURL virtual const std::string url_bbscgi_new(); // 新スレ作成用のsubbbscgi のURL virtual const std::string url_subbbscgi_new(); private: virtual const bool is_valid( const std::string& filename ); virtual ArticleBase* append_article( const std::string& datbase, const std::string& id, const bool cached ); virtual void parse_subject( const char* str_subject_txt ); virtual void regist_article( const bool is_online ); }; } #endif jd-2.8.7-140104/src/dbtree/boardlocal.cpp0000644000076400010400000000636611405713530014444 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boardlocal.h" #include "articlelocal.h" #include "articlehash.h" #include "jdlib/miscutil.h" #include "jdlib/jdregex.h" #include "cache.h" using namespace DBTREE; BoardLocal::BoardLocal( const std::string& root, const std::string& path_board, const std::string& name ) : Board2chCompati( root, path_board, name, std::string() ) { #ifdef _DEBUG std::cout << "BoardLocal::BoardLocal\n"; #endif } BoardLocal::~BoardLocal() {} // // url がこの板のものかどうか // bool BoardLocal::equal( const std::string& url ) { if( url.find( "file://" ) == 0 ) return true; return false; } // そのまま出力 const std::string BoardLocal::url_dat( const std::string& url, int& num_from, int& num_to, std::string& num_str ) { num_from = 0; num_to = 0; num_str = std::string(); return url_readcgi( url, num_from, num_to ); } // そのまま出力 const std::string BoardLocal::url_readcgi( const std::string& url, int num_from, int num_to ) { JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; const std::string query = "^ *file://.*/[1234567890]+" + get_ext() + " *$"; if( ! regex.exec( query , url, offset, icase, newline, usemigemo, wchar ) ) return std::string(); #ifdef _DEBUG std::cout << "BoardLocal::url_readcgi : url = " << url << std::endl; #endif return url; } void BoardLocal::download_subject( const std::string& url_update_view ) { // ダウンロードを実行しない get_url_update_views().push_back( url_update_view ); send_update_board(); } ArticleBase* BoardLocal::append_article( const std::string& datbase, const std::string& id, const bool cached ) { #ifdef _DEBUG std::cout << "BoardLocal::append_article datbase = " << datbase << ", id = " << id << std::endl; #endif ArticleBase* article = new DBTREE::ArticleLocal( datbase, id ); if( article ){ get_hash_article()->push( article ); // subject にも追加する get_list_subject().push_back( article ); } else return get_article_null(); return article; } // datファイルのインポート const std::string BoardLocal::import_dat( const std::string& filename ) { if( empty() ) return FALSE; if( CACHE::file_exists( filename ) != CACHE::EXIST_FILE ) return std::string(); int num_from, num_to; std::string num_str; const std::string urldat = url_dat( filename, num_from, num_to, num_str ); if( urldat.empty() ) return std::string(); const std::string datbase = MISC::get_dir( urldat ); const std::string id = urldat.substr( datbase.length() ); if( ! id.empty() ) return std::string(); ArticleBase* art = get_article( datbase, id ); // データベースに無いのでインポート if( art->empty() ){ #ifdef _DEBUG std::cout << "BoardLocal::import_dat file = " << filename << std::endl; #endif art = append_article( datbase, id, true // キャッシュあり ); assert( art ); art->read_info(); return filename; } return std::string(); } jd-2.8.7-140104/src/dbtree/boardlocal.h0000644000076400010400000000275011273044650014105 0ustar // ライセンス: GPL2 // // ローカルファイル用仮想板 // #ifndef _BOARDLOCAL_H #define _BOARDLOCAL_H #include "board2chcompati.h" namespace DBTREE { class BoardLocal : public Board2chCompati { public: BoardLocal( const std::string& root, const std::string& path_board, const std::string& name ); virtual ~BoardLocal(); // url がこの板のものかどうか virtual bool equal( const std::string& url ); virtual const std::string url_dat( const std::string& url, int& num_from, int& num_to, std::string& num_str ); virtual const std::string url_readcgi( const std::string& url, int num_from, int num_to ); virtual void download_subject( const std::string& url_update_view ); // 板情報の読み書きをキャンセル virtual void read_info(){} virtual void save_info(){} // キャッシュサーチをキャンセル virtual void search_cache( std::list< ArticleBase* >& list_article, const std::string& query, const bool mode_or, const bool& stop ){} // datファイルのインポート virtual const std::string import_dat( const std::string& filename ); private: virtual ArticleBase* append_article( const std::string& datbase, const std::string& id, const bool cached ); virtual void append_all_article_in_cache(){} virtual void load_rule_setting(){} virtual void download_rule_setting(){} }; } #endif jd-2.8.7-140104/src/dbtree/boardmachi.cpp0000644000076400010400000002422712074275756014447 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "boardmachi.h" #include "articlemachi.h" #include "articlehash.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/loaderdata.h" #include "jdlib/jdregex.h" #include "global.h" #include #include using namespace DBTREE; BoardMachi::BoardMachi( const std::string& root, const std::string& path_board, const std::string& name ) : BoardBase( root, path_board, name ) { // dat のURLは特殊なので url_datpath()をオーバライドする set_path_dat( "" ); set_path_readcgi( "/bbs/read.cgi" ); set_path_bbscgi( "/bbs/write.cgi" ); set_path_subbbscgi( "/bbs/write.cgi" ); set_subjecttxt( "subject.txt" ); set_ext( "" ); set_id( path_board.substr( 1 ) ); // 先頭の '/' を除く set_charset( "MS932" ); } // // url がこの板のものかどうか // bool BoardMachi::equal( const std::string& url ) { if( url.find( get_root() ) == 0 ){ if( url.find( get_path_board() + "/" ) != std::string::npos ) return true; if( url.find( "BBS=" + get_id() ) != std::string::npos ) return true; } return false; } // // キャッシュのファイル名が正しいか // const bool BoardMachi::is_valid( const std::string& filename ) { if( filename.length() != 10 ) return false; size_t dig, n; MISC::str_to_uint( filename.c_str(), dig, n ); if( dig != n ) return false; if( dig != 10 ) return false; return true; } // // 新しくArticleBaseクラスを追加してそのポインタを返す // // cached : HDD にキャッシュがあるならtrue // ArticleBase* BoardMachi::append_article( const std::string& datbase, const std::string& id, const bool cached ) { if( empty() ) return get_article_null(); ArticleBase* article = new DBTREE::ArticleMachi( datbase, id, cached ); if( article ){ get_hash_article()->push( article ); // 最大レス数セット article->set_number_max( get_number_max_res() ); } else return get_article_null(); return article; } // // スレの url を dat型のurlに変換して出力 // // (例) "http://hoge.machi.to/bbs/read.cgi?BBS=board&KEY=12345&START=12&END=15"" のとき // 戻り値 : "http://hoge.machi.to/bbs/read.cgi?BBS=board&KEY=12345", num_from = 12, num_to = 15, num_str = 12-15 // const std::string BoardMachi::url_dat( const std::string& url, int& num_from, int& num_to, std::string& num_str ) { if( empty() ) return std::string(); // read.cgi 型の判定 const std::string urldat = BoardBase::url_dat( url, num_from, num_to, num_str ); if( ! urldat.empty() ) return urldat; // 旧形式(read.pl)型の場合 if( url.find( "read.pl" ) != std::string::npos ){ const std::string urldat = BoardBase::url_dat( MISC::replace_str( url, "read.pl", "read.cgi" ), num_from, num_to, num_str ); if( ! urldat.empty() ) return urldat; } #ifdef _DEBUG std::cout << "BoardMachi::url_dat : url = " << url << std::endl; #endif JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string id; // スレッドのID num_from = num_to = 0; // dat 型 // LAST, START, END を考慮する const std::string datpath = MISC::replace_str( url_datpath(), "?", "\\?" ); const std::string query_dat = "^ *(http://.+" + datpath + ")([1234567890]+" + get_ext() + ")(&LAST=[1234567890]+)?(&START=([1234567890])+)?(&END=([1234567890])+)? *$"; #ifdef _DEBUG std::cout << "query_dat = " << query_dat << std::endl; #endif if( regex.exec( query_dat , url, offset, icase, newline, usemigemo, wchar ) ){ id = regex.str( 2 ); if( ! regex.str( 5 ).empty() ){ num_from = atoi( regex.str( 5 ).c_str() ); num_str = MISC::itostr( num_from ); } if( ! regex.str( 7 ).empty() ){ num_to = atoi( regex.str( 7 ).c_str() ); num_str += "-" + MISC::itostr( num_to ); } #ifdef _DEBUG std::cout << "id = " << id << std::endl << "start = " << num_from << std::endl << "end = " << num_to << std::endl << "num = " << num_str << std::endl; #endif } else return std::string(); return url_datbase() + id; } // // read.cgi のURLのパスを返す // // (例) "/bbs/read.cgi?BBS=board&KEY=" (最初に '/' がつく) // const std::string BoardMachi::url_datpath() { if( empty() ) return std::string(); return "/bbs/read.cgi?BBS=" + get_id() + "&KEY="; } const std::string BoardMachi::create_newarticle_message( const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ) { if( subject.empty() ) return std::string(); if( msg.empty() ) return std::string(); // まちではテスト出来ないので新スレを立てない return std::string(); } // // 新スレ作成時のbbscgi(write.cgi) のURL // const std::string BoardMachi::url_bbscgi_new() { return std::string(); } // // 新スレ作成時のsubbbscgi のURL // const std::string BoardMachi::url_subbbscgi_new() { return std::string(); } // // subject.txt から Aarticle のリストにアイテムを追加・更新 // void BoardMachi::parse_subject( const char* str_subject_txt ) { #ifdef _DEBUG std::cout << "BoardMachi::parse_subject" << std::endl; #endif const char* pos = str_subject_txt; while( *pos != '\0' ){ const char* str_id_dat; int lng_id_dat = 0; const char* str_subject; int lng_subject = 0; char str_num[ 16 ]; // datのID取得 // ".cgi" は除く str_id_dat = pos; while( *pos != '.' && *pos != '\0' && *pos != '\n' ) { ++pos; ++lng_id_dat; } // 壊れてる if( *pos == '\0' ) break; if( *pos == '\n' ) { ++pos; continue; } // subject取得 pos += 5; // ' ".cgi," str_subject = pos; while( *pos != '\0' && *pos != '\n' ) ++pos; --pos; while( *pos != '(' && *pos != '\n' && pos != str_subject_txt ) --pos; // 壊れてる if( *pos == '\n' || pos == str_subject_txt ){ MISC::ERRMSG( "subject.txt is broken" ); break; } lng_subject = ( int )( pos - str_subject ); // レス数取得 ++pos; int i = 0; while( '0' <= *pos && *pos <= '9' && i < 16 ) str_num[ i++ ] = *( pos++ ); // 壊れてる if( i == 0 ){ MISC::ERRMSG( "subject.txt is broken (res)" ); break; } if( *pos == '\0' ) break; if( *pos == '\n' ) { ++pos; continue; } str_num[ i ] = '\0'; ++pos; // id, subject, number 取得 ARTICLE_INFO artinfo; artinfo.id.assign( str_id_dat, lng_id_dat ); artinfo.id = MISC::remove_space( artinfo.id ); artinfo.subject.assign( str_subject, lng_subject ); artinfo.subject = MISC::remove_space( artinfo.subject ); artinfo.subject = MISC::replace_str( artinfo.subject, "<", "<" ); artinfo.subject = MISC::replace_str( artinfo.subject, ">", ">" ); artinfo.number = atol( str_num ); get_list_artinfo().push_back( artinfo ); #ifdef _DEBUG std::cout << "pos = " << ( pos - str_subject_txt ) << " lng = " << lng_subject << " id = " << artinfo.id << " num = " << artinfo.number; std::cout << " : " << artinfo.subject << std::endl; #endif } } void BoardMachi::regist_article( const bool is_online ) { if( ! get_list_artinfo().size() ) return; #ifdef _DEBUG std::cout << "BoardMachii::regist_article size = " << get_list_artinfo().size() << std::endl; #endif ArticleBase* article_first = NULL; const std::string datbase = url_datbase(); for( unsigned int i = 0; i < get_list_artinfo().size(); ++i ){ const ARTICLE_INFO& artinfo = get_list_artinfo()[ i ]; // DBに登録されてるならarticle クラスの情報更新 ArticleBase* article = get_article( datbase, artinfo.id ); // DBにないなら新規に article クラスを追加 // // なお BoardBase::receive_finish() のなかで append_all_article_in_cache() が既に呼び出されているため // DBに無いということはキャッシュにも無いということ。よって append_article()で cached = false if( article->empty() ) article = append_article( datbase, artinfo.id, false ); // スレ情報更新 if( article ){ // ステータスをDAT落ち状態から通常状態に変更 int status = article->get_status(); status |= STATUS_NORMAL; status &= ~STATUS_OLD; article->set_status( status ); // 情報ファイル読み込み article->read_info(); // 情報ファイルが無い場合もあるのでsubject.txtから取得したサブジェクト、レス数を指定しておく article->set_subject( artinfo.subject ); article->set_number( artinfo.number, is_online ); // boardビューに表示するリスト更新 // Machiは最初と最後の行が同じになる仕様があるので最後の行を除く bool pushback = true; if( ! article_first ) article_first = article; else if( article == article_first ) pushback = false; if( pushback ){ // 情報ファイル読み込み後にステータスが変わることがあるので、もう一度 // ステータスをDAT落ち状態から通常状態に変更 status = article->get_status(); status |= STATUS_NORMAL; status &= ~STATUS_OLD; article->set_status( status ); // boardビューに表示するリスト更新 if( ! BoardBase::is_abone_thread( article ) ) get_list_subject().push_back( article ); } } } } jd-2.8.7-140104/src/dbtree/boardmachi.h0000644000076400010400000000324511355145520014073 0ustar // ライセンス: GPL2 // // まち 型板 // #ifndef _BOARDMACHI_H #define _BOARDMACHI_H #include "boardbase.h" namespace DBTREE { class BoardMachi : public BoardBase { public: BoardMachi( const std::string& root, const std::string& path_board,const std::string& name ); // url がこの板のものかどうか virtual bool equal( const std::string& url ); // スレの url を dat型のurlに変換して出力 // (例) "http://hoge.machi.to/bbs/read.cgi?BBS=board&KEY=12345&START=12&END=15"" のとき // 戻り値 : "http://hoge.machi.to/bbs/read.cgi?BBS=board&KEY=12345", num_from = 12, num_to = 15, num_str = 12-15 virtual const std::string url_dat( const std::string& url, int& num_from, int& num_to, std::string& num_str ); virtual const std::string url_datpath(); // 新スレ作成用のメッセージ変換 virtual const std::string create_newarticle_message( const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ); // 新スレ作成用のbbscgi のURL virtual const std::string url_bbscgi_new(); // 新スレ作成用のsubbbscgi のURL virtual const std::string url_subbbscgi_new(); private: virtual const bool is_valid( const std::string& filename ); virtual ArticleBase* append_article( const std::string& datbase, const std::string& id, const bool cached ); virtual void parse_subject( const char* str_subject_txt ); virtual void regist_article( const bool is_online ); }; } #endif jd-2.8.7-140104/src/dbtree/etcboardinfo.h0000644000076400010400000000055410765004674014451 0ustar // ライセンス: GPL2 // // 外部板情報 // #ifndef _ETCBOARDINFO_H #define _ETCBOARDINFO_H #include namespace DBTREE { struct ETCBOARDINFO { std::string name; std::string url; std::string basicauth; // basic認証 ID:PASS std::string boardid; // navi2chのetc形式との互換のため }; } #endif jd-2.8.7-140104/src/dbtree/interface.cpp0000644000076400010400000010143311615011401014260 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "interface.h" #include "root.h" #include "boardbase.h" #include "articlebase.h" #include "jdlib/miscutil.h" #include "global.h" // インスタンスは Core でひとつだけ作って、Coreのデストラクタでdeleteする DBTREE::Root *instance_dbtree_root = NULL; void DBTREE::create_root() { if( ! instance_dbtree_root ) instance_dbtree_root = new DBTREE::Root(); } void DBTREE::delete_root() { if( instance_dbtree_root ){ instance_dbtree_root->terminate_load(); delete instance_dbtree_root; } } ////////////////////////////////////// // // ツリーの構成要素のポインタ取得 // // root から葉っぱに向かって順に取得していく // DBTREE::Root* DBTREE::get_root() { assert( instance_dbtree_root != NULL ); return instance_dbtree_root; } DBTREE::BoardBase* DBTREE::get_board( const std::string& url ) { DBTREE::BoardBase* board = DBTREE::get_root()->get_board( url ); assert( board != NULL ); return board; } DBTREE::ArticleBase* DBTREE::get_article( const std::string& url ) { DBTREE::ArticleBase* article = DBTREE::get_board( url )->get_article_fromURL( url ); assert( article != NULL ); return article; } ////////////////////////////////////// const std::string DBTREE::url_subject( const std::string& url ) { return DBTREE::get_board( url )->url_subject(); } const std::string DBTREE::url_root( const std::string& url ) { return DBTREE::get_board( url )->url_root(); } const std::string DBTREE::url_boardbase( const std::string& url ) { return DBTREE::get_board( url )->url_boardbase(); } const std::string DBTREE::url_datbase( const std::string& url ) { return DBTREE::get_board( url )->url_datbase(); } // urlをdat型のurlに変換 const std::string DBTREE::url_dat( const std::string& url, int& num_from, int& num_to, std::string& num_str ) { return DBTREE::get_board( url )->url_dat( url, num_from, num_to, num_str ); } // urlをdat型のurlに変換(簡易版) const std::string DBTREE::url_dat( const std::string& url ) { int num_from, num_to; std::string num_str; return url_dat( url, num_from, num_to, num_str ); } // url を read.cgi型のurlに変換 const std::string DBTREE::url_readcgi( const std::string& url, int num_from, int num_to ) { return DBTREE::get_board( url )->url_readcgi( url, num_from, num_to ); } const std::string DBTREE::url_bbscgibase( const std::string& url ) { return DBTREE::get_board( url )->url_bbscgibase(); } const std::string DBTREE::url_subbbscgibase( const std::string& url ) { return DBTREE::get_board( url )->url_subbbscgibase(); } const std::string DBTREE::url_bbscgi( const std::string& url ) { return DBTREE::get_article( url )->url_bbscgi(); } const std::string DBTREE::url_subbbscgi( const std::string& url ) { return DBTREE::get_article( url )->url_subbbscgi(); } const std::string DBTREE::url_bbscgi_new( const std::string& url ) { return DBTREE::get_board( url )->url_bbscgi_new(); } const std::string DBTREE::url_subbbscgi_new( const std::string& url ) { return DBTREE::get_board( url )->url_subbbscgi_new(); } // 簡易版 const std::string DBTREE::is_board_moved( const std::string& url ) { return get_root()->is_board_moved( url ); } const std::string DBTREE::is_board_moved( const std::string& url, std::string& old_root, std::string& old_path_board, std::string& new_root, std::string& new_path_board ) { return get_root()->is_board_moved( url, old_root, old_path_board, new_root, new_path_board ); } const bool DBTREE::move_board( const std::string& url_old, const std::string& url_new ) { return get_root()->move_board( url_old, url_new, false ); } void DBTREE::set_enable_save_movetable( const bool set ) { get_root()->set_enable_save_movetable( set ); } void DBTREE::save_movetable() { get_root()->save_movetable(); } const XML::Document& DBTREE::get_xml_document() { return get_root()->xml_document(); } const std::list< DBTREE::ETCBOARDINFO >& DBTREE::get_etcboards() { return get_root()->get_etcboards(); } bool DBTREE::add_etc( const std::string& url, const std::string& name, const std::string& basicauth, const std::string& id ) { return get_root()->add_etc( url, name, basicauth, id ); } bool DBTREE::move_etc( const std::string& url_old, const std::string& url_new, const std::string& name_old, const std::string& name_new, const std::string& basicauth, const std::string& boardid ) { return get_root()->move_etc( url_old, url_new, name_old, name_new, basicauth, boardid ); } bool DBTREE::remove_etc( const std::string& url, const std::string& name ) { return get_root()->remove_etc( url, name ); } void DBTREE::save_etc() { get_root()->save_etc(); } void DBTREE::download_bbsmenu() { get_root()->download_bbsmenu(); } // bbsmenuの更新時間( 文字列 ) const std::string DBTREE::get_date_modified() { return get_root()->get_date_modified(); } // bbsmenuの更新時間( time_t ) const time_t DBTREE::get_time_modified() { return get_root()->get_time_modified(); } const std::string DBTREE::board_path( const std::string& url ) { return DBTREE::get_board( url )->get_path_board(); } const std::string DBTREE::board_id( const std::string& url ) { return DBTREE::get_board( url )->get_id(); } // 更新時間( time_t ) const time_t DBTREE::board_time_modified( const std::string& url ) { return DBTREE::get_board( url )->get_time_modified(); } // 板の更新時間( 文字列 ) const std::string DBTREE::board_date_modified( const std::string& url ) { return DBTREE::get_board( url )->get_date_modified(); } // 板の更新時間( 文字列 )をセット void DBTREE::board_set_date_modified( const std::string& url, const std::string& date ) { DBTREE::get_board( url )->set_date_modified( date ); } const std::string& DBTREE::board_get_modified_localrule( const std::string& url ) { return DBTREE::get_board( url )->get_modified_localrule(); } void DBTREE::board_set_modified_localrule( const std::string& url, const std::string& modified ) { DBTREE::get_board( url )->set_modified_localrule( modified ); } const std::string& DBTREE::board_get_modified_setting( const std::string& url ) { return DBTREE::get_board( url )->get_modified_setting(); } void DBTREE::board_set_modified_setting( const std::string& url, const std::string& modified ) { DBTREE::get_board( url )->set_modified_setting( modified ); } const std::string DBTREE::board_name( const std::string& url ) { return DBTREE::get_board( url )->get_name(); } const std::string DBTREE::board_subjecttxt( const std::string& url ) { return DBTREE::get_board( url )->get_subjecttxt(); } const std::string DBTREE::board_charset( const std::string& url ) { return DBTREE::get_board( url )->get_charset(); } const std::string DBTREE::board_cookie_for_write( const std::string& url ) { return DBTREE::get_board( url )->cookie_for_write(); } const std::list< std::string >& DBTREE::board_list_cookies_for_write( const std::string& url ) { return DBTREE::get_board( url )->list_cookies_for_write(); } void DBTREE::board_set_list_cookies_for_write( const std::string& url, const std::list< std::string>& list_cookies ) { DBTREE::get_board( url )->set_list_cookies_for_write( list_cookies ); } void DBTREE::board_reset_list_cookies_for_write( const std::string& url ) { DBTREE::get_board( url )->reset_list_cookies_for_write(); } const std::string DBTREE::board_keyword_for_write( const std::string& url ) { return DBTREE::get_board( url )->get_keyword_for_write(); } void DBTREE::board_set_keyword_for_write( const std::string& url, const std::string& keyword ) { DBTREE::get_board( url )->set_keyword_for_write( keyword ); } void DBTREE::board_analyze_keyword_for_write( const std::string& url, const std::string& html ) { DBTREE::get_board( url )->analyze_keyword_for_write( html ); } const std::string DBTREE::board_basicauth( const std::string& url ) { return DBTREE::get_board( url )->get_basicauth(); } const std::string DBTREE::board_ext( const std::string& url ) { return DBTREE::get_board( url )->get_ext(); } const int DBTREE::board_status( const std::string& url ) { return DBTREE::get_board( url )->get_status(); } const int DBTREE::board_code( const std::string& url ) { return DBTREE::get_board( url )->get_code(); } const std::string DBTREE::board_str_code( const std::string& url ) { return DBTREE::get_board( url )->get_str_code(); } void DBTREE::board_save_info( const std::string& url ) { DBTREE::get_board( url )->save_info(); } void DBTREE::board_download_subject( const std::string& url, const std::string& url_update_view ) { DBTREE::get_board( url )->download_subject( url_update_view, false ); } void DBTREE::board_read_subject_from_cache( const std::string& url ) { DBTREE::get_board( url )->download_subject( std::string(), true ); } const bool DBTREE::board_is_loading( const std::string& url ) { return DBTREE::get_board( url )->is_loading(); } void DBTREE::board_stop_load( const std::string& url ) { DBTREE::get_board( url )->stop_load(); } std::vector< DBTREE::ArticleBase* >& DBTREE::board_list_subject( const std::string& url ) { return DBTREE::get_board( url )->get_list_subject(); } const int DBTREE::board_view_sort_column( const std::string& url ) { return DBTREE::get_board( url )->get_view_sort_column(); } void DBTREE::board_set_view_sort_column( const std::string& url, int column ) { DBTREE::get_board( url )->set_view_sort_column( column ); } const int DBTREE::board_view_sort_mode( const std::string& url ) { return DBTREE::get_board( url )->get_view_sort_mode(); } void DBTREE::board_set_view_sort_mode( const std::string& url, int mode ) { DBTREE::get_board( url )->set_view_sort_mode( mode ); } const int DBTREE::board_view_sort_pre_column( const std::string& url ) { return DBTREE::get_board( url )->get_view_sort_pre_column(); } void DBTREE::board_set_view_sort_pre_column( const std::string& url, int column ) { DBTREE::get_board( url )->set_view_sort_pre_column( column ); } const int DBTREE::board_view_sort_pre_mode( const std::string& url ) { return DBTREE::get_board( url )->get_view_sort_pre_mode(); } void DBTREE::board_set_view_sort_pre_mode( const std::string& url, int mode ) { DBTREE::get_board( url )->set_view_sort_pre_mode( mode ); } const bool DBTREE::board_check_noname( const std::string& url ) { return DBTREE::get_board( url )->get_check_noname(); } void DBTREE::board_set_check_noname( const std::string& url, const bool check ) { DBTREE::get_board( url )->set_check_noname( check ); } const bool DBTREE::board_show_oldlog( const std::string& url ) { return DBTREE::get_board( url )->get_show_oldlog(); } void DBTREE::board_set_show_oldlog( const std::string& url, const bool show ) { DBTREE::get_board( url )->set_show_oldlog( show ); } const int DBTREE::board_get_mode_local_proxy( const std::string& url ) { return DBTREE::get_board( url )->get_mode_local_proxy(); } const std::string& DBTREE::board_get_local_proxy( const std::string& url ) { return DBTREE::get_board( url )->get_local_proxy(); } const int DBTREE::board_get_local_proxy_port( const std::string& url ) { return DBTREE::get_board( url )->get_local_proxy_port(); } const std::string& DBTREE::board_get_local_proxy_basicauth( const std::string& url ) { return DBTREE::get_board( url )->get_local_proxy_basicauth(); } void DBTREE::board_set_mode_local_proxy( const std::string& url, int mode ) { DBTREE::get_board( url )->set_mode_local_proxy( mode ); } void DBTREE::board_set_local_proxy( const std::string& url, const std::string& proxy ) { DBTREE::get_board( url )->set_local_proxy( proxy ); } void DBTREE::board_set_local_proxy_port( const std::string& url, int port ) { DBTREE::get_board( url )->set_local_proxy_port( port ); } const int DBTREE::board_get_mode_local_proxy_w( const std::string& url ) { return DBTREE::get_board( url )->get_mode_local_proxy_w(); } const std::string& DBTREE::board_get_local_proxy_w( const std::string& url ) { return DBTREE::get_board( url )->get_local_proxy_w(); } const std::string& DBTREE::board_get_local_proxy_basicauth_w( const std::string& url ) { return DBTREE::get_board( url )->get_local_proxy_basicauth_w(); } const int DBTREE::board_get_local_proxy_port_w( const std::string& url ) { return DBTREE::get_board( url )->get_local_proxy_port_w(); } void DBTREE::board_set_mode_local_proxy_w( const std::string& url, int mode ) { DBTREE::get_board( url )->set_mode_local_proxy_w( mode ); } void DBTREE::board_set_local_proxy_w( const std::string& url, const std::string& proxy ) { DBTREE::get_board( url )->set_local_proxy_w( proxy ); } void DBTREE::board_set_local_proxy_port_w( const std::string& url, int port ) { DBTREE::get_board( url )->set_local_proxy_port_w( port ); } const std::string& DBTREE::board_get_write_name( const std::string& url ) { return DBTREE::get_board( url )->get_write_name(); } const std::string& DBTREE::board_get_write_mail( const std::string& url ) { return DBTREE::get_board( url )->get_write_mail(); } void DBTREE::board_set_write_name( const std::string& url, const std::string& name ) { DBTREE::get_board( url )->set_write_name( name ); } void DBTREE::board_set_write_mail( const std::string& url, const std::string& mail ) { DBTREE::get_board( url )->set_write_mail( mail ); } // 全スレの書き込み履歴のリセット void DBTREE::clear_all_post_history() { DBTREE::get_root()->clear_all_post_history(); } void DBTREE::read_boardinfo_all() { DBTREE::get_root()->read_boardinfo_all(); } void DBTREE::search_cache_all( std::vector< DBTREE::ArticleBase* >& list_article, const std::string& query, const bool mode_or, const bool bm, const bool& stop ) { DBTREE::get_root()->search_cache( list_article, query, mode_or, bm, stop ); } void DBTREE::search_cache( const std::string& url, std::vector< DBTREE::ArticleBase* >& list_article, const std::string& query, const bool mode_or, const bool bm, const bool& stop ) { DBTREE::get_board( url )->search_cache( list_article, query, mode_or, bm, stop ); } void DBTREE::board_update_writetime( const std::string& url ) { DBTREE::get_board( url )->update_writetime(); } const time_t DBTREE::board_write_time( const std::string& url ) { return DBTREE::get_board( url )->get_write_time(); } const time_t DBTREE::board_write_pass( const std::string& url ) { return DBTREE::get_board( url )->get_write_pass(); } const time_t DBTREE::board_samba_sec( const std::string& url ) { return DBTREE::get_board( url )->get_samba_sec(); } void DBTREE::board_set_samba_sec( const std::string& url, time_t sec ) { DBTREE::get_board( url )->set_samba_sec( sec ); } time_t DBTREE::board_write_leftsec( const std::string& url ) { return DBTREE::get_board( url )->get_write_leftsec(); } void DBTREE::board_show_updateicon( const std::string& url, const bool update ) { DBTREE::get_board( url )->show_updateicon( update ); } const std::list< std::string > DBTREE::board_get_check_update_articles( const std::string& url ) { return DBTREE::get_board( url )->get_check_update_articles(); } // datファイルのインポート const std::string DBTREE::board_import_dat( const std::string& url, const std::string& filename ) { return DBTREE::get_board( url )->import_dat( filename ); } // 板に属する全スレの書き込み履歴のリセット void DBTREE::board_clear_all_post_history( const std::string& url ) { DBTREE::get_board( url )->clear_all_post_history(); } const int DBTREE::board_get_number_max_res( const std::string& url ) { return DBTREE::get_board( url )->get_number_max_res(); } void DBTREE::board_set_number_max_res( const std::string& url, const int number ) { DBTREE::get_board( url )->set_number_max_res( number ); } // datの最大サイズ(Kバイト) const int DBTREE::board_get_max_dat_lng( const std::string& url ) { return DBTREE::get_board( url )->get_max_dat_lng(); } const time_t DBTREE::board_get_live_sec( const std::string& url ) { return DBTREE::get_board( url )->get_live_sec(); } void DBTREE::board_set_live_sec( const std::string& url, time_t sec ) { DBTREE::get_board( url )->set_live_sec( sec ); } const time_t DBTREE::board_last_access_time( const std::string& url ) { return DBTREE::get_board( url )->get_last_access_time(); } ///////////////////////////////////////////////// const std::list< std::string >& DBTREE::get_abone_list_id_board( const std::string& url ) { return DBTREE::get_board( url )->get_abone_list_id_board(); } const std::list< std::string >& DBTREE::get_abone_list_name_board( const std::string& url ) { return DBTREE::get_board( url )->get_abone_list_name_board(); } const std::list< std::string >& DBTREE::get_abone_list_word_board( const std::string& url ) { return DBTREE::get_board( url )->get_abone_list_word_board(); } const std::list< std::string >& DBTREE::get_abone_list_regex_board( const std::string& url ) { return DBTREE::get_board( url )->get_abone_list_regex_board(); } void DBTREE::reset_abone_board( const std::string& url, const std::list< std::string >& ids, const std::list< std::string >& names, const std::list< std::string >& words, const std::list< std::string >& regexs ) { DBTREE::get_board( url )->reset_abone_board( ids, names, words, regexs ); } void DBTREE::add_abone_id_board( const std::string& url, const std::string& id ) { DBTREE::get_board( url )->add_abone_id_board( id ); } void DBTREE::add_abone_name_board( const std::string& url, const std::string& name ) { DBTREE::get_board( url )->add_abone_name_board( name ); } void DBTREE::add_abone_word_board( const std::string& url, const std::string& word ) { DBTREE::get_board( url )->add_abone_word_board( word ); } ///////////////////////////////////////////////// const std::list< std::string >& DBTREE::get_abone_list_thread( const std::string& url ) { return DBTREE::get_board( url )->get_abone_list_thread(); } const std::list< std::string >& DBTREE::get_abone_list_thread_remove( const std::string& url ) { return DBTREE::get_board( url )->get_abone_list_thread_remove(); } const std::list< std::string >& DBTREE::get_abone_list_word_thread( const std::string& url ) { return DBTREE::get_board( url )->get_abone_list_word_thread(); } const std::list< std::string >& DBTREE::get_abone_list_regex_thread( const std::string& url ) { return DBTREE::get_board( url )->get_abone_list_regex_thread(); } const int DBTREE::get_abone_number_thread( const std::string& url ) { return DBTREE::get_board( url )->get_abone_number_thread(); } const int DBTREE::get_abone_hour_thread( const std::string& url ) { return DBTREE::get_board( url )->get_abone_hour_thread(); } void DBTREE::remove_old_abone_thread( const std::string& url ) { DBTREE::get_board( url )->remove_old_abone_thread(); } void DBTREE::update_abone_thread() { DBTREE::get_root()->update_abone_thread(); } void DBTREE::reset_abone_thread( const std::string& url, const std::list< std::string >& threads, const std::list< std::string >& words, const std::list< std::string >& regexs, const int number, const int hour, const bool redraw ) { DBTREE::get_board( url )->reset_abone_thread( threads, words, regexs, number, hour, redraw ); } ///////////////////////////////////////////////// const bool DBTREE::article_is_cached( const std::string& url ) { return DBTREE::get_article( url )->is_cached(); } // 拡張子付き const std::string DBTREE::article_id( const std::string& url ) { return DBTREE::get_article( url )->get_id(); } // idから拡張子を取ったもの const std::string DBTREE::article_key( const std::string& url ) { return DBTREE::get_article( url )->get_key(); } // 移転する前のオリジナルのURL const std::string DBTREE::article_org_host( const std::string& url ) { return DBTREE::get_article( url )->get_org_host(); } const time_t DBTREE::article_since_time( const std::string& url ) { return DBTREE::get_article( url )->get_since_time(); } const std::string DBTREE::article_since_date( const std::string& url ) { return DBTREE::get_article( url )->get_since_date(); } // スレの更新時間( time_t ) const time_t DBTREE::article_time_modified( const std::string& url ) { return DBTREE::get_article( url )->get_time_modified(); } // スレの更新時間( 文字列 ) const std::string DBTREE::article_date_modified( const std::string& url ) { return DBTREE::get_article( url )->get_date_modified(); } // スレの更新時間( 文字列 )をセット void DBTREE::article_set_date_modified( const std::string& url, const std::string& date ) { DBTREE::get_article( url )->set_date_modified( date ); } const int DBTREE::article_hour( const std::string& url ) { return DBTREE::get_article( url )->get_hour(); } // 最終書き込み時刻 const time_t DBTREE::article_write_time( const std::string& url ) { return DBTREE::get_article( url )->get_write_time(); } // 最終書き込み時刻(文字列) const std::string DBTREE::article_write_date( const std::string& url ) { return DBTREE::get_article( url )->get_write_date(); } const int DBTREE::article_status( const std::string& url ) { return DBTREE::get_article( url )->get_status(); } const int DBTREE::article_code( const std::string& url ) { return DBTREE::get_article( url )->get_code(); } const std::string DBTREE::article_str_code( const std::string& url ) { return DBTREE::get_article( url )->get_str_code(); } const std::string DBTREE::article_ext_err( const std::string& url ) { return DBTREE::get_article( url )->get_ext_err(); } const std::string DBTREE::article_subject( const std::string& url ) { return DBTREE::get_article( url )->get_subject(); } const int DBTREE::article_number( const std::string& url ) { return DBTREE::get_article( url )->get_number(); } const int DBTREE::article_number_load( const std::string& url ) { return DBTREE::get_article( url )->get_number_load(); } const int DBTREE::article_number_seen( const std::string& url ) { return DBTREE::get_article( url )->get_number_seen(); } void DBTREE::article_set_number_seen( const std::string& url, int seen ) { DBTREE::get_article( url )->set_number_seen( seen ); } const int DBTREE::article_number_new( const std::string& url ) { return DBTREE::get_article( url )->get_number_new(); } const bool DBTREE::article_is_loading( const std::string& url ) { return DBTREE::get_article( url )->is_loading(); } const bool DBTREE::article_is_checking_update( const std::string& url ) { return DBTREE::get_article( url )->is_checking_update(); } void DBTREE::article_download_dat( const std::string& url, const bool check_update ) { DBTREE::get_article( url )->download_dat( check_update ); } void DBTREE::article_set_url_pre_article( const std::string& url, const std::string& url_pre_article ) { DBTREE::get_article( url )->set_url_pre_article( url_pre_article ); } void DBTREE::article_copy_article_info( const std::string& url, const std::string& url_src ) { DBTREE::get_article( url )->copy_article_info( url_src ); } void DBTREE::article_stop_load( const std::string& url ) { DBTREE::get_article( url )->stop_load(); } const int DBTREE::article_get_speed( const std::string& url ) { return DBTREE::get_article( url )->get_speed(); } // 書き込み履歴のリセット void DBTREE::article_clear_post_history( const std::string& url ) { DBTREE::get_article( url )->clear_post_history(); } // ユーザーエージェント // ダウンロード用 const std::string& DBTREE::get_agent( const std::string& url ) { return DBTREE::get_board( url )->get_agent(); } // 書き込み用 const std::string& DBTREE::get_agent_w( const std::string& url ) { return DBTREE::get_board( url )->get_agent_w(); } const std::string DBTREE::get_proxy_host( const std::string& url ) { return DBTREE::get_board( url )->get_proxy_host(); } const int DBTREE::get_proxy_port( const std::string& url ) { return DBTREE::get_board( url )->get_proxy_port(); } const std::string DBTREE::get_proxy_basicauth( const std::string& url ) { return DBTREE::get_board( url )->get_proxy_basicauth(); } const std::string DBTREE::get_proxy_host_w( const std::string& url ) { return DBTREE::get_board( url )->get_proxy_host_w(); } const int DBTREE::get_proxy_port_w( const std::string& url ) { return DBTREE::get_board( url )->get_proxy_port_w(); } const std::string DBTREE::get_proxy_basicauth_w( const std::string& url ) { return DBTREE::get_board( url )->get_proxy_basicauth_w(); } const std::string DBTREE::localrule( const std::string& url ) { return DBTREE::get_board( url )->localrule(); } const std::string DBTREE::settingtxt( const std::string& url ) { return DBTREE::get_board( url )->settingtxt(); } const std::string DBTREE::default_noname( const std::string& url ) { return DBTREE::get_board( url )->default_noname(); } const int DBTREE::line_number( const std::string& url ) { return DBTREE::get_board( url )->line_number(); } const int DBTREE::message_count( const std::string& url ) { return DBTREE::get_board( url )->message_count(); } // 特殊文字書き込み可能か( pass なら可能、 change なら不可 ) const std::string DBTREE::get_unicode( const std::string& url ) { return DBTREE::get_board( url )->get_unicode(); } const std::string& DBTREE::write_name( const std::string& url ) { return DBTREE::get_article( url )->get_write_name(); } void DBTREE::set_write_name( const std::string& url, const std::string& str ) { DBTREE::get_article( url )->set_write_name( str ); } const bool DBTREE::write_fixname( const std::string& url ) { return DBTREE::get_article( url )->get_write_fixname(); } void DBTREE::set_write_fixname( const std::string& url, bool set ) { DBTREE::get_article( url )->set_write_fixname( set ); } const std::string& DBTREE::write_mail( const std::string& url ) { return DBTREE::get_article( url )->get_write_mail(); } void DBTREE::set_write_mail( const std::string& url, const std::string& str ) { DBTREE::get_article( url )->set_write_mail( str ); } const bool DBTREE::write_fixmail( const std::string& url ) { return DBTREE::get_article( url )->get_write_fixmail(); } void DBTREE::set_write_fixmail( const std::string& url, bool set ) { DBTREE::get_article( url )->set_write_fixmail( set ); } const std::string DBTREE::create_write_message( const std::string& url, const std::string& name, const std::string& mail, const std::string& msg ) { return DBTREE::get_article( url )->create_write_message( name, mail, msg ); } const std::string DBTREE::create_newarticle_message( const std::string& url, const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ) { return DBTREE::get_board( url )->create_newarticle_message( subject, name, mail, msg ); } const std::string DBTREE::get_write_referer( const std::string& url ) { return DBTREE::get_board( url )->get_write_referer(); } // キャッシュ削除 void DBTREE::delete_article( const std::string& url, const bool cache_only ) { DBTREE::get_article( url )->delete_cache( cache_only ); } // キャッシュ保存 bool DBTREE::article_save_dat( const std::string& url, const std::string& path_to ) { return DBTREE::get_article( url )->save_dat( path_to ); } // 全スレ情報の保存 void DBTREE::save_articleinfo_all() { DBTREE::get_root()->save_articleinfo_all(); } void DBTREE::article_update_writetime( const std::string& url ) { DBTREE::get_article( url )->update_writetime(); } size_t DBTREE::article_lng_dat( const std::string& url ) { return DBTREE::get_article( url )->get_lng_dat(); } void DBTREE::update_abone_all_article() { DBTREE::get_root()->update_abone_all_article(); } // 全articlebaseクラスの書き込み時間とスレ立て時間の文字列をリセット void DBTREE::reset_all_write_date() { DBTREE::get_root()->reset_all_write_date(); } void DBTREE::reset_all_since_date() { DBTREE::get_root()->reset_all_since_date(); } const std::list< std::string >& DBTREE::get_abone_list_id( const std::string& url ) { return DBTREE::get_article( url )->get_abone_list_id(); } const std::list< std::string >& DBTREE::get_abone_list_name( const std::string& url ) { return DBTREE::get_article( url )->get_abone_list_name(); } const std::list< std::string >& DBTREE::get_abone_list_word( const std::string& url ) { return DBTREE::get_article( url )->get_abone_list_word(); } const std::list< std::string >& DBTREE::get_abone_list_regex( const std::string& url ) { return DBTREE::get_article( url )->get_abone_list_regex(); } const std::vector< char >& DBTREE::get_abone_vec_res( const std::string& url ) { return DBTREE::get_article( url )->get_abone_vec_res(); } void DBTREE::reset_abone( const std::string& url, const std::list< std::string >& ids, const std::list< std::string >& names, const std::list< std::string >& words, const std::list< std::string >& regexs, const std::vector< char >& vec_abone_res, const bool transparent, const bool chain, const bool age, const bool board, const bool global ) { DBTREE::get_article( url )->reset_abone( ids, names, words, regexs, vec_abone_res, transparent, chain, age, board, global ); } void DBTREE::set_abone_res( const std::string& url, const int num_from, const int num_to, const bool set ) { DBTREE::get_article( url )->set_abone_res( num_from, num_to, set ); } void DBTREE::add_abone_id( const std::string& url, const std::string& id ) { DBTREE::get_article( url )->add_abone_id( id ); } void DBTREE::add_abone_name( const std::string& url, const std::string& name ) { DBTREE::get_article( url )->add_abone_name( name ); } void DBTREE::add_abone_word( const std::string& url, const std::string& word ) { DBTREE::get_article( url )->add_abone_word( word ); } // 透明あぼーん const bool DBTREE::get_abone_transparent( const std::string& url ) { return DBTREE::get_article( url )->get_abone_transparent(); } void DBTREE::set_abone_transparent( const std::string& url, const bool set ) { DBTREE::get_article( url )->set_abone_transparent( set ); } // 連鎖あぼーん const bool DBTREE::get_abone_chain( const std::string& url ) { return DBTREE::get_article( url )->get_abone_chain(); } void DBTREE::set_abone_chain( const std::string& url, const bool set ) { DBTREE::get_article( url )->set_abone_chain( set ); } // ageあぼーん const bool DBTREE::get_abone_age( const std::string& url ) { return DBTREE::get_article( url )->get_abone_age(); } void DBTREE::set_abone_age( const std::string& url, const bool set ) { DBTREE::get_article( url )->set_abone_age( set ); } // 板レベルでのあぼーん const bool DBTREE::get_abone_board( const std::string& url ) { return DBTREE::get_article( url )->get_abone_board(); } void DBTREE::set_abone_board( const std::string& url, const bool set ) { DBTREE::get_article( url )->set_abone_board( set ); } // 全体レベルでのあぼーん const bool DBTREE::get_abone_global( const std::string& url ) { return DBTREE::get_article( url )->get_abone_global(); } void DBTREE::set_abone_global( const std::string& url, const bool set ) { DBTREE::get_article( url )->set_abone_global( set ); } const bool DBTREE::is_bookmarked_thread( const std::string& url ) { return DBTREE::get_article( url )->is_bookmarked_thread(); } void DBTREE::set_bookmarked_thread( const std::string& url, const bool bookmarked ) { DBTREE::get_article( url )->set_bookmarked_thread( bookmarked ); } const int DBTREE::get_num_bookmark( const std::string& url ) { return DBTREE::get_article( url )->get_num_bookmark(); } const bool DBTREE::is_bookmarked( const std::string& url, const int number ) { return DBTREE::get_article( url )->is_bookmarked( number ); } void DBTREE::set_bookmark( const std::string& url, const int number, const bool set ) { DBTREE::get_article( url )->set_bookmark( number, set ); } jd-2.8.7-140104/src/dbtree/interface.h0000644000076400010400000005177211615011401013737 0ustar // ライセンス: GPL2 // // データベースへのインターフェース関数 // #ifndef _INTERFACE_H #define _INTERFACE_H #include "etcboardinfo.h" #include #include #include #include namespace XML { class Document; }; namespace DBTREE { class Root; class BoardBase; class NodeTreeBase; class ArticleBase; void create_root(); void delete_root(); // 各クラスのポインタ取得 Root* get_root(); BoardBase* get_board( const std::string& url ); ArticleBase* get_article( const std::string& url ); // urlの変換関係 const std::string url_subject( const std::string& url ); // 板の subject.txt の URL const std::string url_root( const std::string& url ); const std::string url_boardbase( const std::string& url ); const std::string url_datbase( const std::string& url ); // dat型のurlに変換 const std::string url_dat( const std::string& url, int& num_from, int& num_to, std::string& num_str ); // dat型のurlに変換(簡易版) const std::string url_dat( const std::string& url ); // read.cgi型のurlに変換 const std::string url_readcgi( const std::string& url, int num_from, int num_to ); const std::string url_bbscgibase( const std::string& url ); const std::string url_subbbscgibase( const std::string& url ); const std::string url_bbscgi( const std::string& url ); const std::string url_subbbscgi( const std::string& url ); const std::string url_bbscgi_new( const std::string& url ); const std::string url_subbbscgi_new( const std::string& url ); // 板が移転したかチェックする // 移転した時は移転後のURLを返す const std::string is_board_moved( const std::string& url ); const std::string is_board_moved( const std::string& url, std::string& old_root, std::string& old_path_board, std::string& new_root, std::string& new_path_board ); // 板移転 const bool move_board( const std::string& url_old, const std::string& url_new ); // 板移転情報の保存の有効切り替え void set_enable_save_movetable( const bool set ); // 移転情報保存 void save_movetable(); // bbslist系 const XML::Document& get_xml_document(); const std::list< DBTREE::ETCBOARDINFO >& get_etcboards(); bool add_etc( const std::string& url, const std::string& name, const std::string& basicauth, const std::string& id ); bool move_etc( const std::string& url_old, const std::string& url_new, const std::string& name_old, const std::string& name_new, const std::string& basicauth, const std::string& boardid ); bool remove_etc( const std::string& url, const std::string& name ); void save_etc(); void download_bbsmenu(); const std::string get_date_modified(); // bbsmenuの更新時間( 文字列 ) const time_t get_time_modified(); // bbsmenuの更新時間( time_t ) // board 系 const std::string board_path( const std::string& url ); const std::string board_id( const std::string& url ); const time_t board_time_modified( const std::string& url ); // 板の更新時間( time_t ) const std::string board_date_modified( const std::string& url ); // 板の更新時間( 文字列 ) void board_set_date_modified( const std::string& url, const std::string& date ); // 板の更新時間( 文字列 )をセット const std::string& board_get_modified_localrule( const std::string& url ); void board_set_modified_localrule( const std::string& url, const std::string& modified ); const std::string& board_get_modified_setting( const std::string& url ); void board_set_modified_setting( const std::string& url, const std::string& modified ); const std::string board_name( const std::string& url ); const std::string board_subjecttxt( const std::string& url ); const std::string board_charset( const std::string& url ); const std::string board_cookie_for_write( const std::string& url ); const std::list< std::string >& board_list_cookies_for_write( const std::string& url ); void board_set_list_cookies_for_write( const std::string& url, const std::list< std::string>& list_cookies ); void board_reset_list_cookies_for_write( const std::string& url ); const std::string board_keyword_for_write( const std::string& url ); void board_set_keyword_for_write( const std::string& url, const std::string& keyword ); void board_analyze_keyword_for_write( const std::string& url, const std::string& html ); const std::string board_basicauth( const std::string& url ); const std::string board_ext( const std::string& url ); const int board_status( const std::string& url ); const int board_code( const std::string& url ); const std::string board_str_code( const std::string& url ); void board_save_info( const std::string& url ); void board_download_subject( const std::string& url, const std::string& url_update_view ); void board_read_subject_from_cache( const std::string& url ); const bool board_is_loading( const std::string& url ); void board_stop_load( const std::string& url ); std::vector< DBTREE::ArticleBase* >& board_list_subject( const std::string& url ); const int board_view_sort_column( const std::string& url ); void board_set_view_sort_column( const std::string& url, int column ); const int board_view_sort_mode( const std::string& url ); void board_set_view_sort_mode( const std::string& url, int mode ); const int board_view_sort_pre_column( const std::string& url ); void board_set_view_sort_pre_column( const std::string& url, int column ); const int board_view_sort_pre_mode( const std::string& url ); void board_set_view_sort_pre_mode( const std::string& url, int mode ); const bool board_check_noname( const std::string& url ); void board_set_check_noname( const std::string& url, const bool check ); const bool board_show_oldlog( const std::string& url ); void board_set_show_oldlog( const std::string& url, const bool show ); const int board_get_mode_local_proxy( const std::string& url ); const std::string& board_get_local_proxy( const std::string& url ); const int board_get_local_proxy_port( const std::string& url ); const std::string& board_get_local_proxy_basicauth( const std::string& url ); void board_set_mode_local_proxy( const std::string& url, int mode ); void board_set_local_proxy( const std::string& url, const std::string& proxy ); void board_set_local_proxy_port( const std::string& url, int port ); const int board_get_mode_local_proxy_w( const std::string& url ); const std::string& board_get_local_proxy_w( const std::string& url ); const int board_get_local_proxy_port_w( const std::string& url ); const std::string& board_get_local_proxy_basicauth_w( const std::string& url ); void board_set_mode_local_proxy_w( const std::string& url, int mode ); void board_set_local_proxy_w( const std::string& url, const std::string& proxy ); void board_set_local_proxy_port_w( const std::string& url, int port ); const std::string& board_get_write_name( const std::string& url ); const std::string& board_get_write_mail( const std::string& url ); void board_set_write_name( const std::string& url, const std::string& name ); void board_set_write_mail( const std::string& url, const std::string& mail ); void board_update_writetime( const std::string& url ); const time_t board_write_time( const std::string& url ); const time_t board_write_pass( const std::string& url ); const time_t board_samba_sec( const std::string& url ); void board_set_samba_sec( const std::string& url, time_t sec ); time_t board_write_leftsec( const std::string& url ); // 更新可能状態にしてお気に入りやスレ一覧のタブのアイコンに更新マークを表示 // update == true の時に表示。falseなら戻す void board_show_updateicon( const std::string& url, const bool update ); // 板の更新チェック時に、更新チェックを行うスレのアドレスのリスト // キャッシュが存在し、かつdat落ちしていないで新着数が0のスレを速度の順でソートして返す const std::list< std::string > board_get_check_update_articles( const std::string& url ); // datファイルのインポート // 成功したらdat型のurlを返す const std::string board_import_dat( const std::string& url, const std::string& filename ); // 各板に属する全スレの書き込み履歴のリセット void board_clear_all_post_history( const std::string& url ); const int board_get_number_max_res( const std::string& url ); void board_set_number_max_res( const std::string& url, const int number ); // datの最大サイズ(Kバイト) const int board_get_max_dat_lng( const std::string& url ); const time_t board_get_live_sec( const std::string& url ); void board_set_live_sec( const std::string& url, time_t sec ); const time_t board_last_access_time( const std::string& url ); // 全スレの書き込み履歴のリセット void clear_all_post_history(); // 全板の情報ファイル読み込み void read_boardinfo_all(); // キャッシュ内のログ検索 // ArticleBase のアドレスをリスト(list_article)にセットして返す // query が空の時はキャッシュにあるログを全てヒットさせる // bm がtrueの時、しおりが付いている(スレ一覧でしおりを付けた or レスに一つでもしおりが付いている)スレのみを対象に検索する void search_cache_all( std::vector< DBTREE::ArticleBase* >& list_article, const std::string& query, const bool mode_or, const bool bm, const bool& stop ); void search_cache( const std::string& url, std::vector< DBTREE::ArticleBase* >& list_article, const std::string& query, const bool mode_or, const bool bm, const bool& stop ); // article 系 const bool article_is_cached( const std::string& url ); // キャッシュにあるかどうか const std::string article_id( const std::string& url ); // 拡張子込み "12345.dat" みたいに const std::string article_key( const std::string& url ); // idから拡張子を取ったもの。書き込み用 const std::string article_org_host( const std::string& url ); // 移転する前のオリジナルのURL const time_t article_since_time( const std::string& url ); const std::string article_since_date( const std::string& url ); const time_t article_time_modified( const std::string& url ); // スレの更新時間( time_t ) const std::string article_date_modified( const std::string& url ); // スレの更新時間( 文字列 ) void article_set_date_modified( const std::string& url, const std::string& date ); // スレの更新時間( 文字列 )をセット const int article_hour( const std::string& url ); const time_t article_write_time( const std::string& url ); const std::string article_write_date( const std::string& url ); const int article_status( const std::string& url ); const int article_code( const std::string& url ); const std::string article_str_code( const std::string& url ); const std::string article_ext_err( const std::string& url ); const std::string article_subject( const std::string& url ); const int article_number( const std::string& url ); const int article_number_load( const std::string& url ); const int article_number_seen( const std::string& url ); void article_set_number_seen( const std::string& url, int seen ); const int article_number_new( const std::string& url ); const bool article_is_loading( const std::string& url ); const bool article_is_checking_update( const std::string& url ); void article_download_dat( const std::string& url, const bool check_update ); void article_set_url_pre_article( const std::string& url, const std::string& url_pre_article ); void article_copy_article_info( const std::string& url, const std::string& url_src ); void article_stop_load( const std::string& url ); const int article_get_speed( const std::string& url ); // 書き込み履歴のリセット void article_clear_post_history( const std::string& url ); // キャッシュ削除 // cache_only == true の時はキャッシュだけ削除してスレ情報は消さない void delete_article( const std::string& url, const bool cache_only ); // キャッシュ保存 bool article_save_dat( const std::string& url, const std::string& path_to ); // 全スレ情報の保存 void save_articleinfo_all(); void article_update_writetime( const std::string& url ); size_t article_lng_dat( const std::string& url ); // ユーザーエージェント const std::string& get_agent( const std::string& url ); // ダウンロード用 const std::string& get_agent_w( const std::string& url ); // 書き込み用 // 読み込み用プロキシ const std::string get_proxy_host( const std::string& url ); const int get_proxy_port( const std::string& url ); const std::string get_proxy_basicauth( const std::string& url ); // 書き込み用プロキシ const std::string get_proxy_host_w( const std::string& url ); const int get_proxy_port_w( const std::string& url ); const std::string get_proxy_basicauth_w( const std::string& url ); // ローカルルール const std::string localrule( const std::string& url ); // setting.txt const std::string settingtxt( const std::string& url ); // 書き込み関係 // デフォルトの名無し名 const std::string default_noname( const std::string& url ); // 最大改行数/2 const int line_number( const std::string& url ); // 最大書き込みバイト数 const int message_count( const std::string& url ); // 特殊文字書き込み可能か( pass なら可能、 change なら不可 ) const std::string get_unicode( const std::string& url ); // 書き込み時の名前とメール const std::string& write_name( const std::string& url ); void set_write_name( const std::string& url, const std::string& str ); const bool write_fixname( const std::string& url ); void set_write_fixname( const std::string& url, bool set ); const std::string& write_mail( const std::string& url ); void set_write_mail( const std::string& url, const std::string& str ); const bool write_fixmail( const std::string& url ); void set_write_fixmail( const std::string& url, bool set ); // ポストするメッセージの作成 const std::string create_write_message( const std::string& url, const std::string& name, const std::string& mail, const std::string& msg ); const std::string create_newarticle_message( const std::string& url, const std::string& subject, const std::string& name, const std::string& mail, const std::string& msg ); // 書き込み時のリファラ const std::string get_write_referer( const std::string& url ); // あぼーん関係 // 板レベルでのあぼーん情報 // グローバルなあぼーん情報は globalconf が管理 const std::list< std::string >& get_abone_list_id_board( const std::string& url ); const std::list< std::string >& get_abone_list_name_board( const std::string& url ); const std::list< std::string >& get_abone_list_word_board( const std::string& url ); const std::list< std::string >& get_abone_list_regex_board( const std::string& url ); // 板レベルでのあぼーん状態のリセット(情報セットとスレビューの表示更新を同時におこなう) void reset_abone_board( const std::string& url, const std::list< std::string >& ids, const std::list< std::string >& names, const std::list< std::string >& words, const std::list< std::string >& regexs ); // 板レベルでのあぼ〜ん状態更新(reset_abone()と違って各項目ごと個別におこなう。スレビューの表示更新も同時におこなう) void add_abone_id_board( const std::string& url, const std::string& id ); void add_abone_name_board( const std::string& url, const std::string& name ); void add_abone_word_board( const std::string& url, const std::string& word ); // スレあぼーん情報 // グローバルなあぼーん情報は globalconf が管理 const std::list< std::string >& get_abone_list_thread( const std::string& url ); const std::list< std::string >& get_abone_list_thread_remove( const std::string& url ); const std::list< std::string >& get_abone_list_word_thread( const std::string& url ); const std::list< std::string >& get_abone_list_regex_thread( const std::string& url ); const std::vector< char >& get_abone_vec_res( const std::string& url ); const int get_abone_number_thread( const std::string& url ); const int get_abone_hour_thread( const std::string& url ); // subject.txtのロード後にdat落ちしたスレッドをスレあぼーんのリストから取り除く void remove_old_abone_thread( const std::string& url ); // スレあぼーん情報を更新した時、全boardbaseクラスに対応するスレ一覧の表示を更新させる // CONFIG::set_abone_number_thread() などでグローバル設定をした後などに呼び出す void update_abone_thread(); // スレあぼーん状態のリセット // redraw : スレ一覧の表示更新を行う void reset_abone_thread( const std::string& url, const std::list< std::string >& threads, const std::list< std::string >& words, const std::list< std::string >& regexs, const int number, const int hour, const bool redraw ); // // 各articlebase別のあぼーん情報 // // 全articlebaseクラスのあぼーん状態の更新 void update_abone_all_article(); // 全articlebaseクラスの書き込み時間とスレ立て時間の文字列をリセット void reset_all_write_date(); void reset_all_since_date(); // レスあぼーん // グローバルなあぼーん情報は globalconf が管理 const std::list< std::string >& get_abone_list_id( const std::string& url ); const std::list< std::string >& get_abone_list_name( const std::string& url ); const std::list< std::string >& get_abone_list_word( const std::string& url ); const std::list< std::string >& get_abone_list_regex( const std::string& url ); // 全あぼーん情報の同時セットと更新 void reset_abone( const std::string& url, const std::list< std::string >& ids, const std::list< std::string >& names, const std::list< std::string >& words, const std::list< std::string >& regexs, const std::vector< char >& vec_abone_res, const bool transparent, const bool chain, const bool age, const bool board, const bool global ); // 個別のあぼーん情報のセットと更新 void set_abone_res( const std::string& url, const int num_from, const int num_to, const bool set ); void add_abone_id( const std::string& url, const std::string& id ); void add_abone_name( const std::string& url, const std::string& name ); void add_abone_word( const std::string& url, const std::string& word ); // 透明あぼーん const bool get_abone_transparent( const std::string& url ); void set_abone_transparent( const std::string& url, const bool set ); // 連鎖あぼーん const bool get_abone_chain( const std::string& url ); void set_abone_chain( const std::string& url, const bool set ); // ageあぼーん const bool get_abone_age( const std::string& url ); void set_abone_age( const std::string& url, const bool set ); // 板レベルでのあぼーん const bool get_abone_board( const std::string& url ); void set_abone_board( const std::string& url, const bool set ); // 全体レベルでのあぼーん const bool get_abone_global( const std::string& url ); void set_abone_global( const std::string& url, const bool set ); // ブックマーク関係 // スレのブックマーク const bool is_bookmarked_thread( const std::string& url ); void set_bookmarked_thread( const std::string& url, const bool bookmarked ); // レスのブックマーク const int get_num_bookmark( const std::string& url ); const bool is_bookmarked( const std::string& url, const int number ); void set_bookmark( const std::string& url, const int number, const bool set ); } #endif jd-2.8.7-140104/src/dbtree/Makefile.am0000644000076400010400000000220612072045132013654 0ustar noinst_LIBRARIES = libdbtree.a libdbtree_a_SOURCES = \ interface.cpp \ spchar_decoder.cpp \ root.cpp \ \ boardbase.cpp \ board2ch.cpp \ board2chcompati.cpp \ boardjbbs.cpp \ boardmachi.cpp \ boardlocal.cpp \ \ settingloader.cpp \ ruleloader.cpp \ boardfactory.cpp \ articlehash.cpp \ \ articlebase.cpp \ article2ch.cpp \ article2chcompati.cpp \ articlejbbs.cpp \ articlemachi.cpp \ articlelocal.cpp \ \ nodetreebase.cpp \ nodetree2ch.cpp \ nodetree2chcompati.cpp \ nodetreejbbs.cpp \ nodetreemachi.cpp \ nodetreelocal.cpp \ nodetreedummy.cpp noinst_HEADERS = \ interface.h \ spchar_decoder.h \ spchar_tbl.h \ etcboardinfo.h \ root.h \ \ boardbase.h \ board2ch.h \ board2chcompati.h \ boardlocal.h \ boardjbbs.h \ boardmachi.h \ \ settingloader.h \ ruleloader.h \ boardfactory.h \ articlehash.h \ \ articlebase.h \ article2ch.h \ article2chcompati.h \ articlelocal.h \ articlejbbs.h \ articlemachi.h \ \ node.h \ nodetreebase.h \ nodetree2ch.h \ nodetree2chcompati.h \ nodetreejbbs.h \ nodetreemachi.h \ nodetreelocal.h \ nodetreedummy.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/dbtree/node.h0000644000076400010400000000635712114550710012731 0ustar // ライセンス: GPL2 // // ノードツリーのノード // #ifndef _NODE_H #define _NODE_H namespace DBIMG { class Img; } namespace DBTREE { // NODE::type enum { NODE_HEADER = 0, // ヘッダ NODE_BLOCK, // ブロック先頭 NODE_TEXT, // テキスト NODE_LINK, // リンク NODE_IDNUM, // 発言回数(IDの出現数) NODE_BR, // 改行 NODE_HR, // 水平線 NODE_DIV, // div NODE_IMG, // img // スペース(幅0) NODE_ZWSP, // 連続半角スペース NODE_MULTISP, // 水平タブ(0x09) NODE_HTAB, // sssp アイコン NODE_SSSP, NODE_NONE }; // HEADERINFO::block enum { BLOCK_NUMBER = 0, // レス番号 BLOCK_NAMELINK, // 「名前」の文字列(デフォルト名前で無いときはリンク) BLOCK_NAME, // 名前 BLOCK_MAIL, // メール BLOCK_DATE, // 日付 BLOCK_ID_NAME, // ID BLOCK_MES, // 本文 BLOCK_NUM }; struct NODE; // アンカー情報 // anc_from番 から anc_to番までのアンカー struct ANCINFO { int anc_from; int anc_to; }; // ヘッダ拡張情報 struct HEADERINFO { NODE* next_header; // 次のヘッダノードのアドレス bool abone; // あぼーんされているか int num_reference; // 他のレスから参照されている数 char* name; // 名前 bool sage; // メール欄がsageか int num_id_name; // 同じIDのレスの個数( = 発言数 ) NODE* pre_id_name_header; // 同じIDを持つ一つ前のヘッダノードのアドレス NODE* block[ BLOCK_NUM ]; }; // リンク情報 struct LINKINFO { char* link; // リンクURL // アンカー情報のベクトル // NULL なら一般のリンク // ancinfo->anc_from == ancinfo->anc_to == 0 が終端 ANCINFO* ancinfo; // 画像関係の情報 // // 画像リンクの場合、実際にリンクが画面に表示される段階でノードに DBIMG::Img // のポインタと色をセットする。 // image == true かつ img == NULL ならまだ img は未取得 // 実際にノードが画面に表示された際に img のポインタを取得して画像の状態を取得する // 詳しくは DrawAreaBase::draw_one_node() を参照 bool image; // 画像かどうか char* imglink; // 画像のURL DBIMG::Img* img; // 画像データクラスへのポインタ(危険だが高速化のため直接アクセス、deleteしないこと) }; // ノード構造体 struct NODE { unsigned char type; short id_header; // ヘッダID ( つまりレス番号、ルートヘッダは0 ) NODE* next_node; // 最終ノードはNULL char* text; unsigned char color_text; // 色 bool bold; char fontid; // fontid.h // ヘッダ拡張情報 HEADERINFO* headinfo; // リンク情報 LINKINFO* linkinfo; }; } #endif jd-2.8.7-140104/src/dbtree/nodetree2ch.cpp0000644000076400010400000001610311435220227014531 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "nodetree2ch.h" #include "interface.h" #include "jdlib/jdregex.h" #include "jdlib/loaderdata.h" #include "jdlib/miscutil.h" #include "config/globalconf.h" #include "httpcode.h" #include "session.h" #include "login2ch.h" #include using namespace DBTREE; enum { MODE_NORMAL = 0, MODE_OFFLAW, MODE_KAKO_GZ, MODE_KAKO }; NodeTree2ch::NodeTree2ch( const std::string& url, const std::string& org_url, const std::string& date_modified, time_t since_time ) : NodeTree2chCompati( url, date_modified ) , m_org_url( org_url ) , m_since_time( since_time ) , m_mode( MODE_NORMAL ) { #ifdef _DEBUG std::cout << "NodeTree2ch::NodeTree2ch url = " << url << std::endl << "org_url = " << m_org_url << " modified = " << date_modified << " since = " << m_since_time << std::endl; #endif } NodeTree2ch::~NodeTree2ch() { #ifdef _DEBUG std::cout << "NodeTree2ch::~NodeTree2ch : " << get_url() << std::endl; #endif } // // ロード用データ作成 // void NodeTree2ch::create_loaderdata( JDLIB::LOADERDATA& data ) { #ifdef _DEBUG std::cout << "NodeTree2ch::create_loaderdata : mode = " << m_mode << " url = " << get_url() << std::endl; #endif data.url = std::string(); //offlaw 使用 if( m_mode == MODE_OFFLAW ){ JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( ! regex.exec( "(http://[^/]*)(/.*)/dat(/.*)\\.dat$", m_org_url, offset, icase, newline, usemigemo, wchar ) ) return; std::ostringstream ss; ss << regex.str( 1 ) << "/test/offlaw.cgi" << regex.str( 2 ) << regex.str( 3 ) << "/?raw=." << get_lng_dat(); std::string sid = CORE::get_login2ch()->get_sessionid(); ss << "&sid=" << MISC::url_encode( sid.c_str(), sid.length() ); // レジュームは無し set_resume( false ); data.byte_readfrom = 0; data.url = ss.str(); } // 過去ログ倉庫使用 else if( m_mode == MODE_KAKO_GZ || m_mode == MODE_KAKO ){ JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( ! regex.exec( "(http://[^/]*)(/.*)/dat(/.*)\\.dat$", m_org_url, offset, icase, newline, usemigemo, wchar ) ) return; const int id = atoi( regex.str( 3 ).c_str() + 1 ); std::ostringstream ss; // スレIDが10桁の場合 → http://サーバ/板ID/kako/IDの上位4桁/IDの上位5桁/ID.dat.gz if( id / 1000000000 ) ss << regex.str( 1 ) << regex.str( 2 ) << "/kako/" << ( id / 1000000 ) << "/" << ( id / 100000 ) << regex.str( 3 ); // スレIDが9桁の場合 → http://サーバ/板ID/kako/IDの上位3桁/ID.dat.gz else ss << regex.str( 1 ) << regex.str( 2 ) << "/kako/" << ( id / 1000000 ) << regex.str( 3 ); if( m_mode == MODE_KAKO_GZ ) ss << ".dat.gz"; else ss << ".dat"; // レジュームは無し set_resume( false ); data.byte_readfrom = 0; data.url = ss.str(); } // 普通の読み込み else{ data.url = get_url(); // レジューム設定 // 1byte前からレジュームして '\n' が返ってこなかったらあぼーんがあったってこと if( get_lng_dat() ) { data.byte_readfrom = get_lng_dat() -1; set_resume( true ); } else set_resume( false ); } #ifdef _DEBUG std::cout << "load from " << data.url << std::endl; #endif data.agent = DBTREE::get_agent( get_url() ); #ifdef _DEBUG std::cout << "agent = " << data.agent << std::endl; #endif data.host_proxy = DBTREE::get_proxy_host( get_url() ); data.port_proxy = DBTREE::get_proxy_port( get_url() ); data.basicauth_proxy = DBTREE::get_proxy_basicauth( get_url() ); data.size_buf = CONFIG::get_loader_bufsize(); data.timeout = CONFIG::get_loader_timeout(); if( ! get_date_modified().empty() ) data.modified = get_date_modified(); } // // ロード完了 // void NodeTree2ch::receive_finish() { #ifdef _DEBUG std::cout << "NodeTree2ch::receive_finish : " << get_url() << std::endl << "mode = " << m_mode << " code = " << get_code() << std::endl; #endif // 更新チェックではない、オンラインの場合は offlaw や 過去ログ倉庫から取得出来るか試みる if( ! is_checking_update() && SESSION::is_online() && ( get_code() == HTTP_REDIRECT || get_code() == HTTP_MOVED_PERM || get_code() == HTTP_NOT_FOUND || ( m_mode == MODE_OFFLAW && ! get_ext_err().empty() ) // offlaw 読み込み失敗 ) ){ /* ・スレIDが10桁の場合 → http://サーバ/板ID/kako/IDの上位4桁/IDの上位5桁/ID.dat.gz (例) http://HOGE.2ch.net/test/read.cgi/hoge/1234567890/ を取得 (1) http://HOGE.2ch.net/hoge/dat/1234567890.dat から dat を取得。302で●がある場合(2-1)、無い場合は(2-2)へ(※) (2-1) offlaw.cgiを使って取得 (2-2) http://HOGE.2ch.net/hoge/kako/1234/12345/1234567890.dat.gz から取得。302なら(3)へ (3) http://HOGE.2ch.net/hoge/kako/1234/12345/1234567890.dat から取得 ・スレIDが9桁の場合 → http://サーバ/板ID/kako/IDの上位3桁/ID.dat.gz (例) http://HOGE.2ch.net/test/read.cgi/hoge/123456789/ を取得 (1) http://HOGE.2ch.net/hoge/dat/1234567890.dat から dat を取得。302で●がある場合(2-1)、無い場合は(2-2)へ(※) (2-1) offlaw.cgiを使って取得 (2-2) http://HOGE.2ch.net/hoge/kako/123/123456789.dat.gz から取得。302なら(3)へ (3) http://HOGE.2ch.net/hoge/kako/123/123456789.dat から取得 (※)ただし 2008年1月1日以降に立てられたスレは除く (注) 古すぎる(2000年頃)のdatは形式が違う(<>ではなくて,で区切られている)ので読み込みに失敗する */ // ログインしている場合は offlaw.cgi 経由で旧URLで再取得 if( m_mode == MODE_NORMAL && CORE::get_login2ch()->login_now() ) m_mode = MODE_OFFLAW; // 過去ログ倉庫(gz圧縮) // ただし 2008年1月1日以降に立てられたスレは除く else if( ( m_mode == MODE_NORMAL || m_mode == MODE_OFFLAW ) && m_since_time < 1199113200 ) m_mode = MODE_KAKO_GZ; // 過去ログ倉庫 else if( m_mode == MODE_KAKO_GZ ) m_mode = MODE_KAKO; // 失敗 else m_mode = MODE_NORMAL; #ifdef _DEBUG std::cout << "switch mode to " << m_mode << std::endl; #endif if( m_mode != MODE_NORMAL ){ download_dat( is_checking_update() ); return; } } // offlaw や 過去ログから読み込んだ場合は DAT 落ちにする if( m_mode != MODE_NORMAL ){ m_mode = MODE_NORMAL; set_code( HTTP_OLD ); } NodeTreeBase::receive_finish(); } jd-2.8.7-140104/src/dbtree/nodetree2ch.h0000644000076400010400000000136511362077452014213 0ustar // ライセンス: GPL2 // // 2ch型ノードツリー // #ifndef _NODETREE2ch_H #define _NODETREE2ch_H #include "nodetree2chcompati.h" #include namespace DBTREE { class NodeTree2ch : public NodeTree2chCompati { std::string m_org_url; // 移転前のオリジナルURL time_t m_since_time; // スレが立った時刻 int m_mode; // 読み込みモード public: NodeTree2ch( const std::string& url, const std::string& org_url, const std::string& date_modified, time_t since_time ); ~NodeTree2ch(); protected: virtual void create_loaderdata( JDLIB::LOADERDATA& data ); private: virtual void receive_finish(); }; } #endif jd-2.8.7-140104/src/dbtree/nodetree2chcompati.cpp0000644000076400010400000000742411140340236016110 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "nodetree2chcompati.h" #include "interface.h" #include "jdlib/jdiconv.h" #include "jdlib/loaderdata.h" #include "jdlib/miscmsg.h" #include "config/globalconf.h" using namespace DBTREE; NodeTree2chCompati::NodeTree2chCompati( const std::string& url, const std::string& date_modified ) : NodeTreeBase( url, date_modified ) , m_iconv( 0 ) { #ifdef _DEBUG std::cout << "NodeTree2chCompati::NodeTree2chCompati url = " << url << " modified = " << date_modified << std::endl; #endif } NodeTree2chCompati::~NodeTree2chCompati() { #ifdef _DEBUG std::cout << "NodeTree2chCompati::~NodeTree2chCompati : " << get_url() << std::endl; #endif clear(); } // // バッファなどのクリア // void NodeTree2chCompati::clear() { #ifdef _DEBUG std::cout << "NodeTree2chCompati::clear : " << get_url() << std::endl; #endif NodeTreeBase::clear(); // iconv 削除 if( m_iconv ) delete m_iconv; m_iconv = NULL; } // // ロード実行前に呼ぶ初期化関数 // void NodeTree2chCompati::init_loading() { #ifdef _DEBUG std::cout << "NodeTree2chCompati::init_loading : " << get_url() << std::endl; #endif NodeTreeBase::init_loading(); // iconv 初期化 std::string charset = DBTREE::board_charset( get_url() ); if( ! m_iconv ) m_iconv = new JDLIB::Iconv( charset, "UTF-8" ); } // // キャッシュに保存する前の前処理 // // 先頭にrawモードのステータスが入っていたら取り除く // char* NodeTree2chCompati::process_raw_lines( char* rawlines ) { char* pos = rawlines; if( *pos == '+' || *pos == '-' ){ int status = 0; if( pos[ 1 ] == 'O' && pos[ 2 ] == 'K' ) status = 1; if( pos[ 1 ] == 'E' && pos[ 2 ] == 'R' && pos[ 3 ] == 'R' ) status = 2; if( pos[ 1 ] == 'I' && pos[ 2 ] == 'N' && pos[ 3 ] == 'C' && pos[ 4 ] == 'R' ) status = 3; #ifdef _DEBUG std::cout << "NodeTree2chCompati::process_raw_lines : raw mode status = " << status << std::endl; #endif if( status != 0 ){ // この行を飛ばす char* pos_msg = pos; while( *pos != '\n' && *pos != '\0' ) ++pos; // エラー if( status != 1 ){ int byte; std::string ext_err = std::string( m_iconv->convert( pos_msg, pos - pos_msg, byte ) ); set_ext_err( ext_err ); MISC::ERRMSG( ext_err ); } if( *pos == '\n' ) ++pos; } } return pos; } // // raw データを dat 形式に変換 // // 2ch型サーバの場合は文字コードを変換するだけ // const char* NodeTree2chCompati::raw2dat( char* rawlines, int& byte ) { assert( m_iconv != NULL ); // バッファ自体はiconvクラスの中で持っているのでポインタだけもらう return m_iconv->convert( rawlines, strlen( rawlines ), byte ); } // // ロード用データ作成 // void NodeTree2chCompati::create_loaderdata( JDLIB::LOADERDATA& data ) { data.url = get_url(); data.agent = DBTREE::get_agent( get_url() ); // 1byte前からレジュームして '\n' が返ってこなかったらあぼーんがあったってこと if( get_lng_dat() ) { data.byte_readfrom = get_lng_dat() -1; set_resume( true ); } else set_resume( false ); data.host_proxy = DBTREE::get_proxy_host( get_url() ); data.port_proxy = DBTREE::get_proxy_port( get_url() ); data.basicauth_proxy = DBTREE::get_proxy_basicauth( get_url() ); data.size_buf = CONFIG::get_loader_bufsize(); data.timeout = CONFIG::get_loader_timeout(); data.basicauth = DBTREE::board_basicauth( get_url() ); if( ! get_date_modified().empty() ) data.modified = get_date_modified(); } jd-2.8.7-140104/src/dbtree/nodetree2chcompati.h0000644000076400010400000000134311140340236015547 0ustar // ライセンス: GPL2 // // 2ch互換型ノードツリー // #ifndef _NODETREE2CHCOMPATI_H #define _NODETREE2CHCOMPATI_H #include "nodetreebase.h" namespace JDLIB { class Iconv; } namespace DBTREE { class NodeTree2chCompati : public NodeTreeBase { JDLIB::Iconv* m_iconv; public: NodeTree2chCompati( const std::string& url, const std::string& date_modified ); virtual ~NodeTree2chCompati(); protected: virtual void clear(); virtual void init_loading(); virtual char* process_raw_lines( char* rawlines ); virtual const char* raw2dat( char* rawlines, int& byte ); virtual void create_loaderdata( JDLIB::LOADERDATA& data ); }; } #endif jd-2.8.7-140104/src/dbtree/nodetreebase.cpp0000644000076400010400000033107112175014763015003 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "nodetreebase.h" #include "spchar_decoder.h" #include "interface.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/loaderdata.h" #include "jdlib/jdregex.h" #include "dbimg/imginterface.h" #include "message/logmanager.h" #include "config/globalconf.h" #include "global.h" #include "httpcode.h" #include "colorid.h" #include "fontid.h" #include "command.h" #include "cache.h" #include "session.h" #include "urlreplacemanager.h" #include #include #ifndef MAX #define MAX( a, b ) ( a > b ? a : b ) #endif #ifndef MIN #define MIN( a, b ) ( a < b ? a : b ) #endif enum { SECTION_NUM = 5, LNG_RES = 16, LNG_ID = 256, LNG_LINK = 256, MAX_ANCINFO = 64, RANGE_REF = 20, MAX_LINK_DIGIT = 4, // レスアンカーでMAX_LINK_DIGIT 桁までリンクにする MAXSISE_OF_LINES = 512 * 1024, // ロード時に1回の呼び出しで読み込まれる最大データサイズ SIZE_OF_HEAP = MAXSISE_OF_LINES + 64, INITIAL_RES_BUFSIZE = 128, // レスの文字列を返すときの初期バッファサイズ }; // レジュームのモード enum { RESUME_NO = 0, // レジューム無し RESUME_MODE1, // 通常のレジューム RESUME_MODE2, // サーバが range を無視してデータを送ってきた RESUME_MODE3, // サーバが range を無視してデータを送ってきた時にデータをスキップ中 RESUME_FAILED // レジューム失敗 }; #define IS_URL(node) \ ( node->type == NODE_LINK && node->linkinfo->link \ && ( std::string( node->linkinfo->link ).find( "http" ) == 0 \ || std::string( node->linkinfo->link ).find( "https" ) == 0 \ || std::string( node->linkinfo->link ).find( "ftp" ) == 0 ) \ ) using namespace DBTREE; NodeTreeBase::NodeTreeBase( const std::string& url, const std::string& modified ) : SKELETON::Loadable(), m_url( url ), m_lng_dat( 0 ), m_resume ( RESUME_NO ), m_broken( 0 ), m_heap( SIZE_OF_HEAP ), m_buffer_lines( NULL ), m_parsed_text( NULL ), m_buffer_write( NULL ), m_check_update( false ), m_check_write( false ), m_loading_newthread( false ), m_fout ( 0 ) { set_date_modified( modified ); clear(); // ヘッダのポインタの配列作成 m_vec_header = ( NODE** ) m_heap.heap_alloc( sizeof( NODE* ) * MAX_RESNUMBER ); // ルートヘッダ作成。中は空。 m_id_header = -1; // ルートヘッダIDが 0 になるように -1 NODE* tmpnode = create_node_header(); m_vec_header[ m_id_header ] = tmpnode; m_default_noname = DBTREE::default_noname( m_url ); // 参照で色を変える回数 m_num_reference[ LINK_HIGH ] = CONFIG::get_num_reference_high(); m_num_reference[ LINK_LOW ] = CONFIG::get_num_reference_low(); // 発言数で色を変える回数 m_num_id[ LINK_HIGH ] = CONFIG::get_num_id_high(); m_num_id[ LINK_LOW ] = CONFIG::get_num_id_low(); // レスにアスキーアートがあると判定する正規表現 if( CONFIG::get_aafont_enabled() ){ m_aa_regex = CONFIG::get_regex_res_aa(); } else { m_aa_regex = std::string(); } #ifdef _DEBUG std::cout << "NodeTreeBase::NodeTreeBase url = " << m_url << " modified = " << get_date_modified() << " noname = " << m_default_noname << std::endl; #endif } NodeTreeBase::~NodeTreeBase() { #ifdef _DEBUG std::cout << "NodeTreeBase::~NodeTreeBase : " << m_url << std::endl; #endif clear(); } bool NodeTreeBase::empty() { return m_url.empty(); } // // url の更新 // // 移転があったときなどにarticlebaseから呼ばれる // void NodeTreeBase::update_url( const std::string& url ) { if( empty() ) return; #ifdef _DEBUG std::string old_url = m_url; #endif m_url = url; #ifdef _DEBUG if( ! old_url.empty() ) std::cout << "NodeTreeBase::update_url from " << old_url << " to " << m_url << std::endl; #endif } // // バッファなどのクリア // void NodeTreeBase::clear() { #ifdef _DEBUG std::cout << "NodeTreeBase::clear : " << m_url << std::endl; #endif if( m_buffer_lines ) free( m_buffer_lines ); m_buffer_lines = NULL; m_byte_buffer_lines_left = 0; if( m_parsed_text ) free( m_parsed_text ); m_parsed_text = NULL; if( m_buffer_write ) free( m_buffer_write ); m_buffer_write = NULL; if( m_fout ) fclose( m_fout ); m_fout = NULL; m_ext_err = std::string(); } // // 総レス数 // // ロード中は m_id_header 番のレスはまだ処理中なので m_id_header -1 を返す // const int NodeTreeBase::get_res_number() { if( is_loading() ) return m_id_header -1; return m_id_header; } // // number 番のレスのヘッダのポインタを返す // NODE* NodeTreeBase::res_header( int number ) { if( number > m_id_header || number <= 0 ) return NULL; return m_vec_header[ number ]; } // // 指定したID の重複数( = 発言数 ) // // 下の get_num_id_name( int number ) と違って検索するので遅い // const int NodeTreeBase::get_num_id_name( const std::string& id ) { if( id.empty() ) return 0; if( ! CONFIG::get_check_id() ){ // IDの数を数えていない場合は全て数える int count = 0; for( int i = 1; i <= m_id_header; ++i ){ if( get_id_name( i ) == id ) count++; } return count; } // IDの数を数えている場合 for( int i = 1; i <= m_id_header; ++i ){ if( get_id_name( i ) == id ) return get_num_id_name( i ); } return 0; } // // number番の ID の重複数 // const int NodeTreeBase::get_num_id_name( const int number ) { NODE* head = res_header( number ); if( ! head ) return 0; // IDの数を数えていない場合 if( ! CONFIG::get_check_id() ) return get_num_id_name( get_id_name( number ) ); return head->headinfo->num_id_name; } // // 指定した発言者IDを持つレス番号をリストにして取得 // std::list< int > NodeTreeBase::get_res_id_name( const std::string& id_name ) { std::list< int > list_resnum; for( int i = 1; i <= m_id_header ; ++i ){ if( id_name == get_id_name( i ) && ( ! m_abone_transparent || ! get_abone( i ) ) // 透明あぼーんしていない or あぼーんしていない ) list_resnum.push_back( i ); } return list_resnum; } // // str_num で指定したレス番号をリストにして取得 // str_num は "from-to" の形式 (例) 3から10をセットしたいなら "3-10" // list_jointは出力で true のスレは前のスレに連結される (例) "3+4" なら 4が3に連結 // std::list< int > NodeTreeBase::get_res_str_num( const std::string& str_num, std::list< bool >& list_joint ) { #ifdef _DEBUG std::cout << "NodeTreeBase::get_res_str_num " << str_num << std::endl; #endif std::list< int > list_resnum; // "," ごとにブロック分けする (例) "1-2,3-4+5" -> "1-2","3-4+5" std::list< std::string > list_str_num = MISC::StringTokenizer( str_num, ',' ); std::list< std::string >::iterator it = list_str_num.begin(); for( ; it != list_str_num.end(); ++it ){ // "=" ごとにブロック分けする (例) "1-2=3-4+5" -> "1-2","3-4+5" std::list< std::string > list_str_num_eq = MISC::StringTokenizer( ( *it ), '=' ); std::list< std::string >::iterator it_eq = list_str_num_eq.begin(); for( ; it_eq != list_str_num_eq.end(); ++it_eq ){ // true なら前のスレと結合 bool joint = false; // "+"ごとにブロックを分ける (例) "1+2-3+4" -> "1","2-3","4" std::list< std::string > list_str_num_pl = MISC::StringTokenizer( ( *it_eq ), '+' ); std::list< std::string >::iterator it_pl = list_str_num_pl.begin(); for( ; it_pl != list_str_num_pl.end(); ++it_pl ){ // num_from から num_to まで表示 int num_from = MAX( 1, atol( ( *it_pl ).c_str() ) ); int num_to = 0; if( num_from <= m_id_header ){ size_t i; if( ( i = ( *it_pl ).find( "-" ) ) != std::string::npos ) num_to = atol( ( *it_pl ).substr( i +1 ).c_str() ); num_to = MIN( MAX( num_to, num_from ), m_id_header ); for( int i2 = num_from; i2 <= num_to ; ++i2 ) { // 透明あぼーんしていない or あぼーんしていないなら追加 if( ! m_abone_transparent || ! get_abone( i2 ) ){ #ifdef _DEBUG std::cout << *it_pl << " " << num_from << " - " << num_to << " i2 = " << i2 << " joint = " << joint << std::endl; #endif list_resnum.push_back( i2 ); list_joint.push_back( joint ); // "+"が付いていたら2つ目のブロックから連結指定 if( list_str_num_pl.size() >= 2 ) joint = true; } } } } } } return list_resnum; } // // URL を含むレス番号をリストにして取得 // std::list< int > NodeTreeBase::get_res_with_url() { std::list< int > list_resnum; for( int i = 1; i <= m_id_header; ++i ){ NODE* head = res_header( i ); if( head ){ for( int block = 0; block < BLOCK_NUM; ++block ){ NODE* node = head->headinfo->block[ block ]; while( node ){ if( IS_URL( node ) && ( ! m_abone_transparent || ! get_abone( i ) ) // 透明あぼーんしていない or あぼーんしていない ){ list_resnum.push_back( i ); block = BLOCK_NUM; break; } node = node->next_node; } } } } return list_resnum; } // // 含まれる URL をリストにして取得 // std::list< std::string > NodeTreeBase::get_urls() { std::list< std::string > list_urls; for( int i = 1; i <= m_id_header; ++i ){ NODE* head = res_header( i ); if( head ){ for( int block = 0; block < BLOCK_NUM; ++block ){ NODE* node = head->headinfo->block[ block ]; while( node ){ if( IS_URL( node ) ) list_urls.push_back( node->linkinfo->link ); node = node->next_node; } } } } return list_urls; } // // number番のレスを参照しているレス番号をリストにして取得 // std::list< int > NodeTreeBase::get_res_reference( const int number ) { std::list< int > res_num; res_num.push_back( number ); return get_res_reference( res_num ); } // // res_num に含まれるレスを参照しているレス番号をリストにして取得 // std::list< int > NodeTreeBase::get_res_reference( const std::list< int >& res_num ) { std::list< int > list_resnum; if( ! res_num.size() ) return list_resnum; std::list< int >::const_iterator it_res = res_num.begin(); for( int i = 1; i <= m_id_header; ++i ){ // 透明あぼーんは除外 if( m_abone_transparent && get_abone( i ) ) continue; NODE* head = res_header( i ); if( head ){ for( int block = 0; block < BLOCK_NUM; ++block ){ NODE* node = head->headinfo->block[ block ]; while( node ){ if( node->type == NODE_LINK ){ // アンカーノードの時は node->linkinfo->ancinfo != NULL; if( node->linkinfo->ancinfo ){ int anc = 0; int anc_from; int anc_to; for(;;){ anc_from = node->linkinfo->ancinfo[ anc ].anc_from; anc_to = node->linkinfo->ancinfo[ anc ].anc_to; if( anc_from == 0 ) break; ++anc; it_res = res_num.begin(); for( ; it_res != res_num.end(); ++it_res ){ const int number = ( *it_res ); if( i != number && anc_to - anc_from < RANGE_REF // >>1-1000 みたいなアンカーは弾く && anc_from <= number && number <= anc_to ) { list_resnum.push_back( i ); goto EXIT_LOOP; } } } } } node = node->next_node; } // while( node ) } // for( block ) } // if( head ) EXIT_LOOP:; } // for( int i ) #ifdef _DEBUG std::cout << "NodeTreeBase::get_reference\n"; std::list < int >::iterator it; for( it = list_resnum.begin(); it != list_resnum.end(); ++it ) std::cout << *it << std::endl; #endif return list_resnum; } // // number番のレスに含まれるレスアンカーをリストにして取得 // std::list< ANCINFO* > NodeTreeBase::get_res_anchors( const int number ) { std::list< ANCINFO* > list_resnum; NODE* head = res_header( number ); if( head && head->headinfo && ! head->headinfo->abone ){ for( int block = 0; block < BLOCK_NUM; ++block ){ NODE* node = head->headinfo->block[ block ]; while( node ){ // アンカーノードの時は node->linkinfo->ancinfo != NULL; if( node->type == NODE_LINK && node->linkinfo->ancinfo ){ for(int anc = 0; ; ++anc){ ANCINFO* anchor = &( node->linkinfo->ancinfo[ anc ] ); if( anchor->anc_from == 0 ) break; // >>1-1000 みたいなアンカーは弾く if( anchor->anc_to - anchor->anc_from < RANGE_REF ){ list_resnum.push_back( anchor ); } } } node = node->next_node; } // while( node ) } // for( block ) } // if( head ) return list_resnum; } // // query を含むレス番号をリストにして取得 // // mode_or == true なら OR抽出 // const std::list< int > NodeTreeBase::get_res_query( const std::string& query, const bool mode_or ) { std::list< int > list_resnum; if( query.empty() ) return list_resnum; std::list< JDLIB::Regex > list_regex; const size_t offset = 0; const bool icase = true; // 大文字小文字区別しない const bool newline = true; // . に改行をマッチさせない const bool usemigemo = true; // migemo使用 const bool wchar = true; // 全角半角の区別をしない const std::list< std::string > list_query = MISC::split_line( query ); std::list< std::string >::const_iterator it_query; for( it_query = list_query.begin(); it_query != list_query.end() ; ++it_query ){ const std::string &query = ( *it_query ); list_regex.push_back( JDLIB::Regex() ); list_regex.back().compile( query, icase, newline, usemigemo, wchar ); } for( int i = 1; i <= m_id_header ; ++i ){ const std::string res_str = get_res_str( i ); bool apnd = true; if( mode_or ) apnd = false; std::list< JDLIB::Regex >::iterator it_regex; for( it_regex = list_regex.begin(); it_regex != list_regex.end() ; ++it_regex ){ JDLIB::Regex ®ex = ( *it_regex ); const bool ret = regex.exec( res_str, offset ); // OR if( mode_or ){ if( ret ){ apnd = true; break; } } // AND else{ if( ! ret ){ apnd = false; break; } } } if( apnd && ( ! m_abone_transparent || ! get_abone( i ) ) // 透明あぼーんしていない or あぼーんしていない ) list_resnum.push_back( i ); } return list_resnum; } // // number 番のレスの文字列を返す // // ref == true なら先頭に参照文字( "> "など)を付ける // #define GETNODESTR( id ) do{ \ node = head->headinfo->block[ id ]; \ while( node ){ \ if( node->type == DBTREE::NODE_BR ) str_res += "\n" + ref_prefix; \ else if( node->type == DBTREE::NODE_HTAB ) str_res += "\t"; \ else if( node->text ) str_res += node->text; \ node = node->next_node; \ } }while(0) \ const std::string NodeTreeBase::get_res_str( int number, bool ref ) { std::string str_res; #ifdef _DEBUG std::cout << "NodeTreeBase::get_res_str : num = " << number << std::endl; #endif NODE* head = res_header( number ); if( ! head ) return std::string(); std::string ref_prefix; if( ref ) ref_prefix = CONFIG::get_ref_prefix(); str_res.reserve( INITIAL_RES_BUFSIZE ); str_res += ref_prefix; NODE* node; GETNODESTR( BLOCK_NUMBER ); str_res += " "; GETNODESTR( BLOCK_NAMELINK ); str_res += ":"; GETNODESTR( BLOCK_NAME ); str_res += " "; GETNODESTR( BLOCK_MAIL ); str_res += ": "; GETNODESTR( BLOCK_DATE ); str_res += " "; GETNODESTR( BLOCK_ID_NAME ); str_res += " "; str_res += "\n" + ref_prefix; GETNODESTR( BLOCK_MES ); str_res += "\n"; #ifdef _DEBUG std::cout << str_res << std::endl; #endif return str_res; } // // number 番のレスの生文字列を返す // const std::string NodeTreeBase::get_raw_res_str( int number ) { #ifdef _DEBUG std::cout << "NodeTreeBase::get_raw_res_str : num = " << number << std::endl; #endif std::string retstr; std::string str; std::string path_cache = CACHE::path_dat( m_url ); if( ! CACHE::load_rawdata( path_cache, str ) ) return std::string(); char* rawlines = ( char* ) malloc( str.size() + 64 ); strcpy( rawlines, str.c_str() ); // dat形式に変換 int id_header = m_id_header; m_id_header = 0; init_loading(); int byte; const char* datlines = raw2dat( rawlines, byte ); if( byte ){ std::list< std::string > lines = MISC::get_lines( datlines ); std::list< std::string >::iterator it = lines.begin(); for( int i = 1; it != lines.end() && i < number ; ++it, ++i ); if( it != lines.end() ) retstr = *it; } #ifdef _DEBUG std::cout << retstr << std::endl; #endif clear(); m_id_header = id_header; if( rawlines ) free( rawlines ); return retstr; } // // number番を書いた人の名前を取得 // const std::string NodeTreeBase::get_name( int number ) { NODE* head = res_header( number ); if( ! head ) return std::string(); if( ! head->headinfo->name ) return std::string(); return head->headinfo->name; } // // number番の名前の重複数( = 発言数 ) // int NodeTreeBase::get_num_name( int number ) { int num = 0; std::string name = get_name( number ); for( int i = 1; i <= m_id_header; ++i ){ if( get_name( i ) == name ) ++num; } return num; } // // 指定した発言者の名前のレス番号をリストにして取得 // std::list< int > NodeTreeBase::get_res_name( const std::string& name ) { std::list< int > list_resnum; for( int i = 1; i <= m_id_header ; ++i ){ if( name == get_name( i ) && ( ! m_abone_transparent || ! get_abone( i ) ) // 透明あぼーんしていない or あぼーんしていない ) list_resnum.push_back( i ); } return list_resnum; } // // number番のレスの時刻を文字列で取得 // 内部で regex を使っているので遅い // const std::string NodeTreeBase::get_time_str( int number ) { std::string res_str = get_res_str( number ); if( res_str.empty() ) return std::string(); std::string time_str; JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( " 名前:.+]: +([0-9]*/[0-9]*/[0-9]*[^ ]* [0-9]*:[0-9]*[^ ]*).*$", res_str, offset, icase, newline, usemigemo, wchar ) ){ time_str = regex.str( 1 ); } return time_str; } // // number番の ID 取得 // const std::string NodeTreeBase::get_id_name( int number ) { NODE* head = res_header( number ); if( ! head ) return std::string(); if( ! head->headinfo->block[ BLOCK_ID_NAME ] ) return std::string(); return head->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link; } // // 基本ノード作成 // NODE* NodeTreeBase::create_node() { NODE* tmpnode = ( NODE* ) m_heap.heap_alloc( sizeof( NODE ) ); tmpnode->id_header = m_id_header; tmpnode->fontid = FONT_EMPTY; // フォントID未設定 if( m_node_previous ) m_node_previous->next_node = tmpnode; m_node_previous = tmpnode; return tmpnode; } // // ヘッダノード作成 // NODE* NodeTreeBase::create_node_header() { ++m_id_header; m_node_previous = NULL; NODE* tmpnode = create_node(); tmpnode->type = NODE_HEADER; // ヘッダ情報 tmpnode->headinfo = ( HEADERINFO* )m_heap.heap_alloc( sizeof( HEADERINFO ) ); if( m_id_header >= 2 ) m_vec_header[ m_id_header -1 ]->headinfo->next_header = tmpnode; return tmpnode; } // // block ノード作成 // // 名前や本文などのブロックの先頭に置く // NODE* NodeTreeBase::create_node_block() { m_node_previous = NULL; NODE* tmpnode = create_node(); tmpnode->type = NODE_BLOCK; return tmpnode; } // // 発言回数(IDの出現数)ノード // NODE* NodeTreeBase::create_node_idnum() { const char* dummy = " (10000)"; NODE* tmpnode = create_node_text( dummy, COLOR_CHAR ); tmpnode->type = NODE_IDNUM; tmpnode->text[ 0 ] = '\0'; // メモリだけ確保して文字を消す return tmpnode; } // // 改行ノード作成 // NODE* NodeTreeBase::create_node_br() { NODE* tmpnode = create_node(); tmpnode->type = NODE_BR; return tmpnode; } // // 水平線ノード作成 // NODE* NodeTreeBase::create_node_hr() { NODE* tmpnode = create_node(); tmpnode->type = NODE_HR; return tmpnode; } // // スペースノード // NODE* NodeTreeBase::create_node_space( const int type ) { NODE* tmpnode = create_node(); tmpnode->type = type; return tmpnode; } // // 連続半角スペース // NODE* NodeTreeBase::create_node_multispace( const char* text, const int n ) { NODE* tmpnode = create_node_ntext( text, n, COLOR_CHAR, false ); tmpnode->type = NODE_MULTISP; return tmpnode; } // // 水平タブノード // NODE* NodeTreeBase::create_node_htab() { NODE* tmpnode = create_node(); tmpnode->type = NODE_HTAB; return tmpnode; } // // リンクノード作成 // // bold : 太字か // NODE* NodeTreeBase::create_node_link( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold ) { NODE* tmpnode = create_node_ntext( text, n, color_text, bold ); if( tmpnode ){ tmpnode->type = NODE_LINK; // リンク情報作成 char *tmplink = ( char* )m_heap.heap_alloc( n_link +4 ); memcpy( tmplink, link, n_link ); tmplink[ n_link ] = '\0'; // リンク情報セット tmpnode->linkinfo = ( LINKINFO* )m_heap.heap_alloc( sizeof( LINKINFO ) ); tmpnode->linkinfo->link = tmplink; } return tmpnode; } // // アンカーノード作成 // NODE* NodeTreeBase::create_node_anc( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold, const ANCINFO* ancinfo, const int lng_ancinfo ) { NODE* tmpnode = create_node_link( text, n, link, n_link, color_text, bold ); if( tmpnode ){ tmpnode->linkinfo->ancinfo = ( ANCINFO* )m_heap.heap_alloc( sizeof( ANCINFO ) * ( lng_ancinfo + 1 ) ); memcpy( tmpnode->linkinfo->ancinfo, ancinfo, sizeof( ANCINFO ) * lng_ancinfo ); } return tmpnode; } // // SSSPノード // NODE* NodeTreeBase::create_node_sssp( const char* link, const int n_link ) { NODE* tmpnode = create_node(); tmpnode->type = NODE_SSSP; // リンク情報作成 char *tmplink = ( char* )m_heap.heap_alloc( n_link +4 ); memcpy( tmplink, link, n_link ); tmplink[ n_link ] = '\0'; // リンク情報セット tmpnode->linkinfo = ( LINKINFO* )m_heap.heap_alloc( sizeof( LINKINFO ) ); tmpnode->linkinfo->link = tmplink; tmpnode->linkinfo->image = true; tmpnode->linkinfo->imglink = tmpnode->linkinfo->link; return tmpnode; } // // 画像ノード作成 // NODE* NodeTreeBase::create_node_img( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold ) { NODE* tmpnode = create_node_link( text, n, link, n_link, color_text, bold ); if( tmpnode ){ tmpnode->linkinfo->image = true; tmpnode->linkinfo->imglink = tmpnode->linkinfo->link; } return tmpnode; } // // サムネイル画像ノード ( youtubeなどのサムネイル表示用 ) // NODE* NodeTreeBase::create_node_thumbnail( const char* text, const int n, const char* link, const int n_link, const char* thumb, const int n_thumb, const int color_text, const bool bold ) { NODE* tmpnode = create_node_link( text, n, link, n_link, color_text, bold ); if( tmpnode ){ // サムネイル画像のURLをセット char *tmpthumb = ( char* )m_heap.heap_alloc( n_thumb +4 ); memcpy( tmpthumb, thumb, n_thumb ); tmpthumb[ n_thumb ] = '\0'; tmpnode->linkinfo->imglink = tmpthumb; } return tmpnode; } // // テキストノード作成 // NODE* NodeTreeBase::create_node_text( const char* text, const int color_text, const bool bold ) { return create_node_ntext( text, strlen( text ), color_text, bold ); } // // テキストノード作成( サイズ指定 ) // NODE* NodeTreeBase::create_node_ntext( const char* text, const int n, const int color_text, const bool bold ) { if( n <= 0 ) return NULL; NODE* tmpnode = create_node(); if( tmpnode ){ tmpnode->type = NODE_TEXT; tmpnode->text = ( char* )m_heap.heap_alloc( n +8 ); memcpy( tmpnode->text, text, n ); tmpnode->text[ n ] = '\0'; tmpnode->color_text = color_text; tmpnode->bold = bold; } return tmpnode; } // // html をコメントとして追加 // // パースして追加したノードのポインタを返す // NODE* NodeTreeBase::append_html( const std::string& html ) { if( is_loading() ) return NULL; if( html.empty() ) return NULL; #ifdef _DEBUG std::cout << "NodeTreeBase::append_html url = " << m_url << " html = " << html << std::endl; #endif NODE* header = create_node_header(); m_vec_header[ m_id_header ] = header; init_loading(); header->headinfo->block[ BLOCK_MES ] = create_node_block(); const bool digitlink = false; const bool bold = false; const bool ahref = true; const bool sssp = false; parse_html( html.c_str(), html.length(), COLOR_CHAR, digitlink, bold, ahref, sssp ); clear(); return header; } // // dat を追加 // // パースして追加したノードのポインタを返す // NODE* NodeTreeBase::append_dat( const std::string& dat ) { if( is_loading() ) return NULL; if( dat.empty() ) return NULL; init_loading(); receive_data( dat.c_str(), dat.length() ); receive_finish(); return res_header( m_id_header ); } // // キャッシュからスレッドをロード // void NodeTreeBase::load_cache() { std::string path_cache = CACHE::path_dat( m_url ); if( CACHE::file_exists( path_cache ) == CACHE::EXIST_FILE ){ #ifdef _DEBUG std::cout << "NodeTreeBase::load_cache from " << path_cache << std::endl; #endif std::string str; if( CACHE::load_rawdata( path_cache, str ) ){ const char* data = str.data(); size_t size = 0; m_check_update = false; m_check_write = false; m_loading_newthread = false; set_resume( false ); init_loading(); const size_t str_length = str.length(); while( size < str_length ){ size_t size_tmp = MIN( MAXSISE_OF_LINES - m_byte_buffer_lines_left, str_length - size ); receive_data( data + size, size_tmp ); size += size_tmp; } receive_finish(); // レジューム時のチェック用に生データの先頭から RESUME_CHKSIZE バイト分をコピーしておく // 詳しくは NodeTreeBase::receive_data() を参照せよ const size_t length_chk = MIN( RESUME_CHKSIZE, str_length ); memcpy( m_resume_head, data, length_chk ); m_resume_head[ length_chk ] = '\0'; } } } // // ロード実行前に呼ぶ初期化関数 // void NodeTreeBase::init_loading() { clear(); // 一時バッファ作成 if( ! m_buffer_lines ) m_buffer_lines = ( char* ) malloc( MAXSISE_OF_LINES ); if( ! m_parsed_text ) m_parsed_text = ( char* ) malloc( MAXSISE_OF_LINES ); } // // レジュームのモードをセットする // void NodeTreeBase::set_resume( const bool resume ) { #ifdef _DEBUG std::cout << "NodeTreeBase::set_resume resume = " << resume << std::endl; #endif if( resume ) m_resume = RESUME_MODE1; else m_resume = RESUME_NO; } // // ロード開始 // // check_update : HEADによる更新チェックのみ // void NodeTreeBase::download_dat( const bool check_update ) { if( is_loading() ) return; m_check_update = check_update; m_check_write = ! m_check_update; m_loading_newthread = ( ! get_res_number() ); #ifdef _DEBUG std::cout << "NodeTreeBase::download_dat : " << m_url << " lng = " << m_lng_dat << std::endl << "modified = " << get_date_modified() << " check_update = " << check_update << " newthread = " << m_loading_newthread << std::endl; #endif // オフライン if( ! SESSION::is_online() ){ set_str_code( "" ); // ディスパッチャ経由でreceive_finish()を呼ぶ finish(); return; } // // オンライン // init_loading(); if( ! m_check_update ){ // 保存ディレクトリ作成(無ければ) if( CACHE::mkdir_boardroot( m_url ) ){ // 保存ファイルオープン std::string path_cache = CACHE::path_dat( m_url ); #ifdef _DEBUG std::cout << "open " << path_cache.c_str() << std::endl; #endif m_fout = fopen( to_locale_cstr( path_cache ), "ab" ); if( m_fout == NULL ){ MISC::ERRMSG( "fopen failed : " + path_cache ); } } else{ MISC::ERRMSG( "could not create " + DBTREE::url_boardbase( m_url ) ); } } // ロード開始 // ロード完了したら receive_finish() が呼ばれる JDLIB::LOADERDATA data; create_loaderdata( data ); // 更新チェックの時はHEADを使う if( m_check_update ){ data.head = true; data.timeout = CONFIG::get_loader_timeout_checkupdate(); } if( data.url.empty() || ! start_load( data ) ){ m_sig_finished.emit(); clear(); } } // // ローダからデータ受け取り // void NodeTreeBase::receive_data( const char* data, size_t size ) { // BOF防止 size = MIN( MAXSISE_OF_LINES, size ); if( is_loading() && ( get_code() != HTTP_OK && get_code() != HTTP_PARTIAL_CONTENT ) ){ #ifdef _DEBUG std::cout << "NodeTreeBase::receive_data : code = " << get_code() << std::endl; std::cout << data << std::endl; #endif return; } if( m_check_update ) return; // 通常のレジューム処理 if( m_resume == RESUME_MODE1 ){ #ifdef _DEBUG std::cout << "resume mode = " << m_resume << " -> "; #endif // レジュームした時に先頭が '\n' ならレジューム成功 if( data[ 0 ] == '\n' ){ ++data; --size; m_resume = RESUME_NO; } // サーバが range を無視してデータを送ってきた // 続きは add_raw_lines() を参照 else if( get_code() == HTTP_OK ) m_resume = RESUME_MODE2; // あぼーんが起きた? else{ m_broken = true; MISC::ERRMSG( "failed to resume" ); m_resume = RESUME_NO; } #ifdef _DEBUG std::cout << m_resume << std::endl; #endif } if( m_resume == RESUME_FAILED ) return; if( !size ) return; // バッファが '\n' で終わるように調整 const char* pos = data + size -1; while( *pos != '\n' && pos != data ) --pos; // 前回の残りのデータに新しいデータを付け足して add_raw_lines()にデータを送る size_t size_in = ( int )( pos - data ) + 1; if( size_in > 1 ){ memcpy( m_buffer_lines + m_byte_buffer_lines_left , data, size_in ); m_buffer_lines[ m_byte_buffer_lines_left + size_in ] = '\0'; add_raw_lines( m_buffer_lines, m_byte_buffer_lines_left + size_in ); } // 残りの分をバッファにコピーしておく m_byte_buffer_lines_left = size - size_in; if( m_byte_buffer_lines_left ) memcpy( m_buffer_lines, data + size_in, m_byte_buffer_lines_left ); } // // ロード完了 // void NodeTreeBase::receive_finish() { if( get_code() != HTTP_INIT && get_code() != HTTP_OK && get_code() != HTTP_PARTIAL_CONTENT && get_code() != HTTP_NOT_MODIFIED && get_code() != HTTP_OLD ){ std::ostringstream err; err << m_url << std::endl << "load failed. : " << get_str_code(); if( get_code() == HTTP_REDIRECT || get_code() == HTTP_REDIRECT ) err << " location = " << location(); MISC::ERRMSG( err.str() ); } if( ! m_check_update ){ // Requested Range Not Satisfiable if( get_code() == HTTP_RANGE_ERR ){ m_broken = true; MISC::ERRMSG( "Requested Range Not Satisfiable" ); } // データがロードされなかったらキャッシュを消す if( get_res_number() == 0 ){ std::string path = CACHE::path_dat( m_url ); if( CACHE::file_exists( path ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( path ) ); set_date_modified( std::string() ); } // その他、何かエラーがあったらmodifiedをクリアしておく if( !get_ext_err().empty() ) set_date_modified( std::string() ); // 書き込みチェック終了 if( m_check_write && MESSAGE::get_log_manager()->size() && ( get_code() == HTTP_OK || get_code() == HTTP_PARTIAL_CONTENT || get_code() == HTTP_NOT_MODIFIED ) ) MESSAGE::get_log_manager()->remove_items( m_url ); } #ifdef _DEBUG std::cout << "NodeTreeBase::receive_finish lng = " << m_lng_dat << " raw lng = " << current_length() << " code = " << get_code() << " " << get_str_code() << " modified = " << get_date_modified() << std::endl; #endif // 親 article クラスにシグナルを打ってツリー構造が変わったことを教える m_sig_finished.emit(); clear(); if( ! m_check_update && ( get_code() == HTTP_OK || get_code() == HTTP_PARTIAL_CONTENT ) && ! get_date_modified().empty() ) CACHE::set_filemtime( CACHE::path_dat( m_url ), get_time_modified() ); m_check_update = false; m_check_write = false; m_loading_newthread = false; } // // 鯖から生の(複数)行のデータを受け取ってdat形式に変換して add_one_dat_line() に出力 // void NodeTreeBase::add_raw_lines( char* rawlines, size_t size ) { // 時々サーバ側のdatファイルが壊れていてデータ中に \0 が // 入っている時があるので取り除く for( size_t i = 0; i < size; ++i ){ if( rawlines[ i ] == '\0' ){ MISC::ERRMSG( "EOF was inserted in the middle of the raw data" ); rawlines[ i ] = ' '; } } // 保存前にrawデータを加工 rawlines = process_raw_lines( rawlines ); size_t lng = strlen( rawlines ); if( ! lng ) return; // サーバが range を無視してデータを送ってきたときのレジューム処理 if( m_resume == RESUME_MODE2 ){ #ifdef _DEBUG std::cout << "NodeTreeBase::add_raw_lines : resume\n"; #endif // 先頭からdatを送ってきたかチェック const size_t length_chk = MIN( lng, MIN( RESUME_CHKSIZE, strlen( m_resume_head ) ) ); if( strncmp( rawlines, m_resume_head, length_chk ) == 0 ){ m_resume = RESUME_MODE3; m_resume_lng = 0; } // 全く違うデータを送ってきた else{ m_broken = true; MISC::ERRMSG( "failed to resume" ); m_resume = RESUME_FAILED; return; } } // レジューム処理でデータをスキップ中 if( m_resume == RESUME_MODE3 ){ #ifdef _DEBUG std::cout << "NodeTreeBase::add_raw_lines : resume skip resume_lng = " << m_resume_lng << " lng = " << lng << " / lng_dat = " << m_lng_dat << std::endl; #endif m_resume_lng += lng; if( m_resume_lng <= m_lng_dat ) return; // 越えた分をカットしてレジューム処理終了 rawlines += ( lng - ( m_resume_lng - m_lng_dat ) ); lng = ( m_resume_lng - m_lng_dat ); m_resume = RESUME_NO; #ifdef _DEBUG std::cout << "resume finished : lng = " << lng << std::endl; #endif } if( ! lng ) return; m_lng_dat += lng; // キャッシュに保存 if( m_fout ){ #ifdef _DEBUG std::cout << "NodeTreeBase::add_raw_lines save " << lng << " bytes\n"; #endif if( fwrite( rawlines, 1, lng, m_fout ) < lng ){ MISC::ERRMSG( "write failed in NodeTreeBase::add_raw_lines\n" ); } } // dat形式に変換 int byte; const char* datlines = raw2dat( rawlines, byte ); if( !byte ) return; // '\n' 単位で区切って add_one_dat_line() に渡す int num_before = m_id_header; const char* pos = datlines; while( * ( pos = add_one_dat_line( pos ) ) != '\0' ) ++pos; if( num_before != m_id_header ){ // あぼーん判定 update_abone( num_before +1, m_id_header ); // 発言数更新 update_id_name( num_before +1, m_id_header ); // 参照数更新 update_reference( num_before +1, m_id_header ); // フォント判定 update_fontid( num_before +1, m_id_header ); // articlebase クラスに状態が変わったことを知らせる m_sig_updated.emit(); } } // // dat 解析関数 // // datの1行を解析してノード木を作成する // // 戻り値: バッファの最後の位置 // const char* NodeTreeBase::add_one_dat_line( const char* datline ) { const char* pos = datline; if( *pos == '\0' || *pos == '\n' ) return datline; int i; NODE* header = create_node_header(); m_vec_header[ m_id_header ] = header; // レス番号 char tmplink[ LNG_RES ], tmpstr[ LNG_RES ]; snprintf( tmpstr, LNG_RES, "%d", header->id_header ); snprintf( tmplink, LNG_RES,"%s%d", PROTO_RES, header->id_header ); header->headinfo->block[ BLOCK_NUMBER ] = create_node_block(); create_node_link( tmpstr, strlen( tmpstr ) , tmplink, strlen( tmplink ), COLOR_CHAR_LINK_RES, true ); const char* section[ SECTION_NUM ]; int section_lng[ SECTION_NUM ]; // セクション分けしながら壊れてないかチェック for( i = 0; i < SECTION_NUM ; ++i ){ section[ i ] = pos; while( !( *pos == '<' && *( pos + 1 ) == '>' ) && ( *pos != '\0' && *pos != '\n' ) ) ++pos; section_lng[ i ] = ( int )( pos - section[ i ] ); if( ( *pos == '\0' || *pos == '\n' ) && i < SECTION_NUM -1 ) break; // 壊れてる if ( !( *pos == '\0' || *pos == '\n' ) ) pos += 2; // "<>"の分 } // 壊れている if( i != SECTION_NUM ){ #ifdef _DEBUG std::cout << header->id_header << " is broken section = " << i << std::endl; std::cout << datline << std::endl; #endif m_broken = true; header->headinfo->block[ BLOCK_NAME ] = create_node_block(); create_node_text( " 壊れています", COLOR_CHAR ); header->headinfo->block[ BLOCK_MES ] = create_node_block(); const char str_broken[] = "ここ"; create_node_link( str_broken, strlen( str_broken ) , PROTO_BROKEN, strlen( PROTO_BROKEN ), COLOR_CHAR_LINK, false ); create_node_text( "をクリックしてスレを再取得して下さい。", COLOR_CHAR ); return pos; } // 名前 int color_name = COLOR_CHAR_NAME; if( ! section_lng[ 1 ] ) color_name = COLOR_CHAR_NAME_NOMAIL; parse_name( header, section[ 0 ], section_lng[ 0 ], color_name ); // メール parse_mail( header, section[ 1 ], section_lng[ 1 ] ); // 日付とID parse_date_id( header, section[ 2 ], section_lng[ 2 ] ); // 本文 header->headinfo->block[ BLOCK_MES ] = create_node_block(); const bool digitlink = false; const bool bold = false; const bool ahref = false; const bool sssp = true; parse_html( section[ 3 ], section_lng[ 3 ], COLOR_CHAR, digitlink, bold, ahref, sssp ); // サブジェクト if( header->id_header == 1 ){ m_subject = std::string( section[ 4 ] ).substr( 0, section_lng[ 4 ] ); #ifdef _DEBUG std::cout << "subject = " << m_subject << std::endl; #endif } // 自分の書き込みかチェック if( m_check_write && MESSAGE::get_log_manager()->has_items( m_url, m_loading_newthread ) ){ if( ! m_buffer_write ) m_buffer_write = ( char* ) malloc( MAXSISE_OF_LINES ); // 簡易チェック // 最初の lng_check 文字だけ見る const bool newthread = ( header->id_header == 1 ); const int lng_check = MIN( section_lng[ 3 ], 32 ); parse_write( section[ 3 ], section_lng[ 3 ], lng_check ); if( MESSAGE::get_log_manager()->check_write( m_url, newthread, m_buffer_write, lng_check ) ){ // 全ての文字列で一致しているかチェック parse_write( section[ 3 ], section_lng[ 3 ], 0 ); const bool hit = MESSAGE::get_log_manager()->check_write( m_url, newthread, m_buffer_write, 0 ); if( hit ){ if( ! m_vec_posted.size() ) m_vec_posted.resize( MAX_RESNUMBER ); m_vec_posted[ header->id_header ] = true; } #ifdef _DEBUG std::cout << "check_write id = " << header->id_header << " hit = " << hit << std::endl; #endif } } return pos; } // // 名前 // void NodeTreeBase::parse_name( NODE* header, const char* str, const int lng, const int color_name ) { bool digitlink = true; const bool bold = true; const bool ahref = false; const bool sssp = false; const bool defaultname = ( strncmp( m_default_noname.data(), str, lng ) == 0 ); header->headinfo->block[ BLOCK_NAMELINK ] = create_node_block(); // デフォルトの名前で無いときはリンクにする if( defaultname ) create_node_text( "名前", COLOR_CHAR ); else{ const char namestr[] = "名前"; create_node_link( namestr, strlen( namestr ) , PROTO_NAME, strlen( PROTO_NAME ), COLOR_CHAR, false ); } NODE* node = header->headinfo->block[ BLOCK_NAME ] = create_node_block(); // デフォルト名無しと同じときはアンカーを作らない if( defaultname ){ digitlink = false; parse_html( str, lng, color_name, digitlink, bold, ahref, sssp ); } else{ int pos = 0; int i; while( pos < lng ){ // トリップなどの中の文字列は色を変えて数字をリンクにしない for( i = pos; i < lng; ++i ){ if( str[ i ] == '<' && str[ i+1 ] == '/' && ( str[ i+2 ] == 'b' || str[ i+2 ] == 'B' ) && str[ i+3 ] == '>' ) break; } // の前までパース if( i != pos ){ digitlink = true; parse_html( str + pos, i - pos, color_name, digitlink, bold, ahref, sssp ); } if( i >= lng ) break; pos = i + 4; // 4 = strlen( "" ); // の位置を探す int pos_end = lng; for( i = pos; i < lng; ++i ){ if( str[ i ] == '<' && ( str[ i+1 ] == 'b' || str[ i+1 ] == 'B' ) && str[ i+2 ] == '>' ){ pos_end = i; break; } } #ifdef _DEBUG char tmp_str[256]; memset( tmp_str, 0, 256); memcpy( tmp_str, str + pos, pos_end - pos ); std::cout << "NodeTreeBase::parseName trip = " << tmp_str << " begin = " << pos << " end = " << pos_end << std::endl; #endif // の中をパース digitlink = false; // 数字が入ってもリンクしない parse_html( str + pos, pos_end - pos, COLOR_CHAR_NAME_B, digitlink, bold, ahref, sssp ); pos = pos_end + 3; // 3 = strlen( "" ); } } // plainな名前取得 // 名前あぼーんや名前抽出などで使用する if( defaultname ){ header->headinfo->name = ( char* )m_heap.heap_alloc( lng +2 ); memcpy( header->headinfo->name, str, lng ); } else{ std::string str_tmp; node = node->next_node; while( node ){ if( node->text ) str_tmp += node->text; node = node->next_node; } header->headinfo->name = ( char* )m_heap.heap_alloc( str_tmp.length() +2 ); memcpy( header->headinfo->name, str_tmp.c_str(), str_tmp.length() ); } } // // メール // void NodeTreeBase::parse_mail( NODE* header, const char* str, const int lng ) { // sage 以外の時は色を変える int color = COLOR_CHAR; int i = 0; while( str[ i ] != 's' && i < lng ) ++i; if( str[ i ] != 's' || str[ i+1 ] != 'a' || str[ i+2 ] != 'g' || str[ i+3 ] != 'e' ){ color = COLOR_CHAR_AGE; header->headinfo->sage = FALSE; } else header->headinfo->sage = TRUE; header->headinfo->block[ BLOCK_MAIL ] = create_node_block(); if( ! lng ) create_node_text( "[]", color ); else{ create_node_text( "[", color ); const bool digitlink = true; const bool bold = false; const bool ahref = false; const bool sssp = false; parse_html( str, lng, color, digitlink, bold, ahref, sssp ); create_node_text( "]", color ); } } // // 日付とID、及びBE、株、その他 // void NodeTreeBase::parse_date_id( NODE* header, const char* str, const int lng ) { int start = 0; int lng_text = 0; int lng_link_tmp; char tmplink[ LNG_LINK ]; int lng_id_tmp; char tmpid[ LNG_ID ]; header->headinfo->block[ BLOCK_DATE ] = create_node_block(); for(;;){ // 先頭の空白を飛ばす while( start + lng_text < lng && str[ start + lng_text ] == ' ' ) ++lng_text; // 空白ごとにブロック分けしてパースする int start_block = start + lng_text; int lng_block = 0; // ブロックの長さ while( start_block + lng_block < lng && str[ start_block + lng_block ] != ' ' ) ++lng_block; if( !lng_block ) break; if( // ID ( ??? の時は除く ) ( str[ start_block ] == 'I' && str[ start_block + 1 ] == 'D' && str[ start_block + 3 ] != '?' ) // HOST || ( str[ start_block + 0 ] == 'H' && str[ start_block + 1 ] == 'O' && str[ start_block + 2 ] == 'S' && str[ start_block + 3 ] == 'T' ) // 発言元 || ( str[ start_block + 0 ] == (char)0xe7 && str[ start_block + 1 ] == (char)0x99 && str[ start_block + 2 ] == (char)0xba // 発 && str[ start_block + 3 ] == (char)0xe4 && str[ start_block + 4 ] == (char)0xbf && str[ start_block + 5 ] == (char)0xa1 // 言 && str[ start_block + 6 ] == (char)0xe5 && str[ start_block + 7 ] == (char)0x85 && str[ start_block + 8 ] == (char)0x83 // 元 ) ){ // フラッシュ if( lng_text ){ if( *( str + start + lng_text - 1 ) == ' ' ) --lng_text; create_node_ntext( str + start, lng_text, COLOR_CHAR ); } int offset = 0; if( str[ start_block ] == 'I' ) offset = 3; else if( str[ start_block ] == 'H' ){ offset = 5; // HOST: の場合は途中で空白が入るときがあるので最後までブロックを伸ばす lng_block = lng - start_block; } else if( str[ start_block ] == (char)0xe7 ) offset = 10; // id 取得 lng_id_tmp = MIN( lng_block, LNG_ID - 16 ); memcpy( tmpid, str + start_block, lng_id_tmp ); tmpid[ lng_id_tmp ] = '\0'; // リンク文字作成 memcpy( tmplink, PROTO_ID, sizeof( PROTO_ID ) ); memcpy( tmplink + sizeof( PROTO_ID ) - 1, tmpid, lng_id_tmp + 1 ); lng_link_tmp = strlen( tmplink ); // 後ろに●が付いていたら取り除く if( tmplink[ lng_link_tmp - 3 ] == (char)0xe2 && tmplink[ lng_link_tmp - 2 ] == (char)0x97 && tmplink[ lng_link_tmp - 1 ] == (char)0x8f ){ lng_link_tmp -= 3; tmplink[ lng_link_tmp ] = '\0'; } // リンク作成 header->headinfo->block[ BLOCK_ID_NAME ] = create_node_block(); create_node_link( tmpid, offset, tmplink, lng_link_tmp, COLOR_CHAR, false ); create_node_ntext( tmpid +offset, lng_id_tmp -offset, COLOR_CHAR); // 発言回数ノード作成 create_node_idnum(); // 次のブロックへ移動 start = start_block + lng_block; lng_text = 0; } // BE: else if( str[ start_block ] == 'B' && str[ start_block + 1 ] == 'E' ){ const int strlen_of_BE = 3; // = strlen( "BE:" ); // フラッシュ if( lng_text ) create_node_ntext( str + start, lng_text, COLOR_CHAR ); // id 取得 int lng_header = 0; while( str[ start_block + lng_header ] != '-' && lng_header < lng_block ) ++lng_header; lng_id_tmp = lng_header - strlen_of_BE; if( str[ start_block + lng_header ] == '-' ) ++lng_header; memcpy( tmpid, str + start_block + strlen_of_BE, lng_id_tmp ); tmpid[ lng_id_tmp ] = '\0'; // リンク文字作成 memcpy( tmplink, PROTO_BE, sizeof( PROTO_BE ) ); memcpy( tmplink + sizeof( PROTO_BE ) -1, tmpid, lng_id_tmp + 1 ); // リンク作成 create_node_link( "?", 1, tmplink, strlen( tmplink ), COLOR_CHAR, false ); create_node_ntext( str + start_block + lng_header, lng_block - lng_header, COLOR_CHAR); // 次のブロックへ移動 start = start_block + lng_block; lng_text = 0; } // 株などの else if( str[ start_block ] == '<' && ( str[ start_block + 1 ] == 'a' || str[ start_block + 1 ] == 'A' ) && str[ start_block + 2 ] == ' ' ){ // フラッシュ if( lng_text ) create_node_ntext( str + start, lng_text, COLOR_CHAR ); // までブロックの長さを伸ばす while( start_block + lng_block < lng && ! ( ( str[ start_block + lng_block -1 ] == 'a' || str[ start_block + lng_block -1 ] == 'A' ) && str[ start_block + lng_block ] == '>' ) ) ++lng_block; ++lng_block; const bool digitlink = false; const bool bold = false; const bool ahref = true; const bool sssp = false; parse_html( str + start_block, lng_block, COLOR_CHAR, digitlink, bold, ahref, sssp ); // 次のブロックへ移動 start = start_block + lng_block; lng_text = 0; } // テキスト(日付含む) else lng_text += lng_block; } // フラッシュ if( lng_text ) create_node_ntext( str + start, lng_text, COLOR_CHAR ); } // // HTMLパーサ // // digitlink : true の時は先頭に数字が現れたらアンカーにする( parse_name() などで使う ) // false なら数字の前に >> がついてるときだけアンカーにする // // bold : ボールド表示 // // ahref : からリンクノードを作成する // (例) parse_html( "hoge", 27, COLOR_CHAR, false, false, true ); // // enable_sssp : true の時はssspアイコンを有効にする( ssspは 1 レス 1 つだけアイコン表示) // // (パッチ) // // 行頭の空白は全て除くパッチ // Thanks to 「パッチ投稿スレ」の28氏 // http://jd4linux.sourceforge.jp/cgi-bin/bbs/test/read.cgi/support/1151836078/28 // void NodeTreeBase::parse_html( const char* str, const int lng, const int color_text, bool digitlink, const bool bold, const bool ahref, bool enable_sssp ) { const char* pos = str; const char* pos_end = str + lng; int lng_text = 0; if( *pos == ' ' ){ pos++; // 一文字だけなら取り除く // 連続半角空白 if( *pos == ' ' ){ while( *pos == ' ' ) m_parsed_text[ lng_text++ ] = *(pos++); create_node_multispace( m_parsed_text, lng_text ); lng_text = 0; } } for( ; pos < pos_end; ++pos, digitlink = false ){ /////////////////////// // HTMLタグ if( *pos == '<' ){ bool br = false; // 改行
if( ( *( pos + 1 ) == 'b' || *( pos + 1 ) == 'B' ) && ( *( pos + 2 ) == 'r' || *( pos + 2 ) == 'R' ) ) br = true; // ahref == true かつ else if( ahref && ( *( pos + 1 ) == 'a' || *( pos + 1 ) == 'A' ) && *( pos + 2 ) == ' ' ){ // フラッシュ create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0; while( pos < pos_end && *pos != '=' ) ++pos; ++pos; if( *pos == ' ' ) ++pos; if( pos >= pos_end ) continue; bool dbq = false; if( *pos == '"' ){ dbq = true; ++pos; } const char* pos_link_start = pos; int lng_link = 0; while( pos < pos_end && ( ( ( dbq && *pos != '"' ) || ( !dbq && *pos != ' ' ) ) && *pos != '>' ) ){ ++pos; ++lng_link; } if( pos >= pos_end ) continue; while( pos < pos_end && *pos != '>' ) ++pos; if( pos >= pos_end ) continue; ++pos; const char* pos_str_start = pos; int lng_str = 0; bool exec_decode = false; while( pos < pos_end && *pos != '<' ){ if( *pos == '&' ) exec_decode = true; ++pos; ++lng_str; } if( pos >= pos_end ) continue; while( pos < pos_end && *pos != '>' ) ++pos; if( pos >= pos_end ) continue; ++pos; if( lng_link && lng_str ){ // 特殊文字デコード if( exec_decode ){ for( int pos_tmp = 0; pos_tmp < lng_str; ++ pos_tmp ){ int n_in = 0; int n_out = 0; const int ret_decode = DBTREE::decode_char( pos_str_start + pos_tmp, n_in, m_parsed_text + lng_text, n_out, false ); if( ret_decode != NODE_NONE ){ lng_text += n_out; pos_tmp += n_in; pos_tmp--; } else m_parsed_text[ lng_text++ ] = *( pos_str_start + pos_tmp ); } #ifdef _DEBUG m_parsed_text[ lng_text ] = '\0'; std::cout << m_parsed_text << std::endl; #endif pos_str_start = m_parsed_text; lng_str = lng_text; lng_text = 0; } create_node_link( pos_str_start, lng_str , pos_link_start, lng_link, COLOR_CHAR_LINK, false ); } } // else if( *( pos + 1 ) == '/' && ( *( pos + 2 ) == 'a' || *( pos + 2 ) == 'A' ) && *( pos + 3 ) == '>' ) pos += 4; // 改行にするタグ else if( //

( ( *( pos + 1 ) == 'p' || *( pos + 1 ) == 'P' ) && *( pos + 2 ) == '>' ) //

|| ( ( *( pos + 2 ) == 'p' || *( pos + 2 ) == 'P' ) && *( pos + 3 ) == '>' && *( pos + 1 ) == '/' ) //
|| ( ( *( pos + 1 ) == 'd' || *( pos + 1 ) == 'D' ) && ( *( pos + 2 ) == 'd' || *( pos + 2 ) == 'D' ) ) // || ( ( *( pos + 2 ) == 'd' || *( pos + 2 ) == 'D' ) && ( *( pos + 3 ) == 'l' || *( pos + 3 ) == 'L' ) && *( pos + 1 ) == '/' ) // || ( ( *( pos + 2 ) == 'u' || *( pos + 2 ) == 'U' ) && ( *( pos + 3 ) == 'l' || *( pos + 3 ) == 'L' ) && *( pos + 1 ) == '/' ) // || ( ( *( pos + 2 ) == 'l' || *( pos + 2 ) == 'L' ) && ( *( pos + 3 ) == 'i' || *( pos + 3 ) == 'I' ) && *( pos + 1 ) == '/' ) // || ( ( *( pos + 2 ) == 't' || *( pos + 2 ) == 'T' ) && ( *( pos + 3 ) == 'i' || *( pos + 3 ) == 'I' ) && ( *( pos + 4 ) == 't' || *( pos + 4 ) == 'T' ) && ( *( pos + 5 ) == 'l' || *( pos + 5 ) == 'L' ) && ( *( pos + 6 ) == 'e' || *( pos + 6 ) == 'E' ) && *( pos + 1 ) == '/' ) ) br = true; //
  • は・にする else if( ( *( pos + 1 ) == 'l' || *( pos + 2 ) == 'L' ) && ( *( pos + 2 ) == 'i' || *( pos + 3 ) == 'I' ) ){ pos += 4; int n_in = 0; int n_out = 0; DBTREE::decode_char( "・", n_in, m_parsed_text + lng_text, n_out, false ); lng_text += n_out; } // 水平線
    else if( ( *( pos + 1 ) == 'h' || *( pos + 1 ) == 'H' ) && ( *( pos + 2 ) == 'r' || *( pos + 2 ) == 'R' ) ){ // フラッシュ create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0; // 水平線ノード作成 create_node_hr(); pos += 4; } // その他のタグは無視。タグを取り除いて中身だけを見る else { // フラッシュ create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0; while( pos < pos_end && *pos != '>' ) ++pos; ++pos; } // 改行実行 if( br ){ // フラッシュ if( *( pos - 1 ) == ' ' ) --lng_text; // 改行前の空白を取り除く create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0; // 改行ノード作成 create_node_br(); while( *pos != '>' ) ++pos; ++pos; if( *pos == ' ' ){ pos++; // 一文字だけなら取り除く // 連続半角空白 if( *pos == ' ' ){ while( *pos == ' ' ) m_parsed_text[ lng_text++ ] = *(pos++); create_node_multispace( m_parsed_text, lng_text ); lng_text = 0; } } } // forのところで++されるので--しておく --pos; continue; } /////////////////////// // アンカーのチェック int n_in = 0; int n_out = 0; char tmpstr[ LNG_LINK +16 ]; // 画面に表示する文字列 char tmplink[ LNG_LINK +16 ]; // 編集したリンク文字列 int lng_str = 0, lng_link = strlen( PROTO_ANCHORE ); ANCINFO ancinfo[ MAX_ANCINFO ]; int lng_anc = 0; int mode = 0; if( digitlink ) mode = 2; if( check_anchor( mode , pos, n_in, tmpstr + lng_str, tmplink + lng_link, LNG_LINK - lng_link, ancinfo + lng_anc ) ){ // フラッシュしてからアンカーノードをつくる create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0; memcpy( tmplink, PROTO_ANCHORE, strlen( PROTO_ANCHORE ) ); lng_str += strlen( tmpstr ) - lng_str; lng_link += strlen( tmplink ) - lng_link; ++lng_anc; pos += n_in; // , や = や +が続くとき mode = 1; while( check_anchor( mode, pos, n_in, tmpstr + lng_str, tmplink + lng_link , LNG_LINK - lng_link, ancinfo + lng_anc ) ){ lng_str += strlen( tmpstr ) - lng_str; lng_link += strlen( tmplink ) - lng_link; ++lng_anc; pos += n_in; } create_node_anc( tmpstr, lng_str, tmplink, lng_link, COLOR_CHAR_LINK, bold, ancinfo, lng_anc ); // forのところで++されるので--しておく --pos; continue; } // digitlink = true の時は数字が長すぎるときは飛ばす( 例えば 名前: 12345678 みたいなとき ) if( digitlink ){ --n_in; while( n_in-- > 0 ) m_parsed_text[ lng_text++ ] = *(pos++); } /////////////////////// // リンク(http)のチェック char tmpreplace[ LNG_LINK +16 ]; // Urlreplaceで変換した後のリンク文字列 int lng_replace = 0; int linktype = check_link( pos, (int)( pos_end - pos ), n_in, tmplink, LNG_LINK ); if( linktype != MISC::SCHEME_NONE ){ // リンクノードで実際にアクセスするURLの変換 while( remove_imenu( tmplink ) ); // ime.nuなどの除去 lng_link = convert_amp( tmplink, strlen( tmplink ) ); // & → & // Urlreplaceによる正規表現変換 std::string tmpurl( tmplink, lng_link ); if( CORE::get_urlreplace_manager()->exec( tmpurl ) == false ){ // 変換されてない lng_replace = lng_link; memcpy( tmpreplace, tmplink, lng_replace +1 ); } else { if( tmpurl.size() > LNG_LINK ){ MISC::ERRMSG( std::string( "too long replaced url : " ) + tmplink ); // 変換後のURLが長すぎるので、元のURLのままにする lng_replace = lng_link; memcpy( tmpreplace, tmplink, lng_replace +1 ); } else { // 正常に変換された lng_replace = tmpurl.size(); memcpy( tmpreplace, tmpurl.c_str(), lng_replace +1 ); // 正規表現変換の結果、スキームだけの簡易チェックをする int delim_pos = 0; if( MISC::SCHEME_NONE == MISC::is_url_scheme( tmpreplace, &delim_pos ) ){ // スキーム http:// が消えていた linktype = MISC::SCHEME_NONE; } } } } // リンクノードか再チェック if( linktype != MISC::SCHEME_NONE ){ // フラッシュしてからリンクノードつくる create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0; // リンクノードの表示テキスト memcpy( tmpstr, pos, n_in ); tmpstr[ n_in ] = '\0'; lng_str = convert_amp( tmpstr, n_in ); // & → & // ssspアイコン if( enable_sssp && linktype == MISC::SCHEME_SSSP ){ create_node_sssp( tmpreplace, lng_replace ); enable_sssp = false; } else { // Urlreplaceによる画像コントロールを取得する int imgctrl = CORE::get_urlreplace_manager()->get_imgctrl( std::string( tmpreplace, lng_replace ) ); // youtubeなどのサムネイル画像リンク if( imgctrl & CORE::IMGCTRL_THUMBNAIL ){ create_node_thumbnail( tmpstr, lng_str, tmplink , lng_link, tmpreplace, lng_replace, COLOR_CHAR_LINK, bold ); } // 画像リンク else if( DBIMG::get_type_ext( tmpreplace, lng_replace ) != DBIMG::T_UNKNOWN ){ create_node_img( tmpstr, lng_str, tmpreplace , lng_replace, COLOR_IMG_NOCACHE, bold ); } // 一般リンク else create_node_link( tmpstr, lng_str, tmpreplace , lng_replace, COLOR_CHAR_LINK, bold ); } pos += n_in; // forのところで++されるので--しておく --pos; continue; } /////////////////////// // 特殊文字デコード if( *pos == '&' ){ const int ret_decode = DBTREE::decode_char( pos, n_in, m_parsed_text + lng_text, n_out, false ); if( ret_decode != NODE_NONE ){ // 文字以外の空白ノードならフラッシュして空白ノード追加 if( ret_decode != NODE_TEXT ){ create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0; create_node_space( ret_decode ); } else lng_text += n_out; pos += n_in; // forのところで++されるので--しておく --pos; continue; } } /////////////////////// // 水平タブ(0x09) if( *pos == 0x09 ){ // フラッシュしてからタブノードをつくる create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0; create_node_htab(); continue; } /////////////////////// // LF(0x0A), CR(0x0D) if( *pos == 0x0A || *pos == 0x0D ){ // 無視する continue; } /////////////////////// // 連続半角空白 if( *pos == ' ' && *( pos + 1 ) == ' ' ){ m_parsed_text[ lng_text++ ] = *(pos++); // フラッシュしてから連続半角ノードを作る create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0; while( *pos == ' ' ) m_parsed_text[ lng_text++ ] = *(pos++); create_node_multispace( m_parsed_text, lng_text ); lng_text = 0; // forのところで++されるので--しておく --pos; continue; } m_parsed_text[ lng_text++ ] = *pos; } create_node_ntext( m_parsed_text, lng_text, color_text, bold ); } // // 書き込みログ比較用文字列作成 // // m_buffer_write に作成した文字列をセットする // // max_lng_write > 0 のときは m_buffer_write の文字数が max_lng_write 以上になったら停止 // void NodeTreeBase::parse_write( const char* str, const int lng, const int max_lng_write ) { if( ! m_buffer_write ) return; #ifdef _DEBUG std::cout << "NodeTreeBase::parse_write lng = " << lng << " max = " << max_lng_write << std::endl; #endif bool head = true; const char* pos = str; const char* pos_end = str + lng; int offset_num; int lng_num; char* pos_write = m_buffer_write; // 行頭の空白は全て除く while( *pos == ' ' ) ++pos; for( ; pos < pos_end && ( max_lng_write == 0 || (int)( pos_write - m_buffer_write ) < max_lng_write ) ; ++pos ){ // タグ if( *pos == '<' ){ //
    if( ( *( pos + 1 ) == 'b' || *( pos + 1 ) == 'B' ) && ( *( pos + 2 ) == 'r' || *( pos + 2 ) == 'R' ) ){ *(pos_write++) = '\n'; pos += 3; } // その他のタグは無視 else while( pos < pos_end && *pos != '>' ) ++pos; continue; } // gt else if( *pos == '&' && ( *( pos + 1 ) == 'g' && *( pos + 2 ) == 't' && *( pos + 3 ) == ';' ) ){ *(pos_write++) = '>'; pos += 3; continue; } // lt else if( *pos == '&' && ( *( pos + 1 ) == 'l' && *( pos + 2 ) == 't' && *( pos + 3 ) == ';' ) ){ *(pos_write++) = '<'; pos += 3; continue; } // amp else if( *pos == '&' && ( *( pos + 1 ) == 'a' && *( pos + 2 ) == 'm' && *( pos + 3 ) == 'p' && *( pos + 4 ) == ';' ) ){ *(pos_write++) = '&'; pos += 4; continue; } // quot else if( *pos == '&' && ( *( pos + 1 ) == 'q' && *( pos + 2 ) == 'u' && *( pos + 3 ) == 'o' && *( pos + 4 ) == 't' && *( pos + 5 ) == ';' ) ){ *(pos_write++) = '"'; pos += 5; continue; } // 先頭のsssp else if( head && *pos == 's' && ( *( pos + 1 ) == 's' && *( pos + 2 ) == 's' && *( pos + 3 ) == 'p' ) ){ // 次のタグ(改行)が来るまで進める while( pos < pos_end && *pos != '>' ) ++pos; continue; } // 水平タブ else if( *pos == '\t' ){ // 空白に置き換える *(pos_write++) = ' '; continue; } // 数字参照 else if( *pos == '&' && *( pos + 1 ) == '#' && ( lng_num = MISC::spchar_number_ln( pos, offset_num ) ) != -1 ){ const int num = MISC::decode_spchar_number( pos, offset_num, lng_num ); const int n_out = MISC::ucs2toutf8( num, pos_write ); pos_write += n_out; pos += offset_num + lng_num; continue; } head = false; *(pos_write++) = *pos; } *pos_write = '\0'; } // // アンカーが現れたかチェックして文字列を取得する関数 // // 入力 // mode : 0 なら >> が先頭に無ければアンカーにしない、1 なら,か+か=があればアンカーにする、2 なら数字が先頭に来たらアンカーにする // str_in : 入力文字列の先頭アドレス // lng_link : str_linkのバッファサイズ // // 出力 // n_in : str_in から何バイト読み取ったか // str_out : (画面に表示される)文字列 // str_link : リンクの文字列 // ancinfo : ancinfo->anc_from 番から ancinfo->anc_to 番までのアンカーが現れた // // 戻り値 : アンカーが現れれば true // const bool NodeTreeBase::check_anchor( const int mode, const char* str_in, int& n_in, char* str_out, char* str_link, int lng_link, ANCINFO* ancinfo ) { char tmp_out[ 64 ]; int lng_out = 0; const char* pos = str_in; n_in = 0; // ">" を最大2回チェック if( mode == 0 ){ for( int i = 0; i < 2; ++i ){ // '>' if( *pos == '&' && *( pos + 1 ) == 'g' && *( pos + 2 ) == 't' ){ tmp_out[ lng_out++ ] = '>'; pos += 4; } // utf-8で">" else if( ( unsigned char )( *pos ) == 0xef && ( unsigned char ) ( *( pos + 1 ) ) == 0xbc && ( unsigned char ) ( *( pos + 2 ) ) == 0x9e ){ tmp_out[ lng_out++ ] = 0xef; tmp_out[ lng_out++ ] = 0xbc; tmp_out[ lng_out++ ] = 0x9e; pos += 3; } else if( i == 0 ) return false; } } // カンマかイコールかプラスをチェック else if( mode == 1 ){ if( *( pos ) == '=' || *( pos ) == ',' || *( pos ) == '+' ){ tmp_out[ lng_out++ ] = *( pos ); str_link[ 0 ] = *( pos ); ++str_link; --lng_link; ++pos; } // utf-8で"、" else if( ( unsigned char )( *pos ) == 0xe3 && ( unsigned char ) ( *( pos + 1 ) ) == 0x80 && ( unsigned char ) ( *( pos + 2 ) ) == 0x81 ){ tmp_out[ lng_out++ ] = 0xe3; tmp_out[ lng_out++ ] = 0x80; tmp_out[ lng_out++ ] = 0x81; str_link[ 0 ] = ','; ++str_link; --lng_link; pos += 3; } else return false; } // 数字かチェック size_t n, dig; int num = MISC::str_to_uint( pos, dig, n ); if( dig == 0 || dig > MAX_LINK_DIGIT || num == 0 ){ // モード2で数字が長すぎるときは飛ばす if( mode == 2 && dig > MAX_LINK_DIGIT ) n_in = ( int )( pos - str_in ) + n; return false; } // アンカーが現れたのでとりあえず作成する // 画面に表示する文字 memcpy( str_out, tmp_out, lng_out ); memcpy( str_out + lng_out, pos, n ); str_out[ lng_out + n ] = '\0'; pos += n; lng_out += n; // をキャンセル if( *( pos ) == '<' && *( pos + 1 ) == '/' && ( *( pos + 2 ) == 'a' || *( pos + 2 ) == 'A' ) && *( pos + 3 ) == '>' ){ pos += 4; // もう一度数字チェック // >>11 を書き込むと >>11 となるため size_t n2, dig2; const int num2 = MISC::str_to_uint( pos, dig2, n2 ); if( dig2 > 0 && dig2 <= MAX_LINK_DIGIT ){ for( size_t i = 0; i < dig2; ++i ) num *= 10; num += num2; memcpy( str_out + lng_out, pos, n2 ); str_out[ lng_out + n2 ] = '\0'; pos += n2; lng_out += n2; } } ancinfo->anc_from = ancinfo->anc_to = num; // アンカー文字 snprintf( str_link, lng_link, "%d", ancinfo->anc_from ); // "-" でつながってる場合同じことをもう一回 int offset = 0; if( *( pos ) == '-' ) offset = 1; // utf-8で"−" else if( ( unsigned char )( * pos ) == 0xef && ( unsigned char ) ( *( pos + 1 ) ) == 0xbc && ( unsigned char ) ( *( pos + 2 ) ) == 0x8d ) offset = 3; // 半角"-" else if( ( unsigned char )( * pos ) == 0xef && ( unsigned char ) ( *( pos + 1 ) ) == 0xbd && ( unsigned char ) ( *( pos + 2 ) ) == 0xb0 ) offset = 3; if( offset ){ ancinfo->anc_to = MAX( ancinfo->anc_from, MISC::str_to_uint( pos + offset, dig, n ) ); if( dig && dig <= MAX_LINK_DIGIT && ancinfo->anc_to ){ // 画面に表示する文字 memcpy( str_out + lng_out, pos, offset + n ); str_out[ lng_out + offset + n ] = '\0'; // アンカー文字をもう一度作成 snprintf( str_link, lng_link, "%d-%d", ancinfo->anc_from, ancinfo->anc_to ); pos += offset + n; lng_out += offset + n; } } //">>数字-数字"のパターンの時にをのぞく if( *( pos ) == '<' && *( pos + 1 ) == '/' && ( *( pos + 2 ) == 'a' || *( pos + 2 ) == 'A' ) && *( pos + 3 ) == '>' ) pos += 4; n_in = ( int )( pos - str_in ); return true; } // // リンクが現れたかチェックして文字列を取得する関数 // // 入力 // str_in : 入力文字列の先頭アドレス // lng_str : str_inのバッファサイズ // lng_link : str_linkのバッファサイズ // linktype : is_url_scheme()のリタンコード // delim_pos : is_url_scheme()で得たスキーム文字列の長さ // // 出力 // n_in : str_in から何バイト読み取ったか // str_link : リンクの文字列 // // 戻り値 : リンクのタイプ(例えばSCHEME_HTTPなど) // // 注意 : MISC::is_url_scheme() と MISC::is_url_char() の仕様に合わせる事 // const int NodeTreeBase::check_link_impl( const char* str_in, const int lng_in, int& n_in, char* str_link, const int lng_link, const int linktype, const int delim_pos ) { // CONFIG::get_loose_url() == true の時はRFCで規定されていない文字も含める const bool loose_url = CONFIG::get_loose_url(); // リンクの長さを取得 n_in = delim_pos; int n_in_tmp, n_out_tmp; char buf[16]; while( n_in < lng_in ){ // URLとして扱う文字かどうか if ( MISC::is_url_char( str_in + n_in, loose_url ) == false ) break; // HTML特殊文字( &〜; ) if ( *( str_in + n_in ) == '&' && DBTREE::decode_char( str_in + n_in, n_in_tmp, buf, n_out_tmp, false ) != DBTREE::NODE_NONE ){ // デコード結果が"&(&)"でないもの if( n_out_tmp != 1 || buf[0] != '&' ) break; } n_in++; } // URLとして短かすぎる場合は除外する( 最短ドメイン名の例 "1.cc" ) if( n_in - delim_pos < 4 ) return MISC::SCHEME_NONE; // URL出力バッファより長いときも除外する( 一般に256バイトを超えるとキャッシュをファイル名として扱えなくなる ) if( lng_link <= n_in ) return MISC::SCHEME_NONE; char *pos = str_link; // URLスキームを修正 int str_pos = 0; switch( linktype ){ // ttp -> http case MISC::SCHEME_TTP: if( n_in + 1 >= lng_link ) return MISC::SCHEME_NONE; *pos = 'h'; pos++; break; // tp -> http case MISC::SCHEME_TP: if( n_in + 2 >= lng_link ) return MISC::SCHEME_NONE; *pos = 'h'; *(++pos) = 't'; pos++; break; // sssp -> http case MISC::SCHEME_SSSP: *pos = 'h'; *(++pos) = 't'; *(++pos) = 't'; pos++; str_pos = 3; break; } // srr_inの文字列をstr_linkにコピー int i = str_pos; for( ; i < n_in; i++, pos++ ){ *pos = str_in[ i ]; // loose_urlで含める"^"と"|"をエンコードする // "[]"はダウンローダに渡す用途のためにエンコードしないでおく if( loose_url == true ){ if( str_in[ i ] == '^' ){ // '^' → "%5E"(+2Byte) if( n_in + 2 >= lng_link ) return MISC::SCHEME_NONE; *pos = '%'; *(++pos) = '5'; *(++pos) = 'E'; } else if( str_in[ i ] == '|' ){ // '|' → "%7C"(+2Byte) if( n_in + 2 >= lng_link ) return MISC::SCHEME_NONE; *pos = '%'; *(++pos) = '7'; *(++pos) = 'C'; } } } // str_linkの終端 *pos = '\0'; #ifdef _DEBUG std::cout << str_link << std::endl << "len = " << strlen( str_link ) << " lng_link = " << lng_link << " n_in + offset = " << n_in + offset << std::endl; #endif return linktype; } // あぼーんしているか bool NodeTreeBase::get_abone( int number ) { NODE* head = res_header( number ); if( ! head ) return false; if( ! head->headinfo ) return false; return head->headinfo->abone; } // あぼーんのクリア void NodeTreeBase::clear_abone() { for( int i = 1; i <= m_id_header; ++i ){ NODE* tmphead = m_vec_header[ i ]; if( tmphead && tmphead->headinfo ) tmphead->headinfo->abone = false; } } // あぼーん情報を親クラスのarticlebaseからコピーする void NodeTreeBase::copy_abone_info( const std::list< std::string >& list_abone_id, const std::list< std::string >& list_abone_name, const std::list< std::string >& list_abone_word, const std::list< std::string >& list_abone_regex, const std::vector< char >& vec_abone_res, const bool abone_transparent, const bool abone_chain, const bool abone_age, const bool abone_board, const bool abone_global ) { m_list_abone_id = list_abone_id; m_list_abone_name = list_abone_name; m_list_abone_id_board = DBTREE::get_abone_list_id_board( m_url ); m_list_abone_name_board = DBTREE::get_abone_list_name_board( m_url ); // 設定ファイルには改行は"\\n"で保存されているので "\n" に変換する m_list_abone_word = MISC::replace_str_list( list_abone_word, "\\n", "\n" ); m_list_abone_regex = MISC::replace_str_list( list_abone_regex, "\\n", "\n" ); m_list_abone_word_board = DBTREE::get_abone_list_word_board( m_url ); m_list_abone_word_board = MISC::replace_str_list( m_list_abone_word_board, "\\n", "\n" ); m_list_abone_regex_board = DBTREE::get_abone_list_regex_board( m_url ); m_list_abone_regex_board = MISC::replace_str_list( m_list_abone_regex_board, "\\n", "\n" ); m_list_abone_word_global = MISC::replace_str_list( CONFIG::get_list_abone_word(), "\\n", "\n" ); m_list_abone_regex_global = MISC::replace_str_list( CONFIG::get_list_abone_regex(), "\\n", "\n" ); m_vec_abone_res = vec_abone_res; if( CONFIG::get_abone_transparent() ) m_abone_transparent = true; else m_abone_transparent = abone_transparent; if( CONFIG::get_abone_chain() ) m_abone_chain = true; else m_abone_chain = abone_chain; m_abone_age = abone_age; m_abone_board = abone_board; m_abone_global = abone_global; } // // 全レスのあぼーん状態の更新 // // 発言数や参照数も更新する // void NodeTreeBase::update_abone_all() { // あぼーん更新 clear_abone(); update_abone( 1, m_id_header ); // 発言数更新 clear_id_name(); update_id_name( 1, m_id_header ); // 参照状態更新 clear_reference(); update_reference( 1, m_id_header ); // フォント判定更新 update_fontid( 1, m_id_header ); } // // from_number番から to_number 番までのレスのあぼーん状態を更新 // void NodeTreeBase::update_abone( const int from_number, const int to_number ) { if( empty() ) return; if( to_number < from_number ) return; for( int i = from_number ; i <= to_number; ++i ){ if( check_abone_res( i ) ) continue; if( check_abone_id( i ) ) continue; if( check_abone_name( i ) ) continue; if( check_abone_mail( i ) ) continue; if( check_abone_word( i ) ) continue; if( check_abone_chain( i ) ) continue; } } // // number番のあぼーん判定(レスあぼーん) // // あぼーんの時はtrueを返す // const bool NodeTreeBase::check_abone_res( const int number ) { if( ! m_vec_abone_res.size() ) return false; if( ! m_vec_abone_res[ number ] ) return false; NODE* head = res_header( number ); if( ! head ) return false; if( ! head->headinfo ) return false; head->headinfo->abone = true; return true; } // // number番のあぼーん判定( id / board id ) // // あぼーんの時はtrueを返す // const bool NodeTreeBase::check_abone_id( const int number ) { const bool check_id = ! m_list_abone_id.empty(); const bool check_id_board = ! m_list_abone_id_board.empty(); if( !check_id && !check_id_board ) return false; NODE* head = res_header( number ); if( ! head ) return false; if( ! head->headinfo ) return false; if( head->headinfo->abone ) return true; if( ! head->headinfo->block[ BLOCK_ID_NAME ] ) return false; const int ln_protoid = strlen( PROTO_ID ); // ローカルID if( check_id ){ std::list< std::string >::iterator it = m_list_abone_id.begin(); for( ; it != m_list_abone_id.end(); ++it ){ // std::string の find は遅いのでstrcmp使う if( strcmp( head->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link + ln_protoid, ( *it ).c_str() ) == 0 ){ head->headinfo->abone = true; return true; } } } // 板レベル ID if( check_id_board ){ std::list< std::string >::iterator it = m_list_abone_id_board.begin(); for( ; it != m_list_abone_id_board.end(); ++it ){ // std::string の find は遅いのでstrcmp使う if( strcmp( head->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link + ln_protoid, ( *it ).c_str() ) == 0 ){ head->headinfo->abone = true; return true; } } } return false; } // // number番のあぼーん判定(name / board name / global name ) // // あぼーんの時はtrueを返す // const bool NodeTreeBase::check_abone_name( const int number ) { const bool check_name = ! m_list_abone_name.empty(); const bool check_name_board = ! m_list_abone_name_board.empty(); const bool check_name_global = ! CONFIG::get_list_abone_name().empty(); if( !check_name && !check_name_board && !check_name_global ) return false; NODE* head = res_header( number ); if( ! head ) return false; if( ! head->headinfo ) return false; if( head->headinfo->abone ) return true; if( ! head->headinfo->name ) return false; std::list< std::string >::const_iterator it; const std::string name_str( head->headinfo->name ); // ローカル name if( check_name ){ it = m_list_abone_name.begin(); for( ; it != m_list_abone_name.end(); ++it ){ if( name_str.find( *it ) != std::string::npos ){ head->headinfo->abone = true; return true; } } } // 板レベル name if( check_name_board ){ it = m_list_abone_name_board.begin(); for( ; it != m_list_abone_name_board.end(); ++it ){ if( name_str.find( *it ) != std::string::npos ){ head->headinfo->abone = true; return true; } } } // 全体 name if( check_name_global ){ it = CONFIG::get_list_abone_name().begin(); for( ; it != CONFIG::get_list_abone_name().end(); ++it ){ if( name_str.find( *it ) != std::string::npos ){ head->headinfo->abone = true; return true; } } } return false; } // // number番のあぼーん判定( mail ) // // あぼーんの時はtrueを返す // const bool NodeTreeBase::check_abone_mail( const int number ) { if( ! m_abone_age ) return false; NODE* head = res_header( number ); if( ! head ) return false; if( ! head->headinfo ) return false; if( head->headinfo->abone ) return true; if( ! head->headinfo->sage ){ head->headinfo->abone = true; return true; } return false; } // // number番のあぼーん判定( word, regex / board word, board regex / global word, global regex ) // // あぼーんの時はtrueを返す // const bool NodeTreeBase::check_abone_word( const int number ) { const bool check_word = ! m_list_abone_word.empty(); const bool check_regex = ! m_list_abone_regex.empty(); const bool check_word_board = ( m_abone_board && ! m_list_abone_word_board.empty() ); const bool check_regex_board = ( m_abone_board && ! m_list_abone_regex_board.empty() ); const bool check_word_global = ( m_abone_global && ! m_list_abone_word_global.empty() ); const bool check_regex_global = ( m_abone_global && ! m_list_abone_regex_global.empty() ); if( !check_word && !check_regex && !check_word_board && !check_regex_board && !check_word_global && !check_regex_global ) return false; NODE* head = res_header( number ); if( ! head ) return false; if( ! head->headinfo ) return false; if( head->headinfo->abone ) return true; const std::string res_str = get_res_str( number ); JDLIB::Regex regex; const size_t offset = 0; const bool icase = CONFIG::get_abone_icase(); const bool newline = true; const bool usemigemo = false; const bool wchar = CONFIG::get_abone_wchar(); // ローカル NG word if( check_word ){ std::list< std::string >::iterator it = m_list_abone_word.begin(); for( ; it != m_list_abone_word.end(); ++it ){ if( res_str.find( *it ) != std::string::npos ){ head->headinfo->abone = true; return true; } } } // ローカル NG regex if( check_regex ){ std::list< std::string >::iterator it = m_list_abone_regex.begin(); for( ; it != m_list_abone_regex.end(); ++it ){ if( regex.exec( *it, res_str, offset, icase, newline, usemigemo, wchar ) ){ head->headinfo->abone = true; return true; } } } // 板レベル NG word if( check_word_board ){ std::list< std::string >::iterator it = m_list_abone_word_board.begin(); for( ; it != m_list_abone_word_board.end(); ++it ){ if( res_str.find( *it ) != std::string::npos ){ head->headinfo->abone = true; return true; } } } // 板レベル NG regex if( check_regex_board ){ std::list< std::string >::iterator it = m_list_abone_regex_board.begin(); for( ; it != m_list_abone_regex_board.end(); ++it ){ if( regex.exec( *it, res_str, offset, icase, newline, usemigemo, wchar ) ){ head->headinfo->abone = true; return true; } } } // 全体 NG word if( check_word_global ){ std::list< std::string >::iterator it = m_list_abone_word_global.begin(); for( ; it != m_list_abone_word_global.end(); ++it ){ if( res_str.find( *it ) != std::string::npos ){ head->headinfo->abone = true; return true; } } } // 全体 NG regex if( check_regex_global ){ std::list< std::string >::iterator it = m_list_abone_regex_global.begin(); for( ; it != m_list_abone_regex_global.end(); ++it ){ if( regex.exec( *it, res_str, offset, icase, newline, usemigemo, wchar ) ){ head->headinfo->abone = true; return true; } } } return false; } // // number番のあぼーん判定(連鎖) // // あぼーんしているレスにアンカーを張っているときはtrueを返す // const bool NodeTreeBase::check_abone_chain( const int number ) { if( !m_abone_chain ) return false; NODE* head = res_header( number ); if( ! head ) return false; if( ! head->headinfo ) return false; if( head->headinfo->abone ) return true; bool abone = false; for( int block = 0; block < BLOCK_NUM; ++block ){ NODE* node = head->headinfo->block[ block ]; while( node ){ // アンカーノードの時は node->linkinfo->ancinfo != NULL; if( node->type == NODE_LINK && node->linkinfo->ancinfo ){ int anc = 0; int anc_from; int anc_to; for(;;){ anc_from = node->linkinfo->ancinfo[ anc ].anc_from; anc_to = node->linkinfo->ancinfo[ anc ].anc_to; if( anc_from == 0 ) break; ++anc; // number-1 番以下のレスだけを見る if( anc_from >= number ) continue; anc_to = MIN( anc_to, number -1 ); // anc_from から anc_to まで全てあぼーんされているかチェック // ひとつでもあぼーんされていないレスが見付かったらあぼーんしない while( anc_from <= anc_to ){ NODE* tmphead = res_header( anc_from++ ); if( tmphead && ! tmphead->headinfo->abone ) return false; } abone = true; } } node = node->next_node; } } head->headinfo->abone = abone; return abone; } // 参照数(num_reference)と色のクリア void NodeTreeBase::clear_reference() { for( int i = 1; i <= m_id_header; ++i ){ NODE* tmphead = m_vec_header[ i ]; if( tmphead && tmphead->headinfo && tmphead->headinfo->block[ BLOCK_NUMBER ]->next_node ){ tmphead->headinfo->num_reference = 0; tmphead->headinfo->block[ BLOCK_NUMBER ]->next_node->color_text = COLOR_CHAR_LINK_RES; } } } // // from_number番から to_number 番までのレスが参照しているレスの参照数を更新 // void NodeTreeBase::update_reference( int from_number, int to_number ) { if( empty() ) return; if( to_number < from_number ) return; for( int i = from_number ; i <= to_number; ++i ) check_reference( i ); } // // number番のレスが参照しているレスのレス番号の参照数(num_reference)と色をチェック // void NodeTreeBase::check_reference( const int number ) { NODE* head = res_header( number ); if( ! head ) return; // 既にあぼーんしているならチェックしない if( head->headinfo->abone ) return; // 2重チェック防止用 bool checked[ MAX_RESNUMBER ]; memset( checked, 0, sizeof( bool ) * MAX_RESNUMBER ); const bool posted = m_vec_posted.size(); // 過去のレスから number 番へのアンカーがあった場合 if( m_map_future_refer.size() ){ std::map< int, std::vector< int > >::iterator it_map = m_map_future_refer.find( number ); if( it_map != m_map_future_refer.end() ){ const int size = ( (*it_map).second ).size(); inc_reference( head, size ); #ifdef _DEBUG std::cout << "found number = " << number << " size = " << size << std::endl; #endif // 過去のレスへ自分の書き込みへの参照マークを付ける if( posted && m_vec_posted[ number ] ){ for( int i = 0; i < size; ++ i ){ const int from = ( (*it_map).second )[ i ]; #ifdef _DEBUG std::cout << "from " << from << std::endl; #endif NODE* tmphead = res_header( from ); if( tmphead && ! tmphead->headinfo->abone ){ if( ! m_vec_refer_posted.size() ) m_vec_refer_posted.resize( MAX_RESNUMBER ); m_vec_refer_posted[ from ] = true; } } } m_map_future_refer.erase( it_map ); #ifdef _DEBUG std::cout << "map_future_refer size = " << m_map_future_refer.size() << std::endl; #endif } } for( int block = 0; block < BLOCK_NUM; ++block ){ NODE* node = head->headinfo->block[ block ]; while( node ){ if( node->type == NODE_LINK ){ // アンカーノードの時は node->linkinfo->ancinfo != NULL; if( node->linkinfo->ancinfo ){ int anc = 0; int anc_from; int anc_to; for(;;){ anc_from = node->linkinfo->ancinfo[ anc ].anc_from; anc_to = node->linkinfo->ancinfo[ anc ].anc_to; if( anc_from == 0 ) break; ++anc; anc_to = MIN( anc_to, MAX_RESNUMBER ); // >>1-1000 みたいなアンカーは弾く if( anc_to - anc_from >= RANGE_REF ) continue; for( int i = anc_from; i <= anc_to ; ++i ){ // 既にチェックしている if( checked[ i ] ) continue; // 自分自身 if( i == number ) continue; // 未来へのレス if( i > number ){ #ifdef _DEBUG std::cout << "future ref " << i << " from " << number << std::endl; #endif std::map< int, std::vector< int > >::iterator it_map = m_map_future_refer.find( i ); if( it_map != m_map_future_refer.end() ){ ( (*it_map).second ).push_back( number ); #ifdef _DEBUG std::cout << "found size = " << ( (*it_map).second ).size() << std::endl; #endif } else{ #ifdef _DEBUG std::cout << "not found\n"; #endif std::pair< int, std::vector< int > > tmp_pair; tmp_pair.first = i; tmp_pair.second.push_back( number ); m_map_future_refer.insert( tmp_pair ); } continue; } // 過去へのレス NODE* tmphead = res_header( i ); if( tmphead && ! tmphead->headinfo->abone // 対象スレがあぼーんしていたらカウントしない && tmphead->headinfo->block[ BLOCK_NUMBER ] ){ checked[ i ] = true; // 自分の書き込みに対するレス if( posted && m_vec_posted[ i ] ){ if( ! m_vec_refer_posted.size() ) m_vec_refer_posted.resize( MAX_RESNUMBER ); m_vec_refer_posted[ number ] = true; #ifdef _DEBUG std::cout << "ref " << i << " from " << number << std::endl; #endif } inc_reference( tmphead, 1 ); } } } } } node = node->next_node; } // while( node ) } // for( block ) } // // 参照数を count だけ増やしてして色を変更 // void NodeTreeBase::inc_reference( NODE* head, const int count ) { head->headinfo->num_reference += count; // 参照回数大 if( head->headinfo->num_reference >= m_num_reference[ LINK_HIGH ] ) head->headinfo->block[ BLOCK_NUMBER ]->next_node->color_text = COLOR_CHAR_LINK_HIGH; // 参照回数中 else if( head->headinfo->num_reference >= m_num_reference[ LINK_LOW ] ) head->headinfo->block[ BLOCK_NUMBER ]->next_node->color_text = COLOR_CHAR_LINK_LOW; // 参照無し else head->headinfo->block[ BLOCK_NUMBER ]->next_node->color_text = COLOR_CHAR_LINK_RES; } // 発言数(( num_id_name ))とIDの色のクリア void NodeTreeBase::clear_id_name() { for( int i = 1; i <= m_id_header; ++i ){ NODE* tmphead = m_vec_header[ i ]; if( tmphead && tmphead->headinfo && tmphead->headinfo->block[ BLOCK_ID_NAME ] ){ tmphead->headinfo->num_id_name = 0; tmphead->headinfo->block[ BLOCK_ID_NAME ]->next_node->color_text = COLOR_CHAR; } } } // // from_number番から to_number 番までの発言数の更新 // void NodeTreeBase::update_id_name( const int from_number, const int to_number ) { if( ! CONFIG::get_check_id() ) return; if( empty() ) return; if( to_number < from_number ) return; for( int i = from_number ; i <= to_number; ++i ) check_id_name( i ); } // // number番のレスの発言数を更新 // void NodeTreeBase::check_id_name( const int number ) { NODE* header = res_header( number ); if( ! header ) return; // if( header->headinfo->abone ) return; if( ! header->headinfo->block[ BLOCK_ID_NAME ] ) return; const char* str_id = header->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link; // 同じIDのレスを持つ一つ前のレスを探す NODE* tmphead; NODE* prehead = NULL; for( int i = header->id_header -1 ; i >= 1 ; --i ){ tmphead = m_vec_header[ i ]; if( tmphead // && ! tmphead->headinfo->abone // 対象スレがあぼーんしていたらカウントしない && tmphead->headinfo->block[ BLOCK_ID_NAME ] && str_id[ 0 ] == tmphead->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link[ 0 ] && strcmp( str_id, tmphead->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link ) == 0 ){ prehead = tmphead; break; } } // 見つからなかった if( ! prehead ) set_num_id_name( header, 1, NULL ); // 見つかった else{ set_num_id_name( header, prehead->headinfo->num_id_name+1, prehead ); // 以前に出た同じIDのレスの発言数を更新 tmphead = prehead; while( tmphead ){ set_num_id_name( tmphead, tmphead->headinfo->num_id_name+1, tmphead->headinfo->pre_id_name_header ); tmphead = tmphead->headinfo->pre_id_name_header; } } } // // 発言数( num_id_name )の更新 // // IDノードの色も変更する // void NodeTreeBase::set_num_id_name( NODE* header, const int num_id_name, NODE* pre_id_name_header ) { if( ! header->headinfo->block[ BLOCK_ID_NAME ] ) return; header->headinfo->num_id_name = num_id_name; header->headinfo->pre_id_name_header = pre_id_name_header; if( num_id_name >= m_num_id[ LINK_HIGH ] ) header->headinfo->block[ BLOCK_ID_NAME ]->next_node->color_text = COLOR_CHAR_LINK_ID_HIGH; else if( num_id_name >= m_num_id[ LINK_LOW ] ) header->headinfo->block[ BLOCK_ID_NAME ]->next_node->color_text = COLOR_CHAR_LINK_ID_LOW; else header->headinfo->block[ BLOCK_ID_NAME ]->next_node->color_text = COLOR_CHAR; } // // from_number番から to_number 番までのレスのフォント判定を更新 // void NodeTreeBase::update_fontid( const int from_number, const int to_number ) { if( empty() ) return; if( to_number < from_number ) return; for( int i = from_number ; i <= to_number; ++i ) check_fontid( i ); } // // number番のレスのフォント判定を更新 // void NodeTreeBase::check_fontid( const int number ) { NODE* head = res_header( number ); if( ! head ) return; if( ! head->headinfo ) return; if( head->fontid != FONT_EMPTY ) return; // ヘッダノードには、フォント判定済みの意味を兼ねて、デフォルトフォントを設定しておく head->fontid = FONT_DEFAULT; if( m_aa_regex.empty() ) return; char fontid_mes = FONT_DEFAULT; // 本文のフォント(fontid.h) // AAフォント判定 const std::string res_str = get_res_str( number ); JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( m_aa_regex, res_str, offset, icase, newline, usemigemo, wchar ) ){ fontid_mes = FONT_AA; #ifdef _DEBUG std::cout << "NodeTreeBase::check_fontid() fontid = " << FONT_AA << " res = " << number << std::endl; #endif } // 本文のフォントを設定 if( fontid_mes != FONT_DEFAULT ){ NODE *node = head->headinfo->block[ BLOCK_MES ]; while (node) { node->fontid = fontid_mes; node = node->next_node; } } } // // http://ime.nu/ などをリンクから削除 // // 取り除いたらtrueを返す // // Thanks to 「パッチ投稿」スレの24氏 // // http://jd4linux.sourceforge.jp/cgi-bin/bbs/test/read.cgi/support/1151836078/24 // bool NodeTreeBase::remove_imenu( char* str_link ) { const int lng_http = 7; // = strlen( "http://" ); if( ! ( ( str_link[ lng_http ] == 'i' && str_link[ lng_http + 1 ] == 'm' ) || ( str_link[ lng_http ] == 'n' && str_link[ lng_http + 1 ] == 'u' ) || ( str_link[ lng_http ] == 'p' && str_link[ lng_http + 1 ] == 'i' ) ) ) return false; if( memcmp( str_link, "http://ime.nu/", 14 ) == 0 || memcmp( str_link, "http://ime.st/", 14 ) == 0 || memcmp( str_link, "http://nun.nu/", 14 ) == 0 || memcmp( str_link, "http://pinktower.com/", 21 ) == 0 ) { int linklen = strlen( str_link ); int cutsize = 0; if( str_link[ lng_http ] == 'p' ) cutsize = 14; // = strlen( "pinktower.com/" ) else cutsize = 7; // = strlen( "ime.nu/" ) // "http://ime.nu/"等、URLがそれだけだった場合は削除しない if( linklen == lng_http + cutsize ) return false; memmove( str_link + lng_http, str_link + lng_http + cutsize, linklen + 1 - ( lng_http + cutsize ) ); return true; } return false; } // 文字列中の"&"を"&"に変換する int NodeTreeBase::convert_amp( char* text, const int n ) { int m = n; int i; for( i = 0; i < m; i++ ){ if( text[ i ] == '&' && m > (i + 4) && text[i + 1] == 'a' && text[i + 2] == 'm' && text[i + 3] == 'p' && text[i + 4] == ';' ){ // &の次, &の次, &の次からの長さ memmove( text + i + 1, text + i + 5, n - i - 5 ); // "amp;"の分減らす m -= 4; } } text[m] = '\0'; return m; } // 自分の書き込みにレスしたか const bool NodeTreeBase::is_refer_posted( const int number ) { if( ! m_vec_refer_posted.size() ) return false; if( m_vec_refer_posted.size() <= ( size_t )number ) return false; return m_vec_refer_posted[ number ]; } // 書き込みマークセット void NodeTreeBase::set_posted( const int number, const bool set ) { if( ! m_vec_posted.size() ) m_vec_posted.resize( MAX_RESNUMBER ); if( ! m_vec_refer_posted.size() ) m_vec_refer_posted.resize( MAX_RESNUMBER ); m_vec_posted[ number ] = set; // 自分の書き込みに対するレス std::list< int > res_num = get_res_reference( number ); std::list< int >::const_iterator it_res = res_num.begin(); // レスされたマークを設定する if( set ){ for( ; it_res != res_num.end(); ++it_res ){ const int n = ( *it_res ); m_vec_refer_posted[ n ] = true; } } // レスされてなくなったので、マークを解除する else{ for( ; it_res != res_num.end(); ++it_res ){ const int n = ( *it_res ); // レスアンカーのリストを取得 std::list< ANCINFO* > anchors = get_res_anchors( n ); std::list< ANCINFO* >::const_iterator it_anchor = anchors.begin(); for( ; it_anchor != anchors.end(); ++it_anchor ){ // 他の自分の書き込みに対するレスになっていないか? ANCINFO* anchor = ( *it_anchor ); for( int i = anchor->anc_from; i <= anchor->anc_to; i++ ){ // 他の自分の書き込みに対するレス if( m_vec_posted[ i ] ) goto KEEP_POSTMARK; } } // マークを解除する m_vec_refer_posted[ n ] = false; KEEP_POSTMARK:; } } } // 書き込み履歴のリセット void NodeTreeBase::clear_post_history() { m_vec_posted.clear(); m_vec_refer_posted.clear(); } jd-2.8.7-140104/src/dbtree/nodetreebase.h0000644000076400010400000004070312125473343014445 0ustar // ライセンス: GPL2 // // ノードツリー( DOMみたいな木構造 )のベースクラス および DAT & HTMLパーサ // #ifndef _NODETREEBASE_H #define _NODETREEBASE_H #include "node.h" #include "skeleton/loadable.h" #include "jdlib/heap.h" #include "jdlib/miscutil.h" #include #include namespace JDLIB { class LOADERDATA; } namespace DBTREE { enum { LINK_LOW = 0, LINK_HIGH, LINK_NUM }; enum { RESUME_CHKSIZE = 64 }; //ノードツリーのベースクラス class NodeTreeBase : public SKELETON::Loadable { typedef sigc::signal< void > SIG_UPDATED; typedef sigc::signal< void > SIG_FINISHED; SIG_UPDATED m_sig_updated; SIG_UPDATED m_sig_finished; std::string m_url; std::string m_default_noname; // コード変換前の生データのサイズ ( byte ) size_t m_lng_dat; // レジュームのモード int m_resume; // レジューム時のチェック用 // 生データの先頭から RESUME_CHKSIZE バイト分を入れる char m_resume_head[ RESUME_CHKSIZE ]; // レジューム中にスキップした生データサイズ size_t m_resume_lng; // 現在処理中のヘッダ番号( つまりロード中でないなら総レス数になる ) int m_id_header; // サーバー側であぼーんがあったりしてスレが壊れている bool m_broken; JDLIB::HEAP m_heap; NODE** m_vec_header; // レスのヘッダのポインタの配列 std::string m_subject; // 参照で色を変える回数 int m_num_reference[ LINK_NUM ]; // 発言数で色を変える回数 int m_num_id[ LINK_NUM ]; // あぼーん情報 // 実体は親のarticlebaseクラスが持っていてcopy_abone_info()でコピーする std::list< std::string > m_list_abone_id; // あぼーんするID std::list< std::string > m_list_abone_name; // あぼーんする名前 std::list< std::string > m_list_abone_word; // あぼーんする文字列 std::list< std::string > m_list_abone_regex; // あぼーんする正規表現 std::list< std::string > m_list_abone_id_board; // あぼーんするID(板レベル) std::list< std::string > m_list_abone_name_board; // あぼーんする名前(板レベル) std::list< std::string > m_list_abone_word_board; // あぼーんする文字列(板レベル) std::list< std::string > m_list_abone_regex_board; // あぼーんする正規表現(板レベル) std::list< std::string > m_list_abone_word_global; // あぼーんする文字列(全体) std::list< std::string > m_list_abone_regex_global; // あぼーんする正規表現(全体) std::vector< char > m_vec_abone_res; // レスあぼーん情報 bool m_abone_transparent; // 透明あぼーん bool m_abone_chain; // 連鎖あぼーん bool m_abone_age; // age ているレスはあぼーん bool m_abone_board; // 板レベルでのあぼーんを有効にする bool m_abone_global; // 全体レベルでのあぼーんを有効にする // 自分が書き込んだレスか std::vector< char > m_vec_posted; // 自分の書き込みにレスしているか std::vector< char > m_vec_refer_posted; // 未来のレスに対するアンカーがある時に使用する // check_reference() を参照 std::map< int, std::vector< int > > m_map_future_refer; // ロード用変数 char* m_buffer_lines; size_t m_byte_buffer_lines_left; char* m_parsed_text; char* m_buffer_write; // 書き込みチェック用バッファ bool m_check_update; // HEADによる更新チェックのみ bool m_check_write; // 自分の書き込みかチェックする bool m_loading_newthread; // 新スレ読み込み中 // キャッシュ保存用ファイルハンドラ FILE *m_fout; // パース用雑用変数 NODE* m_node_previous; // AA判定用 std::string m_aa_regex; // その他のエラーメッセージ std::string m_ext_err; protected: void set_resume( const bool resume ); void set_broken( const bool broken ) { m_broken = broken; } const int id_header() const { return m_id_header; } void set_ext_err( const std::string& ext_err ){ m_ext_err = ext_err; } public: NodeTreeBase( const std::string& url, const std::string& date_modified ); virtual ~NodeTreeBase(); bool empty(); void update_url( const std::string& url ); SIG_UPDATED& sig_updated() { return m_sig_updated; } SIG_FINISHED& sig_finished() { return m_sig_finished; } // キャッシュかららロード void load_cache(); const std::string& get_url() const { return m_url; } const std::string& get_subject() const { return m_subject; } const int get_res_number(); const size_t get_lng_dat() const { return m_lng_dat; } const bool is_broken() const{ return m_broken; } const std::string& get_ext_err() const { return m_ext_err; } const bool is_checking_update() const { return m_check_update; } // number番のレスのヘッダノードのポインタを返す NODE* res_header( int number ); // number番の名前 const std::string get_name( int number ); // number番の名前の重複数( = 発言数 ) int get_num_name( int number ); // 指定した発言者の名前のレス番号をリストにして取得 std::list< int > get_res_name( const std::string& name ); // number番のレスの時刻を文字列で取得 // 内部で regex を使っているので遅い const std::string get_time_str( int number ); // number番のID const std::string get_id_name( int number ); // 指定したID の重複数( = 発言数 ) // 下のget_num_id_name( int number )と違って検索するので遅い const int get_num_id_name( const std::string& id ); // number番のID の重複数( = 発言数 ) const int get_num_id_name( const int number ); // 指定した発言者IDを持つレス番号をリストにして取得 std::list< int > get_res_id_name( const std::string& id_name ); // str_num で指定したレス番号をリストにして取得 // str_num は "from-to" の形式 (例) 3から10をセットしたいなら "3-10" // list_jointは出力で true のスレは前のスレに連結される (例) "3+4" なら 4が3に連結 std::list< int > get_res_str_num( const std::string& str_num, std::list< bool >& list_joint ); // URL を含むレス番号をリストにして取得 std::list< int > get_res_with_url(); // 含まれる URL をリストにして取得 std::list< std::string > get_urls(); // number番のレスを参照しているレス番号をリストにして取得 std::list< int > get_res_reference( const int number ); // res_num に含まれるレスを参照しているレス番号をリストにして取得 std::list< int > get_res_reference( const std::list< int >& res_num ); // query を含むレス番号をリストにして取得 // mode_or == true なら OR抽出 const std::list< int > get_res_query( const std::string& query, const bool mode_or ); // number番のレスの文字列を返す // ref == true なら先頭に ">" を付ける const std::string get_res_str( int number, bool ref = false ); // number 番のレスの生文字列を返す const std::string get_raw_res_str( int number ); // 明示的にhtml を加える // パースして追加したノードのポインタを返す // html は UTF-8 であること NODE* append_html( const std::string& html ); // 明示的にdat を加える // パースして追加したノードのポインタを返す // dat は UTF-8 であること NODE* append_dat( const std::string& dat ); // ロード開始 // check_update : HEADによる更新チェックのみ virtual void download_dat( const bool check_update ); // あぼーんしているか bool get_abone( int number ); // あぼーん情報を親クラスのarticlebaseからコピーする void copy_abone_info( const std::list< std::string >& list_abone_id, const std::list< std::string >& list_abone_name, const std::list< std::string >& list_abone_word, const std::list< std::string >& list_abone_regex, const std::vector< char >& vec_abone_res, const bool abone_transparent, const bool abone_chain, const bool abone_age, const bool abone_board, const bool abone_global ); // 全レスのあぼーん状態の更新 // 発言数や参照数も更新する void update_abone_all(); // 自分が書き込んだレスか void copy_post_info( const std::vector< char >& vec_posted ){ m_vec_posted = vec_posted; } const std::vector< char >& get_vec_posted(){ return m_vec_posted; } // 自分の書き込みにレスしたか const bool is_refer_posted( const int number ); // 書き込みマークセット void set_posted( const int number, const bool set ); // 書き込み履歴のリセット void clear_post_history(); protected: virtual void clear(); virtual void init_loading(); // ロード用データ作成 virtual void create_loaderdata( JDLIB::LOADERDATA& data ){} // 保存前にrawデータを加工 // デフォルトでは何もしない virtual char* process_raw_lines( char* rawlines ){ return rawlines; } // raw データを dat に変換 // デフォルトでは何もしない virtual const char* raw2dat( char* rawlines, int& byte ){ byte = strlen( rawlines ); return rawlines; } virtual void receive_data( const char* data, size_t size ); virtual void receive_finish(); private: NODE* create_node(); NODE* create_node_header(); NODE* create_node_block(); NODE* create_node_idnum(); NODE* create_node_br(); NODE* create_node_hr(); NODE* create_node_space( const int type ); NODE* create_node_multispace( const char* text, const int n ); NODE* create_node_htab(); NODE* create_node_link( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold ); NODE* create_node_anc( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold, const ANCINFO* ancinfo, const int lng_ancinfo ); NODE* create_node_sssp( const char* link, const int n_link ); NODE* create_node_img( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold ); NODE* create_node_text( const char* text, const int color_text, const bool bold = false ); NODE* create_node_ntext( const char* text, const int n, const int color_text, const bool bold = false ); NODE* create_node_thumbnail( const char* text, const int n, const char* link, const int n_link, const char* thumb, const int n_thumb, const int color_text, const bool bold ); // 以下、構文解析用関数 void add_raw_lines( char* rawines, size_t size ); const char* add_one_dat_line( const char* datline ); void parse_name( NODE* header, const char* str, const int lng, const int color_name ); void parse_mail( NODE* header, const char* str, const int lng ); void parse_date_id( NODE* header, const char* str, const int lng ); // HTMLパーサ // digitlink : true の時は先頭に数字が現れたらアンカーにする( parse_name() などで使う ) // false なら数字の前に >> がついてるときだけアンカーにする // bold : ボールド表示 // ahref : からリンクノードを作成する // enable_sssp : true の時はssspアイコンを有効にする( ssspは 1 スレ 1 つだけアイコン表示) void parse_html( const char* str, const int lng, const int color_text, bool digitlink, const bool bold, const bool ahref, const bool sssp ); // 書き込みログ比較用文字列作成 // m_buffer_write に作成した文字列をセットする void parse_write( const char* str, const int lng, const int max_lng_write ); const bool check_anchor( const int mode, const char* str_in, int& n, char* str_out, char* str_link, int lng_link, ANCINFO* ancinfo ); const int check_link( const char* str_in, const int lng_in, int& n_in, char* str_link, const int lng_link ); const int check_link_impl( const char* str_in, const int lng_in, int& n_in, char* str_link, const int lng_link, const int linktype, const int delim_pos ); // あぼーんのクリア void clear_abone(); // from_number番から to_number 番までのレスのあぼーん状態を更新 void update_abone( const int from_number, const int to_number ); // あぼーんチェック const bool check_abone_res( const int number ); const bool check_abone_id( const int number ); const bool check_abone_name( const int number ); const bool check_abone_mail( const int number ); const bool check_abone_word( const int number ); const bool check_abone_chain( const int number ); // number番のレスに含まれるレスアンカーをリストにして取得 std::list< ANCINFO* > get_res_anchors( const int number ); // 参照数(num_reference)と色のクリア void clear_reference(); // from_number番から to_number 番までのレスが参照しているレスの参照数を更新 void update_reference( int from_number, int to_number ); // number番のレスが参照しているレスのレス番号の参照数(num_reference)と色をチェック void check_reference( const int number ); // 参照数を count だけ増やしてして色を変更 void inc_reference( NODE* head, const int count ); // 発言数とIDの色のクリア void clear_id_name(); // from_number番から to_number 番までの発言数の更新 void update_id_name( const int from_number, const int to_number ); // number番のレスの発言数をチェック void check_id_name( const int number ); // 発言数( num_id_name )の更新 // IDノードの色も変更する void set_num_id_name( NODE* header, const int num_id_name, NODE* pre_id_name_header ); // from_number番から to_number 番までのレスのフォント判定を更新 void update_fontid( const int from_number, const int to_number ); // number番のレスのフォント判定を更新 void check_fontid( const int number ); // http://ime.nu/ などをリンクから削除 bool remove_imenu( char* str_link ); // 文字列中の"&"を"&"に変換する int convert_amp( char* text, const int n ); }; // // リンクが現れたかチェックして文字列を取得する関数 // (引数の値は、check_link_impl()を見ること) // inline const int NodeTreeBase::check_link( const char* str_in, const int lng_in, int& n_in, char* str_link, const int lng_link ) { // http://, https://, ftp://, ttp(s)://, tp(s):// のチェック int delim_pos = 0; const int linktype = MISC::is_url_scheme( str_in, &delim_pos ); if( linktype == MISC::SCHEME_NONE ) return linktype; return check_link_impl( str_in, lng_in, n_in, str_link, lng_link, linktype, delim_pos ); } } #endif jd-2.8.7-140104/src/dbtree/nodetreedummy.cpp0000644000076400010400000000072111160730160015204 0ustar // ライセンス: GPL2 // #define _DEBUG #include "jddebug.h" #include "nodetreedummy.h" using namespace DBTREE; NodeTreeDummy::NodeTreeDummy( const std::string& url ) : NodeTreeBase( url, std::string() ) { #ifdef _DEBUG std::cout << "NodeTreeDummy::NodeTreeDummy : " << get_url() << std::endl; #endif } NodeTreeDummy::~NodeTreeDummy() { #ifdef _DEBUG std::cout << "NodeTreeDummy::~NodeTreeDummy : " << get_url() << std::endl; #endif } jd-2.8.7-140104/src/dbtree/nodetreedummy.h0000644000076400010400000000074111160730160014653 0ustar // ライセンス: GPL2 // // ARTICLE::LayoutTree::append_html() で使用するダミーノードツリー // #ifndef _NODETREEDUMMY_H #define _NODETREEDUMMY_H #include "nodetreebase.h" namespace DBTREE { class NodeTreeDummy : public NodeTreeBase { public: NodeTreeDummy( const std::string& url ); virtual ~NodeTreeDummy(); // ダウンロードしない virtual void download_dat( const bool check_update ){} }; } #endif jd-2.8.7-140104/src/dbtree/nodetreejbbs.cpp0000644000076400010400000001513211154766170015010 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "nodetreejbbs.h" #include "interface.h" #include "jdlib/jdiconv.h" #include "jdlib/loaderdata.h" #include "config/globalconf.h" #include "global.h" #include #define APPEND_SECTION( num ) do {\ if( lng_sec[ num ] ){ \ assert( byte + lng_sec[ num ] < BUF_SIZE_ICONV_OUT ); \ memcpy( m_decoded_lines + byte, lines + pos_sec[ num ], lng_sec[ num ] ); \ byte += lng_sec[ num ]; \ } } while( 0 ) using namespace DBTREE; NodeTreeJBBS::NodeTreeJBBS( const std::string& url, const std::string& date_modified ) : NodeTreeBase( url, date_modified ) , m_iconv( 0 ) , m_decoded_lines( 0 ) { #ifdef _DEBUG std::cout << "NodeTreeJBBS::NodeTreeJBBS url = " << get_url() << " modified = " << date_modified << std::endl; #endif } NodeTreeJBBS::~NodeTreeJBBS() { #ifdef _DEBUG std::cout << "NodeTreeJBBS::~NodeTreeJBBS : " << get_url() << std::endl; #endif clear(); } // // バッファなどのクリア // void NodeTreeJBBS::clear() { #ifdef _DEBUG std::cout << "NodeTreeJBBS::clear : " << get_url() << std::endl; #endif NodeTreeBase::clear(); // iconv 削除 if( m_iconv ) delete m_iconv; m_iconv = NULL; if( m_decoded_lines ) free( m_decoded_lines ); m_decoded_lines = NULL; } // // ロード実行前に呼ぶ初期化関数 // void NodeTreeJBBS::init_loading() { #ifdef _DEBUG std::cout << "NodeTreeJBBS::init_loading : " << get_url() << std::endl; #endif NodeTreeBase::init_loading(); // iconv 初期化 std::string charset = DBTREE::board_charset( get_url() ); if( ! m_iconv ) m_iconv = new JDLIB::Iconv( charset, "UTF-8" ); if( ! m_decoded_lines ) m_decoded_lines = ( char* )malloc( BUF_SIZE_ICONV_OUT ); } // // ロード用データ作成 // void NodeTreeJBBS::create_loaderdata( JDLIB::LOADERDATA& data ) { std::stringstream ss; ss << get_url() << "/"; // レジュームはしない代わりにスレを直接指定 set_resume( false ); if( id_header() ) ss << id_header() + 1 << "-"; data.url = ss.str(); data.agent = DBTREE::get_agent( get_url() ); data.host_proxy = DBTREE::get_proxy_host( get_url() ); data.port_proxy = DBTREE::get_proxy_port( get_url() ); data.basicauth_proxy = DBTREE::get_proxy_basicauth( get_url() ); data.size_buf = CONFIG::get_loader_bufsize(); data.timeout = CONFIG::get_loader_timeout(); if( ! get_date_modified().empty() ) data.modified = get_date_modified(); #ifdef _DEBUG std::cout << "NodeTreeJBBS::create_loader : " << data.url << std::endl; #endif } // // raw データを dat 形式に変換 // enum { MIN_SECTION = 5, MAX_SECTION = 8 }; const char* NodeTreeJBBS::raw2dat( char* rawlines, int& byte ) { assert( m_iconv != NULL ); assert( m_decoded_lines != NULL ); int byte_lines; const char* lines = m_iconv->convert( rawlines, strlen( rawlines ), byte_lines ); int number = id_header() + 1; #ifdef _DEBUG std::cout << "NodeTreeJBBS::raw2dat : byte_lines = " << byte_lines << std::endl; #endif // セクション分けして再合成する byte = 0; int pos = 0; int section = 0; int pos_sec[ MAX_SECTION ]; int lng_sec[ MAX_SECTION ]; memset( lng_sec, 0, sizeof( int ) * MAX_SECTION ); while( pos < byte_lines ){ // セクション分け pos_sec[ section ] = pos; while( !( lines[ pos ] == '<' && lines[ pos +1 ] == '>' ) && lines[ pos ] != '\n' && pos < byte_lines ) ++pos; lng_sec[ section ] = pos - pos_sec[ section ]; // 最後の行で、かつ壊れている場合 if( pos >= byte_lines ){ set_broken( true ); break; } // スレを2ch型に再構築して改行 if( lines[ pos ] == '\n' ){ // セクション数が MIN_SECTION より小さい時はスレが壊れている if( section >= MIN_SECTION ){ // 透明あぼーんの判定 char number_str[ 64 ]; memset( number_str, 0, 64 ); memcpy( number_str, lines + pos_sec[ 0 ], MIN( lng_sec[ 0 ], 64 -1 ) ); int number_in = atoi( number_str ); while( number_in > number ){ #ifdef _DEBUG std::cout << "abone : number = "<< number << " : " << number_in << std::endl; #endif char broken_str[] = "あぼ〜ん<><>あぼ〜ん<> あぼ〜ん <>\n"; int lng_broken = strlen( broken_str ); memcpy( m_decoded_lines + byte, broken_str, lng_broken ); byte += lng_broken; ++number; } // 名前 APPEND_SECTION( 1 ); memcpy( m_decoded_lines + byte, "<>", 2 ); byte += 2; // メアド APPEND_SECTION( 2 ); memcpy( m_decoded_lines + byte, "<>", 2 ); byte += 2; // 日付 APPEND_SECTION( 3 ); // ID int i = 6; if( lng_sec[ i ] ){ memcpy( m_decoded_lines + byte, " ID:", 4 ); byte += 4; memcpy( m_decoded_lines + byte, lines + pos_sec[ i ], lng_sec[ i ] ); byte += lng_sec[ i ]; } memcpy( m_decoded_lines + byte, "<>", 2 ); byte += 2; // 本文 APPEND_SECTION( 4 ); memcpy( m_decoded_lines + byte, "<>", 2 ); byte += 2; // タイトル APPEND_SECTION( 5 ); m_decoded_lines[ byte++ ] = '\n'; ++number; } // 新しい行へ移動 ++pos; section = 0; memset( lng_sec, 0, sizeof( int ) * MAX_SECTION ); } // 次のセクションへ移動 else{ pos += 2; ++section; // 壊れている if( section >= MAX_SECTION ){ #ifdef _DEBUG std::cout << "NodeTreeJBBS::raw2dat : broken section = " << section-1 << std::endl; #endif set_broken( true ); // その行は飛ばす while( lines[ pos ] != '\n' && pos < byte_lines ) ++pos; ++pos; section = 0; memset( lng_sec, 0, sizeof( int ) * MAX_SECTION ); } } } m_decoded_lines[ byte ] = '\0'; #ifdef _DEBUG std::cout << "byte = " << byte << std::endl; #endif return m_decoded_lines; } jd-2.8.7-140104/src/dbtree/nodetreejbbs.h0000644000076400010400000000124411140340236014436 0ustar // ライセンス: GPL2 // // JBBS型ノードツリー // #ifndef _NODETREEJBBS_H #define _NODETREEJBBS_H #include "nodetreebase.h" namespace JDLIB { class Iconv; } namespace DBTREE { class NodeTreeJBBS : public NodeTreeBase { JDLIB::Iconv* m_iconv; char* m_decoded_lines; public: NodeTreeJBBS( const std::string& url, const std::string& date_modified ); ~NodeTreeJBBS(); protected: virtual void clear(); virtual void init_loading(); virtual void create_loaderdata( JDLIB::LOADERDATA& data ); virtual const char* raw2dat( char* rawlines, int& byte ); }; } #endif jd-2.8.7-140104/src/dbtree/nodetreelocal.cpp0000644000076400010400000000072611160730160015150 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "nodetreelocal.h" using namespace DBTREE; NodeTreeLocal::NodeTreeLocal( const std::string& url ) : NodeTree2chCompati( url, std::string() ) { #ifdef _DEBUG std::cout << "NodeTreeLocal::NodeTreeLocal url = " << get_url() << std::endl; #endif } NodeTreeLocal::~NodeTreeLocal() { #ifdef _DEBUG std::cout << "NodeTreeLocal::~NodeTreeLocal : " << get_url() << std::endl; #endif } jd-2.8.7-140104/src/dbtree/nodetreelocal.h0000644000076400010400000000071511160730160014613 0ustar // ライセンス: GPL2 // // ローカルファイル用ノードツリー // #ifndef _NODETREELOCAL_H #define _NODETREELOCAL_H #include "nodetree2chcompati.h" namespace DBTREE { class NodeTreeLocal : public NodeTree2chCompati { public: NodeTreeLocal( const std::string& url ); virtual ~NodeTreeLocal(); // ダウンロードしない virtual void download_dat( const bool check_update ){} }; } #endif jd-2.8.7-140104/src/dbtree/nodetreemachi.cpp0000644000076400010400000002636311405713530015150 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "nodetreemachi.h" #include "interface.h" #include "jdlib/jdiconv.h" #include "jdlib/jdregex.h" #include "jdlib/loaderdata.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "config/globalconf.h" #include "global.h" #include "httpcode.h" #include using namespace DBTREE; enum { BUF_SIZE_200 = 256 }; NodeTreeMachi::NodeTreeMachi( const std::string& url, const std::string& date_modified ) : NodeTreeBase( url, date_modified ) , m_regex( 0 ) , m_iconv( 0 ) , m_decoded_lines( NULL ) , m_buffer( NULL ) , m_buffer_for_200( NULL ) { #ifdef _DEBUG std::cout << "NodeTreeMachi::NodeTreeMachi url = " << get_url() << " modified = " << date_modified << std::endl; #endif } NodeTreeMachi::~NodeTreeMachi() { #ifdef _DEBUG std::cout << "NodeTreeMachi::~NodeTreeMachi : " << get_url() << std::endl; #endif clear(); } // // バッファなどのクリア // void NodeTreeMachi::clear() { #ifdef _DEBUG std::cout << "NodeTreeMachi::clear : " << get_url() << std::endl; #endif NodeTreeBase::clear(); // regex 削除 if( m_regex ) delete m_regex; m_regex = NULL; // iconv 削除 if( m_iconv ) delete m_iconv; m_iconv = NULL; if( m_decoded_lines ) free( m_decoded_lines ); m_decoded_lines = NULL; if( m_buffer ) free( m_buffer ); m_buffer = NULL; if( m_buffer_for_200 ) free( m_buffer_for_200 ); m_buffer_for_200 = NULL; } // // ロード実行前に呼ぶ初期化関数 // void NodeTreeMachi::init_loading() { #ifdef _DEBUG std::cout << "NodeTreeMachi::init_loading : " << get_url() << std::endl; #endif NodeTreeBase::init_loading(); // regex 初期化 if( ! m_regex ) m_regex = new JDLIB::Regex(); // iconv 初期化 std::string charset = DBTREE::board_charset( get_url() ); if( ! m_iconv ) m_iconv = new JDLIB::Iconv( charset, "UTF-8" ); if( ! m_decoded_lines ) m_decoded_lines = ( char* )malloc( BUF_SIZE_ICONV_OUT ); if( ! m_buffer ) m_buffer = ( char* )malloc( BUF_SIZE_ICONV_OUT + 64 ); if( m_buffer_for_200 ) m_buffer_for_200[ 0 ] = '\0'; m_tmp_buffer = std::string(); } // // ロード用データ作成 // void NodeTreeMachi::create_loaderdata( JDLIB::LOADERDATA& data ) { // レジュームはしない代わりにスレを直接指定 set_resume( false ); // offlaw 形式 if( CONFIG::get_use_machi_offlaw() ){ JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "(http://[^/]*)/bbs/read.cgi\\?BBS=([^&]*)&KEY=([0-9]*)", get_url(), offset, icase, newline, usemigemo, wchar ) ){ data.url = regex.str( 1 ) + std::string( "/bbs/offlaw.cgi/" ) + regex.str( 2 ) + std::string( "/" ) + regex.str( 3 ); if( id_header() >= 1 ) data.url += "/" + MISC::itostr( id_header() +1 ) + "-"; } } // read.cgi 形式 else{ data.url = get_url(); if( id_header() ) data.url += "&START=" + MISC::itostr( id_header() + 1 ); } data.agent = DBTREE::get_agent( get_url() ); data.host_proxy = DBTREE::get_proxy_host( get_url() ); data.port_proxy = DBTREE::get_proxy_port( get_url() ); data.basicauth_proxy = DBTREE::get_proxy_basicauth( get_url() ); data.size_buf = CONFIG::get_loader_bufsize(); data.timeout = CONFIG::get_loader_timeout(); if( ! get_date_modified().empty() ) data.modified = get_date_modified(); #ifdef _DEBUG std::cout << "NodeTreeMachi::create_loader : " << data.url << std::endl; #endif } // // キャッシュに保存する前の前処理 // char* NodeTreeMachi::process_raw_lines( char* rawlines ) { // オフラインか offlaw 形式を使用する場合はそのまま返す if( ! is_loading() || CONFIG::get_use_machi_offlaw() ) return rawlines; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string buffer; // オンラインでかつ read.cgi 形式の場合は // 入力データを行ごとに分割して余計なタグを取り除いて本文だけ取り出す std::list< std::string > lines = MISC::get_lines( rawlines ); std::list< std::string >::iterator it; for( it = lines.begin(); it != lines.end(); ++it ){ std::string line = MISC::remove_space( *it ); if( m_tmp_buffer.empty() ){ if( line.find( "
    " ) == 0 ){ // 既に読み込んでいる場合は飛ばす char num_tmp[ 8 ]; memcpy( num_tmp, line.c_str() + strlen( "
    " ), 5 ); num_tmp[ 5 ] = '0'; if( atoi( num_tmp ) <= id_header() ) continue; // 行の途中で改行が入ったときは一時バッファに貯めておく if( line.find( "
    " ) != std::string::npos ){ buffer += line; buffer += "\n"; } else m_tmp_buffer = line; } // タイトル取得 else if( ! id_header() && m_subject_machi.empty() ){ std::string reg_subject( "([^<]*)" ); if( m_regex->exec( reg_subject, line, offset, icase, newline, usemigemo, wchar ) ){ const std::string charset = DBTREE::board_charset( get_url() ); m_subject_machi = MISC::Iconv( m_regex->str( 1 ), charset, "UTF-8" ); #ifdef _DEBUG std::cout << "NodeTreeMachi::process_raw_lines\n"; std::cout << "subject = " << m_subject_machi << std::endl; #endif } } } else{ if( line.find( "
    " ) != std::string::npos ){ buffer += m_tmp_buffer; buffer += line; buffer += "\n"; m_tmp_buffer.clear(); } } } if( buffer.length() > BUF_SIZE_ICONV_OUT ){ MISC::ERRMSG( "buffer over flow in NodeTreeMachi::process_raw_lines" ); buffer = std::string(); } int byte = buffer.length(); memcpy( m_buffer, buffer.c_str(), byte ); m_buffer[ byte ] = '\0'; return m_buffer; } // // raw データを dat 形式に変換 // const char* NodeTreeMachi::raw2dat( char* rawlines, int& byte ) { #ifdef _DEBUG std::cout << "NodeTreeMachi::raw2dat\n"; #endif const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; int next = id_header() + 1; std::string buffer; // 文字コード変換 int byte_lines; const char* str_lines = m_iconv->convert( rawlines, strlen( rawlines ), byte_lines ); std::list< std::string > lines = MISC::get_lines( str_lines ); std::list< std::string >::iterator it; for( it = lines.begin(); it != lines.end(); ++it ){ std::string line = MISC::remove_space( *it ); if( line.empty() ) continue; int num = 0; std::string name; std::string mail; std::string date; std::string body; // offlaw 形式 if( line.c_str()[ 0 ] != '<' ){ std::string reg( "(.*?)<>(.*?)<>(.*?)<>(.*?)<>(.*?)<>(.*?)$"); if( ! m_regex->exec( reg, line, offset, icase, newline, usemigemo, wchar ) ){ #ifdef _DEBUG std::cout << "失敗\n"; std::cout << line << std::endl; #endif continue; } num = atoi( m_regex->str( 1 ).c_str() ); name = m_regex->str( 2 ); mail = m_regex->str( 3 ); date = m_regex->str( 4 ); body = m_regex->str( 5 ); if( num == 1 ) m_subject_machi = m_regex->str( 6 ); } // read.cgi 形式 else{ std::string reg( "
    ([1-9][0-9]*) ?名前:(|]*>) ?(]*>)?([^<]*)()? ?.+ ?投稿日: ?([^<]*)( ]*>\\[ ?(.*) ?\\])?
    ?(.*) ?

    $" ); if( ! m_regex->exec( reg, line, offset, icase, newline, usemigemo, wchar ) ){ #ifdef _DEBUG std::cout << "失敗\n"; std::cout << line << std::endl; #endif continue; } num = atoi( m_regex->str( 1 ).c_str() ); name = m_regex->str( 5 ); mail = m_regex->str( 3 ); date = m_regex->str( 7 ); if( !m_regex->str( 9 ).empty() ) date += " HOST:" + m_regex->str( 9 ); body = m_regex->str( 10 ); } while( next < num ){ #ifdef _DEBUG std::cout << "abone = " << num << std::endl; #endif buffer += "あぼ〜ん<><>あぼ〜ん<> あぼ〜ん <><>\n"; next++; } if( num == 1 ){ #ifdef _DEBUG std::cout << "subject = " << m_subject_machi << std::endl; #endif buffer = name + "<>" + mail + "<>" + date + "<> " + body + " <>" + m_subject_machi + "<>\n"; } else buffer += name + "<>" + mail + "<>" + date + "<> " + body + " <><>\n"; ++next; } if( buffer.length() > BUF_SIZE_ICONV_OUT ){ MISC::ERRMSG( "buffer over flow in NodeTreeMachi::process_raw_lines" ); buffer = std::string(); } byte = buffer.length(); memcpy( m_decoded_lines, buffer.c_str(), byte ); m_decoded_lines[ byte ] = '\0'; return m_decoded_lines; } // // ローダからデータ受け取り // void NodeTreeMachi::receive_data( const char* data, size_t size ) { // dat落ち判定用処理。 receive_finish() も参照 if( ! is_checking_update() && get_code() == HTTP_OK && ( ! m_buffer_for_200 || m_buffer_for_200[ 0 ] == '\0' ) ){ #ifdef _DEBUG std::cout << "NodeTreeMachi::receive_data : save some bytes\n"; #endif if( ! m_buffer_for_200 ) m_buffer_for_200 = ( char* )malloc( BUF_SIZE_200 + 64 ); const int lng = MIN( size, BUF_SIZE_200 ); memcpy( m_buffer_for_200, data, lng ); m_buffer_for_200[ lng ] = '\0'; } NodeTreeBase::receive_data( data, size ); } // // ロード完了 // void NodeTreeMachi::receive_finish() { #ifdef _DEBUG std::cout << "NodeTreeMachi::receive_finish : " << get_url() << std::endl << " code = " << get_code() << std::endl; #endif // dat落ち判定 if( m_buffer_for_200 && m_buffer_for_200[ 0 ] == '<' && ( m_buffer_for_200[ 1 ] == 'E' || m_buffer_for_200[ 1 ] == 'h' ) ){ int byte_lines; std::string str_lines( m_iconv->convert( m_buffer_for_200, strlen( m_buffer_for_200 ), byte_lines ) ); #ifdef _DEBUG std::cout << str_lines << std::endl; #endif if( str_lines.find( "" ) != std::string::npos || str_lines.find( "\nなんらかの原因により、まちBBSサーバ内にログを見つけることができませんでした。" ) != std::string::npos ){ #ifdef _DEBUG std::cout << "not found\n"; #endif set_code( HTTP_NOT_FOUND ); set_str_code( "Not Found" ); } } NodeTreeBase::receive_finish(); } jd-2.8.7-140104/src/dbtree/nodetreemachi.h0000644000076400010400000000204711340000342014572 0ustar // ライセンス: GPL2 // // Machi型ノードツリー // #ifndef _NODETREEMACHI_H #define _NODETREEMACHI_H #include "nodetreebase.h" namespace JDLIB { class Iconv; class Regex; } namespace DBTREE { class NodeTreeMachi : public NodeTreeBase { JDLIB::Regex* m_regex; JDLIB::Iconv* m_iconv; char* m_decoded_lines; char* m_buffer; char* m_buffer_for_200; // HTTP200が来た時のdat落ち判定用 std::string m_tmp_buffer; std::string m_subject_machi; public: NodeTreeMachi( const std::string& url, const std::string& date_modified ); ~NodeTreeMachi(); protected: virtual void clear(); virtual void init_loading(); virtual void create_loaderdata( JDLIB::LOADERDATA& data ); virtual char* process_raw_lines( char* rawlines ); virtual const char* raw2dat( char* rawlines, int& byte ); virtual void receive_data( const char* data, size_t size ); virtual void receive_finish(); }; } #endif jd-2.8.7-140104/src/dbtree/root.cpp0000644000076400010400000013467312260002463013324 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _SHOW_GETBOARD //#define _SHOW_BOARD //#define _TEST_CACHE #include "jddebug.h" #include "root.h" #include "boardfactory.h" #include "boardbase.h" #include "articlebase.h" #include "jdlib/jdiconv.h" #include "jdlib/jdregex.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/loaderdata.h" #include "skeleton/editviewdialog.h" #include "skeleton/msgdiag.h" #include "type.h" #include "command.h" #include "config/globalconf.h" #include "cache.h" #include "httpcode.h" #include "environment.h" #include "global.h" #include #include #include // chmod #include #ifdef _TEST_CACHE int cache_hit1 = 0; int cache_hit2 = 0; int cache_nohit = 0; #endif enum { SIZE_OF_RAWDATA = 2 * 1024 * 1024 // bbsmenu.html の最大サイズ }; // ルート要素名( boards.xml ) #define ROOT_NODE_NAME "boardlist" using namespace DBTREE; // is_moved() の戻り値 enum { BOARD_MOVED = 0, BOARD_NEW, BOARD_EXISTS }; Root::Root() : SKELETON::Loadable() , m_rawdata ( 0 ) , m_lng_rawdata( 0 ) , m_analyzing_board_xml( false ) , m_board_null( 0 ) , m_get_board( NULL ) , m_enable_save_movetable( true ) { m_xml_document.clear(); clear(); clear_load_data(); load_movetable(); load_cache(); load_etc(); // JDのサポートBBS登録 set_board( ENVIRONMENT::get_jdbbs(), "JDサポートBBS" ); // 2chのスレの過去ログ set_board( ENVIRONMENT::get_jd2chlog(), "2chスレ過去ログ" ); // ローカルファイル set_board( URL_BOARD_LOCAL, "ローカルファイル" ); m_board_null = new DBTREE::BoardBase( "", "", "" ); } // // デストラクタで子Boardクラスをすべて削除 // Root::~Root() { #ifdef _DEBUG std::cout << "Root::~Root\n"; #endif clear(); std::list< BoardBase* >::iterator it; for( it = m_list_board.begin(); it != m_list_board.end(); ++it ){ ( *it )->terminate_load(); delete ( *it ); } if( m_board_null ) delete m_board_null; #ifdef _TEST_CACHE std::cout << "board cache\n" << "hit1 = " << cache_hit1 << std::endl << "hit2 = " << cache_hit2 << std::endl << "nohit = " << cache_nohit << std::endl << "(hit1+hit2)/total*100 = " << (double)(cache_hit1+cache_hit2)/(cache_hit1+cache_hit2+cache_nohit)*100. << std::endl; #endif } void Root::clear() { if( m_rawdata ) free( m_rawdata ); m_rawdata = NULL; m_lng_rawdata = 0; } // // URLから BoardBase を取得する関数 // // count は無限再帰呼び出し禁止用 // BoardBase* Root::get_board( const std::string& url, const int count ) { #ifdef _SHOW_GETBOARD std::cout << "Root::get_board : count = " << count << " url = " << url << std::endl; #endif const int max_count = 50; // キャッシュ if( m_get_board ){ if( url == m_get_board_url ){ #ifdef _TEST_CACHE ++cache_hit1; #endif return m_get_board; } else if( m_get_board->equal( url ) ){ m_get_board_url = url; #ifdef _TEST_CACHE ++cache_hit2; #endif return m_get_board; } } #ifdef _TEST_CACHE ++cache_nohit; #endif m_get_board_url = url; m_get_board = NULL; if( count == 0 ){ size_t pos = url.rfind( "http://" ); // ユーザープロフィールアドレス( http://be.2ch.net/test/p.php?u=d:http://〜 )の様に // 先頭以外に http:// が入っている場合は失敗 if( pos != std::string::npos && pos != 0 ) return m_board_null; // http:// が含まれていなかったら先頭に追加して再帰呼び出し else if( pos == std::string::npos && ! is_local( url ) ){ BoardBase* board = get_board( "http://" + url , count + 1 ); m_get_board_url = url; return board; } } // サーチ std::list< BoardBase* >::iterator it; for( it = m_list_board.begin(); it != m_list_board.end(); ++it ){ BoardBase* board = *( it ); if( board->equal( url ) ){ board->read_info(); // 板情報の取得( 詳しくはBoardBase::read_info()をみること ) m_get_board = board; #ifdef _SHOW_GETBOARD std::cout << "found\n"; #endif return board; } } // 見つからなかった if( count < max_count ){ // 移転した時はrootを付け変えて再帰呼び出し std::string new_url = is_board_moved( url ); if( ! new_url.empty() ){ BoardBase* board = get_board( new_url, count + 1 ); m_get_board_url = url; return board; } // 2ch型の場合、板パスを見てもし一致したら新ホストに移転したと判断して移転テーブルを更新する if( is_2ch( url ) ){ // 全ての板をサーチして移転先の板を探す std::list< BoardBase* >::iterator it; for( it = m_list_board.begin(); it != m_list_board.end(); ++it ){ BoardBase* board = *( it ); // 板パスを見て一致したら移転したと見なす // TODO : 板パスが同じ板が2つ以上あるときどうするか? if( is_2ch( board->get_root() ) && url.find( board->get_path_board() + "/" ) != std::string::npos ){ // 板移転テーブルを更新 push_movetable( MISC::get_hostname( url ), board->get_path_board(), board->get_root(), board->get_path_board() ); std::ostringstream ss; ss << board->get_name() << std::endl << "旧 URL = " << MISC::get_hostname( url ) + board->get_path_board() << "/" << std::endl << "新 URL = " << board->url_boardbase() << std::endl; MISC::MSG( ss.str() ); if( m_enable_save_movetable ){ //移転テーブル保存 save_movetable(); // サイドバーに登録されているURL更新 CORE::core_set_command( "update_sidebar_item" ); } BoardBase* board = get_board( url, count + 1 ); m_get_board_url = url; return board; } } } // 最後が "/" で終わってなかったら足して再帰呼び出し if( url[ url.length() -1 ] != '/' ){ BoardBase* board = get_board( url + "/" , count + 1 ); m_get_board_url = url; return board; } } #ifdef _DEBUG std::cout << "Root::get_board: not found url = " << url << std::endl;; #endif // それでも見つからなかったらNULLクラスを返す return m_board_null; } // ローカルキャッシュから板一覧XML読み込み // // (注) 板一覧 XML の保存は BBSLIST::BBSListViewMain が行う // void Root::load_cache() { clear(); // ファイルが存在しなければ入力を旧ファイル名にする std::string file_in = CACHE::path_xml_listmain(); if( CACHE::file_exists( file_in ) != CACHE::EXIST_FILE ) { file_in = CACHE::path_xml_listmain_old(); } #ifdef _DEBUG std::cout << "Root::load_cache xml = " << file_in << std::endl; #endif std::string xml_bbsmenu; if( CACHE::load_rawdata( file_in, xml_bbsmenu ) ) { // Domノードを初期化 m_xml_document.init( xml_bbsmenu ); // Domノードの内容からDBに板を登録 analyze_board_xml(); } } // // サーバから bbsmenu.html を読み込んで xml に変換開始 // // 読み終わったらreceive_finish()でXMLに変換して"update_bbslist"コマンド発行 // void Root::download_bbsmenu() { if( is_loading() ) return; clear(); m_xml_document.clear(); m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA ); JDLIB::LOADERDATA data; data.init_for_data(); data.url = CONFIG::get_url_bbsmenu(); data.modified = get_date_modified(); start_load( data ); } // // bbsmenu 受信中 // // virtual void Root::receive_data( const char* data, size_t size ) { memcpy( m_rawdata + m_lng_rawdata , data, size ); m_lng_rawdata += size; } // // bbsmenu 受信完了 // // virtual void Root::receive_finish() { #ifdef _DEBUG std::cout << "Root::receive_finish code = " << get_code() << std::endl; #endif if( get_code() == HTTP_NOT_MODIFIED ){ std::string msg = get_str_code() + "\n\nサーバー上の板一覧は更新されていません。強制的に再読み込みをしますか?"; SKELETON::MsgDiag mdiag( NULL, msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_YES ); if( mdiag.run() == Gtk::RESPONSE_YES ){ set_date_modified( std::string() ); download_bbsmenu(); } return; } if( get_code() != HTTP_OK ){ std::string msg = get_str_code() + "\n\n板一覧の読み込みに失敗したため板一覧は更新されませんでした。\n\nプロキシ設定や板一覧を取得するサーバのアドレスを確認して、ファイルメニューから板一覧の再読み込みをして下さい。\n板一覧取得サーバのアドレスはabout:configで確認出来ます。"; SKELETON::MsgDiag mdiag( NULL, msg, false, Gtk::MESSAGE_ERROR ); mdiag.run(); MISC::ERRMSG( "bbsmenu load failed : " + get_str_code() ); CORE::core_set_command( "update_bbslist" ); return; } // 文字コードを変換してXML作成 JDLIB::Iconv* libiconv = new JDLIB::Iconv( "MS932", "UTF-8" ); int byte_out; const char* rawdata_utf8 = libiconv->convert( m_rawdata , m_lng_rawdata, byte_out ); bbsmenu2xml( rawdata_utf8 ); if( m_xml_document.hasChildNodes() ) { // データベース更新 analyze_board_xml(); // bbslistview更新 CORE::core_set_command( "update_bbslist" ); } if( libiconv ) delete libiconv; clear(); } // // bbsmenu.html -> xml 変換 // void Root::bbsmenu2xml( const std::string& menu ) { if( menu.empty() ) return; #ifdef _DEBUG std::cout << "Root::bbsmenu2xml\n"; #endif JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; // menu のノードツリーを取得( menu がHTMLなので第二引数は true ) XML::Document html( menu, true ); // XML用のノードツリーにルートノードを追加 m_xml_document.clear(); XML::Dom* root = m_xml_document.appendChild( XML::NODE_TYPE_ELEMENT, std::string( ROOT_NODE_NAME ) ); // カテゴリの要素 XML::Dom* subdir = 0; // カテゴリの有効/無効 bool enabled = true; // 現在の仕様では HTML > BODY > font[size="2"] の子要素が対象 XML::DomList targets = html.getElementsByTagName( "font" )[0]->childNodes(); std::list< XML::Dom* >::iterator it = targets.begin(); while( it != targets.end() ) { // 要素b( カテゴリ名 ) if( (*it)->nodeName() == "b" ) { const std::string category = (*it)->firstChild()->nodeValue(); // 追加しないカテゴリ if( category == "チャット" || category == "ツール類" || category == "他のサイト" ) { enabled = false; ++it; continue; } else enabled = true; // subdir = root->appendChild( XML::NODE_TYPE_ELEMENT, "subdir" ); subdir->setAttribute( "name", category ); } // 要素bに続く要素a( 板URL ) else if( subdir && enabled && (*it)->nodeName() == "a" ) { const std::string board_name = (*it)->firstChild()->nodeValue(); const std::string url = (*it)->getAttribute( "href" ); // 板として扱うURLかどうかで要素名を変える std::string element_name; if( CONFIG::use_link_as_board() ) element_name = "board"; else if( ( regex.exec( "^http://.*/.*/$", url, offset, icase, newline, usemigemo, wchar ) && ( is_2ch( url ) || is_machi( url ) ) ) || is_JBBS( url ) || is_vip2ch( url ) ) element_name = "board"; else element_name = "link"; XML::Dom* board = subdir->appendChild( XML::NODE_TYPE_ELEMENT, element_name ); board->setAttribute( "name", board_name ); board->setAttribute( "url", url ); } ++it; } root->setAttribute( "date_modified", get_date_modified() ); #ifdef _DEBUG std::cout << "modified = " << get_date_modified() << std::endl; #endif } // // XML に含まれる板情報を取り出してデータベースを更新 // void Root::analyze_board_xml() { m_move_info = std::string(); m_analyzing_board_xml = true; m_analyzed_path_board.clear(); XML::DomList boards = m_xml_document.getElementsByTagName( "board" ); std::list< XML::Dom* >::iterator it = boards.begin(); while( it != boards.end() ) { const std::string name = (*it)->getAttribute( "name" ); const std::string url = (*it)->getAttribute( "url" ); //板情報セット set_board( url, name ); ++it; } // 移転があった if( ! m_move_info.empty() ) { SKELETON::EditViewDialog diag( m_move_info, "移転板一覧", false ); diag.resize( 600, 400 ); diag.run(); if( m_enable_save_movetable ){ //移転テーブル保存 save_movetable(); // サイドバーに登録されているURL更新 CORE::core_set_command( "update_sidebar_item" ); } } XML::Dom* root = m_xml_document.get_root_element( std::string( ROOT_NODE_NAME ) ); if( root ) set_date_modified( root->getAttribute( "date_modified" ) ); m_analyzing_board_xml = false; m_analyzed_path_board.clear(); #ifdef _DEBUG std::cout << "Root::analyze_board_xml\n"; std::cout << "date_modified = " << get_date_modified() << std::endl; #endif } // // 板のタイプを判定 // int Root::get_board_type( const std::string& url, std::string& root, std::string& path_board, const bool etc ) { JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; int type = TYPE_BOARD_UNKNOWN; // 2ch if( ! etc && is_2ch( url ) ){ if( regex.exec( "(http://[^/]*)/([^/]*)/$" , url, offset, icase, newline, usemigemo, wchar ) ){ root = regex.str( 1 ); path_board = "/" + regex.str( 2 ); type = TYPE_BOARD_2CH; } } // JBBS else if( is_JBBS( url ) ){ if( regex.exec( "(http://[^/]*)/(.*)/(index2?\\.html?)?$" , url, offset, icase, newline, usemigemo, wchar ) ){ root = "http://jbbs.shitaraba.net"; path_board = "/" + regex.str( 2 ); type = TYPE_BOARD_JBBS; } } // まち else if( is_machi( url ) ){ if( regex.exec( "(http://[^/]*)/([^/]*)/(index2?\\.html?)?$" , url, offset, icase, newline, usemigemo, wchar ) ){ root = regex.str( 1 ); path_board = "/" + regex.str( 2 ); type = TYPE_BOARD_MACHI; } } // vipサービス else if( is_vip2ch( url ) ){ if( regex.exec( "(http://[^/]*)/([^/]*)/$" , url, offset, icase, newline, usemigemo, wchar ) ){ root = regex.str( 1 ); path_board = "/" + regex.str( 2 ); type = TYPE_BOARD_2CH_COMPATI; } } // ローカルファイル else if( is_local( url ) ){ root = URL_BOARD_LOCAL; path_board = "/local"; type = TYPE_BOARD_LOCAL; } // その他は互換型 else{ if( regex.exec( "(http://.*)/([^/]*)/([^\\.]+\\.html?)?$" , url, offset, icase, newline, usemigemo, wchar ) ){ root = regex.str( 1 ); path_board = "/" + regex.str( 2 ); type = TYPE_BOARD_2CH_COMPATI; } } return type; } // // 板のタイプに合わせて板情報をセット // ついでに移転の自動判定と移転処理もおこなう // // etc == true なら etc.txtに登録された外部板を意味する // bool Root::set_board( const std::string& url, const std::string& name, const std::string& basicauth, bool etc ) { #ifdef _SHOW_BOARD std::cout << "Root::set_board " << url << " " << name << std::endl; #endif std::string root; std::string path_board; // タイプ判定 int type = get_board_type( url, root, path_board, etc ); if( type == TYPE_BOARD_UNKNOWN ) return false; // 移転チェック BoardBase* board = NULL; const int stat = is_moved( root, path_board, name, &board ); #ifdef _SHOW_BOARD std::cout << "root = " << root << " path_board = " << path_board << " basicauth = " << basicauth <<" type = " << type << " stat = " << stat << std::endl; #endif // 新板登録 if( stat == BOARD_NEW ){ board = DBTREE::BoardFactory( type, root, path_board, name, basicauth ); if( board ){ m_list_board.push_back( board ); if( m_analyzing_board_xml ) m_analyzed_path_board.insert( path_board ); } } // 移転処理 else if( stat == BOARD_MOVED ){ // XML解析中に、 // // // のように同じ板で異なるアドレスが現れた場合は、移転処理をせずにキャッシュが存在する方のアドレスを残す if( m_analyzing_board_xml && m_analyzed_path_board.find( path_board ) != m_analyzed_path_board.end() ){ std::string tmp_msg = "Root::set_board : The XML file is broken !\n"; tmp_msg += url + " has already been registered as " + board->url_boardbase(); MISC::ERRMSG( tmp_msg ); const std::string path1 = CACHE::path_board_root_fast( board->url_boardbase() ); const std::string path2 = CACHE::path_board_root_fast( url ); #ifdef _DEBUG std::cout << "path1 = " << path1 << std::endl << "path2 = " << path2 << std::endl; #endif // キャッシュが存在する方を正しいアドレスとする if( CACHE::file_exists( path1 ) == CACHE::EXIST_DIR ){ #ifdef _DEBUG std::cout << "path1 exists\n"; #endif // 既に登録済みなので何もしない } else if( CACHE::file_exists( path2 ) == CACHE::EXIST_DIR ){ #ifdef _DEBUG std::cout << "path2 exists\n"; #endif // url の方を登録する board->update_url( root, path_board ); } } // 移転処理実行 else{ if( ! exec_move_board( board, board->get_root(), board->get_path_board(), root, path_board ) ) return false; if( m_analyzing_board_xml ) m_analyzed_path_board.insert( path_board ); } } return true; } // // (明示的に)板移転 // const bool Root::move_board( const std::string& url_old, const std::string& url_new, const bool etc ) { if( url_old == url_new ) return false; #ifdef _DEBUG std::cout << "Root::move_board " << url_old << " -> " << url_new << std::endl; #endif m_move_info = std::string(); std::string root; std::string path_board; BoardBase * board = get_board( url_old ); if( ! board ) return false; // タイプ判定 int type = get_board_type( url_new, root, path_board, etc ); if( type == TYPE_BOARD_UNKNOWN ) return false; if( ! exec_move_board( board, board->get_root(), board->get_path_board(), root, path_board ) ) return false; // キャッシュを移動した if( ! m_move_info.empty() ){ if( m_enable_save_movetable ){ save_movetable(); // サイドバーに登録されているURL更新 CORE::core_set_command( "update_sidebar_item" ); } } return true; } // // 板移転処理実行 // bool Root::exec_move_board( BoardBase* board, const std::string old_root, const std::string old_path_board, const std::string new_root, const std::string new_path_board ){ if( ! board ) return false; #ifdef _SHOW_BOARD std::cout << "Root::exec_move_board\n"; std::cout << old_root << old_path_board << " -> " << new_root << new_path_board << std::endl; #endif if( old_root == new_root && old_path_board == new_path_board ){ std::string errmsg = "移転元のアドレスと移転先のアドレスが同じです\n\n" + old_root + old_path_board + " → " + new_root + new_path_board; SKELETON::MsgDiag mdiag( NULL, errmsg, false, Gtk::MESSAGE_ERROR ); mdiag.run(); return false; } const std::string old_url = board->url_boardbase(); std::string old_path = CACHE::path_board_root( old_url ); // DB更新 board->update_url( new_root, new_path_board ); std::string new_url = board->url_boardbase(); std::string new_path = CACHE::path_board_root( new_url ); std::ostringstream ss; ss << board->get_name() << std::endl << " 旧 URL = " << old_url << std::endl << " 新 URL = " << new_url << std::endl; MISC::MSG( ss.str() ); m_get_board_url = std::string(); m_get_board = NULL; // もしキャッシュが存在したら移動して移転テーブル更新 if( CACHE::file_exists( old_path ) == CACHE::EXIST_DIR ){ // キャッシュがある場合はダイアログに表示 m_move_info += ss.str() + "\n"; // 移動先に同名のファイルかフォルダ何かあったらリネームしてバックアップをとっておく if( CACHE::file_exists( new_path ) != CACHE::EXIST_ERROR ){ std::string path_tmp = new_path.substr( 0, new_path.length() - 1 ) + "_bk/"; if( rename( new_path.c_str(), path_tmp.c_str() ) == 0 ) MISC::MSG( "rename : " + new_path + " -> " + path_tmp ); else MISC::ERRMSG( "can't rename " + new_path + " to " + path_tmp ); } // キャッシュ移動 if( CACHE::mkdir_parent_of_board( new_url ) ){ if( rename( old_path.c_str(), new_path.c_str() ) == 0 ) MISC::MSG( "cache was moved : " + old_path + " -> " + new_path ); else MISC::ERRMSG( "can't move cache from " + old_path + " to " + new_path ); } #ifdef _DEBUG std::cout << "movetable was updated.\n" << "old_root = " << old_root << std::endl << "new_root = " << new_root << std::endl << "old_path_board = " << old_path_board << std::endl << "new_path_board = " << new_path_board << std::endl; #endif push_movetable( old_root, old_path_board, new_root, new_path_board ); // この板に関連する表示中のviewのURLを更新 CORE::core_set_command( "update_url", old_url, new_url ); } return true; } // // 板移転テーブルを更新 // void Root::push_movetable( const std::string old_root, const std::string old_path_board, const std::string new_root, const std::string new_path_board ) { #ifdef _DEBUG std::cout << "Root::push_movetable : " << old_root << old_path_board << " -> " << new_root << new_path_board << std::endl; #endif if( old_root == new_root && old_path_board == new_path_board ){ std::string errmsg = "移転元のアドレスと移転先のアドレスが同じです (Root::push_movetable)\n\n" + old_root + old_path_board + " → " + new_root + new_path_board; SKELETON::MsgDiag mdiag( NULL, errmsg, false, Gtk::MESSAGE_ERROR ); mdiag.run(); return; } std::string str; // new_root, new_path_board, old_root, old_path が過去に登録済みなら // 消す、または修正する(パフォーマンス向上、循環防止) std::list< MOVETABLE >::iterator it_move = m_movetable.begin(); for( ; it_move != m_movetable.end(); ){ #ifdef _DEBUG std::cout << "size = " << m_movetable.size() << " " << ( *it_move ).old_root << ( *it_move ).old_path_board << "/ -> " << ( *it_move ).new_root << std::endl; #endif if( ( ( *it_move ).old_root == new_root && ( *it_move ).old_path_board == new_path_board ) || ( ( *it_move ).old_root == old_root && ( *it_move ).old_path_board == old_path_board ) ){ const std::string str_tmp = "削除: " +( *it_move ).old_root + ( *it_move ).old_path_board + "/ -> " + ( *it_move ).new_root + "\n"; #ifdef _DEBUG std::cout << str_tmp << std::endl; #endif str += str_tmp; m_movetable.erase( it_move ); it_move = m_movetable.begin(); continue; } // 移転先を最新にする // // (注意) old_root == new_root かつ old_path_board == new_path_board のとき // erase した内容と push_back した内容が同じになるので無限ループに落ちる else if( ( *it_move ).new_root == old_root && ( *it_move ).new_path_board == old_path_board ){ MOVETABLE movetable = *it_move; movetable.new_root = new_root; movetable.new_path_board = new_path_board; const std::string str_tmp = "更新: " +( *it_move ).old_root + ( *it_move ).old_path_board + "/ -> " + ( *it_move ).new_root + " => " + movetable.old_root + movetable.old_path_board + "/ -> " + movetable.new_root + "\n"; #ifdef _DEBUG std::cout << str_tmp << std::endl; #endif str += str_tmp; m_movetable.erase( it_move ); m_movetable.push_back( movetable ); it_move = m_movetable.begin(); continue; } ++it_move; } if( ! str.empty() ) MISC::MSG( "\n" + str ); MOVETABLE movetable; movetable.old_root = old_root; movetable.old_path_board = old_path_board; movetable.new_root = new_root; movetable.new_path_board = new_path_board; m_movetable.push_back( movetable ); } // // 板をデータベースから削除 // bool Root::remove_board( const std::string& url ) { #ifdef _SHOW_BOARD std::cout << "Root::remove_board " << url << std::endl; #endif BoardBase * board = get_board( url ); if( ! board ) return false; #ifdef _SHOW_BOARD std::cout << "found\n" << "root = " << board->get_root() << std::endl << "path = " << board->get_path_board() << std::endl << "name = " << board->get_name() << std::endl; #endif // この板に関連するビューを全て閉じる // delete board する前に全て閉じないとセグフォの原因となるので注意 CORE::core_set_command( "close_board", url ); m_list_board.remove( board ); delete board; m_get_board_url = std::string(); m_get_board = NULL; return true; } // // 板が移転したどうかチェックする関数 // // 戻り値 : // // BOARD_EXISTS : DBに登録されていて移転していない // BOARD_MOVED : DBに登録されていて移転した // BOARD_NEW : DBに登録されていない // // 移転したなら board_old に古いデータが入って戻る // int Root::is_moved( const std::string& root, const std::string& path_board, const std::string& name, BoardBase** board_old ) { std::list< BoardBase* >::iterator it; for( it = m_list_board.begin(); it != m_list_board.end(); ++it ){ BoardBase* board = *( it ); if( board->get_path_board() == path_board ){ // 既にリストに登録されてる if( board->get_root() == root ) return BOARD_EXISTS; // 名前が同じなら移転 if( board->get_name() == name ){ *board_old = board; return BOARD_MOVED; } } } return BOARD_NEW; } // // etc.txtから外部板情報を読み込み // // etc.txt(Navi2ch互換) を読み込んで外部板情報( etcboardinfo.h )作成およびデータベース登録 // void Root::load_etc() { m_etcboards.clear(); JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string file_etctxt = CACHE::path_etcboard(); std::string etcboard; if( CACHE::load_rawdata( file_etctxt, etcboard ) ) { std::list< std::string > list_etc = MISC::get_lines( etcboard ); list_etc = MISC::remove_commentline_from_list( list_etc ); list_etc = MISC::remove_space_from_list( list_etc ); list_etc = MISC::remove_nullline_from_list( list_etc ); std::list< std::string >::iterator it; for( it = list_etc.begin(); it != list_etc.end(); ++it ){ DBTREE::ETCBOARDINFO info; // 名前 info.name = *( it++ ); if( it == list_etc.end() ) break; // url info.url = *( it++ ); if( it == list_etc.end() ) break; // basic認証 if( regex.exec( "http://([^/]+:[^/]+@)(.+)$" , info.url, offset, icase, newline, usemigemo, wchar ) ) { info.basicauth = regex.str( 1 ).substr( 0, regex.str( 1 ).length() - 1 ); info.url = "http://" + regex.str( 2 ); } // board id info.boardid = *( it ); if( it == list_etc.end() ) break; #ifdef _DEBUG std::cout << "etc board : name = " << info.name << std::endl << "url = " << info.url << std::endl << "id:passwd = " <::iterator it = m_etcboards.begin(); for( ; it != m_etcboards.end(); ++it ){ if( (*it).url == url_old && (*it).name == name_old ) break; } if( it == m_etcboards.end() ) return false; #ifdef _DEBUG std::cout << "Root::move_etc " << url_old << " -> " << url_new << std::endl << name_old << " -> " << name_new << std::endl << board->get_basicauth() << " -> " << basicauth << std::endl; #endif // 移転処理 if( url_old != url_new ){ (*it).url = url_new; move_board( url_old, url_new, true ); } // 名前変更 (*it).name = name_new; board->update_name( name_new ); // BASIC認証変更 (*it).basicauth = basicauth; board->set_basicauth( basicauth ); // ID更新 (*it).boardid = boardid; save_etc(); return true; } // // 外部板削除 // bool Root::remove_etc( const std::string& url, const std::string& name ) { #ifdef _DEBUG std::cout << "Root::remove_etc url = " << url << " name = " << name << std::endl; #endif if( m_etcboards.empty() ) return false; std::list< DBTREE::ETCBOARDINFO >::iterator it = m_etcboards.begin(); for( ; it != m_etcboards.end(); ++it ){ if( (*it).url == url && (*it).name == name ){ #ifdef _DEBUG std::cout << "found\n"; #endif remove_board( url ); m_etcboards.erase( it ); return true; } } return false; } // // 外部板保存 // // 外部板情報から etc.txt(Navi2ch互換)作成 // void Root::save_etc() { // m_etcboards が空でも実行する #ifdef _DEBUG std::cout << "Root::save_etc\n"; #endif std::string etcboard; std::list< DBTREE::ETCBOARDINFO >::iterator it = m_etcboards.begin(); for( ; it != m_etcboards.end(); ++it ){ etcboard += (*it).name + "\n"; if( (*it).basicauth.empty() ) etcboard += (*it).url + "\n"; else{ size_t i = (*it).url.find( "://" ); if( i != std::string::npos ){ etcboard += (*it).url.substr( 0, i+3 ) + (*it).basicauth + "@" + (*it).url.substr( i+3 ) + "\n"; } else etcboard += (*it).url + "\n"; } etcboard += (*it).boardid + "\n"; } std::string file_etctxt = CACHE::path_etcboard(); if( ! CACHE::save_rawdata( file_etctxt, etcboard ) ){ MISC::ERRMSG( "failed to save " + file_etctxt ); } // BASIC認証のパスワード対策 else chmod( file_etctxt.c_str(), S_IWUSR | S_IRUSR ); #ifdef _DEBUG std::cout << etcboard << std::endl; #endif } // // 移転テーブル読み込み // void Root::load_movetable() { #ifdef _DEBUG std::cout << "Root::load_movetable\n"; #endif std::string file_move = CACHE::path_movetable(); std::string movetable; if( CACHE::load_rawdata( file_move, movetable ) ){ std::list< std::string > list_table = MISC::get_lines( movetable ); std::list< std::string >::iterator it; for( it = list_table.begin(); it != list_table.end(); ++it ){ std::list< std::string > lines = MISC::split_line( *it ); if( lines.size() == 3 // 旧形式 || lines.size() == 4 ){ std::list< std::string >::iterator it2 = lines.begin(); MOVETABLE movetable; movetable.old_root = *(it2++); movetable.new_root = *(it2++); movetable.old_path_board = *(it2++); if( lines.size() == 4 ) movetable.new_path_board = *(it2++); else movetable.new_path_board = movetable.old_path_board; m_movetable.push_back( movetable ); } } } #ifdef _DEBUG std::cout << "MOVETABLE : \n"; std::list< MOVETABLE >::iterator it_move; for( it_move = m_movetable.begin(); it_move != m_movetable.end(); ++it_move ) std::cout << ( *it_move ).old_root << ( *it_move ).old_path_board << " -> " << ( *it_move ).new_root << ( *it_move ).new_path_board << std::endl; #endif } // // 板が移転したかチェックする // // 移転した時は移転後のURLを返す // const std::string Root::is_board_moved( const std::string& url ) // 簡易版 { std::string old_root; std::string old_path_board; std::string new_root; std::string new_path_board; return is_board_moved( url, old_root, old_path_board, new_root, new_path_board ); } const std::string Root::is_board_moved( const std::string& url, std::string& old_root, std::string& old_path_board, std::string& new_root, std::string& new_path_board, const int count ) { const int max_count = 50; #ifdef _DEBUG std::cout << "Root::is_board_moved count = " << count << " url = " << url << std::endl; #endif // 移転テーブルが循環している場合 2ch 型ならテーブルを修復する if( count > max_count ){ if( is_2ch( url ) ){ std::list< BoardBase* >::iterator it; for( it = m_list_board.begin(); it != m_list_board.end(); ++it ){ // 板の最新のrootとpathを取得する BoardBase* board = *( it ); // 板パスを見て一致したら移転したと見なす // TODO : 板パスが同じ板が2つ以上あるときどうするか? if( is_2ch( board->get_root() ) && url.find( board->get_path_board() + "/" ) != std::string::npos ){ std::string str = "移転テーブルが破損していたので修復しました\n"; std::list< MOVETABLE >::iterator it_move = m_movetable.begin(); for( ; it_move != m_movetable.end(); ){ if( is_2ch( ( *it_move ).old_root ) && url.find( ( *it_move ).old_path_board + "/" ) != std::string::npos ){ // 最新のrootとpathに変更する ( *it_move ).new_root = board->get_root(); ( *it_move ).new_path_board = board->get_path_board(); // url -> url の形となった場合は消す if( ( *it_move ).old_root == ( *it_move ).new_root && ( *it_move ).old_path_board == ( *it_move ).new_path_board ){ str += "削除: " +( *it_move ).old_root + ( *it_move ).old_path_board + "/ -> " + board->url_boardbase() + "\n"; m_movetable.erase( it_move ); it_move = m_movetable.begin(); continue; } str += "更新: " + ( *it_move ).old_root + ( *it_move ).old_path_board + "/ -> " + board->url_boardbase() + "\n"; } ++it_move; } MISC::MSG( str ); if( m_enable_save_movetable ){ //移転テーブル保存 save_movetable(); // サイドバーに登録されているURL更新 CORE::core_set_command( "update_sidebar_item" ); } // 改めてもう一度実行 return is_board_moved( url, old_root, old_path_board, new_root, new_path_board, 0 ); } } } return std::string(); } // 移転テーブルを検索 std::list< MOVETABLE >::iterator it_move = m_movetable.begin(); for( ; it_move != m_movetable.end(); ++it_move ){ if( url.find( ( *it_move ).old_root ) == 0 && url.find( ( *it_move ).old_path_board + "/" ) != std::string::npos ){ const std::string new_url = ( *it_move ).new_root + ( *it_move ).new_path_board + "/"; old_root = ( *it_move ).old_root; old_path_board = ( *it_move ).old_path_board; new_root = ( *it_move ).new_root; new_path_board = ( *it_move ).new_path_board; const std::string old_root_bkup = old_root; const std::string old_path_board_bkup = old_path_board; #ifdef _DEBUG std::cout << "count = " << count << " : " << url << " is moved to " << new_url << std::endl; #endif // 連鎖的に検索 std::string ret_url = is_board_moved( new_url, old_root, old_path_board, new_root, new_path_board, count +1 ); // old_root と old_path_board が書き換わっているので戻しておく // // (注意) もし再帰呼び出ししたis_board_moved() の中で m_movetable.erase を実行すると // it_move は無効になるので、以前の様に // old_root = ( *it_move ).old_root; // old_path_board = ( *it_move ).old_path_board; // と it_move を使ってold_rootなどに代入するとメモリを破壊してセグフォになる時がある // (イテレータのメモリが残っていればセグフォにならないので完全に運まかせ) // 次にJDを起動したときは再帰呼び出ししたis_board_moved() の中の save_movetable()で // 移転テーブルは更新済みで落ちないのでタチが悪い old_root = old_root_bkup; old_path_board = old_path_board_bkup; return ret_url; } } if( count ) return url; // 再起呼び出しの場合 return std::string(); } // 全板の情報ファイル読み込み void Root::read_boardinfo_all() { std::list< BoardBase* >::iterator it; for( it = m_list_board.begin(); it != m_list_board.end(); ++it ){ ( *it )->read_info(); } } // 全スレ情報の保存 void Root::save_articleinfo_all() { #ifdef _DEBUG std::cout << "Root::save_articleinfo_all\n"; #endif std::list< BoardBase* >::iterator it = m_list_board.begin(); for( ; it != m_list_board.end(); ++it ){ ( *it )->save_articleinfo_all(); } #ifdef _DEBUG std::cout << "end\n"; #endif } // 全ログ検索 void Root::search_cache( std::vector< ArticleBase* >& list_article, const std::string& query, const bool mode_or, const bool bm, const bool& stop ) { std::list< BoardBase* >::iterator it; for( it = m_list_board.begin(); it != m_list_board.end(); ++it ){ ( *it )->search_cache( list_article, query, mode_or, bm, stop ); if( stop ) break; } } // 全てのスレの書き込み履歴削除 void Root::clear_all_post_history() { std::list< BoardBase* >::iterator it; for( it = m_list_board.begin(); it != m_list_board.end(); ++it ){ ( *it )->clear_all_post_history(); } } // // 移転テーブル保存 // void Root::save_movetable() { #ifdef _DEBUG std::cout << "Root::save_movetable\n"; #endif std::string file_move = CACHE::path_movetable(); std::ostringstream movetable; std::list< MOVETABLE >::iterator it_move; for( it_move = m_movetable.begin(); it_move != m_movetable.end(); ++it_move ){ movetable <<( *it_move ).old_root << " " << ( *it_move ).new_root << " " << ( *it_move ).old_path_board; // 新形式 if( ! ( *it_move ).new_path_board.empty() && ( *it_move ).old_path_board != ( *it_move ).new_path_board ) movetable << " " << ( *it_move ).new_path_board; movetable << std::endl; } #ifdef _DEBUG std::cout << movetable.str(); #endif CACHE::save_rawdata( file_move, movetable.str() ); } // // 2ch型のURLかどうか // const bool Root::is_2ch( const std::string& url ) { const std::string hostname = MISC::get_hostname( url ); if( ( hostname.find( ".2ch.net" ) != std::string::npos && hostname.find( "info.2ch.net" ) == std::string::npos ) || hostname.find( ".bbspink.com" ) != std::string::npos ) return true; return false; } // // JBBS型のURLかどうか // const bool Root::is_JBBS( const std::string& url ) { const std::string hostname = MISC::get_hostname( url ); if( hostname.find( "jbbs.livedoor.jp" ) != std::string::npos || hostname.find( "jbbs.shitaraba.com" ) != std::string::npos || hostname.find( "jbbs.shitaraba.net" ) != std::string::npos ) return true; return false; } // // まち型のURLかどうか // const bool Root::is_machi( const std::string& url ) { const std::string hostname = MISC::get_hostname( url ); if( hostname.find( ".machi.to" ) != std::string::npos ) return true; return false; } // // vipサービスのURLか // const bool Root::is_vip2ch( const std::string& url ) { const std::string hostname = MISC::get_hostname( url ); if( hostname.find( ".vip2ch.com" ) != std::string::npos ) return true; return false; } // // ローカルファイルか // const bool Root::is_local( const std::string& url ) { if( url.find( "file://" ) != std::string::npos ) return true; return false; } // // スレあぼーん情報を更新した時、全boardbaseクラスに対応するスレ一覧の表示を更新させる // // CONFIG::set_abone_number_thread() などでグローバル設定をした後などに呼び出す // void Root::update_abone_thread() { std::list< BoardBase* >::iterator it = m_list_board.begin(); for( ; it != m_list_board.end(); ++it ) ( *it )->update_abone_thread( true ); } // // 全boardbaseクラスに、それに属する全articlebaseクラスのあぼーん状態の更新をさせる // void Root::update_abone_all_article() { std::list< BoardBase* >::iterator it = m_list_board.begin(); for( ; it != m_list_board.end(); ++it ) ( *it )->update_abone_all_article(); } // // 全boardbaseクラスに、それに属する全articlebaseクラスの書き込み時間とスレ立て時間の文字列をリセットさせる // void Root::reset_all_write_date() { std::list< BoardBase* >::iterator it = m_list_board.begin(); for( ; it != m_list_board.end(); ++it ) ( *it )->reset_all_write_date(); } void Root::reset_all_since_date() { std::list< BoardBase* >::iterator it = m_list_board.begin(); for( ; it != m_list_board.end(); ++it ) ( *it )->reset_all_since_date(); } jd-2.8.7-140104/src/dbtree/root.h0000644000076400010400000001653311506370702012771 0ustar // ライセンス: GPL2 // データベースのルートクラス // // クラス図 [ Root ] ---> [ BoardBase ] ---> [ ArticleBase ] ---> [ NodeTreeBase ] // #ifndef _ROOT_H #define _ROOT_H #include "etcboardinfo.h" #include "skeleton/loadable.h" #include "xml/document.h" #include #include #include namespace DBTREE { class BoardBase; class ArticleBase; // サーバ移転テーブル // // (1) bbsmenuを読み込んで移転していた場合( Root::set_board() ) // // 現在のホストを新ホストに移動する。キャッシュも移動する // // (2) 参照しようとした板が無かった時( Root::get_board() ) // // 参照した古いホストの移動先を現在のホストに設定する。キャッシュは移動しない // // (3) ある板のsubject.txtを読み込んだときにHTTP_REDIRECTが戻ってきて // BoardBase::start_checkking_if_board_moved()により移転が確認されたとき // // 現在のホストを新ホストに移動する。キャッシュも移動する // struct MOVETABLE { std::string old_root; std::string new_root; std::string old_path_board; std::string new_path_board; }; class Root : public SKELETON::Loadable { // Boardクラス のキャッシュ // Boardクラスは一度作ったら~Root()以外ではdeleteしないこと std::list< BoardBase* > m_list_board; // 鯖移転テーブル std::list< MOVETABLE > m_movetable; XML::Document m_xml_document; char* m_rawdata; size_t m_lng_rawdata; std::list< DBTREE::ETCBOARDINFO > m_etcboards; // 外部板情報 // 移転処理用変数 bool m_analyzing_board_xml; // XML 解析中 std::set< std::string > m_analyzed_path_board; // XML 解析中に処理済みの板のpath std::string m_move_info; // 移転したときにダイアログに表示する移転済み板の一覧 // NULL board クラス BoardBase* m_board_null; // get_board()のキャッシュ // get_article_fromURL()のキャッシュ std::string m_get_board_url; BoardBase* m_get_board; bool m_enable_save_movetable; public: Root(); ~Root(); // 板一覧のxml const XML::Document& xml_document() const { return m_xml_document; } // 板移転 const bool move_board( const std::string& url_old, const std::string& url_new, const bool etc ); // 外部板情報取得 const std::list< DBTREE::ETCBOARDINFO >& get_etcboards() const { return m_etcboards; } // 外部板追加 bool add_etc( const std::string& url, const std::string& name, const std::string& basicauth, const std::string& id ); // 外部板更新 bool move_etc( const std::string& url_old, const std::string& url_new, const std::string& name_old, const std::string& name_new, const std::string& basicauth, const std::string& boardid ); // 外部板削除 bool remove_etc( const std::string& url, const std::string& name ); // 外部板情報保存 void save_etc(); // Board クラスのポインタ取得 BoardBase* get_board( const std::string& url, const int count = 0 ); // bbsmenuのダウンロード void download_bbsmenu(); // スレあぼーん情報を更新した時、全boardbaseクラスに対応するスレ一覧の表示を更新させる // CONFIG::set_abone_number_thread() などでグローバル設定をした後などに呼び出す void update_abone_thread(); // 全boardbaseクラスに、それに属する全articlebaseクラスのあぼーん状態の更新をさせる void update_abone_all_article(); // 全boardbaseクラスに、それに属する全articlebaseクラスの書き込み時間とスレ立て時間の文字列をリセットさせる void reset_all_write_date(); void reset_all_since_date(); // 板が移転したかチェックする // 移転した時は移転後のURLを返す const std::string is_board_moved( const std::string& url ); // 簡易版 const std::string is_board_moved( const std::string& url, std::string& old_root, std::string& old_path_board, std::string& new_root, std::string& new_path_board, const int count = 0 ); // 移転情報保存の有効切り替え void set_enable_save_movetable( const bool set ){ m_enable_save_movetable = set; } // 移転情報保存 void save_movetable(); // 全板の情報ファイル読み込み void read_boardinfo_all(); // 全スレ情報の保存 void save_articleinfo_all(); // 全ログ検索 void search_cache( std::vector< ArticleBase* >& list_article, const std::string& query, const bool mode_or, const bool bm, const bool& stop ); // 全てのスレの書き込み履歴削除 void clear_all_post_history(); private: // bbsmenuのダウンロード用関数 void clear(); virtual void receive_data( const char* data, size_t size ); virtual void receive_finish(); void bbsmenu2xml( const std::string& menu ); // XML に含まれる板情報を取り出してデータベースを更新 void analyze_board_xml(); // 板のタイプを判定 int get_board_type( const std::string& url, std::string& root, std::string& path_board, const bool etc ); // 板のタイプに合わせて板情報をセット bool set_board( const std::string& url, const std::string& name, const std::string& basicauth = std::string(), bool etc = false ); // 板移転処理 bool exec_move_board( BoardBase* board, const std::string old_root, const std::string old_path_board, const std::string new_root, const std::string new_path_board ); // 板移転テーブルに追加 void push_movetable( const std::string old_root, const std::string old_path_board, const std::string new_root, const std::string new_path_board ); // 板をデータベースから削除 bool remove_board( const std::string& url ); int is_moved( const std::string& root, const std::string& path_board, const std::string& name, BoardBase** board_old ); void load_cache(); void load_etc(); void load_movetable(); // urlのタイプ判定 const bool is_2ch( const std::string& url ); const bool is_JBBS( const std::string& url ); const bool is_machi( const std::string& url ); const bool is_vip2ch( const std::string& url ); const bool is_local( const std::string& url ); }; } #endif jd-2.8.7-140104/src/dbtree/ruleloader.cpp0000644000076400010400000000405511114172712014467 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "ruleloader.h" #include "interface.h" #include "jdlib/confloader.h" #include "jdlib/loaderdata.h" #include "config/globalconf.h" #include "cache.h" #define HEAD_TXT "head.txt" using namespace DBTREE; RuleLoader::RuleLoader( const std::string& url_boadbase ) : SKELETON::TextLoader(), m_url_boadbase( url_boadbase ) { #ifdef _DEBUG std::cout << "RuleLoader::RuleLoader : " << get_url() << std::endl; #endif set_date_modified( DBTREE::board_get_modified_localrule( m_url_boadbase ) ); } RuleLoader::~RuleLoader() { #ifdef _DEBUG std::cout << "RuleLoader::~RuleLoader : " << get_url() << std::endl; #endif } const std::string RuleLoader::get_url() { return m_url_boadbase + HEAD_TXT; } const std::string RuleLoader::get_path() { return CACHE::path_board_root( m_url_boadbase ) + HEAD_TXT; } const std::string RuleLoader::get_charset() { return DBTREE::board_charset( m_url_boadbase ); } // ロード用データ作成 void RuleLoader::create_loaderdata( JDLIB::LOADERDATA& data ) { if( !CACHE::mkdir_boardroot( m_url_boadbase ) ) data.url = std::string(); else{ // 移転処理 std::string url_boardbase = DBTREE::url_boardbase( m_url_boadbase ); if( m_url_boadbase != url_boardbase ) m_url_boadbase = url_boardbase; data.url = get_url(); data.agent = DBTREE::get_agent( m_url_boadbase ); data.host_proxy = DBTREE::get_proxy_host( m_url_boadbase ); data.port_proxy = DBTREE::get_proxy_port( m_url_boadbase ); data.basicauth_proxy = DBTREE::get_proxy_basicauth( m_url_boadbase ); data.size_buf = CONFIG::get_loader_bufsize(); data.timeout = CONFIG::get_loader_timeout(); if( ! get_date_modified().empty() ) data.modified = get_date_modified(); data.basicauth = DBTREE::board_basicauth( m_url_boadbase ); } } // ロード後に呼び出される void RuleLoader::parse_data() { DBTREE::board_set_modified_localrule( m_url_boadbase, get_date_modified() ); } jd-2.8.7-140104/src/dbtree/ruleloader.h0000644000076400010400000000142310654637723014150 0ustar // ライセンス: GPL2 // // 2chのローカルルールのローダ // #ifndef _RULELOADER_H #define _RULELOADER_H #include "skeleton/textloader.h" #include namespace JDLIB { class LOADERDATA; } namespace DBTREE { class RuleLoader : public SKELETON::TextLoader { std::string m_url_boadbase; public: RuleLoader( const std::string& url_boardbase ); ~RuleLoader(); protected: virtual const std::string get_url(); virtual const std::string get_path(); virtual const std::string get_charset(); // ロード用データ作成 virtual void create_loaderdata( JDLIB::LOADERDATA& data ); // ロード後に呼び出される virtual void parse_data(); }; } #endif jd-2.8.7-140104/src/dbtree/settingloader.cpp0000644000076400010400000000547211455622660015213 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "settingloader.h" #include "interface.h" #include "jdlib/confloader.h" #include "jdlib/loaderdata.h" #include "config/globalconf.h" #include "cache.h" #define SETTING_TXT "SETTING.TXT" using namespace DBTREE; SettingLoader::SettingLoader( const std::string& url_boadbase ) : SKELETON::TextLoader(), m_url_boadbase( url_boadbase ), m_line_number( 0 ), m_message_count( 0 ) { #ifdef _DEBUG std::cout << "SettingLoader::SettingLoader : " << get_url() << std::endl; #endif set_date_modified( DBTREE::board_get_modified_setting( m_url_boadbase ) ); } SettingLoader::~SettingLoader() { #ifdef _DEBUG std::cout << "SettingLoader::~SettingLoader : " << get_url() << std::endl; #endif } const std::string SettingLoader::get_url() { return m_url_boadbase + SETTING_TXT; } const std::string SettingLoader::get_path() { return CACHE::path_board_root( m_url_boadbase ) + SETTING_TXT; } const std::string SettingLoader::get_charset() { return DBTREE::board_charset( m_url_boadbase ); } // ロード用データ作成 void SettingLoader::create_loaderdata( JDLIB::LOADERDATA& data ) { if( !CACHE::mkdir_boardroot( m_url_boadbase ) ) data.url = std::string(); else{ // 移転処理 std::string url_boardbase = DBTREE::url_boardbase( m_url_boadbase ); if( m_url_boadbase != url_boardbase ) m_url_boadbase = url_boardbase; data.url = get_url(); data.agent = DBTREE::get_agent( m_url_boadbase ); data.host_proxy = DBTREE::get_proxy_host( m_url_boadbase ); data.port_proxy = DBTREE::get_proxy_port( m_url_boadbase ); data.basicauth_proxy = DBTREE::get_proxy_basicauth( m_url_boadbase ); data.size_buf = CONFIG::get_loader_bufsize(); data.timeout = CONFIG::get_loader_timeout(); if( ! get_date_modified().empty() ) data.modified = get_date_modified(); data.basicauth = DBTREE::board_basicauth( m_url_boadbase ); } } // ロード後に呼び出される void SettingLoader::parse_data() { JDLIB::ConfLoader cf( "", get_data() ); m_default_noname = cf.get_option_str( "BBS_NONAME_NAME", "No Name" ); m_line_number = cf.get_option_int( "BBS_LINE_NUMBER", 0, 0, 8192 ); m_message_count = cf.get_option_int( "BBS_MESSAGE_COUNT", 0, 0, 81920 ); m_unicode = cf.get_option_str( "BBS_UNICODE", "" ); DBTREE::board_set_modified_setting( m_url_boadbase, get_date_modified() ); #ifdef _DEBUG std::cout << "SettingLoader::parse url = " << get_url() << std::endl << "default_noname = " << m_default_noname << std::endl << "line_number = " << m_line_number << std::endl << "message_count = " << m_message_count << std::endl << "unicode = " << m_unicode << std::endl; #endif } jd-2.8.7-140104/src/dbtree/settingloader.h0000644000076400010400000000251411455622660014652 0ustar // ライセンス: GPL2 // // 2chのSETTING.TXTのローダ // #ifndef _SETTINGLOADER_H #define _SETTINGLOADER_H #include "skeleton/textloader.h" #include namespace JDLIB { class LOADERDATA; } namespace DBTREE { class SettingLoader : public SKELETON::TextLoader { bool m_parsed; std::string m_url_boadbase; // デフォルト名無し std::string m_default_noname; // 最大改行数/2 int m_line_number; // 最大書き込みバイト数 int m_message_count; // 特殊文字書き込み std::string m_unicode; public: SettingLoader( const std::string& url_boardbase ); ~SettingLoader(); const std::string& default_noname() const { return m_default_noname; } const int line_number() { return m_line_number; } const int message_count() { return m_message_count; } const std::string& get_unicode() const { return m_unicode; } protected: virtual const std::string get_url(); virtual const std::string get_path(); virtual const std::string get_charset(); // ロード用データ作成 virtual void create_loaderdata( JDLIB::LOADERDATA& data ); // ロード後に呼び出される virtual void parse_data(); }; } #endif jd-2.8.7-140104/src/dbtree/spchar_decoder.cpp0000644000076400010400000000621612011065263015276 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "spchar_decoder.h" #include "spchar_tbl.h" #include "node.h" #include "jdlib/miscutil.h" #include #include const bool check_spchar( const char* n_in, const char* spchar ) { int i = 0; while( spchar[ i ] != '\0' ){ if( n_in[ i ] != spchar[ i ] ) return false; ++i; } return true; } // // ユニコード文字参照 &#数字; // // in_char: 入力文字列、in_char[1] == "#" であること // n_in : 入力で使用した文字数が返る // out_char : 出力文字列 // n_out : 出力した文字数が返る // only_check : チェックのみ実施 ( out_char は NULL でも可 ) // // 戻り値 : node.h で定義したノード番号 // const int decode_char_number( const char* in_char, int& n_in, char* out_char, int& n_out, const bool only_check ) { int ret = DBTREE::NODE_TEXT; n_in = n_out = 0; int offset; const int lng = MISC::spchar_number_ln( in_char, offset ); if( lng == -1 ) return DBTREE::NODE_NONE; if( only_check ) return ret; const int num = MISC::decode_spchar_number( in_char, offset, lng ); switch( num ){ //zwnj,zwj,lrm,rlm は今のところ無視(zwspにする) case UCS_ZWSP: case UCS_ZWNJ: case UCS_ZWJ: case UCS_LRM: case UCS_RLM: ret = DBTREE::NODE_ZWSP; break; default: n_out = MISC::ucs2toutf8( num, out_char ); if( ! n_out ) return DBTREE::NODE_NONE; } n_in = offset + lng; if( in_char[n_in] == ';' ) n_in++; // 数値文字参照の終端「;」の場合は1文字削除 if( out_char ) out_char[ n_out ] = '\0'; return ret; } // // 文字参照のデコード // // in_char : 入力文字列, in_char[ 0 ] = '&' となっていること // n_in : 入力で使用した文字数が返る // out_char : 出力文字列 // n_out : 出力した文字数が返る // only_check : チェックのみ実施 ( out_char は NULL でも可 ) // // 戻り値 : node.h で定義したノード番号 // const int DBTREE::decode_char( const char* in_char, int& n_in, char* out_char, int& n_out, const bool only_check ) { // 数字参照 &#数字; if( in_char[ 1 ] == '#' ) return decode_char_number( in_char, n_in, out_char, n_out, only_check ); // 文字参照 -> ユニコード変換 int ret = DBTREE::NODE_TEXT; n_in = n_out = 0; int i = 0; for(;;){ const int ucs = ucstbl[ i ].ucs; if( ! ucs ) break; if( in_char[ 1 ] == ucstbl[ i ].str[ 0 ] ){ if( check_spchar( in_char +1, ucstbl[ i ].str ) ){ if( only_check ) return ret; n_in = strlen( ucstbl[ i ].str ) +1; // zwnj, zwj, lrm, rlm は今のところ無視する(zwspにする) if( ucs >= UCS_ZWSP && ucs <= UCS_RLM ) ret = DBTREE::NODE_ZWSP; else n_out = MISC::ucs2toutf8( ucs, out_char ); break; } } ++i; } if( !n_in ) ret = DBTREE::NODE_NONE; if( out_char ) out_char[ n_out ] = '\0'; return ret; } jd-2.8.7-140104/src/dbtree/spchar_decoder.h0000644000076400010400000000123011340760564014744 0ustar // ライセンス: GPL2 // // 特殊HTML文字のデコード関数 // #ifndef _SPCHAR_DECODER_H #define _SPCHAR_DECODER_H namespace DBTREE { // 文字参照のデコード // in_char : 入力文字列, in_char[ 0 ] = '&' となっていること // n_in : 入力で使用した文字数が返る // out_char : 出力文字列 // n_out : 出力した文字数が返る // only_check : チェックのみ実施 ( out_char は NULL でも可 ) // // 戻り値 : node.h で定義したノード番号 // const int decode_char( const char* in_char, int& n_in, char* out_char, int& n_out, const bool only_check ); } #endif jd-2.8.7-140104/src/dbtree/spchar_tbl.h0000644000076400010400000001414311460603610014116 0ustar // ライセンス: GPL2 // // ユニコード(ucs2) <-> 文字参照変換テーブル // #ifndef _SPCHAR_TBL_H #define _SPCHAR_TBL_H struct UCSTBL { int ucs; char str[ 256 ]; }; UCSTBL ucstbl[] = { { 34, "quot;" }, { 38, "amp;" }, { 60, "lt;" }, { 62, "gt;" }, { 32, "nbsp;" }, // { 160, "nbsp;" }, // 正しくはこちら { 161, "iexcl;" }, { 162, "cent;" }, { 163, "pound;" }, { 164, "curren;" }, { 165, "yen;" }, { 166, "brvbar;" }, { 167, "sect;" }, { 168, "uml;" }, { 169, "copy;" }, { 170, "ordf;" }, { 171, "laquo;" }, { 172, "not;" }, { 173, "shy;" }, { 174, "reg;" }, { 175, "macr;" }, { 176, "deg;" }, { 177, "plusmn;" }, { 178, "sup2;" }, { 179, "sup3;" }, { 180, "acute;" }, { 181, "micro;" }, { 182, "para;" }, { 183, "middot;" }, { 184, "cedil;" }, { 185, "sup1;" }, { 186, "ordm;" }, { 187, "raquo;" }, { 188, "frac14;" }, { 189, "frac12;" }, { 190, "frac34;" }, { 191, "iquest;" }, { 192, "Agrave;" }, { 193, "Aacute;" }, { 194, "Acirc;" }, { 195, "Atilde;" }, { 196, "Auml;" }, { 197, "Aring;" }, { 198, "AElig;" }, { 199, "Ccedil;" }, { 200, "Egrave;" }, { 201, "Eacute;" }, { 202, "Ecirc;" }, { 203, "Euml;" }, { 204, "Igrave;" }, { 205, "Iacute;" }, { 206, "Icirc;" }, { 207, "Iuml;" }, { 208, "ETH;" }, { 209, "Ntilde;" }, { 210, "Ograve;" }, { 211, "Oacute;" }, { 212, "Ocirc;" }, { 213, "Otilde;" }, { 214, "Ouml;" }, { 215, "times;" }, { 216, "Oslash;" }, { 217, "Ugrave;" }, { 218, "Uacute;" }, { 219, "Ucirc;" }, { 220, "Uuml;" }, { 221, "Yacute;" }, { 222, "THORN;" }, { 223, "szlig;" }, { 224, "agrave;" }, { 225, "aacute;" }, { 226, "acirc;" }, { 227, "atilde;" }, { 228, "auml;" }, { 229, "aring;" }, { 230, "aelig;" }, { 231, "ccedil;" }, { 232, "egrave;" }, { 233, "eacute;" }, { 234, "ecirc;" }, { 235, "euml;" }, { 236, "igrave;" }, { 237, "iacute;" }, { 238, "icirc;" }, { 239, "iuml;" }, { 240, "eth;" }, { 241, "ntilde;" }, { 242, "ograve;" }, { 243, "oacute;" }, { 244, "ocirc;" }, { 245, "otilde;" }, { 246, "ouml;" }, { 247, "divide;" }, { 248, "oslash;" }, { 249, "ugrave;" }, { 250, "uacute;" }, { 251, "ucirc;" }, { 252, "uuml;" }, { 253, "yacute;" }, { 254, "thorn;" }, { 255, "yuml;" }, { 338, "OElig;" }, { 339, "oelig;" }, { 352, "Scaron;" }, { 353, "scaron;" }, { 376, "Yuml;" }, { 402, "fnof;" }, { 710, "circ;" }, { 732, "tilde;" }, { 913, "Alpha;" }, { 914, "Beta;" }, { 915, "Gamma;" }, { 916, "Delta;" }, { 917, "Epsilon;" }, { 918, "Zeta;" }, { 919, "Eta;" }, { 920, "Theta;" }, { 921, "Iota;" }, { 922, "Kappa;" }, { 923, "Lambda;" }, { 924, "Mu;" }, { 925, "Nu;" }, { 926, "Xi;" }, { 927, "Omicron;" }, { 928, "Pi;" }, { 929, "Rho;" }, { 931, "Sigma;" }, { 932, "Tau;" }, { 933, "Upsilon;" }, { 934, "Phi;" }, { 935, "Chi;" }, { 936, "Psi;" }, { 937, "Omega;" }, { 945, "alpha;" }, { 946, "beta;" }, { 947, "gamma;" }, { 948, "delta;" }, { 949, "epsilon;" }, { 950, "zeta;" }, { 951, "eta;" }, { 952, "theta;" }, { 953, "iota;" }, { 954, "kappa;" }, { 955, "lambda;" }, { 956, "mu;" }, { 957, "nu;" }, { 958, "xi;" }, { 959, "omicron;" }, { 960, "pi;" }, { 961, "rho;" }, { 962, "sigmaf;" }, { 963, "sigma;" }, { 964, "tau;" }, { 965, "upsilon;" }, { 966, "phi;" }, { 967, "chi;" }, { 968, "psi;" }, { 969, "omega;" }, { 977, "thetasym;" }, { 978, "upsih;" }, { 982, "piv;" }, { 8194, "ensp;" }, { 8195, "emsp;" }, { 8201, "thinsp;" }, { 8203, "zwsp;" }, { 8204, "zwnj;" }, { 8205, "zwj;" }, { 8206, "lrm;" }, { 8207, "rlm;" }, { 8211, "ndash;" }, { 8212, "mdash;" }, { 8216, "lsquo;" }, { 8217, "rsquo;" }, { 8218, "sbquo;" }, { 8220, "ldquo;" }, { 8221, "rdquo;" }, { 8222, "bdquo;" }, { 8224, "dagger;" }, { 8225, "Dagger;" }, { 8226, "bull;" }, { 8230, "hellip;" }, { 8240, "permil;" }, { 8242, "prime;" }, { 8243, "Prime;" }, { 8249, "lsaquo;" }, { 8250, "rsaquo;" }, { 8254, "oline;" }, { 8260, "frasl;" }, { 8364, "euro;" }, { 8465, "image;" }, { 8472, "weierp;" }, { 8476, "real;" }, { 8482, "trade;" }, { 8501, "alefsym;" }, { 8592, "larr;" }, { 8593, "uarr;" }, { 8594, "rarr;" }, { 8595, "darr;" }, { 8596, "harr;" }, { 8629, "crarr;" }, { 8656, "lArr;" }, { 8657, "uArr;" }, { 8658, "rArr;" }, { 8659, "dArr;" }, { 8660, "hArr;" }, { 8704, "forall;" }, { 8706, "part;" }, { 8707, "exist;" }, { 8709, "empty;" }, { 8711, "nabla;" }, { 8712, "isin;" }, { 8713, "notin;" }, { 8715, "ni;" }, { 8719, "prod;" }, { 8721, "sum;" }, { 8722, "minus;" }, { 8727, "lowast;" }, { 8730, "radic;" }, { 8733, "prop;" }, { 8734, "infin;" }, { 8736, "ang;" }, { 8743, "and;" }, { 8744, "or;" }, { 8745, "cap;" }, { 8746, "cup;" }, { 8747, "int;" }, { 8756, "there4;" }, { 8764, "sim;" }, { 8773, "cong;" }, { 8776, "asymp;" }, { 8800, "ne;" }, { 8801, "equiv;" }, { 8804, "le;" }, { 8805, "ge;" }, { 8834, "sub;" }, { 8835, "sup;" }, { 8836, "nsub;" }, { 8838, "sube;" }, { 8839, "supe;" }, { 8853, "oplus;" }, { 8855, "otimes;" }, { 8869, "perp;" }, { 8901, "sdot;" }, { 8968, "lceil;" }, { 8969, "rceil;" }, { 8970, "lfloor;" }, { 8971, "rfloor;" }, { 9001, "lang;" }, { 9002, "rang;" }, { 9674, "loz;" }, { 9824, "spades;" }, { 9827, "clubs;" }, { 9829, "hearts;" }, { 9830, "diams;" }, { 0, "" } // 終端 }; enum { UCS_ZWSP = 8203, UCS_ZWNJ = 8204, UCS_ZWJ = 8205, UCS_LRM = 8206, UCS_RLM = 8207, }; #endif jd-2.8.7-140104/src/dispatchmanager.cpp0000644000076400010400000000511611515322702014216 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "dispatchmanager.h" #include "skeleton/dispatchable.h" Glib::StaticMutex dispatch_mutex = GLIBMM_STATIC_MUTEX_INIT; CORE::DispatchManager* instance_dispmanager = NULL; CORE::DispatchManager* CORE::get_dispmanager() { if( ! instance_dispmanager ) instance_dispmanager = new CORE::DispatchManager(); return instance_dispmanager; } void CORE::delete_dispatchmanager() { if( instance_dispmanager ) delete instance_dispmanager; instance_dispmanager = NULL; } ////////////////////// using namespace CORE; DispatchManager::DispatchManager() { #ifdef _DEBUG std::cout << "DispatchManager::DispatchManager\n"; #endif m_dispatch.connect( sigc::mem_fun( *this, &DispatchManager::slot_dispatch ) ); } DispatchManager::~DispatchManager() { #ifdef _DEBUG std::cout << "DispatchManager::~DispatchManager size = " << m_children.size() << std::endl; #endif } void DispatchManager::add( SKELETON::Dispatchable* child ) { Glib::Mutex::Lock lock( dispatch_mutex ); // 既にlistに登録されていたらキャンセルする std::list< SKELETON::Dispatchable* >::iterator it = m_children.begin(); for( ; it != m_children.end(); ++it ){ if( *it == child ){ #ifdef _DEBUG std::cout << "DispatchManager::add canceled\n"; #endif return; } } m_children.push_back( child ); m_dispatch.emit(); #ifdef _DEBUG std::cout << "DispatchManager::add size = " << m_children.size() << std::endl; #endif } void DispatchManager::remove( SKELETON::Dispatchable* child ) { Glib::Mutex::Lock lock( dispatch_mutex ); size_t size = m_children.size(); if( ! size ) return; m_children.remove( child ); #ifdef _DEBUG if( size != m_children.size() ) std::cout << "!!!!!!!\nDispatchManager::remove size " << size << " -> " << m_children.size() << "\n!!!!!!!\n"; #endif } void DispatchManager::slot_dispatch() { Glib::Mutex::Lock lock( dispatch_mutex ); const size_t size = m_children.size(); if( ! size ) return; SKELETON::Dispatchable* child = *( m_children.begin() ); // child->callback_dispatch()の中で再び Dispatchable::add()が呼び出されると // キャンセルされてしまうので callback_dispatch() を呼び出す前にremoveする m_children.remove( child ); lock.release(); if( child ) child->callback_dispatch(); #ifdef _DEBUG std::cout << "DispatchManager::slot_dispatch size = " << size << " -> " << m_children.size() << std::endl; #endif } jd-2.8.7-140104/src/dispatchmanager.h0000644000076400010400000000146711117762115013674 0ustar // ライセンス: GPL2 // // Dispatchの管理クラス // // Glib::Dispatcher::emit()後に呼出先がdeleteされると segmentation fault で落ちるので // Dispatchを一元管理して安全にDispatchする // #ifndef _DISPATCHMANAGER_H #define _DISPATCHMANAGER_H #include #include namespace SKELETON { class Dispatchable; } namespace CORE { class DispatchManager { Glib::Dispatcher m_dispatch; std::list< SKELETON::Dispatchable* > m_children; public: DispatchManager(); virtual ~DispatchManager(); void add( SKELETON::Dispatchable* child ); void remove( SKELETON::Dispatchable* child ); void slot_dispatch(); }; CORE::DispatchManager* get_dispmanager(); void delete_dispatchmanager(); } #endif jd-2.8.7-140104/src/dndmanager.cpp0000644000076400010400000000154011116750152013162 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "dndmanager.h" CORE::DND_Manager* instance_dnd_manager = NULL; CORE::DND_Manager* CORE::get_dnd_manager() { if( ! instance_dnd_manager ) instance_dnd_manager = new DND_Manager(); assert( instance_dnd_manager ); return instance_dnd_manager; } void CORE::delete_dnd_manager() { if( instance_dnd_manager ) delete instance_dnd_manager; instance_dnd_manager = NULL; } void CORE::DND_Begin() { CORE::DND_Manager* manager = CORE::get_dnd_manager(); if( manager ) manager->begin(); } void CORE::DND_End() { CORE::DND_Manager* manager = CORE::get_dnd_manager(); if( manager ) manager->end(); } const bool CORE::DND_Now_dnd() { CORE::DND_Manager* manager = CORE::get_dnd_manager(); if( manager ) return manager->now_dnd(); return false; } jd-2.8.7-140104/src/dndmanager.h0000644000076400010400000000164111125640231012625 0ustar // ライセンス: GPL2 // // ドラッグ&ドロップの管理クラス // #ifndef _DNDMANAGER_H #define _DNDMANAGER_H #include #include // ターゲット #define DNDTARGET_FAVORITE "dnd/favorite" #define DNDTARGET_TAB "dnd/tab" #define DNDTARGET_IMAGETAB "dnd/imagetab" #define DNDTARGET_USRCMD "dnd/usrcmd" namespace CORE { class DND_Manager { // true ならd&d中 bool m_dnd; public: DND_Manager():m_dnd( false ){} virtual ~DND_Manager(){} const bool now_dnd() const{ return m_dnd; } // DnD 開始 void begin(){ m_dnd = true; } // DnD終了 void end(){ m_dnd = false; } }; /////////////////////////////////////// // インターフェース DND_Manager* get_dnd_manager(); void delete_dnd_manager(); void DND_Begin(); void DND_End(); const bool DND_Now_dnd(); } #endif jd-2.8.7-140104/src/environment.cpp0000644000076400010400000004261512101234156013432 0ustar // License GPL2 //#define _DEBUG #include "jddebug.h" #include "environment.h" #include "cache.h" #include "config/globalconf.h" #include "jdversion.h" #include "jdlib/miscutil.h" #include #include #include "gtkmm.h" #ifdef HAVE_SYS_UTSNAME_H #include // uname() #endif #ifdef _WIN32 #include typedef void (WINAPI *GetSystemInfo_t)(LPSYSTEM_INFO); typedef BOOL (WINAPI *GetProductInfo_t)(DWORD, DWORD, DWORD, DWORD, PDWORD); #endif std::string ENVIRONMENT::get_jdcomments(){ return std::string( JDCOMMENT ); } std::string ENVIRONMENT::get_jdcopyright(){ return std::string( JDCOPYRIGHT ); } std::string ENVIRONMENT::get_jdbbs(){ return std::string( JDBBS ); } std::string ENVIRONMENT::get_jd2chlog(){ return std::string( JD2CHLOG ); } std::string ENVIRONMENT::get_jdhelp(){ return std::string( JDHELP ); } std::string ENVIRONMENT::get_jdhelpcmd(){ return std::string( JDHELPCMD ); } std::string ENVIRONMENT::get_jdlicense(){ return std::string( JDLICENSE ); } int window_manager = ENVIRONMENT::WM_UNKNOWN; // // CONFIGURE_ARGSを返す // // mode: 整形モード(デフォルト = CONFIGURE_OMITTED 省略したものを一行で) // std::string ENVIRONMENT::get_configure_args( const int mode ) { std::string configure_args; #ifdef CONFIGURE_ARGS const std::string args = CONFIGURE_ARGS; // FULLはそのまま返す if( mode == CONFIGURE_FULL ) return args; size_t search_pos = 0, found_pos = 0; const size_t end_quote_pos = args.rfind( "'" ); // 複数の項目 bool multi = false; // 省略形として"--with-"や"--enable-"などを取り出す while( ( found_pos = args.find( "'--with-", search_pos ) ) != std::string::npos || ( found_pos = args.find( "'--enable-", search_pos ) ) != std::string::npos ) { size_t quote_pos = args.find( "'", found_pos + 1 ); if( quote_pos != std::string::npos && quote_pos != end_quote_pos) { // 項目が複数の場合は改行かスペースを付与 if( multi ) { if( mode == CONFIGURE_OMITTED_MULTILINE ) configure_args.append( "\n" ); else configure_args.append( " " ); } multi = true; configure_args.append( args.substr( found_pos, ( quote_pos - found_pos ) + 1 ) ); search_pos = quote_pos + 1; } else { configure_args.append( args.substr( found_pos ) ); break; } } #endif return configure_args; } // // SVNリビジョンとして表示する文字列を返す // std::string get_svn_revision( const char* rev = NULL ) { std::string svn_revision = "SVN:"; if( rev ) { // "2000:2002MS"など[0-9:MS]の形式かどうか bool valid = true; unsigned int n; const size_t rev_length = strlen( rev ); for( n = 0; n < rev_length; ++n ) { if( (unsigned char)( rev[n] - 0x30 ) > 0x0A && rev[n] != 'M' && rev[n] != 'S' ) { valid = false; break; } } if( valid ) svn_revision.append( std::string( "Rev." ) + std::string( rev ) ); } if( svn_revision.compare( "SVN:" ) == 0 ) { svn_revision.append( std::string( __DATE__ ) + "-" + std::string( __TIME__ ) ); } return svn_revision; } // // JDのバージョンを取得 // std::string ENVIRONMENT::get_jdversion() { std::stringstream jd_version; #ifdef JDVERSION_SVN #ifdef SVN_REVISION jd_version << get_svn_revision( SVN_REVISION ); #else jd_version << get_svn_revision( NULL ); #endif // SVN_REVISION #else jd_version << MAJORVERSION << "." << MINORVERSION << "." << MICROVERSION << "-" << JDTAG << JDDATE; #endif // JDVERSION_SVN return jd_version.str(); } // // ファイル等からディストリ名を取得 // std::string ENVIRONMENT::get_distname() { #ifdef _DEBUG std::cout << "SESSION::get_dist_name\n"; #endif std::string dist_name; #ifdef _WIN32 std::ostringstream vstr; vstr << "Windows"; OSVERSIONINFOEX osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (GetVersionEx((OSVERSIONINFO *)&osvi) != 0) { switch (osvi.dwPlatformId) { case VER_PLATFORM_WIN32_NT: switch (osvi.dwMajorVersion) { case 6: if (osvi.wProductType != VER_NT_WORKSTATION) { switch (osvi.dwMinorVersion) { case 2: vstr << " Server 2012"; break; case 1: vstr << " Server 2008 R2"; break; case 0: vstr << " Server 2008"; break; } } else { switch (osvi.dwMinorVersion) { case 2: vstr << " 8"; break; case 1: vstr << " 7"; break; case 0: vstr << " Vista"; break; } DWORD product; GetProductInfo_t get_product = (GetProductInfo_t)GetProcAddress( GetModuleHandle("kernel32.dll"), "GetProductInfo"); get_product(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &product); switch (product) { case 0x0001: vstr << " Ultimate"; break; // PRODUCT_ULTIMATE case 0x0002: vstr << " Home Basic"; break; // PRODUCT_HOME_BASIC case 0x0003: vstr << " Home Premium"; break; // PRODUCT_HOME_PREMIUM case 0x0004: vstr << " Enterprise"; break; // PRODUCT_ENTERPRISE case 0x0006: vstr << " Business"; break; // PRODUCT_BUSINESS case 0x000B: vstr << " Starter"; break; // PRODUCT_STARTER case 0x0030: vstr << " Professional"; break; // PRODUCT_PROFESSIONAL } } break; case 5: switch (osvi.dwMinorVersion) { case 2: if (GetSystemMetrics(SM_SERVERR2)) vstr << " Server 2003 R2"; else if (osvi.wSuiteMask & 0x8000) // VER_SUITE_WH_SERVER vstr << " Home Server"; else if (osvi.wProductType == VER_NT_WORKSTATION) vstr << " XP Professional"; // x64 else vstr << " Server 2003"; break; case 1: if (osvi.wSuiteMask & VER_SUITE_PERSONAL) vstr << " XP Home"; else vstr << " XP Professional"; break; case 0: if (osvi.wProductType == VER_NT_WORKSTATION) vstr << " 2000 Professional"; else vstr << " 2000 Server"; break; } break; case 4: vstr << " NT 4.0"; break; } // additional informations if (osvi.dwMajorVersion >= 5) { // OS architecture SYSTEM_INFO sysi; GetSystemInfo_t get_system = (GetSystemInfo_t)GetProcAddress( GetModuleHandle("kernel32.dll"), "GetNativeSystemInfo"); if (get_system != NULL) get_system(&sysi); else GetSystemInfo(&sysi); if (sysi.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) vstr << " x64"; else if (sysi.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) vstr << " ia64"; // Service pack version if (strlen(osvi.szCSDVersion) > 0) { vstr << " " << osvi.szCSDVersion; } // Build version vstr << " (build " << osvi.dwBuildNumber << ")"; } break; case VER_PLATFORM_WIN32_WINDOWS: // Not support versions if (osvi.dwMajorVersion == 4) { switch (osvi.dwMinorVersion) { case 90: vstr << " Me"; break; case 10: vstr << " 98"; break; case 0: vstr << " 95"; break; } } break; } } dist_name = vstr.str(); #else // _WIN32 std::string tmp; std::string text_data; // 各ディストリビューション共通の形式として定められた // http://www.freedesktop.org/software/systemd/man/os-release.html // 旧形式のコードは頃合いを見て削除する予定 if( CACHE::load_rawdata( "/etc/os-release", text_data ) ) { std::list< std::string > lines = MISC::get_lines( text_data ); std::list< std::string >::reverse_iterator it = lines.rbegin(); while( it != lines.rend() ) { std::string name, value; size_t e; if( ( e = (*it).find( "=" ) ) != std::string::npos ) { name = MISC::remove_spaces( (*it).substr( 0, e ) ); value = MISC::remove_spaces( (*it).substr( e + 1 ) ); } if( name == "PRETTY_NAME" && ! value.empty() ) { tmp = MISC::cut_str( value, "\"", "\"" ); break; } ++it; } } // LSB系 ( Ubuntu ..etc ) else if( CACHE::load_rawdata( "/etc/lsb-release", text_data ) ) { std::list< std::string > lines = MISC::get_lines( text_data ); std::list< std::string >::reverse_iterator it = lines.rbegin(); while( it != lines.rend() ) { std::string lsb_name, lsb_data; size_t e; if( ( e = (*it).find( "=" ) ) != std::string::npos ) { lsb_name = MISC::remove_spaces( (*it).substr( 0, e ) ); lsb_data = MISC::remove_spaces( (*it).substr( e + 1 ) ); } // 「DISTRIB_DESCRIPTION="Ubuntu 7.10"」などから「Ubuntu 7.10」を取得 if( lsb_name == "DISTRIB_DESCRIPTION" && ! lsb_data.empty() ) { tmp = MISC::cut_str( lsb_data, "\"", "\"" ); break; } ++it; } } // KNOPPIX (LSB?) else if( CACHE::load_rawdata( "/etc/knoppix-version", text_data ) ) { tmp = "KNOPPIX "; tmp.append( text_data ); } // SUSE else if( CACHE::load_rawdata( "/etc/SuSE-release", text_data ) ) { std::list< std::string > lines = MISC::get_lines( text_data ); tmp = lines.front(); // 1行目のみ } // Debian else if( CACHE::load_rawdata( "/etc/debian_version", text_data ) ) { tmp = "Debian GNU/Linux "; tmp.append( text_data ); } // Solaris系 else if( CACHE::load_rawdata( "/etc/release", text_data ) ) { std::list< std::string > lines = MISC::get_lines( text_data ); std::list< std::string >::iterator it = lines.begin(); while( it != lines.end() ) { // 名前が含まれている行を取得 if( (*it).find( "BeleniX" ) != std::string::npos || (*it).find( "Nexenta" ) != std::string::npos || (*it).find( "SchilliX" ) != std::string::npos || (*it).find( "Solaris" ) != std::string::npos ) { tmp = *it; break; } ++it; } } // ファイルの中身がそのままディストリ名として扱える物 else { // ディストリ名が書かれているファイル std::string dist_files[] = { "/etc/fedora-release", "/etc/gentoo-release", "/etc/lfs-release", "/etc/mandriva-release", "/etc/momonga-release", "/usr/lib/setup/plamo-version", "/etc/puppyversion", "/etc/redhat-release", // Redhat, CentOS, WhiteBox, PCLinuxOS "/etc/sabayon-release", "/etc/slackware-version", "/etc/turbolinux-release", "/etc/vine-release", "/etc/zenwalk-version" }; unsigned int i; for( i = 0; i < sizeof( dist_files ) / sizeof( std::string ); ++i ) { if( CACHE::load_rawdata( dist_files[i], text_data ) ) { tmp = text_data; break; } } } // 文字列両端のスペースなどを削除する dist_name = MISC::remove_spaces( tmp ); // 取得した文字が異常に長い場合は空にする if( dist_name.length() > 50 ) dist_name.clear(); #ifdef HAVE_SYS_UTSNAME_H char *sysname = 0, *release = 0, *machine = 0; // システムコール uname() 準拠:SVr4, POSIX.1-2001. struct utsname* uts; uts = (struct utsname*)malloc( sizeof( struct utsname ) ); if( uname( uts ) != -1 ) { sysname = uts->sysname; release = uts->release; machine = uts->machine; } // FreeBSD等やディストリ名が取得できなかった場合は"$ uname -rs"と同じ様式 if( dist_name.empty() && sysname && release ) { dist_name = std::string( sysname ) + " " + std::string( release ); } // アーキテクチャがx86でない場合 if( machine && ( strlen( machine ) != 4 || ! ( machine[0] == 'i' && machine[1] >= '3' && machine[1] <= '6' && machine[2] == '8' && machine[3] == '6' ) ) ) { const std::string arch = "(" + std::string( machine ) + ")"; if ( dist_name.find(arch, 0) == std::string::npos ) dist_name.append( " " + arch); } free( uts ); uts = NULL; #endif #endif // _WIN32 return dist_name; } // // WM 判定 // TODO: 環境変数で判定できない場合の判定方法を考える // const int ENVIRONMENT::get_wm() { if( window_manager != WM_UNKNOWN ) return window_manager; const std::string str_wm = MISC::getenv_limited( "DESKTOP_SESSION", 5 ); if( str_wm.find( "xfce" ) != std::string::npos ) window_manager = WM_XFCE; else if( str_wm.find( "gnome" ) != std::string::npos ) window_manager = WM_GNOME; else if( str_wm.find( "kde" ) != std::string::npos ) window_manager = WM_KDE; else if( str_wm.find( "LXDE" ) != std::string::npos ) window_manager = WM_LXDE; if( window_manager == WM_UNKNOWN ) { if( ! MISC::getenv_limited( "GNOME_DESKTOP_SESSION_ID" ).empty() ) { window_manager = WM_GNOME; } else { const std::string str_wm = MISC::getenv_limited( "KDE_FULL_SESSION", 4 ); if( str_wm == "true" ) window_manager = WM_KDE; } } return window_manager; } // // WM名を文字列で返す // std::string ENVIRONMENT::get_wm_str() { std::string desktop; #ifdef _WIN32 #ifdef __MINGW32__ return std::string( "build by mingw32" ); #else return std::string( "build with _WIN32" ); #endif #else switch( get_wm() ) { case WM_GNOME : desktop = "GNOME"; break; case WM_XFCE : desktop = "XFCE"; break; case WM_KDE : desktop = "KDE"; break; case WM_LXDE : desktop = "LXDE"; break; } #endif return desktop; } // // gtkmmのバージョンを取得 // std::string ENVIRONMENT::get_gtkmm_version() { std::stringstream gtkmm_ver; gtkmm_ver << GTKMM_MAJOR_VERSION << "." << GTKMM_MINOR_VERSION << "." << GTKMM_MICRO_VERSION; return gtkmm_ver.str(); } // // glibmmのバージョンを取得 // std::string ENVIRONMENT::get_glibmm_version() { std::stringstream glibmm_ver; glibmm_ver << GLIBMM_MAJOR_VERSION << "." << GLIBMM_MINOR_VERSION << "." << GLIBMM_MICRO_VERSION; return glibmm_ver.str(); } // // 動作環境を取得 // std::string ENVIRONMENT::get_jdinfo() { std::stringstream jd_info; // バージョンを取得(jdversion.h) const std::string version = get_jdversion(); // ディストリビューション名を取得 const std::string distribution = get_distname(); // デスクトップ環境を取得( 環境変数から判別可能の場合 ) std::string desktop = get_wm_str(); // その他 std::string other; // $LANG が ja_JP.UTF-8 でない場合は"その他"に追加する。 const std::string lang = MISC::getenv_limited( "LANG", 11 ); if( lang.empty() ) other.append( "LANG 未定義" ); else if( lang != "ja_JP.utf8" && lang != "ja_JP.UTF-8" ) other.append( "LANG = " + lang ); jd_info << "[バージョン] " << version << "\n" << //#ifdef SVN_REPOSITORY // "[リポジトリ ] " << SVN_REPOSITORY << "\n" << //#endif "[ディストリ ] " << distribution << "\n" << "[パッケージ] " << "バイナリ/ソース( <配布元> )" << "\n" << "[ DE/WM ] " << desktop << "\n" << "[ gtkmm  ] " << get_gtkmm_version() << "\n" << "[ glibmm  ] " << get_glibmm_version()<< "\n" << #ifdef CONFIGURE_ARGS "[オプション ] " << get_configure_args( CONFIGURE_OMITTED_MULTILINE ) << "\n" << #endif "[ そ の 他 ] " << other << "\n"; return jd_info.str(); } jd-2.8.7-140104/src/environment.h0000644000076400010400000000157012101234156013072 0ustar // License GPL2 #ifndef _ENVIRINMENT_H #define _ENVIRONMENT_H #include namespace ENVIRONMENT { // WM enum { WM_GNOME = 0, WM_XFCE, WM_KDE, WM_LXDE, WM_UNKNOWN }; // configure_argsのモード enum { CONFIGURE_OMITTED = 0, CONFIGURE_OMITTED_MULTILINE, CONFIGURE_FULL }; std::string get_jdcomments(); std::string get_jdcopyright(); std::string get_jdbbs(); std::string get_jd2chlog(); std::string get_jdhelp(); std::string get_jdhelpcmd(); std::string get_jdlicense(); std::string get_configure_args( const int mode = CONFIGURE_OMITTED ); std::string get_jdversion(); std::string get_distname(); const int get_wm(); std::string get_wm_str(); std::string get_gtkmm_version(); std::string get_glibmm_version(); std::string get_jdinfo(); } #endif jd-2.8.7-140104/src/fontcolorpref.cpp0000644000076400010400000005133312175125752013761 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "skeleton/msgdiag.h" #include "config/globalconf.h" #include "config/defaultconf.h" #include "jdlib/miscgtk.h" #include "control/controlid.h" #include "control/controlutil.h" #include "fontcolorpref.h" #include "colorid.h" #include "fontid.h" #include "command.h" #define WARNING_STRICTCHAR "スレビューのフォント幅の近似計算を厳密に行います\n\nレイアウトが崩れにくくなるかわりにパフォーマンスが著しく低下します。通常は設定しないでください" #define WARNING_GTKRC_TREE "gtkrc 関係の設定はJDの再起動後に有効になります" using namespace CORE; FontColorPref::FontColorPref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url, true, true ), m_label_aafont( true, "AAレスと判定する正規表現(_R): " ), m_bt_reset_font( "フォントの設定を全てデフォルトに戻す(_F)", true ), m_bt_change_color( "選択行の色を設定する(_S)", true ), m_bt_reset_color( "選択行の色をデフォルトに戻す(_R)", true ), m_bt_reset_all_colors( "色の設定を全てデフォルトに戻す(_C)", true ) { CONFIG::bkup_conf(); pack_widget(); // フォント設定をセット set_font_settings( "スレビュー", FONT_MAIN, "スレビューのフォント" ); set_font_settings( "ポップアップ", FONT_POPUP, "ポップアップのフォント" ); set_font_settings( "アスキーアート", FONT_AA, "AA(スレビュー)のフォント" ); set_font_settings( "板一覧/お気に入り", FONT_BBS, "板一覧/お気に入りのフォント" ); set_font_settings( "スレ一覧", FONT_BOARD, "スレ一覧のフォント" ); set_font_settings( "書き込みビュー", FONT_MESSAGE, "書き込みビューのフォント" ); // 色設定をセット set_color_settings( COLOR_NONE, "■ " + CONTROL::get_mode_label( CONTROL::MODE_COMMON ), "" ); set_color_settings( COLOR_BACK_HIGHLIGHT_TREE, "板、スレ一覧での検索結果などのハイライトの背景色", CONF_COLOR_BACK_HIGHLIGHT_TREE ); set_color_settings( COLOR_NONE, "", "" ); set_color_settings( COLOR_NONE, "■ "+ CONTROL::get_mode_label( CONTROL::MODE_BBSLIST ), "" ); set_color_settings( COLOR_CHAR_BBS, "文字色", CONF_COLOR_CHAR_BBS ); set_color_settings( COLOR_CHAR_BBS_COMMENT, "コメントの文字色", CONF_COLOR_CHAR_BBS_COMMENT ); set_color_settings( COLOR_BACK_BBS, "奇数行の背景色", CONF_COLOR_BACK_BBS ); set_color_settings( COLOR_BACK_BBS_EVEN, "偶数行の背景色", CONF_COLOR_BACK_BBS_EVEN ); set_color_settings( COLOR_NONE, "", "" ); set_color_settings( COLOR_NONE, "■ "+ CONTROL::get_mode_label( CONTROL::MODE_BOARD ), "" ); set_color_settings( COLOR_CHAR_BOARD, "文字色", CONF_COLOR_CHAR_BOARD ); set_color_settings( COLOR_BACK_BOARD, "奇数行の背景色", CONF_COLOR_BACK_BOARD ); set_color_settings( COLOR_BACK_BOARD_EVEN, "偶数行の背景色", CONF_COLOR_BACK_BOARD_EVEN ); set_color_settings( COLOR_NONE, "", "" ); set_color_settings( COLOR_NONE, "■ "+ CONTROL::get_mode_label( CONTROL::MODE_ARTICLE ), "" ); set_color_settings( COLOR_CHAR, "基本の文字色", CONF_COLOR_CHAR ); set_color_settings( COLOR_CHAR_NAME, "名前欄の通常の文字色", CONF_COLOR_CHAR_NAME ); set_color_settings( COLOR_CHAR_NAME_B, "名前欄のトリップ等の文字色", CONF_COLOR_CHAR_NAME_B ); set_color_settings( COLOR_CHAR_NAME_NOMAIL, "メール無しの名前欄の文字色", CONF_COLOR_CHAR_NAME_NOMAIL ); set_color_settings( COLOR_CHAR_AGE, "sage でないメール欄の文字色", CONF_COLOR_CHAR_AGE ); set_color_settings( COLOR_CHAR_SELECTION, "選択範囲の文字色", CONF_COLOR_CHAR_SELECTION ); set_color_settings( COLOR_CHAR_HIGHLIGHT, "検索結果などのハイライトの文字色", CONF_COLOR_CHAR_HIGHLIGHT ); set_color_settings( COLOR_CHAR_LINK, "通常のリンクの文字色", CONF_COLOR_CHAR_LINK ); set_color_settings( COLOR_CHAR_LINK_ID_LOW, "複数発言したIDの文字色", CONF_COLOR_CHAR_LINK_ID_LOW ); set_color_settings( COLOR_CHAR_LINK_ID_HIGH, "多く発言したIDの文字色", CONF_COLOR_CHAR_LINK_ID_HIGH ); set_color_settings( COLOR_CHAR_LINK_RES, "参照されていないレス番号の文字色", CONF_COLOR_CHAR_LINK_RES ); set_color_settings( COLOR_CHAR_LINK_LOW, "他のレスから参照されたレス番号の文字色", CONF_COLOR_CHAR_LINK_LOW ); set_color_settings( COLOR_CHAR_LINK_HIGH, "参照された数が多いレス番号の文字色", CONF_COLOR_CHAR_LINK_HIGH ); set_color_settings( COLOR_IMG_NOCACHE, "画像として扱うリンクのうち、キャッシュされていない物の文字色", CONF_COLOR_IMG_NOCACHE ); set_color_settings( COLOR_IMG_CACHED, "画像として扱うリンクのうち、キャッシュされている物の文字色", CONF_COLOR_IMG_CACHED ); set_color_settings( COLOR_IMG_LOADING, "画像として扱うリンクのうち、ロード中の物の文字色", CONF_COLOR_IMG_LOADING ); set_color_settings( COLOR_IMG_ERR, "画像として扱うリンクのうち、エラーになっている物の文字色", CONF_COLOR_IMG_ERR ); set_color_settings( COLOR_BACK, "スレビューの背景色", CONF_COLOR_BACK ); set_color_settings( COLOR_BACK_POPUP, "ポップアップの背景色", CONF_COLOR_BACK_POPUP ); set_color_settings( COLOR_BACK_SELECTION, "選択範囲の背景色", CONF_COLOR_BACK_SELECTION ); set_color_settings( COLOR_BACK_HIGHLIGHT, "検索結果などのハイライトの背景色", CONF_COLOR_BACK_HIGHLIGHT ); set_color_settings( COLOR_SEPARATOR_NEW, "新着しおりの色", CONF_COLOR_SEPARATOR_NEW ); set_color_settings( COLOR_FRAME, "ポップアップのフレーム色", CONF_COLOR_FRAME ); set_color_settings( COLOR_MARKER, "オートスクロールのマーカ色", CONF_COLOR_MARKER ); set_color_settings( COLOR_NONE, "", "" ); set_color_settings( COLOR_NONE, "■ " + CONTROL::get_mode_label( CONTROL::MODE_MESSAGE ), "" ); set_color_settings( COLOR_CHAR_MESSAGE, "文字色", CONF_COLOR_CHAR_MESSAGE ); set_color_settings( COLOR_CHAR_MESSAGE_SELECTION, "選択範囲の文字色", CONF_COLOR_CHAR_MESSAGE_SELECTION ); set_color_settings( COLOR_BACK_MESSAGE, "背景色", CONF_COLOR_BACK_MESSAGE ); set_color_settings( COLOR_BACK_MESSAGE_SELECTION, "選択範囲の背景色", CONF_COLOR_BACK_MESSAGE_SELECTION ); m_combo_font.set_active( 0 ); m_fontbutton.set_font_name( CONFIG::get_fontname( m_font_tbl[ 0 ] ) ); m_tooltips.set_tip( m_event_font, m_tooltips_font[ 0 ] ); m_tooltips.set_tip( m_fontbutton, m_tooltips_font[ 0 ] ); set_title( "フォントと色の詳細設定" ); show_all_children(); } FontColorPref::~FontColorPref() {} // // 各ウィジェットを追加 // void FontColorPref::pack_widget() { const int mrg = 8; // フォント m_event_font.add( m_combo_font ); m_hbox_font.pack_start( m_event_font, Gtk::PACK_SHRINK ); m_hbox_font.pack_start( m_fontbutton, Gtk::PACK_EXPAND_WIDGET, mrg ); m_vbox_font.set_border_width( mrg ); m_vbox_font.pack_start( m_hbox_font, Gtk::PACK_SHRINK, mrg/2 ); m_checkbutton_font.add_label( "スレビューでフォント幅の近似計算を厳密に行う(_S)", true ), m_checkbutton_font.set_active( CONFIG::get_strict_char_width() ); m_tooltips.set_tip( m_checkbutton_font, WARNING_STRICTCHAR ); m_hbox_checkbutton.pack_start( m_checkbutton_font, Gtk::PACK_SHRINK ); m_vbox_font.pack_start( m_hbox_checkbutton, Gtk::PACK_SHRINK, mrg/2 ); // 行高さ m_spin_space.set_digits( 1 ); m_spin_space.set_range( 0.1, 10.0 ); m_spin_space.set_increments( 0.1, 0.1 ); m_spin_space.set_value( CONFIG::get_adjust_line_space() ); m_label_space.set_text_with_mnemonic( "スレビューの文字列の行の高さ(_H): " ); m_label_space.set_mnemonic_widget( m_spin_space ); m_hbox_space.set_spacing ( mrg ); m_hbox_space.pack_start( m_label_space, Gtk::PACK_SHRINK ); m_hbox_space.pack_start( m_spin_space, Gtk::PACK_SHRINK ); m_tooltips.set_tip( m_spin_space, "スレビューにおいて行の高さを調節します( 標準は 1 )" ); m_vbox_font.pack_start( m_hbox_space, Gtk::PACK_SHRINK, mrg/2 ); set_activate_entry( m_spin_space ); // 下線位置 m_spin_ubar.set_digits( 1 ); m_spin_ubar.set_range( 0.1, 10.0 ); m_spin_ubar.set_increments( 0.1, 0.1 ); m_spin_ubar.set_value( CONFIG::get_adjust_underline_pos() ); m_label_ubar.set_text_with_mnemonic( "スレビューの文字列の下線位置(_U): " ); m_label_ubar.set_mnemonic_widget( m_spin_ubar ); m_hbox_ubar.pack_start( m_label_ubar, Gtk::PACK_SHRINK ); m_hbox_ubar.pack_start( m_spin_ubar, Gtk::PACK_SHRINK ); m_vbox_font.pack_start( m_hbox_ubar, Gtk::PACK_SHRINK, mrg/2 ); m_tooltips.set_tip( m_spin_ubar, "スレビューにおいてアンカーなどの下線の位置を調節します( 標準は 1 )" ); set_activate_entry( m_spin_ubar ); // AAレスと判定する正規表現 m_label_aafont.set_text( CONFIG::get_regex_res_aa() ); m_vbox_font.pack_start( m_label_aafont, Gtk::PACK_SHRINK, mrg/2 ); m_tooltips.set_tip( m_label_aafont, "この正規表現に一致したレスは、アスキーアートフォントで表示します( 次に開いたスレから有効 )" ); set_activate_entry( m_label_aafont ); // フォントのリセット m_bt_reset_font.signal_clicked().connect( sigc::mem_fun( *this, &FontColorPref::slot_reset_font ) ); m_vbox_font.pack_end( m_bt_reset_font, Gtk::PACK_SHRINK ); m_notebook.append_page( m_vbox_font, "フォントの設定" ); m_combo_font.signal_changed().connect( sigc::mem_fun( *this, &FontColorPref::slot_combo_font_changed ) ); m_fontbutton.signal_font_set().connect( sigc::mem_fun( *this, &FontColorPref::slot_fontbutton_on_set ) ); m_checkbutton_font.signal_toggled().connect( sigc::mem_fun( *this, &FontColorPref::slot_checkbutton_font_toggled ) ); // 色 m_vbox_color.set_border_width( mrg ); m_vbox_color.set_spacing( mrg ); m_label_warning_color.set_text( "Ctrl+クリック又はShift+クリックで複数行選択可能\nテーマによってはツリービュー(板一覧、スレ一覧)の背景色が正しく設定されない場合があります。" ); m_vbox_color.pack_start( m_label_warning_color, Gtk::PACK_SHRINK ); m_liststore_color = Gtk::ListStore::create( m_columns_color ); m_treeview_color.set_model( m_liststore_color ); m_treeview_color.set_size_request( 480, 280 ); m_treeview_color.get_selection()->set_mode( Gtk::SELECTION_MULTIPLE ); m_treeview_color.signal_row_activated().connect( sigc::mem_fun( *this, &FontColorPref::slot_row_activated ) ); m_scrollwin_color.add( m_treeview_color ); m_scrollwin_color.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS ); m_vbox_color.pack_start( m_scrollwin_color, Gtk::PACK_EXPAND_WIDGET ); Gtk::TreeViewColumn* column = Gtk::manage( new Gtk::TreeViewColumn( "設定名", m_columns_color.m_col_name ) ); column->set_fixed_width( 430 ); column->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ); column->set_resizable( true ); m_treeview_color.append_column( *column ); Gtk::CellRenderer *cell = column->get_first_cell_renderer(); if( cell ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &FontColorPref::slot_cell_data_name ) ); column = Gtk::manage( new Gtk::TreeViewColumn( "色", m_columns_color.m_col_color ) ); m_treeview_color.append_column( *column ); cell = column->get_first_cell_renderer(); if( cell ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &FontColorPref::slot_cell_data_color ) ); m_bt_change_color.signal_clicked().connect( sigc::mem_fun( *this, &FontColorPref::slot_change_color ) ); m_bt_reset_color.signal_clicked().connect( sigc::mem_fun( *this, &FontColorPref::slot_reset_color ) ); m_hbox_change_color.set_spacing( mrg ); m_hbox_change_color.pack_end( m_bt_reset_color, Gtk::PACK_SHRINK ); m_hbox_change_color.pack_end( m_bt_change_color , Gtk::PACK_SHRINK ); m_vbox_color.pack_start( m_hbox_change_color, Gtk::PACK_SHRINK ); m_chk_use_gtkrc_tree.add_label( "ツリービューの背景色設定に gtkrc を用いる(_T)", true ), m_chk_use_gtkrc_tree.set_active( CONFIG::get_use_tree_gtkrc() ); m_chk_use_gtkrc_tree.signal_toggled().connect( sigc::mem_fun( *this, &FontColorPref::slot_chk_use_gtkrc_toggled ) ); m_vbox_color.pack_start( m_chk_use_gtkrc_tree, Gtk::PACK_SHRINK ); m_chk_use_gtkrc_selection.add_label( "スレビューの選択範囲の色設定に gtkrc を用いる(_S)", true ), m_chk_use_gtkrc_selection.set_active( CONFIG::get_use_select_gtkrc() ); m_vbox_color.pack_start( m_chk_use_gtkrc_selection, Gtk::PACK_SHRINK ); m_bt_reset_all_colors.signal_clicked().connect( sigc::mem_fun( *this, &FontColorPref::slot_reset_all_colors ) ); m_vbox_color.pack_end( m_bt_reset_all_colors, Gtk::PACK_SHRINK ); m_notebook.append_page( m_vbox_color, "色の設定" ); // 全体 get_vbox()->pack_start( m_notebook ); get_vbox()->set_spacing( mrg ); set_border_width( mrg ); } // // 設定ダイアログで OK が押された // void FontColorPref::slot_ok_clicked() { #ifdef _DEBUG std::cout << "FontColorPref::slot_ok_clicked\n"; #endif CONFIG::set_adjust_line_space( m_spin_space.get_value() ); CONFIG::set_adjust_underline_pos( m_spin_ubar.get_value() ); CONFIG::set_regex_res_aa( m_label_aafont.get_text() ); CONFIG::set_strict_char_width( m_checkbutton_font.property_active() ); CONFIG::set_use_tree_gtkrc( m_chk_use_gtkrc_tree.property_active() ); CONFIG::set_use_select_gtkrc( m_chk_use_gtkrc_selection.property_active() ); CORE::core_set_command( "relayout_all_bbslist" ); CORE::core_set_command( "relayout_all_board" ); CORE::core_set_command( "init_font_all_article" ); CORE::core_set_command( "relayout_all_article" ); CORE::core_set_command( "relayout_all_message" ); } void FontColorPref::slot_apply_clicked() { #ifdef _DEBUG std::cout << "FontColorPref::slot_apply_clicked\n"; #endif slot_ok_clicked(); CONFIG::bkup_conf(); } // // 設定ダイアログでキャンセルが押された // void FontColorPref::slot_cancel_clicked() { #ifdef _DEBUG std::cout << "FontColorPref::slot_cancel_clicked\n"; #endif CONFIG::restore_conf(); } // // フォント設定の名前と設定値をセット // void FontColorPref::set_font_settings( const std::string& name, const int fontid, const std::string& tooltip ) { if( ! name.empty() && fontid < FONT_NUM ) { m_combo_font.append_text( name ); m_font_tbl.push_back( fontid ); m_tooltips_font.push_back( tooltip ); } } // // フォント設定のコンボボックスの状態が変わった // void FontColorPref::slot_combo_font_changed() { const int num = m_combo_font.get_active_row_number(); m_fontbutton.set_font_name( CONFIG::get_fontname( m_font_tbl[ num ] ) ); m_tooltips.set_tip( m_event_font, m_tooltips_font[ num ] ); m_tooltips.set_tip( m_fontbutton, m_tooltips_font[ num ] ); } // // チェックボックスの状態が変わった // void FontColorPref::slot_checkbutton_font_toggled() { if( m_checkbutton_font.property_active() ) { SKELETON::MsgDiag mdiag( NULL, WARNING_STRICTCHAR ); mdiag.run(); } } void FontColorPref::slot_chk_use_gtkrc_toggled() { if( m_chk_use_gtkrc_tree.property_active() ) { SKELETON::MsgDiag mdiag( NULL, WARNING_GTKRC_TREE ); mdiag.run(); } } // // フォント選択ダイアログで OK が押された // void FontColorPref::slot_fontbutton_on_set() { const int num = m_combo_font.get_active_row_number(); const std::string result = m_fontbutton.get_font_name(); CONFIG::set_fontname( m_font_tbl[ num ], result ); } // // フォント設定のリセット // void FontColorPref::slot_reset_font() { CONFIG::reset_fonts(); const int num = m_combo_font.get_active_row_number(); m_fontbutton.set_font_name( CONFIG::get_fontname( m_font_tbl[ num ] ) ); m_checkbutton_font.set_active( CONFIG::CONF_STRICT_CHAR_WIDTH ); m_spin_space.set_value( CONFIG::CONF_ADJUST_LINE_SPACE ); m_spin_ubar.set_value( CONFIG::CONF_ADJUST_UNDERLINE_POS ); m_label_aafont.set_text( CONF_REGEX_RES_AA_DEFAULT ); } // // 色設定の名前と設定値をセット // void FontColorPref::set_color_settings( const int colorid, const std::string& name, const std::string& defaultval ) { #ifdef _DEBUG std::cout << " FontColorPref::set_color_settings name = " << name << " id = " << colorid << std::endl; #endif Gtk::TreeModel::Row row; row = *( m_liststore_color->append() ); row[ m_columns_color.m_col_name ] = name; row[ m_columns_color.m_col_color ] = std::string(); row[ m_columns_color.m_col_colorid ] = colorid; row[ m_columns_color.m_col_default ] = defaultval; } // // 行選択 // void FontColorPref::slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ) { #ifdef _DEBUG std::cout << "FontColorPref::slot_row_activated path = " << path.to_string() << std::endl; #endif slot_change_color(); } // // 実際の描画の際に cellrendere のプロパティをセットするスロット関数 // void FontColorPref::slot_cell_data_name( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ) { Gtk::TreeModel::Row row = *it; const int colorid = row[ m_columns_color.m_col_colorid ]; const std::string defaultcolor = row[ m_columns_color.m_col_default ]; if( colorid != COLOR_NONE && CONFIG::get_color( colorid ) != defaultcolor ){ cell->property_cell_background() = CONFIG::get_color( COLOR_BACK_HIGHLIGHT_TREE ); cell->property_cell_background_set() = true; } else cell->property_cell_background_set() = false; } void FontColorPref::slot_cell_data_color( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ) { Gtk::TreeModel::Row row = *it; const int colorid = row[ m_columns_color.m_col_colorid ]; if( colorid != COLOR_NONE ){ cell->property_cell_background() = CONFIG::get_color( colorid ); cell->property_cell_background_set() = true; } else cell->property_cell_background_set() = false; } // // 選択行の色の変更 // void FontColorPref::slot_change_color() { Gtk::TreeModel::Path path; Gtk::TreeRow row; std::list< Gtk::TreePath > selection_path = m_treeview_color.get_selection()->get_selected_rows(); if( selection_path.empty() ) return; std::list< Gtk::TreePath >::iterator it = selection_path.begin(); int colorid = COLOR_NONE; if( selection_path.size() == 1 ){ row = *m_liststore_color->get_iter( *it ); if( ! row ) return; colorid = row[ m_columns_color.m_col_colorid ]; if( colorid == COLOR_NONE ) return; } Gtk::ColorSelectionDialog colordiag; if( colorid != COLOR_NONE ) colordiag.get_colorsel()->set_current_color( Gdk::Color( CONFIG::get_color( colorid ) ) ); colordiag.set_transient_for( *CORE::get_mainwindow() ); const int ret = colordiag.run(); if( ret == Gtk::RESPONSE_OK ){ for( ; it != selection_path.end(); ++it ){ row = *m_liststore_color->get_iter( *it ); if( ! row ) continue; colorid = row[ m_columns_color.m_col_colorid ]; if( colorid != COLOR_NONE ) CONFIG::set_color( colorid , MISC::color_to_str( colordiag.get_colorsel()->get_current_color() ) ); } } } // // 選択行の色のリセット // void FontColorPref::slot_reset_color() { std::list< Gtk::TreePath > selection_path = m_treeview_color.get_selection()->get_selected_rows(); if( selection_path.empty() ) return; std::list< Gtk::TreePath >::iterator it = selection_path.begin(); for( ; it != selection_path.end(); ++it ){ Gtk::TreeRow row = *m_liststore_color->get_iter( *it ); if( ! row ) continue; const int colorid = row[ m_columns_color.m_col_colorid ]; if( colorid != COLOR_NONE ){ const std::string defaultcolor = row[ m_columns_color.m_col_default ]; CONFIG::set_color( colorid , defaultcolor ); m_treeview_color.queue_draw(); } } } // // 全ての色のリセット // void FontColorPref::slot_reset_all_colors() { if( m_chk_use_gtkrc_tree.property_active() ) { SKELETON::MsgDiag mdiag( NULL, WARNING_GTKRC_TREE ); mdiag.run(); } m_chk_use_gtkrc_tree.set_active( CONFIG::CONF_USE_TREE_GTKRC ); m_chk_use_gtkrc_selection.set_active( CONFIG::CONF_USE_SELECT_GTKRC ); CONFIG::reset_colors(); m_treeview_color.queue_draw(); } jd-2.8.7-140104/src/fontcolorpref.h0000644000076400010400000000652212112060142013404 0ustar // ライセンス: GPL2 #ifndef _FONTCOLORPREF_H #define _FONTCOLORPREF_H #include "skeleton/prefdiag.h" #include "skeleton/spinbutton.h" #include "skeleton/label_entry.h" #include namespace CORE { class ColorTreeColumn : public Gtk::TreeModel::ColumnRecord { public: Gtk::TreeModelColumn< Glib::ustring > m_col_name; Gtk::TreeModelColumn< std::string > m_col_color; Gtk::TreeModelColumn< int > m_col_colorid; Gtk::TreeModelColumn< std::string > m_col_default; ColorTreeColumn() { add( m_col_name ); add( m_col_color ); add( m_col_colorid ); add( m_col_default ); } }; //////////////////////////////// class FontColorPref : public SKELETON::PrefDiag { Gtk::Notebook m_notebook; // ツールチップ Gtk::Tooltips m_tooltips; // フォントの設定 std::vector< int > m_font_tbl; std::vector< std::string > m_tooltips_font; Gtk::HBox m_hbox_font; Gtk::VBox m_vbox_font; Gtk::EventBox m_event_font; Gtk::ComboBoxText m_combo_font; Gtk::FontButton m_fontbutton; Gtk::HBox m_hbox_checkbutton; Gtk::CheckButton m_checkbutton_font; Gtk::HBox m_hbox_space; Gtk::HBox m_hbox_ubar; Gtk::Label m_label_space; SKELETON::SpinButtonDouble m_spin_space; Gtk::Label m_label_ubar; SKELETON::SpinButtonDouble m_spin_ubar; SKELETON::LabelEntry m_label_aafont; Gtk::Button m_bt_reset_font; // 色の設定 Gtk::Label m_label_warning_color; Gtk::VBox m_vbox_color; Gtk::CheckButton m_chk_use_gtkrc_tree; Gtk::CheckButton m_chk_use_gtkrc_selection; Gtk::TreeView m_treeview_color; Glib::RefPtr< Gtk::ListStore > m_liststore_color; CORE::ColorTreeColumn m_columns_color; Gtk::ScrolledWindow m_scrollwin_color; Gtk::HBox m_hbox_change_color; Gtk::Button m_bt_change_color; Gtk::Button m_bt_reset_color; Gtk::Button m_bt_reset_all_colors; public: FontColorPref( Gtk::Window* parent, const std::string& url ); ~FontColorPref(); private: // ウィジェットを追加 void pack_widget(); // フォントの設定 void set_font_settings( const std::string& name, const int fontid, const std::string& tooltip ); void slot_combo_font_changed(); void slot_fontbutton_on_set(); void slot_checkbutton_font_toggled(); void slot_chk_use_gtkrc_toggled(); void slot_reset_font(); // 色の設定 void set_color_settings( const int colorid, const std::string& name, const std::string& defaultval ); void slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ); void slot_cell_data_name( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ); void slot_cell_data_color( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ); void slot_change_color(); void slot_reset_color(); void slot_reset_all_colors(); // OK,cancel,apply が押された virtual void slot_ok_clicked(); virtual void slot_apply_clicked(); virtual void slot_cancel_clicked(); }; } #endif jd-2.8.7-140104/src/fontid.h0000644000076400010400000000106512076543115012021 0ustar // フォントID #ifndef _FONT_ID_H #define _FONT_ID_H enum { FONT_MAIN = 0, // スレッドビューなどの基本の物 FONT_POPUP, // ポップアップ FONT_AA, // AA(スレビュー) FONT_BBS, // スレ一覧 FONT_BOARD, // 板一覧 FONT_MESSAGE, // 書き込みビューのエディタ FONT_ENTRY_DEFAULT, // Gtk::Entryのデフォルトフォント FONT_NUM, FONT_EMPTY, // フォントID未設定 FONT_DEFAULT, // ビューの標準フォントを使用 }; #endif jd-2.8.7-140104/src/global.h0000644000076400010400000002115512112060255011766 0ustar // グローバルな定数などの定義 #ifndef _GLOBAL_H #define _GLOBAL_H #include enum{ TIMER_TIMEOUT = 50, // msec 内部クロックの周期 TIMER_TIMEOUT_SMOOTH_SCROLL = 33, // msec スレビューのスムーススクロール描画用クロック周期 MAX_RESNUMBER = 11000, // 最大表示可能レス数 MAX_MG_LNG = 5, // マウスジェスチャの最大ストローク ICON_SIZE = 32 // 画像アイコンの大きさ }; // 書き込みビューの名前欄の空白 #define JD_NAME_BLANK "jd_name_blank" // 書き込みビューのメール欄の空白 #define JD_MAIL_BLANK "jd_mail_blank" // SKELETON::SelectItemPrefの項目名 #define ITEM_NAME_BBSLISTVIEW "板一覧" #define ITEM_NAME_FAVORITEVIEW "お気に入り" #define ITEM_NAME_HISTVIEW "スレ履歴" #define ITEM_NAME_HIST_BOARDVIEW "板履歴" #define ITEM_NAME_HIST_CLOSEVIEW "最近閉じたスレ" #define ITEM_NAME_HIST_CLOSEBOARDVIEW "最近閉じた板" #define ITEM_NAME_HIST_CLOSEIMGVIEW "最近閉じた画像" #define ITEM_NAME_BOARDVIEW "スレ一覧" #define ITEM_NAME_ARTICLEVIEW "スレビュー" #define ITEM_NAME_IMAGEVIEW "画像ビュー" #define ITEM_NAME_URL "URL" #define ITEM_NAME_GO "移動" #define ITEM_NAME_SEPARATOR "区切り" #define ITEM_NAME_MARK "!" #define ITEM_NAME_ID "番号" #define ITEM_NAME_BOARD "板" #define ITEM_NAME_NAME "タイトル" #define ITEM_NAME_RES "レス" #define ITEM_NAME_LOAD "取得" #define ITEM_NAME_NEW "新着" #define ITEM_NAME_SINCE "since" #define ITEM_NAME_LASTWRITE "最終書込" #define ITEM_NAME_ACCESS "最終取得" #define ITEM_NAME_SPEED "速度" #define ITEM_NAME_DIFF "増分" #define ITEM_NAME_WRITEMSG "書き込み" #define ITEM_NAME_OPENBOARD "板を開く" #define ITEM_NAME_OPENARTICLETAB "タブでスレを開く" #define ITEM_NAME_REGETARTICLE "スレ情報を消さずに再取得" #define ITEM_NAME_BOOKMARK "しおりを設定/解除" #define ITEM_NAME_SEARCH "検索" #define ITEM_NAME_DRAWOUT "抽出" #define ITEM_NAME_RELOAD "再読み込み" #define ITEM_NAME_STOPLOADING "読み込み中止" #define ITEM_NAME_APPENDFAVORITE "お気に入りに追加" #define ITEM_NAME_FAVORITE_ARTICLE "スレをお気に入りに追加" #define ITEM_NAME_CHECK_UPDATE_ROOT "サイドバー更新チェック" #define ITEM_NAME_CHECK_UPDATE_OPEN_ROOT "サイドバー更新チェックして開く" #define ITEM_NAME_COPY "コピー" #define ITEM_NAME_COPY_URL "URLをコピー" #define ITEM_NAME_COPY_TITLE_URL "タイトルとURLをコピー" #define ITEM_NAME_COPY_TITLE_URL_THREAD "スレのタイトルとURLをコピー" #define ITEM_NAME_COPY_THREAD_INFO "スレ情報のコピー" #define ITEM_NAME_DELETE "削除" #define ITEM_NAME_QUIT "閉じる" #define ITEM_NAME_BACK "前へ戻る" #define ITEM_NAME_FORWARD "次へ進む" #define ITEM_NAME_LOCK "タブをロックする" #define ITEM_NAME_LIVE "実況開始/停止" #define ITEM_NAME_NEWARTICLE "新スレ作成" #define ITEM_NAME_SEARCHBOX "検索ボックス" #define ITEM_NAME_SEARCH_NEXT "次検索" #define ITEM_NAME_SEARCH_PREV "前検索" #define ITEM_NAME_NEXTARTICLE "次スレ検索" #define ITEM_NAME_CLEAR_HIGHLIGHT "ハイライト解除" #define ITEM_NAME_INSERTTEXT "テキストファイル挿入" #define ITEM_NAME_LOCK_MESSAGE "書き込み後に閉じない" #define ITEM_NAME_PREVIEW "プレビュー表示" #define ITEM_NAME_UNDO "元に戻す(Undo)" #define ITEM_NAME_REDO "やり直し(Redo)" #define ITEM_NAME_NGWORD "NGワード" #define ITEM_NAME_ABONE_SELECTION "選択範囲のレスをあぼ〜ん" #define ITEM_NAME_ABONE_ARTICLE "スレをあぼ〜んする" #define ITEM_NAME_QUOTE_SELECTION "引用してレスする" #define ITEM_NAME_OPEN_BROWSER "ブラウザで開く" #define ITEM_NAME_OPEN_CACHE_BROWSER "キャッシュをブラウザで開く" #define ITEM_NAME_USER_COMMAND "ユーザコマンド" #define ITEM_NAME_ETC "その他" #define ITEM_NAME_SAVE_DAT "datを保存" #define ITEM_NAME_SELECTIMG "選択範囲の画像を開く" #define ITEM_NAME_SELECTDELIMG "選択範囲の画像を削除" #define ITEM_NAME_SELECTABONEIMG "選択範囲の画像をあぼ〜ん" #define ITEM_NAME_PREFERENCEVIEW "プロパティ" #define ITEM_NAME_PREF_BOARD "板のプロパティ" #define ITEM_NAME_PREF_THREAD "スレのプロパティ" #define ITEM_NAME_PREF_IMAGE "画像のプロパティ" // SESSION::get_item_*() の戻り値 enum { ITEM_BBSLISTVIEW = 0, ITEM_FAVORITEVIEW, ITEM_BOARDVIEW, ITEM_HISTVIEW, ITEM_HIST_BOARDVIEW, ITEM_HIST_CLOSEVIEW, ITEM_HIST_CLOSEBOARDVIEW, ITEM_HIST_CLOSEIMGVIEW, ITEM_ARTICLEVIEW, ITEM_IMAGEVIEW, ITEM_URL, ITEM_GO, ITEM_SEPARATOR, ITEM_MARK, ITEM_ID, ITEM_BOARD, ITEM_NAME, ITEM_RES, ITEM_LOAD, ITEM_NEW, ITEM_SINCE, ITEM_LASTWRITE, ITEM_ACCESS, ITEM_SPEED, ITEM_DIFF, ITEM_WRITEMSG, ITEM_OPENBOARD, ITEM_OPENARTICLETAB, ITEM_REGETARTICLE, ITEM_BOOKMARK, ITEM_SEARCH, ITEM_DRAWOUT, ITEM_RELOAD, ITEM_STOPLOADING, ITEM_APPENDFAVORITE, ITEM_FAVORITE_ARTICLE, ITEM_CHECK_UPDATE_ROOT, ITEM_CHECK_UPDATE_OPEN_ROOT, ITEM_COPY, ITEM_COPY_URL, ITEM_COPY_TITLE_URL, ITEM_COPY_TITLE_URL_THREAD, ITEM_COPY_THREAD_INFO, ITEM_DELETE, ITEM_QUIT, ITEM_BACK, ITEM_FORWARD, ITEM_LOCK, ITEM_LIVE, ITEM_NEWARTICLE, ITEM_SEARCHBOX, ITEM_SEARCH_NEXT, ITEM_SEARCH_PREV, ITEM_NEXTARTICLE, ITEM_CLEAR_HIGHLIGHT, ITEM_INSERTTEXT, ITEM_LOCK_MESSAGE, ITEM_PREVIEW, ITEM_UNDO, ITEM_REDO, ITEM_NGWORD, ITEM_ABONE_SELECTION, ITEM_ABONE_ARTICLE, ITEM_QUOTE_SELECTION, ITEM_OPEN_BROWSER, ITEM_OPEN_CACHE_BROWSER, ITEM_USER_COMMAND, ITEM_ETC, ITEM_SAVE_DAT, ITEM_SELECTIMG, ITEM_SELECTDELIMG, ITEM_SELECTABONEIMG, ITEM_PREFERENCEVIEW, ITEM_PREF_BOARD, ITEM_PREF_THREAD, ITEM_PREF_IMAGE, ITEM_END }; // 板やスレッドの状態 enum { STATUS_UNKNOWN = 0, // 不明 STATUS_NORMAL = 1, // 通常 STATUS_OLD = 2, // DAT落ち or 板が移転した STATUS_BROKEN = 4, // あぼーんなどで壊れている STATUS_UPDATE = 8, // 更新可能 STATUS_UPDATED = 16, // 更新済み STATUS_BROKEN_SUBJECT = 32 // subject.txt が壊れている( subject.txt に示されたレス数よりも実際の取得数の方が多い ) }; // オートリロードのモード enum { AUTORELOAD_NOT = 0, AUTORELOAD_ONCE, // 1 回だけリロードして終わり AUTORELOAD_ON // オートリロード実行中 }; enum { AUTORELOAD_MINSEC = 2, // オートリロードの最小秒数 MIN_LIVE_RELOAD_SEC = 10, // 実況時の最小リロード間隔 WAITLOADIMG_SEC = 2, // 画像のロード待ち間隔 CHECKUPDATE_MINSEC = 60 // 更新チェックの最小秒数 }; // 実況スクロールモード enum { LIVE_SCRMODE_VARIABLE = 0, // 速度可変、速度がしきい値を越えると行単位でスクロール LIVE_SCRMODE_STEADY, // 速度一定、遅れがしきい値を越えると行単位でスクロール LIVE_SCRMODE_NUM }; // プロトコル #define PROTO_ANCHORE "anc://" #define PROTO_RES "res://" #define PROTO_NAME "name://" #define PROTO_ID "ID://" #define PROTO_BE "BE://" #define PROTO_ABONE "abone://" #define PROTO_OR "or://" #define PROTO_BM "bm://" #define PROTO_BROKEN "bloken://" #define PROTO_POSTLOG "postlog://" #define PROTO_SSSP "sssp://" // 仮想 URL #define URL_LOGIN2CH "jdlogin://login2ch" #define URL_LOGINBE "jdlogin://loginbe" #define URL_LOGINP2 "jdlogin://loginp2" #define URL_BBSLISTADMIN "jdadmin://bbslist" #define URL_BOARDADMIN "jdadmin://board" #define URL_ARTICLEADMIN "jdadmin://article" #define URL_IMAGEADMIN "jdadmin://image" #define URL_MESSAGEADMIN "jdadmin://message" #define URL_BBSLISTVIEW "jdview://bbslist" #define URL_FAVORITEVIEW "jdview://favorite" #define URL_HISTTHREADVIEW "jdview://histthread" #define URL_HISTBOARDVIEW "jdview://histboard" #define URL_HISTCLOSEVIEW "jdview://histclose" #define URL_HISTCLOSEBOARDVIEW "jdview://histcloseboard" #define URL_HISTCLOSEIMGVIEW "jdview://histcloseimg" #define URL_ALLLOG "jdview://alllog" #define URL_USRCMD "jdpref://usrcmd" #define URL_LINKFILTER "jdpref://linkfilter" #define URL_BROWSER "jdpref://browser" #define URL_ABOUTCONFIG "jdpref://aboutconfig" #define URL_PRIVACY "jdpref://privacy" #define URL_BOARD_LOCAL "file:///local" #define URL_SEARCH_ALLBOARD "allboard" #define URL_SEARCH_TITLE "title" #endif jd-2.8.7-140104/src/globalabonepref.h0000644000076400010400000000571610614661150013663 0ustar // ライセンス: GPL2 // 全体あぼーん設定ダイアログ #ifndef _GLOBALABONPREF_H #define _GLOBALABONPREF_H #include "skeleton/prefdiag.h" #include "skeleton/editview.h" #include "config/globalconf.h" #include "dbtree/interface.h" #include "command.h" namespace CORE { class GlobalAbonePref : public SKELETON::PrefDiag { Gtk::Notebook m_notebook; SKELETON::EditView m_edit_name, m_edit_word, m_edit_regex; Gtk::Label m_label_warning; // OK押した virtual void slot_ok_clicked(){ // 全体あぼーん再設定 std::list< std::string > list_name = MISC::get_lines( m_edit_name.get_text() ); std::list< std::string > list_word = MISC::get_lines( m_edit_word.get_text() ); std::list< std::string > list_regex = MISC::get_lines( m_edit_regex.get_text() ); CONFIG::set_list_abone_name( list_name ); CONFIG::set_list_abone_word( list_word ); CONFIG::set_list_abone_regex( list_regex ); // あぼーん情報更新 DBTREE::update_abone_all_article(); CORE::core_set_command( "relayout_all_article" ); } public: GlobalAbonePref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url ) { std::string str_name, str_word, str_regex; std::list< std::string >::iterator it; // name std::list< std::string > list_name = CONFIG::get_list_abone_name(); for( it = list_name.begin(); it != list_name.end(); ++it ) if( ! ( *it ).empty() ) str_name += ( *it ) + "\n"; m_edit_name.set_text( str_name ); // word std::list< std::string > list_word = CONFIG::get_list_abone_word(); for( it = list_word.begin(); it != list_word.end(); ++it ) if( ! ( *it ).empty() ) str_word += ( *it ) + "\n"; m_edit_word.set_text( str_word ); // regex std::list< std::string > list_regex = CONFIG::get_list_abone_regex(); for( it = list_regex.begin(); it != list_regex.end(); ++it ) if( ! ( *it ).empty() ) str_regex += ( *it ) + "\n"; m_edit_regex.set_text( str_regex ); m_label_warning.set_text( "ここでのあぼーん設定は全板の全スレに適用されます。\n\n設定のし過ぎは全板の全スレの表示速度を低下させます。\n\n指定のし過ぎに気を付けてください。" ); m_notebook.append_page( m_label_warning, "注意" ); m_notebook.append_page( m_edit_name, "NG 名前" ); m_notebook.append_page( m_edit_word, "NG ワード" ); m_notebook.append_page( m_edit_regex, "NG 正規表現" ); get_vbox()->pack_start( m_notebook ); set_title( "全体あぼ〜ん設定" ); resize( 600, 400 ); show_all_children(); } virtual ~GlobalAbonePref(){} }; } #endif jd-2.8.7-140104/src/globalabonethreadpref.h0000644000076400010400000001123411360116564015046 0ustar // ライセンス: GPL2 // 全体スレあぼーん設定ダイアログ #ifndef _GLOBALABONTHREADPREF_H #define _GLOBALABONTHREADPREF_H #include "skeleton/prefdiag.h" #include "skeleton/editview.h" #include "skeleton/spinbutton.h" #include "config/globalconf.h" #include "dbtree/interface.h" #include "command.h" namespace CORE { class GlobalAboneThreadPref : public SKELETON::PrefDiag { Gtk::Notebook m_notebook; SKELETON::EditView m_edit_word, m_edit_regex; Gtk::Label m_label_warning; Gtk::VBox m_vbox_abone_thread; Gtk::Label m_label_abone_thread; Gtk::HBox m_hbox_number; Gtk::Label m_label_number; SKELETON::SpinButton m_spin_number; Gtk::HBox m_hbox_hour; Gtk::Label m_label_hour; SKELETON::SpinButton m_spin_hour; // OK押した virtual void slot_ok_clicked(){ // 全体あぼーん再設定 // スレ数、時間 CONFIG::set_abone_number_thread( m_spin_number.get_value_as_int() ); CONFIG::set_abone_hour_thread( m_spin_hour.get_value_as_int() ); // word std::list< std::string > list_word = MISC::get_lines( m_edit_word.get_text() ); // regex std::list< std::string > list_regex = MISC::get_lines( m_edit_regex.get_text() ); CONFIG::set_list_abone_word_thread( list_word ); CONFIG::set_list_abone_regex_thread( list_regex ); // スレ一覧再描画 DBTREE::update_abone_thread(); } public: GlobalAboneThreadPref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url ) { std::string str_name, str_word, str_regex; std::list< std::string >::iterator it; // スレ数、時間 m_label_abone_thread.set_text( "以下の数字が0の時は未設定になります。\nまたキャッシュにログがあるスレはあぼ〜んされません。\n\n" ); m_label_number.set_text( "レス以上のスレをあぼ〜ん" ); m_spin_number.set_range( 0, 9999 ); m_spin_number.set_increments( 1, 1 ); m_spin_number.set_value( CONFIG::get_abone_number_thread() ); m_hbox_number.set_spacing( 4 ); m_hbox_number.pack_start( m_spin_number, Gtk::PACK_SHRINK ); m_hbox_number.pack_start( m_label_number, Gtk::PACK_SHRINK ); set_activate_entry( m_spin_number ); m_label_hour.set_text( "時間以上スレ立てから経過したスレをあぼ〜ん" ); m_spin_hour.set_range( 0, 9999 ); m_spin_hour.set_increments( 1, 1 ); m_spin_hour.set_value( CONFIG::get_abone_hour_thread() ); m_hbox_hour.set_spacing( 4 ); m_hbox_hour.pack_start( m_spin_hour, Gtk::PACK_SHRINK ); m_hbox_hour.pack_start( m_label_hour, Gtk::PACK_SHRINK ); set_activate_entry( m_spin_hour ); m_vbox_abone_thread.set_border_width( 16 ); m_vbox_abone_thread.set_spacing( 8 ); m_vbox_abone_thread.pack_start( m_label_abone_thread, Gtk::PACK_SHRINK ); m_vbox_abone_thread.pack_start( m_hbox_number, Gtk::PACK_SHRINK ); m_vbox_abone_thread.pack_start( m_hbox_hour, Gtk::PACK_SHRINK ); // word std::list< std::string > list_word = CONFIG::get_list_abone_word_thread(); for( it = list_word.begin(); it != list_word.end(); ++it ) if( ! ( *it ).empty() ) str_word += ( *it ) + "\n"; m_edit_word.set_text( str_word ); // regex std::list< std::string > list_regex = CONFIG::get_list_abone_regex_thread(); for( it = list_regex.begin(); it != list_regex.end(); ++it ) if( ! ( *it ).empty() ) str_regex += ( *it ) + "\n"; m_edit_regex.set_text( str_regex ); m_label_warning.set_text( "ここでのあぼーん設定は全板のスレ一覧に適用されます。\n\n設定のし過ぎは全板の全スレ一覧表示速度を低下させます。\n\n指定のし過ぎに気を付けてください。" ); m_notebook.append_page( m_label_warning, "注意" ); m_notebook.append_page( m_vbox_abone_thread, "一般" ); m_notebook.append_page( m_edit_word, "NG ワード" ); m_notebook.append_page( m_edit_regex, "NG 正規表現" ); get_vbox()->pack_start( m_notebook ); set_title( "全体スレあぼ〜ん設定" ); resize( 600, 400 ); show_all_children(); } virtual ~GlobalAboneThreadPref(){} }; } #endif jd-2.8.7-140104/src/gtkmmversion.h0000644000076400010400000000071512006761301013254 0ustar // ライセンス: GPL2 #ifndef GTKMM_VERSION_H #define GTKMM_VERSION_H // GTK_CHECK_VERSION in gtk/gtkversion.h (GPL2) #ifndef GTKMM_CHECK_VERSION #define GTKMM_CHECK_VERSION(major,minor,micro) \ (GTKMM_MAJOR_VERSION > (major) || \ (GTKMM_MAJOR_VERSION == (major) && GTK_MINOR_VERSION > (minor)) || \ (GTKMM_MAJOR_VERSION == (major) && GTK_MINOR_VERSION == (minor) && \ GTKMM_MICRO_VERSION >= (micro))) #endif #endif // GTKMM_VERSION_H jd-2.8.7-140104/src/history/0000755000076400010400000000000012261751612012063 5ustar jd-2.8.7-140104/src/history/historymanager.cpp0000644000076400010400000004216311577662613015644 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "historymanager.h" #include "historymenu.h" #include "viewhistory.h" #include "viewhistoryitem.h" #include "dbtree/interface.h" #include "xml/document.h" #include "xml/tools.h" #include "cache.h" #include "session.h" #include "sharedbuffer.h" #include "command.h" #include "global.h" HISTORY::History_Manager* instance_history_manager = NULL; HISTORY::History_Manager* HISTORY::get_history_manager() { if( ! instance_history_manager ) instance_history_manager = new History_Manager(); assert( instance_history_manager ); return instance_history_manager; } void HISTORY::delete_history_manager() { if( instance_history_manager ) delete instance_history_manager; instance_history_manager = NULL; } // url_history で指定した履歴に追加 void HISTORY::append_history( const std::string& url_history, const std::string& url, const std::string& name, const int type ) { get_history_manager()->append_history( url_history, url, name, type ); } // url_history で指定した履歴の先頭を復元 void HISTORY::restore_history( const std::string& url_history ) { get_history_manager()->restore_history( url_history ); } // url_history で指定した履歴を全クリア void HISTORY::remove_allhistories( const std::string& url_history ) { get_history_manager()->remove_allhistories( url_history ); } /////////////////////////////////////////////// using namespace HISTORY; // XML ルート要素名 #define ROOT_NODE_NAME "viewhistory" History_Manager::History_Manager() : m_menu_thread( NULL ), m_menu_board( NULL ), m_menu_close( NULL ), m_menu_closeboard( NULL ), m_menu_closeimg( NULL ), m_last_viewhistory( NULL ) { #ifdef _DEBUG std::cout << "History_Manager::History_Manager\n"; #endif xml2viewhistory(); } History_Manager::~History_Manager() { #ifdef _DEBUG std::cout << "History_Manager::~History_Manager\n"; #endif if( m_menu_thread ) delete m_menu_thread; if( m_menu_board ) delete m_menu_board; if( m_menu_close ) delete m_menu_close; if( m_menu_closeimg ) delete m_menu_closeimg; if( m_view_histories.size() ){ std::list< ViewHistory* >::iterator it = m_view_histories.begin(); for( ; it != m_view_histories.end(); ++it ) delete *it; } } // 履歴メニュー取得 Gtk::MenuItem* History_Manager::get_menu_thread() { if( ! m_menu_thread ) m_menu_thread = new HistoryMenu( URL_HISTTHREADVIEW, std::string( ITEM_NAME_HISTVIEW ) + "(_T)" ); return m_menu_thread; } Gtk::MenuItem* History_Manager::get_menu_board() { if( ! m_menu_board ) m_menu_board = new HistoryMenu( URL_HISTBOARDVIEW, std::string( ITEM_NAME_HIST_BOARDVIEW ) + "(_B)" ); return m_menu_board; } Gtk::MenuItem* History_Manager::get_menu_close() { if( ! m_menu_close ) m_menu_close = new HistoryMenu( URL_HISTCLOSEVIEW, std::string( ITEM_NAME_HIST_CLOSEVIEW ) + "(_M)" ); return m_menu_close; } Gtk::MenuItem* History_Manager::get_menu_closeboard() { if( ! m_menu_closeboard ) m_menu_closeboard = new HistoryMenu( URL_HISTCLOSEBOARDVIEW, std::string( ITEM_NAME_HIST_CLOSEBOARDVIEW ) + "(_N)" ); return m_menu_closeboard; } Gtk::MenuItem* History_Manager::get_menu_closeimg() { if( ! m_menu_closeimg ) m_menu_closeimg = new HistoryMenu( URL_HISTCLOSEIMGVIEW, std::string( ITEM_NAME_HIST_CLOSEIMGVIEW ) + "(_I)" ); return m_menu_closeimg; } // url_history で指定した履歴に追加 void History_Manager::append_history( const std::string& url_history, const std::string& url, const std::string& name, const int type ) { if( SESSION::is_booting() ) return; CORE::DATA_INFO info; info.type = type; if( url_history == URL_HISTTHREADVIEW || url_history == URL_HISTCLOSEVIEW ){ info.url = DBTREE::url_dat( url ); info.name = DBTREE::article_subject( info.url ); } if( url_history == URL_HISTBOARDVIEW || url_history == URL_HISTCLOSEBOARDVIEW ){ if( type == TYPE_BOARD ){ info.url = DBTREE::url_boardbase( url ); info.name = DBTREE::board_name( info.url ); } else{ info.url = url; info.name = name; } } if( url_history == URL_HISTCLOSEIMGVIEW ){ info.url = url; info.name = name; } CORE::DATA_INFO_LIST list_info; list_info.push_back( info ); CORE::SBUF_set_list( list_info ); CORE::core_set_command( "append_history", url_history ); set_menulabel( url_history ); } // url_history で指定した履歴の先頭を復元 void History_Manager::restore_history( const std::string& url_history ) { if( url_history == URL_HISTCLOSEVIEW && m_menu_close ) m_menu_close->restore_history(); if( url_history == URL_HISTCLOSEBOARDVIEW && m_menu_closeboard ) m_menu_closeboard->restore_history(); if( url_history == URL_HISTCLOSEIMGVIEW && m_menu_closeimg ) m_menu_closeimg->restore_history(); } // url_history で指定した履歴を全クリア void History_Manager::remove_allhistories( const std::string& url_history ) { CORE::core_set_command( "remove_allhistories", url_history ); } // url_history で指定した履歴メニューのラベルを更新 void History_Manager::set_menulabel( const std::string& url_history ) { if( url_history == URL_HISTTHREADVIEW && m_menu_thread ) m_menu_thread->set_menulabel(); if( url_history == URL_HISTBOARDVIEW && m_menu_board ) m_menu_board->set_menulabel(); if( url_history == URL_HISTCLOSEVIEW && m_menu_close ) m_menu_close->set_menulabel(); if( url_history == URL_HISTCLOSEBOARDVIEW && m_menu_closeboard ) m_menu_closeboard->set_menulabel(); if( url_history == URL_HISTCLOSEIMGVIEW && m_menu_closeimg ) m_menu_closeimg->set_menulabel(); } /////////////////////////////////////////////////////////////////////////////// // // XMLを読み込んで View履歴に変換 // void History_Manager::xml2viewhistory() { std::string xml; CACHE::load_rawdata( CACHE::path_xml_history_view(), xml ); #ifdef _DEBUG std::cout << "History_Manager::xml2viewhistory\n"; std::cout << "xml:\n" << xml << std::endl; #endif if( xml.empty() ) return; XML::Document document( xml ); XML::Dom* root = document.get_root_element( std::string( ROOT_NODE_NAME ) ); XML::DomList domlist; domlist = root->childNodes(); std::list< XML::Dom* >::iterator it = domlist.begin(); for( ; it != domlist.end(); ++it ){ if( (*it)->nodeType() != XML::NODE_TYPE_ELEMENT ) continue; // viewhistory 作成 const int type = XML::get_type( (*it)->nodeName() ); if( type != TYPE_DIR ) continue; const int top = atoi( (*it)->getAttribute( "top" ).c_str() ); const int cur = atoi( (*it)->getAttribute( "cur" ).c_str() ); const int end = atoi( (*it)->getAttribute( "end" ).c_str() ); #ifdef _DEBUG std::cout << "\n---------------\nnew viewhistory\n" << "top = " << top << std::endl << "cur = " << cur << std::endl << "end = " << end << std::endl; #endif ViewHistory* history = new ViewHistory(); assert( history ); m_view_histories.push_back( history ); // viewhistory に item を append XML::DomList domlist_hist; domlist_hist = (*it)->childNodes(); std::list< XML::Dom* >::iterator it_hist = domlist_hist.begin(); for( ; it_hist != domlist_hist.end(); ++it_hist ){ if( (*it_hist)->nodeType() != XML::NODE_TYPE_ELEMENT ) continue; const int type = XML::get_type( (*it_hist)->nodeName() ); if( type != TYPE_HISTITEM ) continue; const std::string name = (*it_hist)->getAttribute( "name" ); const std::string url = (*it_hist)->getAttribute( "url" ); #ifdef _DEBUG std::cout << "type = " << type << std::endl << "name = " << name << std::endl << "url = " << url << std::endl; #endif history->append( url ); history->replace_current_title( name ); } history->set_top( top ); history->set_cur( cur ); history->set_end( end ); } } // // View履歴をXMLに変換して保存 // void History_Manager::viewhistory2xml() { #ifdef _DEBUG std::cout << "History_Manager::viewhistory2xml\n"; #endif XML::Document document; // タブに表示されているViewのアドレスを取得 std::set< std::string > taburls; const std::list< std::string >& article_urls = SESSION::get_article_URLs(); const std::list< std::string >& board_urls = SESSION::get_board_URLs(); std::list< std::string >::const_iterator it_url = article_urls.begin(); for( ; it_url != article_urls.end(); ++it_url ){ #ifdef _DEBUG std::cout << "insert " << *it_url << std::endl; #endif taburls.insert( *it_url ); } it_url = board_urls.begin(); for( ; it_url != board_urls.end(); ++it_url ){ #ifdef _DEBUG std::cout << "insert " << *it_url << std::endl; #endif taburls.insert( *it_url ); } // root XML::Dom* root = document.appendChild( XML::NODE_TYPE_ELEMENT, std::string( ROOT_NODE_NAME ) ); std::list< ViewHistory* >::iterator it = m_view_histories.begin(); for( ; it != m_view_histories.end(); ++it ){ const int size = (*it)->get_size(); const int top = (*it)->get_top(); const int cur = (*it)->get_cur(); const int end = (*it)->get_end(); #ifdef _DEBUG std::cout << "\n---------------\nviewhistory\n" << "size = "<< size << std::endl << "top = " << top << std::endl << "cur = " << cur << std::endl << "end = " << end << std::endl << "url = " << (*it)->get_item( cur )->url << std::endl << "title = " << (*it)->get_item( cur )->title << std::endl; #endif // タブに表示されていない履歴はXMLにしない if( taburls.find( (*it)->get_item( cur )->url ) == taburls.end() ) continue; #ifdef _DEBUG std::cout << "make xml\n"; #endif std::string node_name = XML::get_name( TYPE_DIR ); XML::Dom* node = root->appendChild( XML::NODE_TYPE_ELEMENT, node_name ); node->setAttribute( "top", top ); node->setAttribute( "cur", cur ); node->setAttribute( "end", end ); if( ! size ) continue; node_name = XML::get_name( TYPE_HISTITEM ); for( int i = 0; i < size; ++i ){ XML::Dom* node_hist = node->appendChild( XML::NODE_TYPE_ELEMENT, node_name ); node_hist->setAttribute( "name", (*it)->get_item( i )->title ); node_hist->setAttribute( "url", (*it)->get_item( i )->url ); } } std::string xml; if( root->hasChildNodes() ) xml = document.get_xml(); if( ! xml.empty() ){ CACHE::save_rawdata( CACHE::path_xml_history_view(), xml ); #ifdef _DEBUG std::cout << xml << std::endl; #endif } } // // View履歴取得 // ViewHistory* History_Manager::get_viewhistory( const std::string& url ) { if( url.empty() ) return NULL; // キャッシュ if( m_last_viewhistory && m_last_viewhistory->get_current_url() == url ) return m_last_viewhistory; #ifdef _DEBUG std::cout << "History_Manager::get_view_history : " << url << std::endl << "size = " << m_view_histories.size() << std::endl; #endif if( m_view_histories.size() ){ std::list< ViewHistory* >::iterator it = m_view_histories.begin(); for( ; it != m_view_histories.end(); ++it ){ if( ( *it )->get_current_url() == url ){ #ifdef _DEBUG std::cout << "found\n"; #endif m_last_viewhistory = *it; return *it; } } } #ifdef _DEBUG std::cout << "not found\n"; #endif return NULL; } // // View履歴作成 // void History_Manager::create_viewhistory( const std::string& url ) { ViewHistory* history = get_viewhistory( url ); if( history ) return; #ifdef _DEBUG std::cout << "History_Manager::create_viewhistory : " << url << std::endl; #endif history = new ViewHistory(); if( history ){ m_view_histories.push_back( history ); history->append( url ); } } // // View履歴削除 // void History_Manager::delete_viewhistory( const std::string& url ) { #ifdef _DEBUG std::cout << "History_Manager::delete_view_history : " << url << std::endl << "size = " << m_view_histories.size() << std::endl; #endif if( m_view_histories.size() ){ std::list< ViewHistory* >::iterator it = m_view_histories.begin(); for( ; it != m_view_histories.end(); ++it ){ if( ( *it )->get_current_url() == url ){ ViewHistory* history = *it; m_view_histories.erase( it ); delete history; m_last_viewhistory = NULL; break; } } } } // // 現在表示中のViewのURL( url_old) を新しいURL( url_new )に変更 // const bool History_Manager::replace_current_url_viewhistory( const std::string& url_old, const std::string& url_new ) { #ifdef _DEBUG std::cout << "History_Manager::replace_current_url_viewhistory\n" << "old = " << url_old << std::endl << "new = " << url_new << std::endl; #endif ViewHistory* history = get_viewhistory( url_old ); if( !history ) return false; history->replace_current_url( url_new ); return true; } // // 履歴全体で url_old を url_new に変更 // void History_Manager::replace_url_viewhistory( const std::string& url_old, const std::string& url_new ) { #ifdef _DEBUG std::cout << "History_Manager::replace_url_viewhistory\n" << "old = " << url_old << std::endl << "new = " << url_new << std::endl; #endif if( m_view_histories.size() ){ std::list< ViewHistory* >::iterator it = m_view_histories.begin(); for( ; it != m_view_histories.end(); ++it ) ( *it )->replace_url( url_old, url_new ); } } // // View履歴タイトル更新 // const bool History_Manager::replace_current_title_viewhistory( const std::string& url, const std::string& title ) { #ifdef _DEBUG std::cout << "History_Manager::replace_current_title_viewhistory\n" << "url = " << url << std::endl << "new = " << title << std::endl; #endif ViewHistory* history = get_viewhistory( url ); if( !history ) return false; history->replace_current_title( title ); return true; } // item の取得 std::vector< ViewHistoryItem* >& History_Manager::get_items_back_viewhistory( const std::string& url, const int count ) { static std::vector< ViewHistoryItem* > nullitems; ViewHistory* history = get_viewhistory( url ); if( !history ) return nullitems; return history->get_items_back( count ); } std::vector< ViewHistoryItem* >& History_Manager::get_items_forward_viewhistory( const std::string& url, const int count ) { static std::vector< ViewHistoryItem* > nullitems; ViewHistory* history = get_viewhistory( url ); if( !history ) return nullitems; return history->get_items_forward( count ); } // // View履歴追加 // const bool History_Manager::append_viewhistory( const std::string& url_current, const std::string& url_append ) { #ifdef _DEBUG std::cout << "History_Manager::append_viewhistory" << std::endl << "currnet = " << url_current << std::endl << "append = " << url_append << std::endl; #endif ViewHistory* history = get_viewhistory( url_current ); if( !history ) return false; history->append( url_append ); return true; } // // View履歴「戻る」可能 // const bool History_Manager::can_back_viewhistory( const std::string& url, const int count ) { ViewHistory* history = get_viewhistory( url ); if( ! history ) return false; return history->can_back( count ); } // // View履歴「進む」可能 // const bool History_Manager::can_forward_viewhistory( const std::string& url, const int count ) { ViewHistory* history = get_viewhistory( url ); if( ! history ) return false; return history->can_forward( count ); } // // View履歴戻る // // exec = true のときは履歴の位置を変更する // false の時はURLの取得のみ // const ViewHistoryItem* History_Manager::back_viewhistory( const std::string& url, const int count, const bool exec ) { #ifdef _DEBUG std::cout << "History_Manager::back_viewhistory count = " << count << " exec = " << exec << " url = " << url << std::endl; #endif ViewHistory* history = get_viewhistory( url ); if( ! history ) return NULL; return history->back( count, exec ); } // // View履歴進む // // exec = true のときは履歴の位置を変更する // false の時はURLの取得のみ // const ViewHistoryItem* History_Manager::forward_viewhistory( const std::string& url, const int count, const bool exec ) { #ifdef _DEBUG std::cout << "History_Manager::forward_viewhistory count = " << count << " exec = " << exec << " url = " << url << std::endl; #endif ViewHistory* history = get_viewhistory( url ); if( ! history ) return NULL; return history->forward( count, exec ); } jd-2.8.7-140104/src/history/historymanager.h0000644000076400010400000001005311577662613015302 0ustar // ライセンス: GPL2 // // 履歴管理クラス // #ifndef _HISTORYMANAGER_H #define _HISTORYMANAGER_H #include #include #include namespace Gtk { class Menu; class MenuItem; }; namespace HISTORY { class HistoryMenu; class ViewHistory; class ViewHistoryItem; class History_Manager { // 履歴メニュー HistoryMenu* m_menu_thread; HistoryMenu* m_menu_board; HistoryMenu* m_menu_close; HistoryMenu* m_menu_closeboard; HistoryMenu* m_menu_closeimg; // View履歴 std::list< ViewHistory* > m_view_histories; ViewHistory* m_last_viewhistory; public: History_Manager(); virtual ~History_Manager(); // 履歴メニュー取得 Gtk::MenuItem* get_menu_thread(); Gtk::MenuItem* get_menu_board(); Gtk::MenuItem* get_menu_close(); Gtk::MenuItem* get_menu_closeboard(); Gtk::MenuItem* get_menu_closeimg(); // url_history で指定した履歴に追加 void append_history( const std::string& url_history, const std::string& url, const std::string& name, const int type ); // url_history で指定した履歴の先頭を復元 void restore_history( const std::string& url_history ); // url_history で指定した履歴を全クリア void remove_allhistories( const std::string& url_history ); // url_history で指定した履歴メニューのラベルを更新 void set_menulabel( const std::string& url_history ); ////////////////////////////////////////////////////////////////////////////// // // View履歴 public: // View履歴をXMLに変換して保存 void viewhistory2xml(); // 作成 / 削除 void create_viewhistory( const std::string& url ); void delete_viewhistory( const std::string& url ); // 現在表示中のViewのURL( url_old) を新しいURL( url_new )に変更 const bool replace_current_url_viewhistory( const std::string& url_old, const std::string& url_new ); // 履歴全体で url_old を url_new に変更 void replace_url_viewhistory( const std::string& url_old, const std::string& url_new ); // タイトル更新 const bool replace_current_title_viewhistory( const std::string& url, const std::string& title ); // item の取得 std::vector< ViewHistoryItem* >& get_items_back_viewhistory( const std::string& url, const int count ); std::vector< ViewHistoryItem* >& get_items_forward_viewhistory( const std::string& url, const int count ); // 追加 const bool append_viewhistory( const std::string& url_current, const std::string& url_append ); // 戻る / 進む // exec = true のときは履歴の位置を変更する // false の時はURLの取得のみ const bool can_back_viewhistory( const std::string& url, const int count ); const bool can_forward_viewhistory( const std::string& url, const int count ); const ViewHistoryItem* back_viewhistory( const std::string& url, const int count, const bool exec ); const ViewHistoryItem* forward_viewhistory( const std::string& url, const int count, const bool exec ); private: // XMLを読み込んで View履歴に変換 void xml2viewhistory(); // View履歴取得 ViewHistory* get_viewhistory( const std::string& url ); }; /////////////////////////////////////// // インターフェース History_Manager* get_history_manager(); void delete_history_manager(); // url_history で指定した履歴に追加 void append_history( const std::string& url_history, const std::string& url, const std::string& name, const int type ); // url_history で指定した履歴の先頭を復元 void restore_history( const std::string& url_history ); // url_history で指定した履歴を全クリア void remove_allhistories( const std::string& url_history ); } #endif jd-2.8.7-140104/src/history/historymenu.cpp0000644000076400010400000000236411511354253015157 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "historymenu.h" #include "historysubmenu.h" using namespace HISTORY; HistoryMenu::HistoryMenu( const std::string& url_history, const std::string& label ) : Gtk::MenuItem( label, true ), m_activate( false ) { m_submenu = Gtk::manage( new HistorySubMenu( url_history ) ); set_submenu( *m_submenu ); signal_activate().connect( sigc::mem_fun( *this, &HistoryMenu::slot_activate_menu ) ); signal_deselect().connect( sigc::mem_fun( *this, &HistoryMenu::slot_deactivate_menu ) ); } void HistoryMenu::restore_history() { m_submenu->restore_history(); } // ラベルをセットする void HistoryMenu::set_menulabel() { if( ! m_activate ) return; if( ! m_submenu ) return; #ifdef _DEBUG std::cout << "HistoryMenu::set_menulabel\n"; #endif m_submenu->set_menulabel(); } // activeになった void HistoryMenu::slot_activate_menu() { #ifdef _DEBUG std::cout << "HistoryMenu::slot_activate_menu\n"; #endif m_activate = true; set_menulabel(); } // メニューが deactive になった void HistoryMenu::slot_deactivate_menu() { #ifdef _DEBUG std::cout << "HistoryMenu::slot_deactivate_menu\n"; #endif m_activate = false; } jd-2.8.7-140104/src/history/historymenu.h0000644000076400010400000000122611511354253014620 0ustar // ライセンス: GPL2 // // 履歴メニュー // #ifndef _HISTORYMENU_H #define _HISTORYMENU_H #include namespace HISTORY { class HistorySubMenu; class HistoryMenu : public Gtk::MenuItem { HistorySubMenu* m_submenu; bool m_activate; public: HistoryMenu( const std::string& url_history, const std::string& label ); // 履歴の先頭を復元 void restore_history(); void set_menulabel(); private: // メニューがactiveになった時にラベルをセットする void slot_activate_menu(); void slot_deactivate_menu(); }; } #endif jd-2.8.7-140104/src/history/historysubmenu.cpp0000644000076400010400000002267111511354253015674 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "historysubmenu.h" #include "command.h" #include "prefdiagfactory.h" #include "session.h" #include "jdlib/miscutil.h" #include "skeleton/msgdiag.h" #include "dbtree/interface.h" #include "dbimg/imginterface.h" #include "config/globalconf.h" #include "control/controlid.h" #include "control/controlutil.h" #include "xml/tools.h" #include using namespace HISTORY; #define HIST_NONAME "--------------" enum { SPACING_MENU = 3, // アイコンと項目名の間のスペース HIST_MAX_LNG = 50 // 履歴に表示する文字数(半角) }; HistorySubMenu::HistorySubMenu( const std::string& url_history ) : Gtk::Menu(), m_url_history( url_history ) { Gtk::MenuItem* item; // メニュー項目作成 // 履歴クリア Gtk::Menu* menu = Gtk::manage( new Gtk::Menu() ); item = Gtk::manage( new Gtk::MenuItem( "クリアする(_C)", true ) ); menu->append( *item ); item->signal_activate().connect( sigc::mem_fun( *this, &HistorySubMenu::slot_clear ) ); item = Gtk::manage( new Gtk::MenuItem( "履歴クリア(_C)", true ) ); item->set_submenu( *menu ); append( *item ); item = Gtk::manage( new Gtk::MenuItem( "サイドバーに全て表示(_S)", true ) ); append( *item ); item->signal_activate().connect( sigc::mem_fun( *this, &HistorySubMenu::slot_switch_sideber ) ); // セパレータ item = Gtk::manage( new Gtk::SeparatorMenuItem() ); append( *item ); // 履歴項目 for( int i = 0; i < CONFIG::get_history_size(); ++i ){ Gtk::Image* image = Gtk::manage( new Gtk::Image() ); m_vec_images.push_back( image ); Gtk::Label* label = Gtk::manage( new Gtk::Label( HIST_NONAME ) ); m_vec_label.push_back( label ); Gtk::Label *label_motion = Gtk::manage( new Gtk::Label() ); if( i == 0 ) label_motion->set_text( CONTROL::get_str_motions( CONTROL::RestoreLastTab ) ); Gtk::HBox* hbox = Gtk::manage( new Gtk::HBox() ); hbox->set_spacing( SPACING_MENU ); hbox->pack_start( *image, Gtk::PACK_SHRINK ); hbox->pack_start( *label, Gtk::PACK_SHRINK ); hbox->pack_end( *label_motion, Gtk::PACK_SHRINK ); Gtk::MenuItem* item = Gtk::manage( new Gtk::MenuItem( *hbox ) ); append( *item ); item->signal_activate().connect( sigc::bind< int >( sigc::mem_fun( *this, &HistorySubMenu::slot_active ), i ) ); item->signal_button_press_event().connect( sigc::bind< int >( sigc::mem_fun( *this, &HistorySubMenu::slot_button_press ), i ) ); } // ポップアップメニュー作成 m_popupmenu.signal_deactivate().connect( sigc::mem_fun( *this, &HistorySubMenu::deactivate ) ); item = Gtk::manage( new Gtk::MenuItem( "タブで開く" ) ); item->signal_activate().connect( sigc::mem_fun( *this, &HistorySubMenu::slot_open_history ) ); m_popupmenu.append( *item ); item = Gtk::manage( new Gtk::SeparatorMenuItem() ); m_popupmenu.append( *item ); item = Gtk::manage( new Gtk::MenuItem( "履歴から削除" ) ); item->signal_activate().connect( sigc::mem_fun( *this, &HistorySubMenu::slot_remove_history ) ); m_popupmenu.append( *item ); item = Gtk::manage( new Gtk::SeparatorMenuItem() ); m_popupmenu.append( *item ); item = Gtk::manage( new Gtk::MenuItem( "プロパティ" ) ); item->signal_activate().connect( sigc::mem_fun( *this, &HistorySubMenu::slot_show_property ) ); m_popupmenu.append( *item ); m_popupmenu.show_all_children(); } HistorySubMenu::~HistorySubMenu() { #ifdef _DEBUG std::cout << "HistorySubMenu::~HistorySubMenu\n"; #endif } // 履歴の先頭を復元 void HistorySubMenu::restore_history() { #ifdef _DEBUG std::cout << "HistorySubMenu::restore_history " << m_url_history << std::endl; #endif if( open_history( 0 ) ) CORE::core_set_command( "remove_headhistory", m_url_history ); } // 履歴を開く const bool HistorySubMenu::open_history( const int i ) { bool ret = false; CORE::DATA_INFO_LIST info_list; SESSION::get_history( m_url_history, info_list ); if( (int)info_list.size() <= i ) return ret; if( ! info_list[ i ].url.empty() ){ #ifdef _DEBUG std::cout << "open " << info_list[ i ].url << std::endl; #endif const std::string tab = "true"; const std::string mode = ""; switch( info_list[ i ].type ){ case TYPE_THREAD: case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: CORE::core_set_command( "open_article" , DBTREE::url_dat( info_list[ i ].url ), tab, mode ); ret = true; break; case TYPE_BOARD: CORE::core_set_command( "open_board" , DBTREE::url_subject( info_list[ i ].url ), tab, mode ); ret = true; break; case TYPE_VBOARD: CORE::core_set_command( "open_sidebar_board", info_list[ i ].url, tab, mode, "", "set_history" ); ret = true; break; case TYPE_IMAGE: if( DBIMG::get_abone( info_list[ i ].url )){ SKELETON::MsgDiag mdiag( NULL, "あぼ〜んされています" ); mdiag.run(); } else{ CORE::core_set_command( "open_image", info_list[ i ].url ); CORE::core_set_command( "switch_image" ); ret = true; } break; } } return ret; } // メニューアイテムがactiveになった void HistorySubMenu::slot_active( const int i ) { #ifdef _DEBUG std::cout << "HistorySubMenu::slot_key_press key = " << "no = " << i << std::endl; #endif m_number_menuitem = i; open_history( i ); } // マウスボタンをクリックした bool HistorySubMenu::slot_button_press( GdkEventButton* event, int i ) { #ifdef _DEBUG std::cout << "HistorySubMenu::slot_button_press button = " << event->button << " no = " << i << std::endl; #endif m_number_menuitem = i; // ポップアップメニュー表示 if( event->button == 3 ) { m_popupmenu.popup( 0, gtk_get_current_event_time() ); } return true; } // アクティブ時にラベルをセットする void HistorySubMenu::set_menulabel() { #ifdef _DEBUG std::cout << "HistorySubMenu::set_menulabel\n"; #endif CORE::DATA_INFO_LIST info_list; SESSION::get_history( m_url_history, info_list ); for( size_t i = 0; i < m_vec_label.size(); ++i ){ std::string name; int type = TYPE_UNKNOWN; if( i < info_list.size() ){ name = info_list[ i ].name; type = info_list[ i ].type; } if( name.empty() ) name = HIST_NONAME; m_vec_images[ i ]->set( XML::get_icon( type ) ); m_vec_label[ i ]->set_text( MISC::cut_str( name, HIST_MAX_LNG ) ); } } // 履歴クリア void HistorySubMenu::slot_clear() { #ifdef _DEBUG std::cout << "HistorySubMenu::slot_clear " << m_url_history << std::endl; #endif CORE::core_set_command( "remove_allhistories", m_url_history ); } // サイドバー切り替え void HistorySubMenu::slot_switch_sideber() { #ifdef _DEBUG std::cout << "HistorySubMenu::slot_switch_sideber " << m_url_history << std::endl; #endif CORE::core_set_command( "switch_sidebar", m_url_history ); } // 指定した履歴を開く // これを呼ぶ前に m_number_menuitem に番号をセットしておく void HistorySubMenu::slot_open_history() { #ifdef _DEBUG std::cout << "HistorySubMenu::slot_open_history no = " << m_number_menuitem << std::endl; #endif open_history( m_number_menuitem ); } // 指定した履歴を削除 // これを呼ぶ前に m_number_menuitem に番号をセットしておく void HistorySubMenu::slot_remove_history() { #ifdef _DEBUG std::cout << "HistorySubMenu::slot_remove_history no = " << m_number_menuitem << std::endl; #endif const int i = m_number_menuitem; CORE::DATA_INFO_LIST info_list; SESSION::get_history( m_url_history, info_list ); if( (int)info_list.size() <= i ) return; CORE::core_set_command( "remove_history", m_url_history, info_list[ i ].url ); } // プロパティ表示 // これを呼ぶ前に m_number_menuitem に番号をセットしておく void HistorySubMenu::slot_show_property() { #ifdef _DEBUG std::cout << "HistorySubMenu::slot_show_property no = " << m_number_menuitem << std::endl; #endif const int i = m_number_menuitem; CORE::DATA_INFO_LIST info_list; SESSION::get_history( m_url_history, info_list ); if( (int)info_list.size() <= i ) return; if( ! info_list[ i ].url.empty() ){ #ifdef _DEBUG std::cout << "url " << info_list[ i ].url << std::endl; #endif SKELETON::PrefDiag* pref = NULL; switch( info_list[ i ].type ){ case TYPE_THREAD: case TYPE_THREAD_UPDATE: case TYPE_THREAD_OLD: pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_ARTICLE, info_list[ i ].url ); break; case TYPE_BOARD: case TYPE_VBOARD: pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_BOARD, info_list[ i ].url ); break; case TYPE_IMAGE: pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_IMAGE, info_list[ i ].url ); break; } if( pref ){ pref->run(); delete pref; } } } jd-2.8.7-140104/src/history/historysubmenu.h0000644000076400010400000000231611511354253015333 0ustar // ライセンス: GPL2 // // 履歴サブメニュー // #ifndef _HISTORYSUBMENU_H #define _HISTORYSUBMENU_H #include #include namespace HISTORY { class HistorySubMenu : public Gtk::Menu { std::string m_url_history; std::vector< Gtk::Image* > m_vec_images; std::vector< Gtk::Label* > m_vec_label; // ポップアップメニュー Gtk::Menu m_popupmenu; int m_number_menuitem; public: HistorySubMenu( const std::string& url_history ); virtual ~HistorySubMenu(); // 履歴の先頭を復元 void restore_history(); // アクティブ時にラベルをセットする void set_menulabel(); private: const bool open_history( const int i ); // メニューのslot関数 void slot_clear(); void slot_switch_sideber(); // メニューアイテムがactiveになった void slot_active( const int i ); bool slot_button_press( GdkEventButton* event, int i ); // ポップアップメニューのslot void slot_open_history(); void slot_remove_history(); void slot_show_property(); }; } #endif jd-2.8.7-140104/src/history/Makefile.am0000644000076400010400000000047412072045132014115 0ustar noinst_LIBRARIES = libhistory.a libhistory_a_SOURCES = \ historymanager.cpp \ historymenu.cpp \ historysubmenu.cpp \ viewhistory.cpp noinst_HEADERS = \ historymanager.h \ historymenu.h \ historysubmenu.h \ viewhistory.h \ viewhistoryitem.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/history/viewhistory.cpp0000644000076400010400000002431210775166015015172 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "viewhistory.h" using namespace HISTORY; enum { MAX_LOCAL_HISTORY = 20 // 履歴保持数 }; ViewHistory::ViewHistory() : m_history_top( 0 ), m_history_current( 0 ), m_history_end( 0 ) { #ifdef _DEBUG std::cout << "ViewHistory::ViewHistory\n"; #endif m_items.push_back( new ViewHistoryItem() ); } ViewHistory::~ViewHistory() { #ifdef _DEBUG std::cout << "ViewHistory::~ViewHistory\n"; #endif for( size_t i = 0; i < m_items.size(); ++i ) delete m_items[ i ]; } void ViewHistory::set_top( const int top ) { if( m_items.size() < MAX_LOCAL_HISTORY && top > m_history_top ) return; m_history_top = top; #ifdef _DEBUG std::cout << "ViewHistory::set_top" << std::endl << "size = " << m_items.size() << std::endl << "top = " << m_history_top << std::endl << "cur = " << m_history_current << std::endl << "end = " << m_history_end << std::endl; #endif } void ViewHistory::set_cur( const int cur ) { if( m_items.size() < MAX_LOCAL_HISTORY && cur > m_history_top ) m_history_current = m_history_top; else m_history_current = cur; #ifdef _DEBUG std::cout << "ViewHistory::set_cur" << std::endl << "size = " << m_items.size() << std::endl << "top = " << m_history_top << std::endl << "cur = " << m_history_current << std::endl << "end = " << m_history_end << std::endl; #endif } void ViewHistory::set_end( const int end ) { m_history_end = end; #ifdef _DEBUG std::cout << "ViewHistory::set_end" << std::endl << "size = " << m_items.size() << std::endl << "top = " << m_history_top << std::endl << "cur = " << m_history_current << std::endl << "end = " << m_history_end << std::endl; #endif } const std::string& ViewHistory::get_current_url() { #ifdef _DEBUG std::cout << "ViewHistory::get_current_url" << std::endl << "size = " << m_items.size() << std::endl << "top = " << m_history_top << std::endl << "cur = " << m_history_current << std::endl << "end = " << m_history_end << std::endl; assert( m_items[ m_history_current ] != NULL ); #endif return m_items[ m_history_current ]->url; } const std::string& ViewHistory::get_current_title() { return m_items[ m_history_current ]->title; } // // URL更新 // void ViewHistory::replace_current_url( const std::string& url ) { #ifdef _DEBUG std::cout << "ViewHistory::replace_current_url\n" << "old = " << m_items[ m_history_current ]->url << std::endl << "new = " << url << std::endl << "size = " << m_items.size() << std::endl << "top = " << m_history_top << std::endl << "cur = " << m_history_current << std::endl << "end = " << m_history_end << std::endl; #endif m_items[ m_history_current ]->url = url; } void ViewHistory::replace_url( const std::string& url_old, const std::string& url_new ) { #ifdef _DEBUG std::cout << "ViewHistory::replace_url\n" << "old = " << url_old << std::endl << "new = " << url_new << std::endl << "size = " << m_items.size() << std::endl << "top = " << m_history_top << std::endl << "cur = " << m_history_current << std::endl << "end = " << m_history_end << std::endl; #endif int size = m_items.size(); for( int i = 0; i < size; ++i ){ if( m_items[ i ]->url == url_old ){ m_items[ i ]->url = url_new; #ifdef _DEBUG std::cout << "replaced\n"; #endif } } } // // タイトル更新 // void ViewHistory::replace_current_title( const std::string& title ) { #ifdef _DEBUG std::cout << "ViewHistory::replace_current_title\n" << "old = " << m_items[ m_history_current ]->title << std::endl << "new = " << title << std::endl << "size = " << m_items.size() << std::endl << "top = " << m_history_top << std::endl << "cur = " << m_history_current << std::endl << "end = " << m_history_end << std::endl; #endif m_items[ m_history_current ]->title = title; } // item の取得 std::vector< ViewHistoryItem* >& ViewHistory::get_items_back( const int count ) { static std::vector< ViewHistoryItem* > items; items.clear(); if( count <= 0 ) return items; int tmp_current = m_history_current; for( int i = 0; i < count; ++i ){ if( tmp_current == m_history_end ) break; tmp_current = ( tmp_current + MAX_LOCAL_HISTORY - 1 ) % MAX_LOCAL_HISTORY; items.push_back( m_items[ tmp_current ] ); } return items; } std::vector< ViewHistoryItem* >& ViewHistory::get_items_forward( const int count ) { static std::vector< ViewHistoryItem* > items; items.clear(); if( count <= 0 ) return items; int tmp_current = m_history_current; for( int i = 0; i < count; ++i ){ if( tmp_current == m_history_top ) break; tmp_current = ( tmp_current + 1 ) % MAX_LOCAL_HISTORY; items.push_back( m_items[ tmp_current ] ); } return items; } // // 「戻る」可能 // const bool ViewHistory::can_back( const int count ) { if( count <= 0 ) return false; int tmp_current = m_history_current; for( int i = 0; i < count; ++i ){ if( tmp_current == m_history_end ) return false; tmp_current = ( tmp_current + MAX_LOCAL_HISTORY - 1 ) % MAX_LOCAL_HISTORY; } return true; } // // 「進む」可能 // const bool ViewHistory::can_forward( const int count ) { if( count <= 0 ) return false; int tmp_current = m_history_current; for( int i = 0; i < count; ++i ){ if( tmp_current == m_history_top ) return false; tmp_current = ( tmp_current + 1 ) % MAX_LOCAL_HISTORY; } return true; } // ローカル履歴追加 void ViewHistory::append( const std::string& url ) { #ifdef _DEBUG std::cout << "-------------\nViewhHstory::append : " << url << std::endl; #endif // 一番最初の呼び出し if( m_items.size() == 1 && m_items[ 0 ]->url.empty() ) m_items[ 0 ]->url = url; else{ if( get_current_url() == url ) return; // 既に登録されていないか確認 bool exist = false; int tmp_current = m_history_current; for( int i = 0; i < MAX_LOCAL_HISTORY; ++i ){ if( m_items[ tmp_current ]->url == url ){ exist = true; break; } if( tmp_current == m_history_end ) break; tmp_current = ( tmp_current + MAX_LOCAL_HISTORY - 1 ) % MAX_LOCAL_HISTORY; } // 登録されている場合は前に詰める if( exist ){ #ifdef _DEBUG std::cout << "exist\n"; #endif ViewHistoryItem* item = m_items[ tmp_current ]; for( int i = 0; i < MAX_LOCAL_HISTORY; ++i ){ if( tmp_current == m_history_current ) break; int next = ( tmp_current + 1 ) % MAX_LOCAL_HISTORY; #ifdef _DEBUG std::cout << "current = " << tmp_current << " next = " << next << std::endl; #endif m_items[ tmp_current ] = m_items[ next ]; tmp_current = next; } m_items[ tmp_current ] = item; m_history_top = m_history_current; } // 新しく追加 else{ #ifdef _DEBUG std::cout << "append\n"; #endif bool pback = ( m_items.size() < MAX_LOCAL_HISTORY && m_history_top == ( int )m_items.size() -1 && m_history_top == m_history_current ); m_history_current = ( m_history_current + 1) % MAX_LOCAL_HISTORY; if( pback ){ #ifdef _DEBUG std::cout << "push_back\n"; #endif ViewHistoryItem *item = new ViewHistoryItem(); item->url = url; m_items.push_back( item ); } else m_items[ m_history_current ]->url = url; m_history_top = m_history_current; if( m_history_top == m_history_end ) m_history_end = ( m_history_end + 1 ) % MAX_LOCAL_HISTORY; } } #ifdef _DEBUG std::cout << "size = " << m_items.size() << std::endl << "top = " << m_history_top << std::endl << "cur = " << m_history_current << std::endl << "end = " << m_history_end << std::endl << "cur = " << get_current_url() << std::endl << "title = " << get_current_title() << std::endl; assert( get_current_url() == url ); #endif } // // 戻る // // exec = true のときは履歴の位置を変更する // false の時はURLの取得のみ // const ViewHistoryItem* ViewHistory::back( const int count, const bool exec ) { return back_forward( true, count, exec ); } // // 進む // // exec = true のときは履歴の位置を変更する // false の時はURLの取得のみ // const ViewHistoryItem* ViewHistory::forward( const int count, const bool exec ) { return back_forward( false, count, exec ); } // // 戻る / 進む // const ViewHistoryItem* ViewHistory::back_forward( const bool back, const int count, const bool exec ) { #ifdef _DEBUG std::cout << "ViewHistory::back_forward count = " << count << " back = " << back << " exec = " << exec << std::endl; #endif int tmp_current = m_history_current; if( back ){ if( ! can_back( count ) ) return NULL; tmp_current = ( tmp_current + MAX_LOCAL_HISTORY - count ) % MAX_LOCAL_HISTORY; } else{ if( ! can_forward( count ) ) return NULL; tmp_current = ( tmp_current + count ) % MAX_LOCAL_HISTORY; } // 更新 if( exec ) m_history_current = tmp_current; #ifdef _DEBUG std::cout << "size = " << m_items.size() << std::endl << "top = " << m_history_top << std::endl << "cur = " << m_history_current << std::endl << "end = " << m_history_end << std::endl << "ret.url = " << m_items[ tmp_current ]->url << std::endl << "ret.title = " << m_items[ tmp_current ]->title << std::endl; #endif return m_items[ tmp_current ]; } jd-2.8.7-140104/src/history/viewhistory.h0000644000076400010400000000413310775166015014636 0ustar // ライセンス: GPL2 // View履歴クラス // #ifndef _VIEW_HISTORY_H #define _VIEW_HISTORY_H #include "viewhistoryitem.h" #include #include namespace HISTORY { class ViewHistory { friend class History_Manager; // History_Manager 以外からは直接操作禁止 std::vector< ViewHistoryItem* > m_items; int m_history_top; int m_history_current; int m_history_end; ViewHistory(); virtual ~ViewHistory(); const int get_size() const { return m_items.size(); } const ViewHistoryItem* get_item( const int pos ){ return m_items[ pos ]; } const int get_top() const { return m_history_top; } const int get_cur() const { return m_history_current; } const int get_end() const { return m_history_end; } void set_top( const int top ); void set_cur( const int cur ); void set_end( const int end ); const std::string& get_current_url(); const std::string& get_current_title(); // URL更新 void replace_current_url( const std::string& url ); // 現在のアドレス void replace_url( const std::string& url_old, const std::string& url_new ); // 全体 // タイトル更新 void replace_current_title( const std::string& title ); // item の取得 std::vector< ViewHistoryItem* >& get_items_back( const int count ); std::vector< ViewHistoryItem* >& get_items_forward( const int count ); // 戻る / 進む 可能かの判定 const bool can_back( const int count ); const bool can_forward( const int count ); // 追加 void append( const std::string& url ); // 戻る / 進む // exec = true のときは履歴の位置を変更する // false の時はitemの取得のみ const ViewHistoryItem* back( const int count, const bool exec ); const ViewHistoryItem* forward( const int count, const bool exec ); const ViewHistoryItem* back_forward( const bool back, const int count, const bool exec ); }; } #endif jd-2.8.7-140104/src/history/viewhistoryitem.h0000644000076400010400000000040410742563303015505 0ustar // ライセンス: GPL2 // View履歴で使う構造体 // #ifndef _VIEW_HISTORYITEM_H #define _VIEW_HISTORYITEM_H #include namespace HISTORY { struct ViewHistoryItem { std::string url; std::string title; }; } #endif jd-2.8.7-140104/src/httpcode.h0000644000076400010400000000076011437471144012353 0ustar /* HTTP コード */ #ifndef _HTTPCODE_H #define _HTTPCODE_H enum { HTTP_ERR = -1, HTTP_INIT = 0, HTTP_CANCEL = 1, HTTP_OLD = 2, // offlaw や 過去ログ倉庫からの読み込み HTTP_OK = 200, HTTP_CREATED = 201, HTTP_PARTIAL_CONTENT = 206, HTTP_MOVED_PERM = 301, HTTP_REDIRECT = 302, HTTP_NOT_MODIFIED = 304, HTTP_FORBIDDEN = 403, HTTP_NOT_FOUND = 404, HTTP_TIMEOUT = 408, HTTP_RANGE_ERR = 416, HTTP_TEMP_UNAV = 503 }; #endif jd-2.8.7-140104/src/icons/0000755000076400010400000000000012261751612011475 5ustar jd-2.8.7-140104/src/icons/bkmark.png0000644000076400010400000000026410605207706013454 0ustar PNG  IHDRa{IDAT8 C鲏ڑOWu#d\TT@RmDH4?{9n)́q$ @o29B2HW%6^AT2 2bg8)dicncW(IENDB`jd-2.8.7-140104/src/icons/bkmark_broken_subject.png0000644000076400010400000000026711252206623016532 0ustar PNG  IHDRa~IDAT8 C0 ONB( QC-P~!_.-A CL(m!1kV&y3 bD5O[X5O8^c GG^h~IENDB`jd-2.8.7-140104/src/icons/bkmark_thread.png0000644000076400010400000000030111032705755014775 0ustar PNG  IHDR "aIDAT(K0\n=sA?~RIHI-$f%&c`G>(H*jJ(CWhҩ $'# WYCk[&Ŏ?px nq+8tmZURx3>c/f(8IENDB`jd-2.8.7-140104/src/icons/bkmark_update.png0000644000076400010400000000025310605207706015014 0ustar PNG  IHDRarIDAT8Q0 BxzrZ\KoMxa$L$Z@ rTŔ p @܁, \HFRWҦz]s p 5 3PBfh=m]ݎ"X6qIENDB`jd-2.8.7-140104/src/icons/board.png0000644000076400010400000000032310472610325013265 0ustar PNG  IHDRaIDAT8c?%HдЃ\&3z&7l a` !7o 9sv 12bP k0dg,/ p;xe w\p `DFe(ܡGVU$IENDB`jd-2.8.7-140104/src/icons/board_update.png0000644000076400010400000000041510472610325014631 0ustar PNG  IHDRaIDAT8 0EL,$ұ 3`@C"IDG(+\c y}ޝ- ISѻ42'@DRoc樺"&_` !8벜(Wge|;0mj$d&NvEɡ*DP^?<ݓ3z(GP 4^N6#LGۋݕfڦ^; K'Djx#SmIENDB`jd-2.8.7-140104/src/icons/board_updated.png0000644000076400010400000000045210650414542014777 0ustar PNG  IHDRaIDAT8S!@%hj*%4~@rcGR45\u%EЖ.4-vv'@d:՘5Db8U[dDmQ~Fd#wTm[TB /gD ̚YȊ;a5@.Q. (rEr^/U"6٤)4JIENDB`jd-2.8.7-140104/src/icons/check.png0000644000076400010400000000032710472610325013257 0ustar PNG  IHDRaIDAT8 C_Sw̧sd_ k`TUZHıMINdf Xg- HH :⫱^q69K W}B.k\$af^%F [s C.>ܯ q XW7=+2,\7D^DIENDB`jd-2.8.7-140104/src/icons/dir.png0000644000076400010400000000025310473331004012751 0ustar PNG  IHDRarIDAT8 9"-r(R]yH+RHj y!X&^5웥 X[>ni.G?E&0KpWu$@'(0 IENDB`jd-2.8.7-140104/src/icons/down.png0000644000076400010400000000026311031614713013145 0ustar PNG  IHDRazIDAT8 L 7dDl Ue7q  81ffc&gwVBZrv= ڦHZ!Oin/8ŌqD<}$Y m掼uZIENDB`jd-2.8.7-140104/src/icons/hist_closeimg.png0000644000076400010400000000042711506370702015035 0ustar PNG  IHDRh6sBITO pHYs+IDAT(R EI dI3i8#;n!qBA?M [#Atғ'C@U5e2Usvm CDjݐ`atR*< y]u͛6z'<VUi=gyQbb@IENDB`jd-2.8.7-140104/src/icons/iconfiles.h0000644000076400010400000000564511631111353013623 0ustar // ライセンス: GPL2 // アイコンテーマのファイル #ifndef _ICONFILES_H #define _ICONFILSE_H enum { MAX_ICON_FILES = 32 }; namespace ICON { char iconfiles[][ MAX_ICON_FILES ]={ "jd16", "jd32", "jd48", "jd96", // サイドバーで使用するアイコン "dir", "image", "link", // サイドバーやタブで使用するアイコン "board", "board_update", "thread", "thread_update", "thread_old", // タブで使用するアイコン "board_updated", "thread_updated", "loading", "loading_stop", // スレ一覧で使用するアイコン "bkmark_update", "bkmark_broken_subject", "bkmark", "update", "newthread", "newthread_hour", "broken_subject", "check", "old", "info", // スレビューで使用するアイコン "bkmark_thread", "post", "post_refer", // その他 "down", "transparent", //////////////////////// // ツールバーのアイコン // 共通 "search_prev", // 前検索 "search_next", // 次検索 "stoploading", // 読み込み中止 "write", // 書き込み / 新スレ作成 "reload", // 再読み込み "appendfavorite", // お気に入りに追加 "delete", // 削除 "quit", // 閉じる "back", // 前へ戻る "forward", // 次へ進む "lock", // タブをロックする "undo", // 元に戻す(Undo) "redo", // やり直し(Redo) // メイン "bbslistview", // 板一覧 "favoriteview", // お気に入り "histview", // スレ履歴 "hist_boardview", // 板履歴 "hist_closeview", // 最近閉じたスレ "hist_closeboardview", // 最近閉じた板 "hist_closeimgview", // 最近閉じた画像 "boardview", // スレ一覧 "articleview", // スレビュー "imageview", // 画像ビュー "go", // 移動 // サイドバー "check_update_root", // サイドバー更新チェック "check_update_open_root", // サイドバー更新チェックして開く // スレビュー "search", // 検索 "live", // 実況開始/停止 // 検索バー "close_search", // 検索バーを閉じる "clear_search", // ハイライト解除 "search_and", // AND 抽出 "search_or", // OR 抽出 // 書き込みビュー "preview", // プレビュー表示 "inserttext", // テキストファイル挿入 "" }; } #endif jd-2.8.7-140104/src/icons/iconid.h0000644000076400010400000000553711577662613013140 0ustar // ライセンス: GPL2 // アイコンのID // // !!注意!! 項目を増やしたら iconfiles.h も修正すること // #ifndef _ICONID_H #define _ICONID_H namespace ICON { enum { NONE = -1, JD16 = 0, JD32, JD48, JD96, // サイドバーで使用するアイコン DIR, IMAGE, LINK, // サイドバーやタブで使用するアイコン BOARD, BOARD_UPDATE, THREAD, THREAD_UPDATE, THREAD_OLD, // タブで使用するアイコン BOARD_UPDATED, THREAD_UPDATED, LOADING, LOADING_STOP, // スレ一覧で使用するアイコン BKMARK_UPDATE, BKMARK_BROKEN_SUBJECT, BKMARK, UPDATE, NEWTHREAD, NEWTHREAD_HOUR , BROKEN_SUBJECT, CHECK, OLD, INFO, // スレビューで使用するアイコン BKMARK_THREAD, POST, POST_REFER, // その他 DOWN, TRANSPARENT, //////////////////////// // ツールバーのアイコン // 共通 SEARCH_PREV, // 前検索 SEARCH_NEXT, // 次検索 STOPLOADING, // 読み込み中止 WRITE, // 書き込み / 新スレ作成 RELOAD, // 再読み込み APPENDFAVORITE, // お気に入りに追加 DELETE, // 削除 QUIT, // 閉じる BACK, // 前へ戻る FORWARD, // 次へ進む LOCK, // タブをロックする UNDO, // 元に戻す(Undo) REDO, // やり直し(Redo) // メイン BBSLISTVIEW, // 板一覧 FAVORITEVIEW, // お気に入り HISTVIEW, // スレ履歴 HIST_BOARDVIEW, // 板履歴 HIST_CLOSEVIEW, // 最近閉じたスレ HIST_CLOSEBOARDVIEW, // 最近閉じた板 HIST_CLOSEIMGVIEW, // 最近閉じた画像 BOARDVIEW, // スレ一覧 ARTICLEVIEW, // スレビュー IMAGEVIEW, // 画像ビュー GO, // 移動 // サイドバー CHECK_UPDATE_ROOT, // サイドバー更新チェック CHECK_UPDATE_OPEN_ROOT, // サイドバー更新チェックして開く // スレビュー SEARCH, // 検索 LIVE, // 実況開始/停止 // 検索バー CLOSE_SEARCH, // 検索バーを閉じる CLEAR_SEARCH, // ハイライト解除 SEARCH_AND, // AND 抽出 SEARCH_OR, // OR 抽出 // 書き込みビュー PREVIEW, // プレビュー表示 INSERTTEXT, // テキストファイル挿入 //////////////////////// NUM_ICONS }; } #endif jd-2.8.7-140104/src/icons/iconmanager.cpp0000644000076400010400000002465512006761301014471 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "gtkmmversion.h" #include "iconmanager.h" #include "iconfiles.h" #include "cache.h" #include "jd16.h" #include "jd32.h" #include "jd48.h" #include "jd96.h" #include "bkmark_update.h" #include "bkmark.h" #include "bkmark_broken_subject.h" #include "bkmark_thread.h" #include "update.h" #include "newthread.h" #include "newthread_hour.h" #include "broken_subject.h" #include "check.h" #include "down.h" #include "write.h" #include "post.h" #include "post_refer.h" #include "loading.h" #include "loading_stop.h" #include "dir.h" #include "favorite.h" #include "hist.h" #include "hist_board.h" #include "hist_close.h" #include "hist_closeboard.h" #include "hist_closeimg.h" #include "board.h" #include "board_update.h" #include "board_updated.h" #include "thread.h" #include "thread_update.h" #include "thread_updated.h" #include "thread_old.h" #include "image.h" #include "link.h" #include "info.h" #if !GTKMM_CHECK_VERSION(2,5,0) #include "play.h" #endif #include ICON::ICON_Manager* instance_icon_manager = NULL; ICON::ICON_Manager* ICON::get_icon_manager() { if( ! instance_icon_manager ) instance_icon_manager = new ICON::ICON_Manager(); assert( instance_icon_manager ); return instance_icon_manager; } void ICON::delete_icon_manager() { if( instance_icon_manager ) delete instance_icon_manager; instance_icon_manager = NULL; } Glib::RefPtr< Gdk::Pixbuf > ICON::get_icon( int id ) { return get_icon_manager()->get_icon( id ); } /////////////////////////////////////////////// using namespace ICON; ICON_Manager::ICON_Manager() { Gtk::Image m_dummy; m_list_icons.resize( NUM_ICONS ); m_list_icons[ ICON::JD16 ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_jd16 ), icon_jd16 ); m_list_icons[ ICON::JD32 ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_jd32 ), icon_jd32 ); m_list_icons[ ICON::JD48 ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_jd48 ), icon_jd48 ); m_list_icons[ ICON::JD96 ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_jd96 ), icon_jd96 ); // サイドバーで使用するアイコン m_list_icons[ ICON::DIR ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_dir ), icon_dir ); m_list_icons[ ICON::IMAGE ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_image ), icon_image ); m_list_icons[ ICON::LINK ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_link ), icon_link ); // サイドバーやタブで使用するアイコン m_list_icons[ ICON::BOARD ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_board ), icon_board ); m_list_icons[ ICON::BOARD_UPDATE ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_board_update ), icon_board_update ); m_list_icons[ ICON::THREAD ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_thread ), icon_thread ); m_list_icons[ ICON::THREAD_UPDATE ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_thread_update ), icon_thread_update ); m_list_icons[ ICON::THREAD_OLD ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_thread_old ), icon_thread_old ); // タブで使用するアイコン m_list_icons[ ICON::BOARD_UPDATED ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_board_updated ), icon_board_updated ); m_list_icons[ ICON::THREAD_UPDATED ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_thread_updated ), icon_thread_updated ); m_list_icons[ ICON::LOADING ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_loading ), icon_loading ); m_list_icons[ ICON::LOADING_STOP ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_loading_stop ), icon_loading_stop ); // スレ一覧で使用するアイコン m_list_icons[ ICON::BKMARK_UPDATE ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_bkmark_update ), icon_bkmark_update ); m_list_icons[ ICON::BKMARK_BROKEN_SUBJECT ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_bkmark_broken_subject ), icon_bkmark_broken_subject ); m_list_icons[ ICON::BKMARK ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_bkmark ), icon_bkmark ); m_list_icons[ ICON::UPDATE ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_update ), icon_update ); m_list_icons[ ICON::NEWTHREAD ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_newthread ), icon_newthread ); m_list_icons[ ICON::NEWTHREAD_HOUR ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_newthread_hour ), icon_newthread_hour ); m_list_icons[ ICON::BROKEN_SUBJECT ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_broken_subject ), icon_broken_subject ); m_list_icons[ ICON::CHECK ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_check ), icon_check ); m_list_icons[ ICON::OLD ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_down ), icon_down ); m_list_icons[ ICON::INFO ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_info ), icon_info ); // スレビューで使用するアイコン m_list_icons[ ICON::BKMARK_THREAD ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_bkmark_thread ), icon_bkmark_thread ); m_list_icons[ ICON::POST ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_post ), icon_post ); m_list_icons[ ICON::POST_REFER ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_post_refer ), icon_post_refer ); // その他 m_list_icons[ ICON::DOWN ] = m_list_icons[ ICON::OLD ]; m_list_icons[ ICON::TRANSPARENT ] = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, true, 8, 1, 1 ); m_list_icons[ ICON::TRANSPARENT ]->fill( 0 ); ////////////////////////////// // ツールバーのアイコン // 共通 m_list_icons[ ICON::SEARCH_PREV ] = m_dummy.render_icon( Gtk::Stock::GO_UP, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::SEARCH_NEXT ] = m_dummy.render_icon( Gtk::Stock::GO_DOWN, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::STOPLOADING ] = m_dummy.render_icon( Gtk::Stock::STOP, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::WRITE ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_write ), icon_write ); m_list_icons[ ICON::RELOAD ] = m_dummy.render_icon( Gtk::Stock::REFRESH, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::APPENDFAVORITE ] = m_dummy.render_icon( Gtk::Stock::COPY, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::DELETE ] = m_dummy.render_icon( Gtk::Stock::DELETE, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::QUIT ] = m_dummy.render_icon( Gtk::Stock::CLOSE, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::BACK ] = m_dummy.render_icon( Gtk::Stock::GO_BACK, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::FORWARD ] = m_dummy.render_icon( Gtk::Stock::GO_FORWARD, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::LOCK ] = m_dummy.render_icon( Gtk::Stock::NO, Gtk::ICON_SIZE_MENU ); // メイン m_list_icons[ ICON::BBSLISTVIEW ] = m_list_icons[ ICON::DIR ]; m_list_icons[ ICON::FAVORITEVIEW ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_favorite ), icon_favorite ); m_list_icons[ ICON::HISTVIEW ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_hist ), icon_hist ); m_list_icons[ ICON::HIST_BOARDVIEW ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_hist_board ), icon_hist_board ); m_list_icons[ ICON::HIST_CLOSEVIEW ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_hist_close ), icon_hist_close ); m_list_icons[ ICON::HIST_CLOSEBOARDVIEW ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_hist_closeboard ), icon_hist_closeboard ); m_list_icons[ ICON::HIST_CLOSEIMGVIEW ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_hist_closeimg ), icon_hist_closeimg ); m_list_icons[ ICON::BOARDVIEW ] = m_list_icons[ ICON::BOARD ]; m_list_icons[ ICON::ARTICLEVIEW ] = m_list_icons[ ICON::THREAD ]; m_list_icons[ ICON::IMAGEVIEW ] = m_list_icons[ ICON::IMAGE ]; m_list_icons[ ICON::GO ] = m_dummy.render_icon( Gtk::Stock::JUMP_TO, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::UNDO ] = m_dummy.render_icon( Gtk::Stock::UNDO, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::REDO ] = m_dummy.render_icon( Gtk::Stock::REDO, Gtk::ICON_SIZE_MENU ); // サイドバー m_list_icons[ ICON::CHECK_UPDATE_ROOT ] = m_dummy.render_icon( Gtk::Stock::REFRESH, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::CHECK_UPDATE_OPEN_ROOT ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_thread ), icon_thread ); // スレビュー m_list_icons[ ICON::SEARCH ] = m_dummy.render_icon( Gtk::Stock::FIND, Gtk::ICON_SIZE_MENU ); #if GTKMM_CHECK_VERSION(2,5,0) m_list_icons[ ICON::LIVE ] = m_dummy.render_icon( Gtk::Stock::MEDIA_PLAY, Gtk::ICON_SIZE_MENU ); #else m_list_icons[ ICON::LIVE ] = Gdk::Pixbuf::create_from_inline( sizeof( icon_play ), icon_play ); #endif // 検索バー m_list_icons[ ICON::CLOSE_SEARCH ] = m_dummy.render_icon( Gtk::Stock::UNDO, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::CLEAR_SEARCH ] = m_dummy.render_icon( Gtk::Stock::CLEAR, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::SEARCH_AND ] = m_dummy.render_icon( Gtk::Stock::CUT, Gtk::ICON_SIZE_MENU ); m_list_icons[ ICON::SEARCH_OR ] = m_dummy.render_icon( Gtk::Stock::ADD, Gtk::ICON_SIZE_MENU ); // 書き込みビュー m_list_icons[ ICON::PREVIEW ] = m_list_icons[ ICON::THREAD ]; m_list_icons[ ICON::INSERTTEXT ] = m_dummy.render_icon( Gtk::Stock::OPEN, Gtk::ICON_SIZE_MENU ); load_theme(); } ICON_Manager::~ICON_Manager() { #ifdef _DEBUG std::cout << "ICON::~ICON_Manager\n"; #endif } Glib::RefPtr< Gdk::Pixbuf > ICON_Manager::get_icon( const int id ) { return m_list_icons[ id ]; } // // アイコンテーマ読み込み // void ICON_Manager::load_theme() { if( CACHE::file_exists( CACHE::path_theme_icon_root() ) != CACHE::EXIST_DIR ) return; const std::list< std::string > files = CACHE::get_filelist( CACHE::path_theme_icon_root() ); if( ! files.size() ) return; #ifdef _DEBUG std::cout << "ICON::load_theme\n"; #endif std::list< std::string >::const_iterator it = files.begin(); for(; it != files.end(); ++it ){ #ifdef _DEBUG std::cout << *it << std::endl; #endif int id = 0; // 拡張子を削除 std::string filename = (*it); size_t i = (*it).rfind( '.' ); if( i != std::string::npos ) filename = filename.substr( 0, i ); while( iconfiles[ id ][ 0 ] != '\0' ){ if( iconfiles[ id ][ 0 ] == filename[ 0 ] && filename.compare( iconfiles[ id ] ) == 0 ){ #ifdef _DEBUG std::cout << "hit : " << iconfiles[ id ] << " id = " << id << std::endl; #endif m_list_icons[ id ] = Gdk::Pixbuf::create_from_file( CACHE::path_theme_icon_root() + (*it) ); break; } ++id; } } } jd-2.8.7-140104/src/icons/iconmanager.h0000644000076400010400000000142311506370702014127 0ustar // ライセンス: GPL2 // // アイコンの管理クラス // #ifndef _ICONNAGER_H #define _ICONNAGER_H #ifdef _WIN32 #ifdef TRANSPARENT // will be conflict to wingdi.h #undef TRANSPARENT #endif #endif #include "iconid.h" #include #include namespace ICON { class ICON_Manager { std::vector< Glib::RefPtr< Gdk::Pixbuf > > m_list_icons; public: ICON_Manager(); virtual ~ICON_Manager(); Glib::RefPtr< Gdk::Pixbuf > get_icon( const int id ); private: void load_theme(); }; /////////////////////////////////////// // インターフェース ICON_Manager* get_icon_manager(); void delete_icon_manager(); Glib::RefPtr< Gdk::Pixbuf > get_icon( const int id ); } #endif jd-2.8.7-140104/src/icons/image.png0000644000076400010400000000044110553160717013266 0ustar PNG  IHDRaIDAT8Mj@ ֻ^ ͢ФwU&GaRhr.yƮc R5鋪I#U,8DUBydC 3 *sBRHJr"R$ 'B"HJ s.@6ϫI p =+7wyY'Xn_jY=kœb69qV\&"%afVi:[/ːoElIENDB`jd-2.8.7-140104/src/icons/info.png0000644000076400010400000000021111314407521013123 0ustar PNG  IHDRaPIDAT8; b7rr\L(+ 8Z (X7[€C/1H@>`E )oIENDB`jd-2.8.7-140104/src/icons/jd16.png0000644000076400010400000000076411301511462012745 0ustar PNG  IHDRaIDATxڕ1HaVRCAP9%JD6cK MF;8)7$HWhaH84A7)X߻EEp,&_T:U<nL* "Mgf Bn>$!`uu [t:PUh4 gAi]VE c,--2l"?VM~}h`X x}ˋwx|ԸHP E$I:E>_\4m.r:+D"yC%3\nĹ\`# @Uhrr},Bz'XYYf%il6p8 ͆zQpqq_-NbvvBjwpǿ%R;76133MjQ̭,Tq|Lf|c s?I%ͪ{IENDB`jd-2.8.7-140104/src/icons/jd32.png0000644000076400010400000000314111301511462012733 0ustar PNG  IHDR szz(IDATxڵ LTW h*ఌh(6DKbjl3#΀h] T^k4#1 "3;82z?޽޹{޴y@?M =$ #u'ݤIߑ񮭞TiGbѸyӒ$ Io`T[؍ K_̜_ZZ-^lƃڵxIY6f*i OGll8,7a~榽Z<}@qD4t:61 --QvmmmCo p ~ƹK bȐ!1b$lll8X}DnXL (HLɅ:88 Ν 2jOoՊS}6{=Z bٲ q YǏ1s,0`o  9}_ `TpXt=k娮0Ny\iptv5MB";;{񒗗Kˠ2Nu[VFR >>>Ah44h0O+7@wС"PHpuuŢE`kkK1gN <|8=8n")3SJ)HKSq7~@kvއ7 wa(* .;w2"PJ\n>Dի C;!\zI„ (.. 66--zn)+K Zʕ!+򒡦gTT!@\L ^R 22mdq~OOo2~wO@l'zwb+p7kl{{L>|H' &)G._f)`6BTFEmH>J/36T }.Ø1cTs|>6mH`0jh2^Z\JyK9#QY%S`'kc|ku:-e&ܽ{o;&22')K5~_2㍍q-:ߜ-wtD7f[G''̆tb2y=5LM aـ V࿾mT{IENDB`jd-2.8.7-140104/src/icons/jd48.png0000644000076400010400000000504411301511462012746 0ustar PNG  IHDR00W IDATx՚ PW?/]QC<0Q@ qksBPLɮaR)ٵ\L r F4( 0};XW~}=6^l~FwfT=Dv`6RPQR?3AbPG#<@>>0c >}: dDHH899Cf,g͒AD'nݪ?#~/ Ѵ=@{ăB^ ‰?/nFE"H 3gN ͞E`ڱ@\cy(*c4|W^R5AA5Xb;_I+ @ҥ7eVФOJ:.hKMF9DM`5 X6 '#6m3RR|>12 Vl]iD-PP*G]cq򁘘H8vZ 6 ~ %0v%1^̆R_"d$@sFA?ZVPQqrO[L>n0i$5j ܺUn9'j0~(!س'(` M۷+h֧9kdepl3qㆱcR7! b%KϗKdfr6H$$p^x=C7zFB˖I<C}`缽1Wr<`k@]]Y,;< 0y=48GɔPz]Qe9@myPq b ԉ~hyGGG0a碐U55*TB.7Z b<@)p\4ɘk`f=>Ao0;wP*U&رc#ErfCdfOM=zB?prJi"0bWAde)pQ1py0L/(u2{FoeaJ Jp KJvv9 E/;,Xy_0Ega#࣏ -4T/@uuJu+W1JLr:90tpS~G{*q  /ƕSd)͛<MO?MWסK4a* E̜9ˍ'4>mEv;d6 0KA[jW  Ҫ.?-[ bMh| !UP7nTΝ[ɠ ww称q`<ȼ8fCƻ ٩7\XPyX0?QW8pM{h4 A" JJ!OC>wQkiidÆMA728N29adGaxS.4BB~,W.ei?`C%jn.ӵ uA:EUժOEkL&%>e!>SzXzaۊg_XkR:2Tp(|\&fpp//L=)cMִ +y꩟au.mþ'8v D…sG9lp0 |A*a4PEYg-/JouҵPגNg8} gX9۷?W˺t_<Nj7ez=LBBUU5ޓ!jY8x.eb͖y2y.|1x\q +fǎwE[1uqcZk DdU 4zoJ2ܹ/d!zz}x>|>>Ϗ' y9Raٲ%AΜ9G(m%V,>>_+fD1V\ƍYn[nEQ|7rmmD" mN㎎zzdRzzres5* BbCZD2"zu=Պ6)rW*Zu28p~6o̖-[XjU)$ ^` h4~X1---lt3ܲtr-eK!Lq%JVJ/҃u6fy`4<< 05UF6%4"D">zgOzcߨ /\}ٲek-P{Bi/Dpiv}ǓO>G}T1L]zuzf3ZhmmUrwI-}lvAv ߈\.CCC~nVn|sCC>,_B@WW9V\EOዕH-)A6^c۶m>Oٿuj\`Ag[FƇј7"Hw^}Q^z%Kn^O"p\jD P(5U+N 5/Z;A*bpp۷388hhmB~Fywd<(V@_5bgLi8qTzcѣŢsahӳBYJY0fn"199E*/s>;B:6B>Z$4QT) {UR,ccakx.L&I3OLZ[ToZW`7aOp Witt:cxGV(Bܨ܆v,}Us~5LU͛<VVt-,:a%_y8t9߿}vLO'N஻b5i[-ڙkZՐɤ˺[ס3Nws7XpXˣж/qF6mTu~ի[عi&&m)ɐϫ|Q=OC2)jѱUVsUZ܌dPU{ݻwHT,Wfٲؼif2ScWp(-cmVdn={]vqbE? [gŊs%+@r5-VpFLMM{n;VN{ɀ9FGsOm74ƴl6˾}8x` Bm( e3ȅ (5A9v팡!^}բhOxN>{>22ž={HEZcX٬ª/ҳ?׺ M*JtnINI w^rIMu2/JO)B97ӱH$'Ӎ8κ +ndhꎊlPf PkE bX6Ir#2/@*nzn2865 NH1F3MAMN)Sd2GڐS&kX7g٣eϫ;6$ ;qMQccc|h8PWr;Zn9\%FFFvB(N]V4,tZh7X4oA`#lX*%0`4 _x^C7bQS3ro? Q S[o oآd)L{2fǎ풨 ]T _:'DQ9lx<,݃q+[x<^ɴA2\g~d2SVVskv ȅuԸ&p<#5-,Y Pf=zur E^uQUͫEP!H^/`]u…]DKK!]]=e$ ɷTYobŕ]ڵغ΢rC'Y ^+]7o% 륻{1PH "O!#5tx}b₫ChWk hmm VX`!mm%8Yk׮c׮=LMH$y-WWE}B0B sAuYP=Ea >_~^y忸xjŖ PYK 7ldrr?\ZU# VTL] 믿rn 1N=O>_z41ffM56v={v* xW \\.M,6YX47yX Av;k8/gMr?m1' V)* ـ{ݣQy}/ z=~H! (;~nڂbEVB9iNOOE&D.'Lp5-<5 hfRPh&E,>7>clM f͚m,P6茛An:Ưbb1mrK۲˸LHY!@.x+ L&`PM$PuZbHg5w!ۀ=L.V+|([8_oiO"wȋ'8W֪p$t"_7y`1aCYت)O+np%r)_<r/-t!T*/N[^k{ ^B9rH8st!Dr1Sb>ߑ~:IENDB`jd-2.8.7-140104/src/icons/jd_windres.ico0000644000076400010400000005372611232724502014331 0ustar 00f h00 %  B hnS(0` """%%%...333888???BBBDDDMMMQQQ\\\oooQq,/KPhp1Qq/!P7pLcyϏ1Qq/Pp",6@J[1qQq/Pp  =1[Qyq/"P0p=LYgx1Qq&/@PZpt1Qq/&PAp[tϩ1Qq/P"p0>M[iy1Qqұ/Pp  >1\Qzq/Pp!+6@IZ1pQq/ P6pLbx1Qq,/KPip1Qq/-P?pRcv1Qqϑܱ/Pp!&,>X1qQq ?( @  $"$$&$424LJLlnltrttvt|z||~|1Qq/!P7pLcyϏ1Qq/Pp",6@J[1qQq/Pp  =1[Qyq/"P0p=LYgx1Qq&/@PZpt1Qq/&PAp[tϩ1Qq/P"p0>M[iy1Qqұ/Pp  >1\Qzq/Pp!+6@IZ1pQq/ P6pLbx1Qq,/KPip1Qq/-P?pRcv1Qqϑܱ/Pp!&,>X1qQq??( 111666AAAoooqqq/-P?pQcv1Qq,/KPhp1Qq/!P7pLcyϏ1Qq/Pp",6@J[1qQq/Pp  =1[Qyq/"P0p=LYgx1Qq&/@PZpt1Qq/&PAp[tϩ1Qq/P"p0>M[iy1Qqұ/Pp  >1\Qzq/Pp!+6@IZ1pQq/ P6pLbx1Qq,/KPip1Qq/-P?pRcv1Qqϑܱ/Pp!&,>X1qQq                 (0` $5@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>82$ >X@:Zq@0% F 4                           F*h``zzKDD@̶5//l2տֿɴ0,,@ VPPLGGLGGLGGLGGLFFTNN_WWuuϾMFFJDDJDDJCCJCCJCCJCCIBBIBBOGGVMMj__̵dzTull˺VOOzzưE@@,WOOӼϻ{{6;66WPP:44ɴ<WPPŰ´@ϿWQQŶ @˼WQQƶ @A??FCCKGG744ȻXQQ1--yy)%%Ʒ @faaƹXRRC== Ʒ @źXRRC>>μ,,,Ʒ @ŹXRRC>>>>>Ʒ @źXSSC>>999>>>Ʒ @źXSSC??)))CCC>>>Ʒ @ƺXTTD??GGGCCC>>>Ʒ @ƻXTTD??CCCHHHCCC>>>Ƹ @ǼYTTD@@999LLLHHHCCC>>>Ƹ @ǼYTTD@@000QQQLLLHHHCCC>>>Ƹ @ǾYUUD@@$$$VVVQQQLLLHHHCCC>>>Ƹ @ȿYUUD@@YYYVVVQQQLLLHHHCCC>>>Ƹ @YUUDAAZZZVVVQQQLLLHHHCCC>>>Ƹ @ZVVVSSZZZVVVQQQLLLHHHCCC>>>Ƹ @ZVV'''ZZZVVVQQQLLLHHHCCC>>>Ƹ @ZWW===lllZZZVVVQQQLLLHHHCCC>>>Ƹ @ZWWTTTrrrmmmZZZVVVQQQLLLHHHCCC>>>Ƹ @[WWjjjvvvrrrmmmZZZVVVQQQLLLHHHCCC>>>Ƹ @uss^[[GGG~~~{{{vvvrrrmmmhhhddd___ZZZVVVQQQLLLHHHCCC>>>Ʒ >uss{{{vvvrrrmmmhhhddd___ZZZVVVQQQLLLHHHCCC@@@´:utt{{{vvvrrrmmmhhhddd___ZZZVVVQQQLLLHHHCCCecc5vtt___{{{vvvrrrmmmhhhddd___ZZZVVVQQQLLLHHHCCC*vuu+++eee{{{vvvrrrmmmhhhddd___ZZZVVVQQQLLLHHH`YYvuuXXX{{{vvvrrrmmmhhhddd___ZZZVVVQQQbaaĶo umm4 sjj9iaa_WWf                          ~ ^=~L??( @ CuH3 C@ .**uuvvuuuuuuuuuuuuuuuuuuuuuutttttttttttt{ooj``<660yy̶woowoowoo{qq}rrtjjtiithhshhsggviiqq̵&;88riiʶ:55j<884..Ӽmee...<88̶||<99~~yyyss||$!! oii||-))511{uu{{-))C>>888{uu||-**IDD)))???{vv||-**JDDFFF???|ww}}-**JEEEEEFFF???|xx~~-**NIICCCMMMFFF???|xx-++{{TTTMMMFFF???}yy.,,TTTMMMFFF???}zzdbbTTTMMMFFF???Ż~zz YYYTTTMMMFFF???fdd!!!kkkpppfffTTTMMMFFF???MMM~~~wwwpppiiibbb[[[TTTMMMFFF???~~~~~wwwpppiiibbb[[[TTTMMMFFFQPPzqq555~~~~~~wwwpppiiibbb[[[TTTMMMFFFWQQ[[[~~~wwwpppiiibbb[[[TTTWVV!Ŀyqq yyxpp<.++ww~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xxvmmUNNxCo$C^$?(  FAAFAA FAAFAAFAAFAAFAAFAAFAAFAAFAA?????????FFF??????FFFFFF??????www[[[TTTFFF???___~~~www[[[TTTFAAFAAFAA FAAFAAFAAFAAAAAAAAAAAAAAAAAAjd-2.8.7-140104/src/icons/link.png0000644000076400010400000000042010472610325013131 0ustar PNG  IHDRaIDAT8SA @Kԛ7T=3U vv fLe) `oH.IbRtk IH*YbYOc0NR1+z~@eoวO K*wsf;ASY@G)wpuՈЧi7 YZ,]ad$ǑHEXBK5F _ ) IENDB`jd-2.8.7-140104/src/icons/loading.png0000644000076400010400000000034310473316242013617 0ustar PNG  IHDRaIDAT8S |r<m4GY-P25)./$žC ^f2puoAZ{`* INVHDɏ;{}tn"[grM;8Ȍ10S6aA.P`LENԽNɐ8zHa'dNoaM)IENDB`jd-2.8.7-140104/src/icons/loading_stop.png0000644000076400010400000000035210473316242014664 0ustar PNG  IHDRaIDAT8 0 DOAZrg@ Y";d%Bfa@%6 VurKջxo,][`2}2Đbml8j"qY^!:c}fۂgdTB֘,C$P6X2X:;pHe`YCZ< _IENDB`jd-2.8.7-140104/src/icons/Makefile.am0000644000076400010400000000146512072045132013530 0ustar noinst_LIBRARIES = libicon.a libicon_a_SOURCES = \ iconmanager.cpp icon_headers = jd16.h jd32.h jd48.h jd96.h \ dir.h board.h board_update.h board_updated.h thread.h thread_update.h thread_updated.h thread_old.h \ image.h link.h loading.h loading_stop.h check.h down.h \ update.h newthread.h newthread_hour.h broken_subject.h bkmark.h bkmark_broken_subject.h bkmark_update.h bkmark_thread.h favorite.h write.h post.h post_refer.h \ play.h hist.h hist_board.h hist_close.h hist_closeboard.h hist_closeimg.h info.h noinst_HEADERS = \ iconmanager.h $(icon_headers) AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src DISTCLEANFILES = $(icon_headers) clean_icons : rm -rf $(icon_headers) iconmanager.cpp : $(icon_headers) SUFFIXES = .png .h .png.h: gdk-pixbuf-csource --raw --name=icon_$* $< > $@ jd-2.8.7-140104/src/icons/newthread.png0000644000076400010400000000024210605207706014162 0ustar PNG  IHDRaiIDAT8 0 ψ[HmR?<7e;l2{ʱѴ 7C3_x pttRvŤ$yZ"(;!:'pE+ IENDB`jd-2.8.7-140104/src/icons/newthread_hour.png0000644000076400010400000000023511046077703015223 0ustar PNG  IHDRadIDAT8͒A 0Ǽ|z,m4!`630p`X,%}pG {fk/s)GXx? V)W ܖf_vIENDB`jd-2.8.7-140104/src/icons/play.png0000644000076400010400000000024011072710470013140 0ustar PNG  IHDRagIDAT8Q d`GfkCDۊWHRNrM^fՃ@@)Pk eYR@l @4-D5%IENDB`jd-2.8.7-140104/src/icons/post.png0000644000076400010400000000034511032705755013174 0ustar PNG  IHDR "aIDAT(͒0 D @ + jO0Eek8Eq 6`oy/"NJIB)ƨ}ܽguH),`B:DD;:0^Vr}ې^PD<9), rz6g^kz{ xs=0IENDB`jd-2.8.7-140104/src/icons/post_refer.png0000644000076400010400000000025611032705755014360 0ustar PNG  IHDR "auIDAT(Q ClMPPB{&Ai?I{MKO w SY,e޷;a\ &5(-y%ѿqTqk|8.Z0L}3it!IENDB`jd-2.8.7-140104/src/icons/thread.png0000644000076400010400000000034110472610325013445 0ustar PNG  IHDRaIDAT8͓A E<G16޴;[nM<߅BHJZčxJ/i M$feZ7$af  C/j9@-RHTݟ8 ཏuܒ& Jcfz_UP9ͨ`mqV]"S *y& Sߘ^CWK` RjIENDB`jd-2.8.7-140104/src/icons/thread_old.png0000644000076400010400000000043510650414542014310 0ustar PNG  IHDRaIDAT80Dgܨ%RK\ DjID `c~DJkIv3{%3y 1-/L!|gۙ3z IOL9)2N`FıGpIENDB`jd-2.8.7-140104/src/icons/write.png0000644000076400010400000000040610553160717013337 0ustar PNG  IHDRaIDAT8ݓ 0 D;IG A nR`_,EN}$Jefd7'$IOt 6 @tI  y'l1" ); m_left.set_focus_on_click( false ); m_right.set_focus_on_click( false ); m_left.signal_pressed().connect( sigc::mem_fun( *this, &ImageAdmin::slot_press_left ) ); m_right.signal_pressed().connect( sigc::mem_fun( *this, &ImageAdmin::slot_press_right ) ); m_left.signal_released().connect( sigc::mem_fun( *this, &ImageAdmin::slot_release_left ) ); m_right.signal_released().connect( sigc::mem_fun( *this, &ImageAdmin::slot_release_right ) ); m_tab.pack_start( m_scrwin ); m_tab.pack_end( m_right, Gtk::PACK_SHRINK ); m_tab.pack_end( m_left, Gtk::PACK_SHRINK ); m_tab.show_all_children(); } ImageAdmin::~ImageAdmin() { #ifdef _DEBUG std::cout << "ImageAdmin::~ImageAdmin\n"; #endif close_window(); } void ImageAdmin::save_session() { Admin::save_session(); // 開いているURLを保存 SESSION::set_image_URLs( get_URLs() ); SESSION::set_image_locked( get_locked() ); SESSION::set_image_page( get_current_page() ); } // 前回開いていたURLを復元 void ImageAdmin::restore( const bool only_locked ) { #ifdef _DEBUG std::cout << "ImageAdmin::restore\n"; #endif int set_page_num = 0; std::list< std::string > list_url = SESSION::image_URLs(); std::list< std::string >::iterator it_url= list_url.begin(); std::list< bool > list_locked = SESSION::get_image_locked(); std::list< bool >::iterator it_locked = list_locked.begin(); for( int page = 0; it_url != list_url.end(); ++it_url, ++page ){ // タブのロック状態 bool lock = false; if( it_locked != list_locked.end() ){ if( (*it_locked ) ) lock = true; ++it_locked; } // ロックされているものだけ表示 if( only_locked && ! lock ) continue; if( page == SESSION::image_page() ) set_page_num = get_tab_nums(); COMMAND_ARGS command_arg = url_to_openarg( *it_url, true, lock ); if( ! command_arg.url.empty() ) open_view( command_arg ); } SKELETON::View* view = get_nth_icon( set_page_num ); if( view ){ switch_img( view->get_url() ); switch_admin(); } } COMMAND_ARGS ImageAdmin::url_to_openarg( const std::string& url, const bool tab, const bool lock ) { COMMAND_ARGS command_arg; command_arg.command = "open_view"; command_arg.url = url; if( lock ) command_arg.arg3 = "lock"; return command_arg; } void ImageAdmin::switch_admin() { if( ! has_focus() ) CORE::core_set_command( "switch_image" ); } // // ページが含まれていないか // bool ImageAdmin::empty() { return ( m_list_view.size() == 0 ); } // // 含まれているタブの数 // int ImageAdmin::get_tab_nums() { return m_iconbox.children().size(); } // // 含まれているページのURLのリスト取得 // const std::list< std::string > ImageAdmin::get_URLs() { std::list< std::string > urls; Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ) urls.push_back( view->get_url() ); } return urls; } // // コアからのクロック入力 // // 各viewにクロックを渡すだけ // void ImageAdmin::clock_in() { // アイコンにクロックを送る Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ) view->clock_in(); } // 画像が表示されている場合viewにクロックを回す if( SESSION::is_shown_win_img() ){ // アクティブなviewにだけクロックを送る SKELETON::View* view = get_current_view(); if( view ) view->clock_in(); } // タブのスクロール if( m_scroll != SCROLL_NO ){ const int timing = 100; // msec ++m_counter_scroll; if( timing / TIMER_TIMEOUT <= m_counter_scroll ){ scroll_tab( m_scroll ); m_counter_scroll = 0; } } if( get_jdwin() ) get_jdwin()->clock_in(); } // // 現在表示されているページ番号 // int ImageAdmin::get_current_page() { int pos; SKELETON::View* view = get_current_view(); if( !view ) return -1; get_icon( view->get_url(), pos ); return pos; } // // ローカルなコマンド // void ImageAdmin::command_local( const COMMAND_ARGS& command ) { // 切り替え if( command.command == "switch_image" ) switch_img( command.url ); // 画像強制表示 if( command.command == "show_image" ){ clock_in(); clock_in(); clock_in(); } // すべて保存 else if( command.command == "save_all" ) save_all(); // 並び替え else if( command.command == "reorder" ) reorder( command.arg1, command.arg2 ); else if( command.command == "close_other_views" ) close_other_views( command.url ); else if( command.command == "close_left_views" ) close_left_views( command.url ); else if( command.command == "close_right_views" ) close_right_views( command.url ); else if( command.command == "close_error_views" ) close_error_views( command.arg1 ); else if( command.command == "close_noerror_views" ) close_noerror_views(); else if( command.command == "close_all_views" ) close_other_views( std::string() ); // キャッシュに無いviewを削除 else if( command.command == "close_nocached_views" ) close_error_views( "nocached" ); // 画面のスクロール else if( command.command == "scroll_up" ){ SKELETON::View* view = get_current_view(); if( view ) view->scroll_up(); } else if( command.command == "scroll_down" ){ SKELETON::View* view = get_current_view(); if( view ) view->scroll_down(); } else if( command.command == "scroll_left" ){ SKELETON::View* view = get_current_view(); if( view ) view->scroll_left(); } else if( command.command == "scroll_right" ){ SKELETON::View* view = get_current_view(); if( view ) view->scroll_right(); } else if( command.command == "set_imgtab_operating" ){ if( command.arg1 == "true" ) SESSION::set_tab_operating( get_url(), true ); else{ SESSION::set_tab_operating( get_url(), false ); if( ! empty() ){ update_status_of_all_views(); } } } } // // 画像を開く // void ImageAdmin::open_view( const COMMAND_ARGS& command ) { #ifdef _DEBUG std::cout << "ImageAdmin::open_view url = " << command.url << std::endl; #endif // まだ表示されていない if( ! get_view( command.url ) ){ // アイコン作成 & 表示 SKELETON::View* icon = Gtk::manage( CORE::ViewFactory( CORE::VIEW_IMAGEICON, command.url ) ); if( icon ){ if( command.arg3 == "lock" ) icon->lock(); icon->set_size_request( ICON_SIZE , ICON_SIZE ); icon->show_view(); m_iconbox.pack_start( *icon, Gtk::PACK_SHRINK ); m_iconbox.show_all_children(); } // view作成 SKELETON::View* view = Gtk::manage( CORE::ViewFactory( CORE::VIEW_IMAGEVIEW, command.url ) ); if( view ){ view->show_view(); m_list_view.push_back( view ); } } open_window(); update_status_of_all_views(); switch_img( command.url ); } // // タブの切替え // void ImageAdmin::tab_left( const bool updated ) { if( m_iconbox.children().size() == 1 ) return; SKELETON::View* view; std::string url_to; SKELETON::View* icon = get_current_icon(); Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ){ if( view == icon ) break; url_to = view->get_url(); } } // 一番最後へ戻る if( url_to.empty() ){ it = m_iconbox.children().end(); view = dynamic_cast< SKELETON::View* >( (--it)->get_widget() ); if( view ) url_to = view->get_url(); } if( !url_to.empty() ) switch_img( url_to ); focus_current_view(); } void ImageAdmin::tab_right( const bool updated ) { if( m_iconbox.children().size() == 1 ) return; std::string url_to; SKELETON::View* icon = get_current_icon(); Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view == icon ){ ++it; // 一番最初へ戻る if( it == m_iconbox.children().end() ) it = m_iconbox.children().begin(); view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ) url_to = view->get_url(); break; } } if( !url_to.empty() ) switch_img( url_to ); focus_current_view(); } // // タブの最初に移動 // void ImageAdmin::tab_head() { if( m_iconbox.children().size() == 1 ) return; std::string url_to; Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ) url_to = view->get_url(); if( !url_to.empty() ) switch_img( url_to ); switch_admin(); } // // タブの最後に移動 // void ImageAdmin::tab_tail() { if( m_iconbox.children().size() == 1 ) return; std::string url_to; Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().end(); it--; SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ) url_to = view->get_url(); if( !url_to.empty() ) switch_img( url_to ); switch_admin(); } // // タブアイコンの並び替え // void ImageAdmin::reorder( const std::string& url_from, const std::string& url_to ) { SKELETON::View* view_from = get_icon( url_from ); int pos; get_icon( url_to, pos ); if( view_from && pos != -1 ){ #ifdef _DEBUG std::cout << "ImageAdmin::reorder " << url_from << "\n-> " << url_to << " pos = " << pos << std::endl; #endif m_iconbox.reorder_child( *view_from, pos ); update_status_of_all_views(); } } // // 全てのビューのステータス表示内容更新の予約 // void ImageAdmin::update_status_of_all_views() { if( SESSION::is_tab_operating( get_url() ) ) return; #ifdef _DEBUG std::cout << "ImageAdmin::update_status_of_all_views\n"; #endif std::list< SKELETON::View* >::iterator it_view; for( it_view = m_list_view.begin(); it_view != m_list_view.end(); ++it_view ){ if( *it_view ) (*it_view)->set_command( "update_status" ); } } // // 指定したビューを再描画 // void ImageAdmin::redraw_view( const std::string& url ) { #ifdef _DEBUG std::cout << "ImageAdmin::redraw_view url = " << url << std::endl; #endif SKELETON::View* view = get_view( url ); if( view ) view->redraw_view(); view = get_icon( url ); if( view ) view->redraw_view(); } // // 現在のビューを再描画 // void ImageAdmin::redraw_current_view() { #ifdef _DEBUG std::cout << "ImageAdmin::redraw_current_view\n"; #endif SKELETON::View* view = get_current_view(); if( view ) view->redraw_view(); view = get_current_icon(); if( view ) view->redraw_view(); } // // 閉じる // void ImageAdmin::close_view( const std::string& url ) { #ifdef _DEBUG std::cout << "ImageAdmin::close_view : url = " << url << std::endl; #endif // 次に表示するviewのURL std::string url_next = std::string(); SKELETON::View* icon = get_icon( url ); SKELETON::View* view = get_view( url ); if( ! icon && ! view ) return; if( DBIMG::is_cached( url ) && icon->is_locked() ) return; // 現在表示中のviewを閉じた場合は次か前の画像に切り替える if( view && view == get_current_view() ){ m_view.remove(); SKELETON::View* view_prev = NULL; SKELETON::View* view_next = NULL; Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view_tmp = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view_tmp->get_url() == url ){ if( ++it != m_iconbox.children().end() ) view_next = dynamic_cast< SKELETON::View* >( it->get_widget() ); break; } view_prev = view_tmp; } if( view_next ) url_next = view_next->get_url(); else if( view_prev ) url_next = view_prev->get_url(); } if( icon ){ m_iconbox.remove( *icon ); delete icon; } if( view ){ m_list_view.remove( view ); delete view; } if( empty() ){ close_window(); CORE::core_set_command( "empty_page", get_url() ); } else if( ! url_next.empty() ){ update_status_of_all_views(); switch_img( url_next ); } } // // ウィンドウ開く // void ImageAdmin::open_window() { ImageWin* win = dynamic_cast< ImageWin* >( get_jdwin() ); if( ! SESSION::get_embedded_img() && ! win && ! empty() ){ win = new IMAGE::ImageWin(); set_jdwin( win ); win->pack_remove_tab( false, m_tab ); win->pack_remove_end( false, m_view ); win->show_all(); } else if( win && win->is_hide() ){ win->show(); win->focus_in(); } } // // ウィンドウ閉じる // void ImageAdmin::close_window() { ImageWin* win = dynamic_cast< ImageWin* >( get_jdwin() ); if( win ){ win->pack_remove_tab( true, m_tab ); win->pack_remove_end( true, m_view ); delete_jdwin(); } } // // url 以外の画像を閉じる // void ImageAdmin::close_other_views( const std::string& url ) { set_command( "set_imgtab_operating", "", "true" ); Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view && view->get_url() != url ) set_command( "close_view", view->get_url() ); } set_command( "set_imgtab_operating", "", "false" ); } // // url の左側の画像を閉じる // void ImageAdmin::close_left_views( const std::string& url ) { set_command( "set_imgtab_operating", "", "true" ); Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view->get_url() == url ) break; if( view ) set_command( "close_view", view->get_url() ); } set_command( "set_imgtab_operating", "", "false" ); } // // url の右側の画像を閉じる // void ImageAdmin::close_right_views( const std::string& url ) { set_command( "set_imgtab_operating", "", "true" ); Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view->get_url() == url ) break; } ++it; for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ) set_command( "close_view", view->get_url() ); } set_command( "set_imgtab_operating", "", "false" ); } // // エラーになっている画像を閉じる // void ImageAdmin::close_error_views( const std::string mode ) { #ifdef _DEBUG std::cout << "ImageAdmin::close_error_views\n"; #endif set_command( "set_imgtab_operating", "", "true" ); Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ){ const std::string url = view->get_url(); if( DBIMG::is_cached ( url ) ) continue; if( mode != "all" && DBIMG::is_loading ( url ) ) continue; if( DBIMG::is_wait ( url ) ) continue; const int code = DBIMG::get_code( url ); if( ( code == HTTP_FORBIDDEN || code == HTTP_NOT_FOUND ) // 404,403 は無条件で閉じる || ( mode == "notimeout" && code != HTTP_TIMEOUT && code != HTTP_TEMP_UNAV ) // timeout,503以外 || ( mode == "nocached" && code == HTTP_INIT ) // キャッシュに無い(削除済み)の画像 || mode == "all" // 読み込み中も含めて閉じる ){ set_command( "close_view", url ); if( mode == "all" ) DBIMG::stop_load( url ); } } } set_command( "set_imgtab_operating", "", "false" ); } // // エラーでない画像を閉じる // void ImageAdmin::close_noerror_views() { #ifdef _DEBUG std::cout << "ImageAdmin::close_noerror_views\n"; #endif set_command( "set_imgtab_operating", "", "true" ); Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ){ const std::string url = view->get_url(); if( ! DBIMG::is_cached ( url ) ) continue; const int code = DBIMG::get_code( url ); if( code == HTTP_OK ) set_command( "close_view", url ); } } set_command( "set_imgtab_operating", "", "false" ); } void ImageAdmin::restore_lasttab() { HISTORY::restore_history( URL_HISTCLOSEIMGVIEW ); } // // 現在のviewをフォーカスする // // 他のクラスからは直接呼ばないで、set_command()経由で呼ぶこと // void ImageAdmin::focus_view( int) { #ifdef _DEBUG std::cout << "ImageAdmin::focus_view\n"; #endif SKELETON::View* view_icon = get_current_icon(); if( view_icon ) { if( get_jdwin() ) get_jdwin()->focus_in(); focus_out_all(); view_icon->focus_view(); SKELETON::View* view = get_current_view(); if( view ) update_status( view, false ); } } void ImageAdmin::focus_current_view() { focus_view( 0 ); } // // 全アイコンのフォーカスをはずす // void ImageAdmin::focus_out_all() { Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ) view->focus_out(); } } // // 画像切り替え // void ImageAdmin::switch_img( const std::string& url ) { #ifdef _DEBUG std::cout << "ImageAdmin::switch_img url = " << url << std::endl; #endif // 画像切り替え int page = 0; std::list< SKELETON::View* >::iterator it_view; for( it_view = m_list_view.begin(); it_view != m_list_view.end(); ++it_view ){ SKELETON::View* view = ( *it_view ); if( view->get_url() == url ){ if( view != get_current_view() ){ #ifdef _DEBUG std::cout << "view was toggled.\n"; #endif m_view.remove(); m_view.add( *view ); m_view.show_all_children(); } break; } } focus_out_all(); // アイコン切り替え SKELETON::View* view_icon = get_icon( url, page ); if( view_icon ) view_icon->set_command( "switch_icon" ); // タブをスクロール Gtk::Adjustment* adjust = m_scrwin.get_hadjustment(); if( page != -1 && adjust ){ double pos = adjust->get_value(); double upper = m_list_view.size() * ICON_SIZE; double width = adjust->get_page_size(); double pos_to = page * ICON_SIZE; #ifdef _DEBUG std::cout << "pos = " << pos << std::endl; std::cout << "page = " << page << std::endl; std::cout << "pos_to = " << pos_to << std::endl; std::cout << "upper = " << upper << std::endl; std::cout << "width = " << width << std::endl; #endif if( pos_to <= pos || pos_to >= pos + width ){ if( pos_to + width >= upper ) pos_to = upper - width; adjust->set_value( pos_to ); } } if( has_focus() ) focus_current_view(); } // // アイコン取得 // // pos にアイコンの位置が入る(見付からないときは-1) // SKELETON::View* ImageAdmin::get_icon( const std::string& url, int& pos ) { Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for( pos = 0; it != m_iconbox.children().end(); ++it, ++pos ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view && view->get_url() == url ) return view; } pos = -1; return NULL; } // 簡易版 SKELETON::View* ImageAdmin::get_icon( const std::string& url) { int pos; return get_icon( url, pos ); } // // アイコン取得(番号で) // SKELETON::View* ImageAdmin::get_nth_icon( const unsigned int n ) { if( n >= m_iconbox.children().size() ) return NULL; Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for( unsigned int i = 0; i < n; ++i, ++it ); return dynamic_cast< SKELETON::View* >( it->get_widget() ); } // // カレントアイコン取得 // SKELETON::View* ImageAdmin::get_current_icon() { SKELETON::View* view = get_current_view(); if( !view ) return NULL; return get_icon( view->get_url() ); } // // view 取得 // SKELETON::View* ImageAdmin::get_view( const std::string& url ) { SKELETON::View* view = get_current_view(); if( view && view->get_url() == url ) return view; std::list< SKELETON::View* >::iterator it_view; for( it_view = m_list_view.begin(); it_view != m_list_view.end(); ++it_view ){ if( ( *it_view )->get_url() == url ) return ( *it_view ); } return NULL; } // // カレントview 取得 // SKELETON::View* ImageAdmin::get_current_view() { return dynamic_cast< SKELETON::View* >( m_view.get_child() ); } // // スクロール // void ImageAdmin::scroll_tab( int scroll ) { if( scroll == SCROLL_NO ) return; #ifdef _DEBUG std::cout << "ImageAdmin::scroll_tab " << scroll << std::endl; #endif Gtk::Adjustment* adjust = m_scrwin.get_hadjustment(); if( adjust ){ double pos = adjust->get_value(); double upper = adjust->get_upper(); double width = adjust->get_page_size(); #ifdef _DEBUG std::cout << "pos = " << pos << std::endl; std::cout << "upper = " << upper << std::endl; std::cout << "width = " << width << std::endl; #endif if( upper == width ) return; if( scroll == SCROLL_LEFT ) pos -= ICON_SIZE; else pos += ICON_SIZE; if( pos <= 0 ) pos = 0; else if( pos + width >= upper ) pos = upper - width; // ICON_SIZEの倍数にする else pos = ICON_SIZE * ( ( (int)pos ) / ICON_SIZE ); adjust->set_value( pos ); } } //左押した void ImageAdmin::slot_press_left() { m_scroll = SCROLL_LEFT; m_counter_scroll = 0; scroll_tab( m_scroll ); } //右押した void ImageAdmin::slot_press_right() { m_scroll = SCROLL_RIGHT; m_counter_scroll = 0; scroll_tab( m_scroll ); } //左離した void ImageAdmin::slot_release_left() { m_scroll = SCROLL_NO; } // 右離した void ImageAdmin::slot_release_right() { m_scroll = SCROLL_NO; } // // 画像ファイルのコピー // bool ImageAdmin::copy_file( const std::string& url, const std::string& path_from, const std::string& path_to ) { #ifdef _DEBUG std::cout << "ImageAdmin::copy_file url = " << url << std::endl << "from = " << path_from << std::endl << "to = " << path_to << std::endl; #endif if( ! CACHE::jdcopy( path_from, path_to ) ){ // ビューを切り替えてURLやステータス更新 switch_img( url ); SKELETON::View* view = get_current_view(); if( view ) update_status( view, true ); SKELETON::MsgDiag mdiag( get_win(), path_to + "\n\nの保存に失敗しました。\nハードディスクの容量やパーミッションなどを確認してください。\n\n画像保存をキャンセルしました。原因を解決してからもう一度保存を行ってください。" ); mdiag.run(); return false; } return true; } // // すべて保存 // void ImageAdmin::save_all() { #ifdef _DEBUG std::cout << "ImageAdmin::save_all\n"; #endif int overwrite = Gtk::RESPONSE_NO; bool use_name_in_cache = false; std::list< std::string > list_urls = get_URLs(); // ディレクトリ選択 SKELETON::FileDiag diag( get_win(), "保存先選択", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER ); diag.set_current_folder( SESSION::dir_img_save() ); if( diag.run() == Gtk::RESPONSE_ACCEPT ){ diag.hide(); std::string path_dir = MISC::recover_path( diag.get_filename() ); if( path_dir.empty() ) return; if( path_dir.c_str()[ path_dir.length()-1 ] != '/' ) path_dir += "/"; #ifdef _DEBUG std::cout << "dir = " << path_dir << std::endl; #endif if( CACHE::jdmkdir( path_dir ) ){ SESSION::set_dir_img_save( path_dir ); std::list< std::string >::iterator it = list_urls.begin(); for( ; it != list_urls.end(); ++it ){ std::string url = (*it); if( ! DBIMG::is_cached( url ) || DBIMG::get_mosaic( url ) ) continue; std::string path_from = DBIMG::get_cache_path( url ); std::string path_to = path_dir + MISC::get_filename( url ); #ifdef _DEBUG std::cout << "from = " << path_from << std::endl; std::cout << "to = " << path_to << std::endl; #endif // 既にファイルがある場合 if( CACHE::file_exists( path_to ) == CACHE::EXIST_FILE ){ // すべて上書き if( overwrite == SKELETON::OVERWRITE_YES_ALL ){ if( ! copy_file( url, path_from, path_to ) ) return; } // ファイル名として画像キャッシュでのファイル名を使用 else if( use_name_in_cache ){ if( ! copy_file( url, path_from, path_dir + CACHE::filename_img( url ) ) ) return; } // すべていいえ else if( overwrite == SKELETON::OVERWRITE_NO_ALL ){} else{ // ビューを切り替えてURLやステータス更新 switch_img( url ); SKELETON::View* view = get_current_view(); if( view ) update_status( view, true ); for(;;){ SKELETON::MsgOverwriteDiag mdiag( get_win() ); overwrite = mdiag.run(); mdiag.hide(); switch( overwrite ){ // すべて上書き case SKELETON::OVERWRITE_YES_ALL: // 上書き case SKELETON::OVERWRITE_YES: if( ! copy_file( url, path_from, path_to ) ) return; break; // 名前変更 case Gtk::RESPONSE_YES: { SKELETON::MsgDiag mdiag_name( get_win(), "ファイル名として画像キャッシュでのファイル名を使用しますか?\n\nいいえを選ぶとファイル選択ダイアログを開きます。", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag_name.add_button( "すべてはい", SKELETON::OVERWRITE_YES_ALL ); mdiag_name.set_default_response( Gtk::RESPONSE_YES ); const int ret = mdiag_name.run(); if( ret == Gtk::RESPONSE_YES || ret == SKELETON::OVERWRITE_YES_ALL ){ if( ret == SKELETON::OVERWRITE_YES_ALL ) use_name_in_cache = true; if( ! copy_file( url, path_from, path_dir + CACHE::filename_img( url ) ) ) return; } else{ if( ! DBIMG::save( url, get_win(), path_to ) ) continue; } break; } default: break; } break; } } } else if( ! copy_file( url, path_from, path_to ) ) return; } } else{ SKELETON::MsgDiag mdiag( get_win(), path_dir + "\n\nの作成に失敗しました。\nハードディスクの容量やパーミッションなどを確認してください。\n\n画像保存をキャンセルしました。原因を解決してからもう一度保存を行ってください。" ); mdiag.run(); } } } // ページがロックされているかリストで取得 std::list< bool > ImageAdmin::get_locked() { std::list< bool > locked; Gtk::Box_Helpers::BoxList::iterator it = m_iconbox.children().begin(); for(; it != m_iconbox.children().end(); ++it ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( it->get_widget() ); if( view ) locked.push_back( view->is_locked() ); } return locked; } // タブのロック/アンロック const bool ImageAdmin::is_lockable( const int page ) { SKELETON::View* view = get_nth_icon( page ); if( view ) return view->is_lockable(); return false; } const bool ImageAdmin::is_locked( const int page ) { SKELETON::View* view = get_nth_icon( page ); if( view ) return view->is_locked(); return false; } void ImageAdmin::lock( const int page ) { SKELETON::View* view = get_nth_icon( page ); if( view ) return view->lock(); } void ImageAdmin::unlock( const int page ) { SKELETON::View* view = get_nth_icon( page ); if( view ) return view->unlock(); } jd-2.8.7-140104/src/image/imageadmin.h0000644000076400010400000000762411546077763013736 0ustar // ライセンス: GPL2 // // 板の管理クラス // #ifndef _IMAGEADMIN_H #define _IMAGEADMIN_H #include "skeleton/admin.h" #include namespace IMAGE { // スクロール方向 enum{ SCROLL_NO, SCROLL_LEFT, SCROLL_RIGHT }; class ImageAdmin : public SKELETON::Admin { Gtk::HBox m_tab; Gtk::HBox m_iconbox; Gtk::ScrolledWindow m_scrwin; Gtk::Button m_left, m_right; Gtk::EventBox m_view; // Gtk::manageで作ってるので view は deleteしなくても良い std::list< SKELETON::View* > m_list_view; int m_scroll; int m_counter_scroll; public: ImageAdmin( const std::string& url ); ~ImageAdmin(); virtual void save_session(); Gtk::HBox& tab() { return m_tab; } virtual Gtk::Widget* get_widget() { return &m_view; } virtual bool empty(); virtual void clock_in(); // タブの数 virtual int get_tab_nums(); // 含まれているページのURLのリスト取得 virtual const std::list< std::string > get_URLs(); // 現在表示してるページ番号 virtual int get_current_page(); protected: virtual void command_local( const COMMAND_ARGS& command ); virtual void restore( const bool only_locked ); virtual COMMAND_ARGS url_to_openarg( const std::string& url, const bool tab, const bool lock ); virtual void switch_admin(); virtual void open_view( const COMMAND_ARGS& command ); virtual void tab_left( const bool updated ); virtual void tab_right( const bool updatd ); virtual void tab_head(); virtual void tab_tail(); virtual void redraw_view( const std::string& url ); virtual void redraw_current_view(); virtual void close_view( const std::string& url ); virtual void close_other_views( const std::string& url ); virtual void restore_lasttab(); virtual void focus_view( int page ); virtual void focus_current_view(); virtual void open_window(); virtual void close_window(); virtual SKELETON::View* get_view( const std::string& url ); virtual SKELETON::View* get_current_view(); // ページがロックされているかリストで取得 virtual std::list< bool > get_locked(); // タブのロック/アンロック virtual const bool is_lockable( const int page ); virtual const bool is_locked( const int page ); virtual void lock( const int page ); virtual void unlock( const int page ); // タブの D&D 処理は SKELETON::Admin とは違うロジックでおこなう virtual void slot_drag_data_get( Gtk::SelectionData& selection_data, const int page ){} private: void close_left_views( const std::string& url ); void close_right_views( const std::string& url ); void close_error_views( const std::string mode ); void close_noerror_views(); void reorder( const std::string& url_from, const std::string& url_to ); void update_status_of_all_views(); void focus_out_all(); void switch_img( const std::string& url ); SKELETON::View* get_icon( const std::string& url, int& pos ); SKELETON::View* get_icon( const std::string& url ); SKELETON::View* get_nth_icon( const unsigned int n ); SKELETON::View* get_current_icon(); // スクロール void scroll_tab( int scroll ); // スクロールボタン void slot_press_left(); void slot_press_right(); void slot_release_left(); void slot_release_right(); bool copy_file( const std::string& url, const std::string& path_from, const std::string& path_to ); void save_all(); }; IMAGE::ImageAdmin* get_admin(); void delete_admin(); }; #endif jd-2.8.7-140104/src/image/imagearea.cpp0000644000076400010400000000501511157223410014055 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imagearea.h" #include "dbimg/img.h" #include "config/globalconf.h" #include "session.h" #ifndef MIN #define MIN( a, b ) ( a < b ? a : b ) #endif using namespace IMAGE; ImageAreaMain::ImageAreaMain( const std::string& url ) : ImageAreaBase( url, CONFIG::get_imgmain_interp() ) { #ifdef _DEBUG std::cout << "ImageAreaMain::ImageAreaMain url = " << url << std::endl; #endif } ImageAreaMain::~ImageAreaMain() { #ifdef _DEBUG std::cout << "ImageAreaMain::~ImageAreaMain url = " << get_url() << std::endl; #endif } // // 表示 // void ImageAreaMain::show_image() { #ifdef _DEBUG std::cout << "ImageAreaMain::show_image url = " << get_url() << std::endl; #endif if( is_loading() ) return; set_errmsg( std::string() ); int width_max = 0; int height_max = 0; if( get_parent() && get_parent()->get_parent() ){ // 親(EventBox)の親(ScrolledWindow)がいるときはそのサイズ const int mrg = 32; width_max = get_parent()->get_parent()->get_width() - mrg; height_max = get_parent()->get_parent()->get_height() - mrg; } else{ width_max = Gtk::Image::get_width(); height_max = Gtk::Image::get_height(); } // まだrealizeしてなくてウィンドウサイズが取得できていないのでImageViewMain::clock_in()経由で後でもう一度呼ぶ if( ! is_ready() && ( width_max <= 1 || height_max <= 1 ) ) return; bool zoom_to_fit = get_img()->is_zoom_to_fit(); int size = get_img()->get_size(); // スケール調整 double scale = 1; int w_org = get_img()->get_width(); int h_org = get_img()->get_height(); set_width( w_org ); set_height( h_org ); // 画面サイズに合わせる if( zoom_to_fit && w_org && h_org ){ double scale_w = ( double ) width_max / w_org; double scale_h = ( double ) height_max / h_org; if( SESSION::get_img_fit_mode() == SESSION::IMG_FIT_NORMAL ) scale = MIN( scale_w, scale_h ); else scale = scale_w; if( scale < 1 ){ set_width( (int)( w_org * scale ) ); set_height( (int)( h_org * scale ) ); } } // サイズ変更 else if( size != 100 ){ scale = size/100.; set_width( (int)( w_org * scale ) ); set_height( (int)( h_org * scale ) ); } //データベースのサイズ情報更新 get_img()->set_size( get_width() * 100 / get_img()->get_width() ); load_image(); } jd-2.8.7-140104/src/image/imagearea.h0000644000076400010400000000054210755613777013550 0ustar // ライセンス: GPL2 // // メイン画像クラス // #ifndef _IMAGEAREA_H #define _IMAGEAREA_H #include "imageareabase.h" namespace IMAGE { class ImageAreaMain : public ImageAreaBase { public: ImageAreaMain( const std::string& url ); virtual ~ImageAreaMain(); virtual void show_image(); }; } #endif jd-2.8.7-140104/src/image/imageareabase.cpp0000644000076400010400000001323411330751043014713 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imageareabase.h" #include "jdlib/miscmsg.h" #include "dbimg/imginterface.h" #include "dbimg/img.h" #include "config/globalconf.h" // // スレッドのランチャ // Glib::StaticMutex imgarea_launcher_mutex = GLIBMM_STATIC_MUTEX_INIT; void* imgarea_launcher( void* dat ) { Glib::Mutex::Lock lock( imgarea_launcher_mutex); #ifdef _DEBUG std::cout << "start imgarea_launcher" << std::endl; #endif IMAGE::ImageAreaBase* area = ( IMAGE::ImageAreaBase* )( dat ); area->load_image_thread(); #ifdef _DEBUG std::cout << "end" << std::endl; #endif return 0; } ////////////////////////////////// using namespace IMAGE; // interptype : // 0 -> INTERP_NEAREST // 1 -> INTERP_BILINEAR // 3 -> INTERP_HYPER ImageAreaBase::ImageAreaBase( const std::string& url, const int interptype ) : m_url( url ), m_img ( DBIMG::get_img( m_url ) ), m_ready( false ), m_width( 0 ), m_height( 0 ) { #ifdef _DEBUG std::cout << "ImageAreaBase::ImageAreaBase url = " << m_url << " type = " << interptype << std::endl; #endif assert( m_img ); m_interptype = Gdk::INTERP_NEAREST; if( interptype == 1 ) m_interptype = Gdk::INTERP_BILINEAR; else if( interptype >= 2 ) m_interptype = Gdk::INTERP_HYPER; set_alignment( Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER ); } ImageAreaBase::~ImageAreaBase() { #ifdef _DEBUG std::cout << "ImageAreaBase::~ImageAreaBase url = " << m_url << std::endl; #endif // デストラクタの中からdispatchを呼ぶと落ちるので dispatch不可にする set_dispatchable( false ); stop(); wait(); } void ImageAreaBase::stop() { #ifdef _DEBUG std::cout << "ImageAreaBase::stop" << std::endl; #endif if( m_imgloader ) m_imgloader->request_stop(); } void ImageAreaBase::wait() { #ifdef _DEBUG std::cout << "ImageAreaBase::wait" << std::endl; #endif m_thread.join(); #ifdef _DEBUG std::cout << "ImageAreaBase::wait ok" << std::endl; #endif } // // 幅、高さセット // // 0にするとGdk::Pixbuf::create()で落ちるので注意 // void ImageAreaBase::set_width( const int width ) { m_width = MAX( 1, width ); } void ImageAreaBase::set_height( const int height ) { m_height = MAX( 1, height ); } // // 画像読み込み // void ImageAreaBase::load_image() { #ifdef _DEBUG std::cout << "ImageAreaBase::load_image" << std::endl; #endif // 大きい画像を表示しようとするとJDが固まるときがあるのでスレッドを使用する // ランチャ経由で load_image_thread() を動かす if( ! m_thread.create( imgarea_launcher, ( void* ) this, JDLIB::NODETACH ) ) { MISC::ERRMSG( "ImageAreaBase::load_image : could not start thread" ); } } // // 画像読み込みスレッド // void ImageAreaBase::load_image_thread() { #ifdef _DEBUG std::cout << "ImageAreaBase::load_image_thread url = " << get_url() << std::endl; #endif const int w_org = get_img()->get_width(); const int h_org = get_img()->get_height(); // アニメーションoff bool pixbufonly = ( w_org != get_width() || h_org != get_height() ); // pixbufonly = trueにすると プログレッシブJPGではモザイクがかかったようになる const int minsize = w_org/4; if( pixbufonly && get_width() > minsize && m_img->get_type() == DBIMG::T_JPG ) pixbufonly = false; // BMP の場合 pixbufonly = true にすると真っ黒になる if( pixbufonly && m_img->get_type() == DBIMG::T_BMP ) pixbufonly = false; std::string errmsg; if( ! create_imgloader( pixbufonly, errmsg ) ){ set_errmsg( errmsg ); MISC::ERRMSG( get_errmsg() ); } // 表示 // スレッドの中でset_image()すると固まるときがあるのでディスパッチャ経由で // callback_dispatch() -> set_image() の順に呼び出す dispatch(); #ifdef _DEBUG std::cout << "ImageAreaBase::load_image_thread finished" << std::endl; #endif } const bool ImageAreaBase::create_imgloader( const bool pixbufonly, std::string& errmsg ) { m_imgloader = JDLIB::ImgLoader::get_loader( m_img->get_cache_path() ); bool ret = m_imgloader->load( pixbufonly ); if( ! ret ) { errmsg = m_imgloader->get_errmsg(); } return ret; } // // ディスパッチャのコールバック関数 // void ImageAreaBase::callback_dispatch() { set_image(); wait(); } // // Gtk::Image::set()を使用して画像表示 // void ImageAreaBase::set_image() { #ifdef _DEBUG std::cout << "ImageAreaBase::set_image" << std::endl; #endif clear(); const int w_org = get_img()->get_width(); const int h_org = get_img()->get_height(); Glib::RefPtr< Gdk::Pixbuf > pixbuf = m_imgloader->get_pixbuf(); if( pixbuf ){ if( m_img->get_mosaic() ){ // モザイク set_mosaic( pixbuf ); }else if( w_org != get_width() || h_org != get_height() ){ // 拡大縮小 set( pixbuf->scale_simple( get_width(), get_height(), m_interptype ) ); }else{ // 通常 set( m_imgloader->get_animation() ); } } m_imgloader.clear(); set_ready( true ); } // // モザイク表示 // void ImageAreaBase::set_mosaic( Glib::RefPtr< Gdk::Pixbuf > pixbuf ) { const int moswidth = get_img()->get_width_mosaic(); const int mosheight = get_img()->get_height_mosaic(); if( moswidth && mosheight ){ Glib::RefPtr< Gdk::Pixbuf > pixbuf2; pixbuf2 = pixbuf->scale_simple( moswidth, mosheight, Gdk::INTERP_NEAREST ); set( pixbuf2->scale_simple( get_width(), get_height(), Gdk::INTERP_NEAREST ) ); } } jd-2.8.7-140104/src/image/imageareabase.h0000644000076400010400000000416011330751043014356 0ustar // ライセンス: GPL2 // // 画像クラスのベースクラス // #ifndef _IMAGEAREABASE_H #define _IMAGEAREABASE_H #include #include "skeleton/dispatchable.h" #include "jdlib/constptr.h" #include "jdlib/jdthread.h" #include "jdlib/imgloader.h" namespace DBIMG { class Img; } namespace IMAGE { class ImageAreaBase : public Gtk::Image, public SKELETON::Dispatchable { std::string m_url; JDLIB::ConstPtr< DBIMG::Img > m_img; Gdk::InterpType m_interptype; std::string m_errmsg; // エラーメッセージ bool m_ready; // 画像がsetされた int m_width; int m_height; // スレッド用変数 JDLIB::Thread m_thread; protected: Glib::RefPtr< JDLIB::ImgLoader > m_imgloader; public: // interptype : // 0 -> INTERP_NEAREST // 1 -> INTERP_BILINEAR // 3 -> INTERP_HYPER ImageAreaBase( const std::string& url, const int interptype ); virtual ~ImageAreaBase(); void stop(); void wait(); const std::string& get_url() const{ return m_url;} const std::string& get_errmsg() const{ return m_errmsg;} const bool is_ready() const { return m_ready; } const bool is_loading(){ return m_thread.is_running(); } const int get_width() const { return m_width; } const int get_height() const { return m_height; } virtual void show_image() = 0; void set_fit_in_win( bool fit ); virtual void load_image_thread(); protected: JDLIB::ConstPtr< DBIMG::Img >& get_img(){ return m_img; } void set_errmsg( const std::string& errmsg ){ m_errmsg = errmsg; } void set_ready( bool ready ){ m_ready = ready; } void set_width( const int width ); void set_height( const int height ); void load_image(); const bool create_imgloader( const bool pixbufonly, std::string& errmsg ); private: virtual void callback_dispatch(); virtual void set_image(); void set_mosaic( Glib::RefPtr< Gdk::Pixbuf > pixbuf ); }; } #endif jd-2.8.7-140104/src/image/imageareaicon.cpp0000644000076400010400000001225011334022056014725 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imageareaicon.h" #include "dbimg/img.h" #include "dbimg/imginterface.h" #include "jdlib/miscmsg.h" #include "jdlib/miscgtk.h" #include "config/globalconf.h" #include "global.h" #include "httpcode.h" #include "colorid.h" using namespace IMAGE; ImageAreaIcon::ImageAreaIcon( const std::string& url ) : ImageAreaBase( url, 0 ) // アイコンは常に Gdk::INTERP_NEAREST , m_shown( false ) { #ifdef _DEBUG std::cout << "ImageAreaIcon::ImageAreaIcon url = " << url << std::endl; #endif set_width( ICON_SIZE ); set_height( ICON_SIZE ); } ImageAreaIcon::~ImageAreaIcon() { #ifdef _DEBUG std::cout << "ImageAreaIcon::~ImageAreaIcon url = " << get_url() << std::endl; #endif } // // 表示 // // メインスレッドで大きい画像を開くと反応が無くなるので別の // スレッドを起動して開く。 // void ImageAreaIcon::show_image() { #ifdef _DEBUG std::cout << "ImageAreaIcon::show_image url = " << get_url() << std::endl; #endif if( is_loading() ) return; // 既に画像が表示されている if( m_shown && get_img()->is_cached() ) return; if( m_pixbuf ){ m_pixbuf.clear(); m_pixbuf_loading.clear(); m_pixbuf_err.clear(); } if( m_pixbuf_icon ) m_pixbuf_icon.clear(); m_shown = false; set_ready( false ); // キャッシュされてない時は読み込みorエラーマークを表示 if( ! get_img()->is_cached() ){ show_indicator( ( get_img()->is_loading() || get_img()->is_wait() || get_img()->get_code() == HTTP_INIT ) ); set_image(); } // スレッドを起動してバックグラウンドでアイコン表示 else{ // 縮小比率を計算 double scale; int w_org = get_img()->get_width(); int h_org = get_img()->get_height(); double scale_w = ( double ) ICON_SIZE / w_org; double scale_h = ( double ) ICON_SIZE / h_org; scale = MIN( scale_w, scale_h ); set_width( (int)( w_org * scale ) ); set_height( (int)( h_org * scale ) ); load_image(); } } // // 表示スレッド // void ImageAreaIcon::load_image_thread() { #ifdef _DEBUG std::cout << "ImageAreaIcon::load_image_thread url = " << get_url() << std::endl; #endif bool pixbufonly = true; if( get_img()->get_type() == DBIMG::T_BMP ) pixbufonly = false; // BMP の場合 pixbufonly = true にすると真っ黒になる std::string errmsg; if( create_imgloader( pixbufonly, errmsg ) ){ Glib::RefPtr< Gdk::Pixbuf > pixbuf = m_imgloader->get_pixbuf(); if( pixbuf ) m_pixbuf_icon = pixbuf->scale_simple( get_width(), get_height(), Gdk::INTERP_NEAREST ); } m_imgloader.clear(); if( m_pixbuf_icon ){ m_imagetype = IMAGE_SHOW_ICON; m_shown = true; } else{ set_errmsg( errmsg ); MISC::ERRMSG( get_errmsg() ); show_indicator( false ); } // 表示 // スレッドの中でset_image()すると固まるときがあるのでディスパッチャ経由で // callback_dispatch() -> set_image() の順に呼び出す dispatch(); #ifdef _DEBUG std::cout << "ImageAreaIcon::load_image_thread finished" << std::endl; #endif } // // インジケータ幅、高さ const int ImageAreaIcon::width_indicator() { return MAX( 1, get_width()/4 ); } const int ImageAreaIcon::height_indicator() { return MAX( 1, get_height()/4 ); } // // インジゲータ画像表示 // void ImageAreaIcon::show_indicator( bool loading ) { #ifdef _DEBUG std::cout << "ImageAreaIcon::show_indicator load = " << loading << std::endl; #endif if( ! m_pixbuf ){ m_pixbuf = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, get_width(), get_height() ); m_pixbuf_err = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, width_indicator(), height_indicator() ); m_pixbuf_loading = Gdk::Pixbuf::create( Gdk::COLORSPACE_RGB, false, 8, width_indicator(), height_indicator() ); assert( m_pixbuf ); assert( m_pixbuf_err ); assert( m_pixbuf_loading ); m_pixbuf->fill( 0xffffff00 ); m_pixbuf_loading->fill( MISC::color_to_int( Gdk::Color( CONFIG::get_color( COLOR_IMG_LOADING ) ) ) ); m_pixbuf_err->fill( MISC::color_to_int( Gdk::Color( CONFIG::get_color( COLOR_IMG_ERR ) ) ) ); } // 読み込み中 if( loading ) m_pixbuf_loading->copy_area( 0, 0, width_indicator(), height_indicator(), m_pixbuf, 4, 4 ); // エラー else m_pixbuf_err->copy_area( 0, 0, width_indicator(), height_indicator(), m_pixbuf, 4, 4 ); m_imagetype = IMAGE_SHOW_INDICATOR; } // // 表示 // void ImageAreaIcon::set_image() { #ifdef _DEBUG std::cout << "ImageAreaIcon::set_image type = " << m_imagetype << std::endl; #endif clear(); if( m_imagetype == IMAGE_SHOW_ICON ){ #ifdef _DEBUG std::cout << "show icon" << std::endl; #endif set( m_pixbuf_icon ); } else if( m_imagetype == IMAGE_SHOW_INDICATOR ){ #ifdef _DEBUG std::cout << "show indicator" << std::endl; #endif set( m_pixbuf ); } set_ready( true ); } jd-2.8.7-140104/src/image/imageareaicon.h0000644000076400010400000000175410755613777014427 0ustar // ライセンス: GPL2 // // アイコン画像クラス // #ifndef _IMAGEAREAICON_H #define _IMAGEAREAICON_H #include "imageareabase.h" namespace IMAGE { // m_imagetype にセットする値 enum { IMAGE_SHOW_ICON = 0, IMAGE_SHOW_INDICATOR }; class ImageAreaIcon : public ImageAreaBase { bool m_shown; int m_imagetype; // dispatch()前に表示する画像を入れる Glib::RefPtr< Gdk::Pixbuf > m_pixbuf; Glib::RefPtr< Gdk::Pixbuf > m_pixbuf_loading; Glib::RefPtr< Gdk::Pixbuf > m_pixbuf_err; Glib::RefPtr< Gdk::Pixbuf > m_pixbuf_icon; public: ImageAreaIcon( const std::string& url ); virtual ~ImageAreaIcon(); virtual void show_image(); virtual void load_image_thread(); private: const int width_indicator(); const int height_indicator(); void show_indicator( bool loading ); virtual void set_image(); }; } #endif jd-2.8.7-140104/src/image/imageareapopup.cpp0000644000076400010400000000272211330751043015144 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imageareapopup.h" #include "dbimg/img.h" #include "config/globalconf.h" #ifndef MIN #define MIN( a, b ) ( a < b ? a : b ) #endif using namespace IMAGE; ImageAreaPopup::ImageAreaPopup( const std::string& url ) : ImageAreaBase( url, CONFIG::get_imgpopup_interp() ) { #ifdef _DEBUG std::cout << "ImageAreaPopup::ImageAreaPopup url = " << url << std::endl; #endif } ImageAreaPopup::~ImageAreaPopup() { #ifdef _DEBUG std::cout << "ImageAreaPopup::~ImageAreaPopup url = " << get_url() << std::endl; #endif } // // 表示 // void ImageAreaPopup::show_image() { if( is_loading() ) return; if( ! get_img()->is_cached() ) return; #ifdef _DEBUG std::cout << "ImageAreaPopup::show_image url = " << get_url() << std::endl; #endif set_errmsg( std::string() ); const int width_max = CONFIG::get_imgpopup_width(); const int height_max = CONFIG::get_imgpopup_height(); // 縮小比率を計算 const int w_org = get_img()->get_width(); const int h_org = get_img()->get_height(); const double scale_w = ( double ) width_max / w_org; const double scale_h = ( double ) height_max / h_org; const double scale = MIN( scale_w, scale_h ); if( scale < 1 ){ set_width( (int)( w_org * scale ) ); set_height( (int)( h_org * scale ) ); } else{ set_width( w_org ); set_height( h_org ); } load_image(); } jd-2.8.7-140104/src/image/imageareapopup.h0000644000076400010400000000060010755613777014627 0ustar // ライセンス: GPL2 // // ポップアップ画像クラス // #ifndef _IMAGEAREAPOPUP_H #define _IMAGEAREAPOPUP_H #include "imageareabase.h" namespace IMAGE { class ImageAreaPopup : public ImageAreaBase { public: ImageAreaPopup( const std::string& url ); virtual ~ImageAreaPopup(); virtual void show_image(); }; } #endif jd-2.8.7-140104/src/image/imageview.cpp0000644000076400010400000003571011546644243014141 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imageadmin.h" #include "imageview.h" #include "imagearea.h" #include "skeleton/msgdiag.h" #include "dbimg/img.h" #include "jdlib/miscutil.h" #include "config/globalconf.h" #include "control/controlid.h" #include "history/historymanager.h" #include "command.h" #include "httpcode.h" #include "session.h" #include "global.h" #include #ifndef MAX #define MAX( a, b ) ( a > b ? a : b ) #endif #ifndef MIN #define MIN( a, b ) ( a < b ? a : b ) #endif enum { IMGWIN_REDRAWTIME = 250 // msec }; using namespace IMAGE; ImageViewMain::ImageViewMain( const std::string& url ) : ImageViewBase( url ), m_scrwin( 0 ), m_length_prev( 0 ), m_show_status( false ), m_update_status( false ), m_show_label( false ), m_do_resizing( false ), m_scrolled( false ) { #ifdef _DEBUG std::cout << "ImageViewMain::ImageViewMain : " << get_url() << std::endl; #endif // コントロールモード設定 get_control().add_mode( CONTROL::MODE_IMAGEVIEW ); // スクロールウィンドウを作ってEventBoxを貼る m_scrwin = Gtk::manage( new Gtk::ScrolledWindow() ); assert( m_scrwin ); m_scrwin->property_vscrollbar_policy() = Gtk::POLICY_AUTOMATIC; m_scrwin->property_hscrollbar_policy() = Gtk::POLICY_AUTOMATIC; m_scrwin->add( get_event() ); pack_start( *m_scrwin ); setup_common(); // タイトルセット set_title( "[ 画像 ]" ); IMAGE::get_admin()->set_command( "set_title", get_url(), get_title() ); } ImageViewMain::~ImageViewMain() { // 閉じた画像履歴更新 HISTORY::append_history( URL_HISTCLOSEIMGVIEW, get_url(), MISC::get_filename( get_url() ), TYPE_IMAGE ); } // // クロック入力 // // アクティブ(表示されている)view以外にはクロックは来ないのに注意 // void ImageViewMain::clock_in() { View::clock_in(); const int width_view = get_width(); const int height_view = get_height(); // ステータスのタブ番号などの表示内容更新 if( m_update_status ){ m_update_status = false; add_tab_number(); m_show_status = true; } // viewがアクティブになった(クロック入力が来た)ときにステータス表示 if( m_show_status ){ m_show_status = false; IMAGE::get_admin()->set_command( "set_status", get_url(), get_status() ); } // ロード待ち if( is_wait() ){ // ロード待ち状態解除 if( ! get_img()->is_wait() ){ set_wait( false ); if( get_img()->is_loading() ){ set_loading( true ); set_status_local( "読み込み中" ); add_tab_number(); if( m_show_label ) m_label.set_text( get_status_local() ); } else{ set_loading( false ); show_view(); show_status(); } } } // ロード中 else if( is_loading() ){ // 読み込みサイズの表示更新 if( get_img()->is_loading() ) show_status(); // ロード完了 else{ set_loading( false ); show_view(); show_status(); } } // ロード中でなく、viewが表示されている else if( get_imagearea() && ! get_imagearea()->is_loading() && width_view > 1 && height_view > 1 ){ // バックグラウンドで開いた時やロード直後に画像を表示すると重くなるので // ビューがアクティブになった(クロック入力が来た) 時点で画面を表示する if( ! get_imagearea()->is_ready() ){ m_pre_width = width_view; m_pre_height = height_view; m_redraw_count = 10000; get_imagearea()->show_image(); // 読み込みエラーが起きたらimageareaを除いてラベルを貼る if( ! get_imagearea()->get_errmsg().empty() ){ set_status_local( get_imagearea()->get_errmsg() ); add_tab_number(); remove_imagearea(); set_label(); } show_status(); if( CONFIG::get_instruct_tglimg() ) show_instruct_diag(); } // サイズが変わって、かつ zoom to fit モードの場合再描画 else if( get_imagearea()->is_ready() && get_img()->is_cached() && get_img()->is_zoom_to_fit() && ( m_pre_width != width_view || m_pre_height != height_view ) ){ // 毎回再描画していると遅いのでカウンタを付ける ++m_redraw_count; if( m_redraw_count >= ( IMGWIN_REDRAWTIME / TIMER_TIMEOUT ) ) { m_pre_width = width_view; m_pre_height = height_view; m_redraw_count = 0; #ifdef _DEBUG std::cout << "ImageViewMain::clock_in resize\n" << get_url() << " " << m_pre_width << " - " << m_pre_height << std::endl; #endif get_imagearea()->show_image(); show_status(); } } else m_redraw_count = 0; } } // // スレビューとの切り替え方法説明ダイアログ表示 // void ImageViewMain::show_instruct_diag() { SKELETON::MsgCheckDiag mdiag( get_parent_win(), "画像ビューからスレビューに戻る方法として\n\n(1) マウスジェスチャを使う\n(マウス右ボタンを押しながら左または下にドラッグして右ボタンを離す)\n\n(2) マウスの5ボタンを押す\n\n(3) Alt+x か h か ← を押す\n\n(4) ツールバーのスレビューアイコンを押す\n\n(5) 表示メニューからスレビューを選ぶ\n\nなどがあります。詳しくはオンラインマニュアルを参照してください。", "今後表示しない(_D)" ); mdiag.set_title( "ヒント" ); mdiag.run(); if( mdiag.get_chkbutton().get_active() ) CONFIG::set_instruct_tglimg( false ); } // // ラベルを貼る // void ImageViewMain::set_label() { if( !m_show_label ){ m_label.set_text( get_status_local() ); get_event().add( m_label ); m_label.show(); m_show_label = true; } } // // ラベルをremove // void ImageViewMain::remove_label() { if( m_show_label ){ get_event().remove(); m_show_label = false; } } // // 表示 // void ImageViewMain::show_view() { if( is_loading() ) return; if( is_wait() ) return; #ifdef _DEBUG std::cout << "ImageViewMain::show_view url = " << get_url() << std::endl; #endif // 画像を既に表示している if( get_imagearea() ){ // キャッシュされてるなら再描画 if( get_img()->is_cached() ){ #ifdef _DEBUG std::cout << "redraw\n"; #endif get_imagearea()->show_image(); show_status(); return; } remove_imagearea(); } remove_label(); // ロード待ち、又は読み込み中 if( get_img()->is_wait() || get_img()->is_loading() ){ if( get_img()->is_wait() ){ #ifdef _DEBUG std::cout << "wait\n"; #endif set_wait( true ); set_loading( false ); set_status_local( "待機中" ); } else{ #ifdef _DEBUG std::cout << "loading\n"; #endif set_wait( false ); set_loading( true ); set_status_local( "読み込み中" ); } add_tab_number(); m_length_prev = 0; m_show_status = true; // viewがアクティブになった時点でステータス表示 set_label(); } // キャッシュがあるなら画像を表示 else if( get_img()->is_cached() ){ #ifdef _DEBUG std::cout << "set image\n"; #endif // 表示はビューがアクティブになった時に clock_in()の中で行う set_imagearea( Gtk::manage( new ImageAreaMain( get_url() ) ) ); } // エラー else{ if( ! get_img()->get_str_code().empty() ) set_status_local( get_img()->get_str_code() ); else set_status_local( "画像情報が存在しません。再読み込みして下さい" ); add_tab_number(); m_show_status = true; // viewがアクティブになった時点でステータス表示 set_label(); } show_all_children(); } // // ステータス表示 // void ImageViewMain::show_status() { if( ! is_loading() && ! is_wait() ){ // 画像が表示されていたら画像情報 if( get_imagearea() ){ std::stringstream ss; ss << get_img()->get_width() << " x " << get_img()->get_height(); if( get_img()->get_width() ) ss << " (" << get_img()->get_size() << " %)"; ss << " " << get_img()->total_length()/1024 << " K "; if( get_img()->is_protected() ) ss << " 保護中"; set_status_local( ss.str() ); } // エラー(ネットワーク系) else if( get_img()->get_code() != HTTP_OK ) set_status_local( get_img()->get_str_code() ); add_tab_number(); m_show_status = true; // viewがアクティブになった時点でステータス表示 if( m_show_label ) m_label.set_text( get_status_local() ); } // ロード中 else if( is_loading() ){ // 読み込みサイズが更新した場合 if( m_length_prev != get_img()->current_length() ){ m_length_prev = get_img()->current_length(); char tmpstr[ 256 ]; snprintf( tmpstr, 256, "%zd k / %zd k", m_length_prev/1024, get_img()->total_length()/1024 ); set_status_local( tmpstr ); add_tab_number(); m_show_status = true; // viewがアクティブになった時点でステータス表示 if( m_show_label ) m_label.set_text( get_status_local() ); } } } void ImageViewMain::update_status() { m_update_status = true; // viewがアクティブになった時点でステータス表示更新 } // // ステータスのタブ番号などの表示内容更新 // void ImageViewMain::add_tab_number() { set_status( " [" + MISC::itostr( IMAGE::get_admin()->get_current_page() + 1 ) + "/" + MISC::itostr( IMAGE::get_admin()->get_tab_nums() ) + "] " + get_status_local() + " [" + MISC::get_filename( get_url() ) + " (" + MISC::get_hostname( get_url(), false ) + ")]" ); #ifdef _DEBUG std::cout << "ImageViewMain::add_tab_number : " << get_status() << std::endl;; #endif } // // ポップアップメニュー取得 // // SKELETON::View::show_popupmenu() を参照すること // Gtk::Menu* ImageViewMain::get_popupmenu( const std::string& url ) { Gtk::Menu* popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu" ) ); return popupmenu; } // // ボタンクリック // bool ImageViewMain::slot_button_press( GdkEventButton* event ) { ImageViewBase::slot_button_press( event ); // ドラッグして画像移動するときの起点 m_x_motion = event->x_root; m_y_motion = event->y_root; m_scrolled = false; // ボタンをリリースした時に大きさを変更 m_do_resizing = false; if( ! is_loading() && ! is_wait() && get_control().button_alloted( event, CONTROL::ResizeImageButton ) ) m_do_resizing = true; return true; } // // マウスモーション // bool ImageViewMain::slot_motion_notify( GdkEventMotion* event ) { ImageViewBase::slot_motion_notify( event ); // スクロールバー移動 if( m_scrwin ){ GdkEventButton event_button; get_control().get_eventbutton( CONTROL::ScrollImageButton, event_button ); #ifdef _DEBUG // std::cout << "state = " << event->state << " / " << GDK_BUTTON1_MASK << " button = " << event_button.button << std::endl; #endif if( ( ( event->state & GDK_BUTTON1_MASK ) && event_button.button == 1 ) || ( ( event->state & GDK_BUTTON2_MASK ) && event_button.button == 2 ) || ( ( event->state & GDK_BUTTON3_MASK ) && event_button.button == 3 ) ){ Gtk::Adjustment* hadj = m_scrwin->get_hadjustment(); Gtk::Adjustment* vadj = m_scrwin->get_vadjustment(); gdouble dx = event->x_root - m_x_motion; gdouble dy = event->y_root - m_y_motion; #ifdef _DEBUG // std::cout << "dx = " << dx << " dy = " << dy << std::endl; #endif m_x_motion = event->x_root; m_y_motion = event->y_root; if( hadj ) hadj->set_value( MAX( hadj->get_lower(), MIN( hadj->get_upper() - hadj->get_page_size(), hadj->get_value() - dx ) ) ); if( vadj ) vadj->set_value( MAX( vadj->get_lower(), MIN( vadj->get_upper() - vadj->get_page_size(), vadj->get_value() - dy ) ) ); m_scrolled = true; } } return true; } // // 上スクロール // void ImageViewMain::scroll_up() { #ifdef _DEBUG std::cout << "ImageViewMain::scroll_up\n"; #endif Gtk::Adjustment* vadjust = m_scrwin->get_vadjustment(); if( !vadjust ) return; vadjust->set_value( MAX( 0, vadjust->get_value() - vadjust->get_step_increment() ) ); } // // 下スクロール // void ImageViewMain::scroll_down() { #ifdef _DEBUG std::cout << "ImageViewMain::scroll_down\n"; #endif Gtk::Adjustment* vadjust = m_scrwin->get_vadjustment(); if( !vadjust ) return; vadjust->set_value( MIN( vadjust->get_upper() - vadjust->get_page_size(), vadjust->get_value() + vadjust->get_step_increment() ) ); } // // 左スクロール // void ImageViewMain::scroll_left() { #ifdef _DEBUG std::cout << "ImageViewMain::scroll_left\n"; #endif Gtk::Adjustment* hadjust = m_scrwin->get_hadjustment(); if( !hadjust ) return; hadjust->set_value( MAX( 0, hadjust->get_value() - hadjust->get_step_increment() ) ); } // // 右スクロール // void ImageViewMain::scroll_right() { #ifdef _DEBUG std::cout << "ImageViewMain::scroll_right\n"; #endif Gtk::Adjustment* hadjust = m_scrwin->get_hadjustment(); if( !hadjust ) return; hadjust->set_value( MIN( hadjust->get_upper() - hadjust->get_page_size(), hadjust->get_value() + hadjust->get_step_increment() ) ); } // // viewの操作 // const bool ImageViewMain::operate_view( const int control ) { // スクロールしたときはキャンセル if( m_scrolled ){ m_scrolled = false; return false; } int cntl = control; if( m_do_resizing ){ m_do_resizing = false; if( get_img()->get_size() == 100 ) cntl = CONTROL::ZoomFitImage; else cntl = CONTROL::OrgSizeImage; } return ImageViewBase::operate_view( cntl ); } jd-2.8.7-140104/src/image/imageview.h0000644000076400010400000000307111546644243013601 0ustar // ライセンス: GPL2 // // 画像ビュークラス // #ifndef _IMAGEVIEW_H #define _IMAGEVIEW_H #include "imageviewbase.h" namespace IMAGE { class ImageViewMain : public ImageViewBase { Gtk::ScrolledWindow* m_scrwin; Gtk::Label m_label; gdouble m_x_motion; gdouble m_y_motion; size_t m_length_prev; bool m_show_status; bool m_update_status; bool m_show_label; std::string m_status_local; int m_pre_width; int m_pre_height; int m_redraw_count; bool m_do_resizing; bool m_scrolled; public: ImageViewMain( const std::string& url ); virtual ~ImageViewMain(); virtual void clock_in(); virtual void show_view(); virtual void scroll_up(); virtual void scroll_down(); virtual void scroll_left(); virtual void scroll_right(); virtual const bool operate_view( const int control ); protected: virtual Gtk::Menu* get_popupmenu( const std::string& url ); virtual bool slot_button_press( GdkEventButton* event ); virtual bool slot_motion_notify( GdkEventMotion* event ); private: void set_status_local( const std::string& status ){ m_status_local = status; } const std::string& get_status_local(){ return m_status_local; } virtual void show_status(); virtual void update_status(); void add_tab_number(); void show_instruct_diag(); void set_label(); void remove_label(); }; } #endif jd-2.8.7-140104/src/image/imageviewbase.cpp0000644000076400010400000010417512073555710014772 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imageadmin.h" #include "imageviewbase.h" #include "imageareabase.h" #include "skeleton/msgdiag.h" #include "dbtree/interface.h" #include "dbimg/imginterface.h" #include "dbimg/img.h" #include "jdlib/miscutil.h" #include "jdlib/miscgtk.h" #include "control/controlutil.h" #include "control/controlid.h" #include "config/globalconf.h" #include "cache.h" #include "command.h" #include "sharedbuffer.h" #include "global.h" #include "type.h" #include "prefdiagfactory.h" #include "usrcmdmanager.h" #include "httpcode.h" #include "session.h" #include #define SIZE_MENU { 25, 50, 75, 100, 150, 200, 400 } using namespace IMAGE; ImageViewBase::ImageViewBase( const std::string& url, const std::string& arg1, const std::string& arg2 ) : SKELETON::View( url ), m_wait( false ), m_loading( false ), m_under_mouse( false ), m_enable_menuslot( true ) { // 高速化のためデータベースに直接アクセス m_img = DBIMG::get_img( get_url() ); assert( m_img ); // マウスジェスチャ可能 set_enable_mg( true ); } ImageViewBase::~ImageViewBase() { #ifdef _DEBUG std::cout << "ImageViewBase::~ImageViewBase : " << get_url() << std::endl; #endif } SKELETON::Admin* ImageViewBase::get_admin() { return IMAGE::get_admin(); } // // 親ウィンドウを取得 // Gtk::Window* ImageViewBase::get_parent_win() { return IMAGE::get_admin()->get_win(); } // // 共通セットアップ // void ImageViewBase::setup_common() { const int default_width = 200; const int default_height = 50; set_width_client( default_width ); set_height_client( default_height ); // focus 可、モーションキャプチャ可 m_event.set_flags( m_event.get_flags() | Gtk::CAN_FOCUS ); m_event.add_events( Gdk::POINTER_MOTION_MASK ); m_event.signal_button_press_event().connect( sigc::mem_fun( *this, &ImageViewBase::slot_button_press ) ); m_event.signal_button_release_event().connect( sigc::mem_fun( *this, &ImageViewBase::slot_button_release ) ); m_event.signal_motion_notify_event().connect( sigc::mem_fun( *this, &ImageViewBase::slot_motion_notify ) ); m_event.signal_key_press_event().connect( sigc::mem_fun(*this, &ImageViewBase::slot_key_press ) ); m_event.signal_scroll_event().connect( sigc::mem_fun(*this, &ImageViewBase::slot_scroll_event ) ); m_event.signal_enter_notify_event().connect( sigc::mem_fun( *this, &ImageViewBase::slot_enter_notify_event ) ); m_event.signal_leave_notify_event().connect( sigc::mem_fun( *this, &ImageViewBase::slot_leave_notify_event ) ); m_event.grab_focus(); // ポップアップメニューの設定 // アクショングループを作ってUIマネージャに登録 action_group() = Gtk::ActionGroup::create(); action_group()->add( Gtk::Action::create( "CancelMosaic", "CancelMosaic"), sigc::mem_fun( *this, &ImageViewBase::slot_cancel_mosaic ) ); action_group()->add( Gtk::Action::create( "ShowLargeImg", "サイズが大きい画像を表示(_G)"), sigc::mem_fun( *this, &ImageViewBase::slot_show_large_img ) ); action_group()->add( Gtk::Action::create( "LoadStop", "StopLoading" ), sigc::mem_fun( *this, &ImageViewBase::stop ) ); action_group()->add( Gtk::Action::create( "Reload", "強制再読み込み(_E)"), sigc::mem_fun( *this, &ImageViewBase::slot_reload_force ) ); action_group()->add( Gtk::Action::create( "AppendFavorite", "AppendFavorite"), sigc::mem_fun( *this, &ImageViewBase::slot_favorite ) ); action_group()->add( Gtk::Action::create( "ZoomFitImage", "ZoomFitImage" ), sigc::mem_fun( *this, &ImageViewBase::slot_fit_win ) ); action_group()->add( Gtk::Action::create( "ZoomInImage", "ZoomInImage" ), sigc::mem_fun( *this, &ImageViewBase::slot_zoom_in ) ); action_group()->add( Gtk::Action::create( "ZoomOutImage", "ZoomOutImage" ), sigc::mem_fun( *this, &ImageViewBase::slot_zoom_out ) ); action_group()->add( Gtk::Action::create( "OrgSizeImage", "OrgSizeImage" ), sigc::bind< int >( sigc::mem_fun( *this, &ImageViewBase::slot_resize_image ), 100 ) ); action_group()->add( Gtk::Action::create( "Size_Menu", "サイズ変更(_R)" ) ); // サイズ unsigned int size[] = SIZE_MENU; for( unsigned int i = 0; i < sizeof( size )/sizeof( unsigned int ) ; ++i ){ int tmp_size = size[ i ]; std::string str_size = MISC::itostr( tmp_size ); //ショートカットは、1から始まる std::string str_shortcut = "(_" + MISC::itostr( i+1 ) + ")"; Glib::RefPtr< Gtk::Action > action = Gtk::Action::create( "Size" + str_size, str_size + "%" + str_shortcut ); action_group()->add( action, sigc::bind< int >( sigc::mem_fun( *this, &ImageViewBase::slot_resize_image ), tmp_size ) ); } action_group()->add( Gtk::Action::create( "Move_Menu", ITEM_NAME_GO "(_M)" ) ); action_group()->add( Gtk::Action::create( "MoveHead", "先頭に移動(_H)" ), sigc::mem_fun( *this, &ImageViewBase::slot_move_head ) ); action_group()->add( Gtk::Action::create( "MoveTail", "最後に移動(_T)" ), sigc::mem_fun( *this, &ImageViewBase::slot_move_tail ) ); action_group()->add( Gtk::Action::create( "Quit", "Quit" ), sigc::mem_fun( *this, &ImageViewBase::close_view ) ); action_group()->add( Gtk::Action::create( "Close_Menu", "複数の画像を閉じる(_L)" ) ); action_group()->add( Gtk::Action::create( "CloseOther", "他の画像(_O)" ), sigc::mem_fun( *this, &ImageViewBase::slot_close_other_views ) ); action_group()->add( Gtk::Action::create( "CloseLeft", "左←の画像(_L)" ), sigc::mem_fun( *this, &ImageViewBase::slot_close_left_views ) ); action_group()->add( Gtk::Action::create( "CloseRight", "右→の画像(_R)" ), sigc::mem_fun( *this, &ImageViewBase::slot_close_right_views ) ); action_group()->add( Gtk::Action::create( "CloseError404", "エラー画像(404,403のみ)(_E)" ), sigc::mem_fun( *this, &ImageViewBase::slot_close_error_views ) ); action_group()->add( Gtk::Action::create( "CloseError503", "エラー画像(timeout,503以外)(_T)" ), sigc::mem_fun( *this, &ImageViewBase::slot_close_notimeout_error_views ) ); action_group()->add( Gtk::Action::create( "CloseErrorAll", "エラー画像(読込み中含め全て)(_W)" ), sigc::mem_fun( *this, &ImageViewBase::slot_close_all_error_views ) ); action_group()->add( Gtk::Action::create( "CloseNoError", "エラー以外の画像(_N)" ), sigc::mem_fun( *this, &ImageViewBase::slot_close_noerror_views ) ); action_group()->add( Gtk::Action::create( "CloseAll", "全ての画像(_A)" ), sigc::mem_fun( *this, &ImageViewBase::slot_close_all_views ) ); action_group()->add( Gtk::ToggleAction::create( "LockTab", "タブをロックする(_K)", std::string(), false ), sigc::mem_fun( *this, &ImageViewBase::slot_lock ) ); action_group()->add( Gtk::Action::create( "OpenBrowser", ITEM_NAME_OPEN_BROWSER "(_W)" ), sigc::mem_fun( *this, &ImageViewBase::slot_open_browser ) ); action_group()->add( Gtk::Action::create( "OpenCacheBrowser", ITEM_NAME_OPEN_CACHE_BROWSER "(_X)" ), sigc::mem_fun( *this, &ImageViewBase::slot_open_cache_browser ) ); action_group()->add( Gtk::Action::create( "OpenRef", "参照元のレスを開く(_O)"), sigc::mem_fun( *this, &ImageViewBase::slot_open_ref ) ); action_group()->add( Gtk::Action::create( "CopyURL", ITEM_NAME_COPY_URL "(_U)" ), sigc::mem_fun( *this, &ImageViewBase::slot_copy_url ) ); action_group()->add( Gtk::Action::create( "Save", "Save"), sigc::mem_fun( *this, &ImageViewBase::slot_save ) ); action_group()->add( Gtk::Action::create( "SaveAll", "全ての画像を保存(_A)..."), sigc::mem_fun( *this, &ImageViewBase::slot_save_all ) ); action_group()->add( Gtk::Action::create( "DeleteMenu", "Delete" ) ); action_group()->add( Gtk::Action::create( "DeleteImage", "削除する(_D)"), sigc::mem_fun( *this, &ImageViewBase::delete_view ) ); action_group()->add( Gtk::ToggleAction::create( "ProtectImage", "キャッシュを保護する(_H)", std::string(), false ), sigc::mem_fun( *this, &ImageViewBase::slot_toggle_protectimage ) ); action_group()->add( Gtk::Action::create( "AboneImage", "画像をあぼ〜んする(_B)"), sigc::mem_fun( *this, &ImageViewBase::slot_abone_img ) ); action_group()->add( Gtk::Action::create( "PreferenceImage", "PreferenceImage"), sigc::mem_fun( *this, &ImageViewBase::show_preference ) ); action_group()->add( Gtk::Action::create( "Preference", "プロパティ(_P)..."), sigc::mem_fun( *this, &ImageViewBase::show_preference ) ); const std::string usrcmd = CORE::get_usrcmd_manager()->create_usrcmd_menu( action_group() ); const int usrcmd_size = CORE::get_usrcmd_manager()->get_size(); for( int i = 0; i < usrcmd_size; ++i ){ Glib::RefPtr< Gtk::Action > act = CORE::get_usrcmd_manager()->get_action( action_group(), i ); if( act ) act->signal_activate().connect( sigc::bind< int >( sigc::mem_fun( *this, &ImageViewBase::slot_usrcmd ), i ) ); } ui_manager() = Gtk::UIManager::create(); ui_manager()->insert_action_group( action_group() ); // 画像ビューのメニュー const std::string menu = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" + usrcmd + std::string( "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ); // アイコンのメニュー const std::string menu_icon = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; // 画像ポップアップのメニュー const std::string menu_popup = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ; ui_manager()->add_ui_from_string( "" + menu + menu_icon + menu_popup + "" ); // ポップアップメニューにキーアクセレータやマウスジェスチャを表示 Gtk::Menu* popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu" ) ); CONTROL::set_menu_motion( popupmenu ); popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_icon" ) ); CONTROL::set_menu_motion( popupmenu ); popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_popup" ) ); CONTROL::set_menu_motion( popupmenu ); } // // ImageAreaBaseのセット // void ImageViewBase::set_imagearea( ImageAreaBase* imagearea ) { assert( imagearea ); m_imagearea.clear(); m_imagearea = imagearea; set_width_client( imagearea->get_width() ); set_height_client( imagearea->get_height() ); m_event.add( *m_imagearea ); } // // ImageAreaBaseのクリア // void ImageViewBase::remove_imagearea() { if( m_imagearea ){ m_event.remove(); m_imagearea.clear(); } } // // コマンド // const bool ImageViewBase::set_command( const std::string& command, const std::string& arg1, const std::string& arg2 ) { if( command == "switch_icon" ) switch_icon(); else if( command == "update_status" ) update_status(); return true; } // // 再読込 // void ImageViewBase::reload() { #ifdef _DEBUG std::cout << "ImageViewBase::reload url = " << get_url() << std::endl; #endif std::string refurl = m_img->get_refurl(); const bool mosaic = m_img->get_mosaic(); m_img->download_img( refurl, mosaic, 0 ); if( m_img->is_loading() ){ CORE::core_set_command( "redraw", get_url() ); CORE::core_set_command( "redraw_article" ); } } // // ロード停止 // void ImageViewBase::stop() { #ifdef _DEBUG std::cout << "ImageViewBase::stop url = " << get_url() << std::endl; #endif m_img->stop_load(); } // // 再描画 // void ImageViewBase::redraw_view() { #ifdef _DEBUG std::cout << "ImageViewBase::redraw_view url = " << get_url() << std::endl; #endif show_view(); } // // 先頭に移動 // void ImageViewBase::slot_move_head() { IMAGE::get_admin()->set_command( "tab_head", "" ); } // // 最後に移動 // void ImageViewBase::slot_move_tail() { IMAGE::get_admin()->set_command( "tab_tail", "" ); } // // 閉じる // void ImageViewBase::close_view() { IMAGE::get_admin()->set_command( "close_view", get_url() ); } // // 他の画像を閉じる // void ImageViewBase::slot_close_other_views() { IMAGE::get_admin()->set_command( "close_other_views", get_url() ); } // // 左の画像を閉じる // void ImageViewBase::slot_close_left_views() { IMAGE::get_admin()->set_command( "close_left_views", get_url() ); } // // 右の画像を閉じる // void ImageViewBase::slot_close_right_views() { IMAGE::get_admin()->set_command( "close_right_views", get_url() ); } // // エラーの画像を閉じる( HTTP404 のみ ) // void ImageViewBase::slot_close_error_views() { IMAGE::get_admin()->set_command( "close_error_views", "", "" ); } // // エラーの画像を閉じる( timeout, 503 以外 ) // void ImageViewBase::slot_close_notimeout_error_views() { IMAGE::get_admin()->set_command( "close_error_views", "", "notimeout" ); } // // エラーの画像を閉じる( 全て ) // void ImageViewBase::slot_close_all_error_views() { IMAGE::get_admin()->set_command( "close_error_views", "", "all" ); } // // エラー以外の画像を閉じる // void ImageViewBase::slot_close_noerror_views() { IMAGE::get_admin()->set_command( "close_noerror_views" ); } // // 全ての画像を閉じる // void ImageViewBase::slot_close_all_views() { IMAGE::get_admin()->set_command( "close_all_views" ); } // // プロパティ // void ImageViewBase::show_preference() { CORE::core_set_command( "hide_popup" ); SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_IMAGE, get_url() ); IMAGE::get_admin()->set_command_immediately( "disable_fold_win" ); // run 直前に呼ぶこと pref->run(); IMAGE::get_admin()->set_command_immediately( "enable_fold_win" ); // run 直後に呼ぶこと delete pref; } // // 削除 // void ImageViewBase::delete_view() { delete_view_impl( false ); } void ImageViewBase::delete_view_impl( const bool show_diag ) { CORE::core_set_command( "hide_popup" ); if( show_diag ){ if( m_img->is_protected() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "キャッシュ保護されています" ); mdiag.run(); return; } else if( CONFIG::get_show_delimgdiag() ){ SKELETON::MsgCheckDiag mdiag( get_parent_win(), "画像を削除しますか?", "今後表示しない(常に削除) (_D)", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, Gtk::RESPONSE_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; if( mdiag.get_chkbutton().get_active() ) CONFIG::set_show_delimgdiag( false ); } } CORE::core_set_command( "delete_image", get_url() ); } // // クリックした時の処理 // void ImageViewBase::clicked() { IMAGE::get_admin()->set_command( "switch_image", get_url() ); IMAGE::get_admin()->set_command( "switch_admin" ); } // // viewの操作 // const bool ImageViewBase::operate_view( const int control ) { if( CONTROL::operate_common( control, get_url(), IMAGE::get_admin() ) ) return true; #ifdef _DEBUG std::cout << "ImageViewBase::operate_view control = " << control << std::endl; #endif switch( control ){ case CONTROL::CancelMosaic: case CONTROL::CancelMosaicButton: slot_cancel_mosaic(); break; case CONTROL::ZoomInImage: slot_zoom_in(); break; case CONTROL::ZoomOutImage: slot_zoom_out(); break; case CONTROL::ZoomFitImage: slot_fit_win(); break; case CONTROL::OrgSizeImage: slot_resize_image( 100 ); break; case CONTROL::ReloadTabButton: case CONTROL::Reload: reload(); break; case CONTROL::StopLoading: stop(); break; case CONTROL::CloseImageButton: case CONTROL::CloseImageTabButton: case CONTROL::Quit: close_view(); break; // スクロール case CONTROL::ScrollUpImage: IMAGE::get_admin()->set_command( "scroll_up" ); break; case CONTROL::ScrollDownImage: IMAGE::get_admin()->set_command( "scroll_down" ); break; case CONTROL::ScrollLeftImage: IMAGE::get_admin()->set_command( "scroll_left" ); break; case CONTROL::ScrollRightImage: IMAGE::get_admin()->set_command( "scroll_right" ); break; // article に切り替え case CONTROL::Left: CORE::core_set_command( "switch_leftview" ); break; case CONTROL::ToggleArticle: CORE::core_set_command( "toggle_article" ); break; case CONTROL::Save: case CONTROL::SaveImageButton: slot_save(); break; case CONTROL::Delete: delete_view_impl( true ); break; // お気に入りに追加 case CONTROL::AppendFavorite: slot_favorite(); break; // 画像のプロパティ case CONTROL::PreferenceView: show_preference(); break; default: return false; } return true; } // // キープレスイベント // const bool ImageViewBase::slot_key_press( GdkEventKey* event ) { #ifdef _DEBUG std::cout << "ImageViewBase::slot_key_press url = " << get_url() << std::endl; #endif return operate_view( get_control().key_press( event ) ); } // // ボタンクリック // bool ImageViewBase::slot_button_press( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "ImageViewBase::slot_button_press url = " << get_url() << std::endl; #endif // マウスジェスチャ get_control().MG_start( event ); // ホイールマウスジェスチャ get_control().MG_wheel_start( event ); // ダブルクリック // button_release_eventでは event->type に必ず GDK_BUTTON_RELEASE が入る m_dblclick = false; if( event->type == GDK_2BUTTON_PRESS ) m_dblclick = true; // クリック // 反応を良くするため slot_button_release() ではなくてボタンを押した時点で処理する if( get_control().button_alloted( event, CONTROL::ClickButton ) ) clicked(); return true; } // // マウスボタンのリリースイベント // bool ImageViewBase::slot_button_release( GdkEventButton* event ) { /// マウスジェスチャ int mg = get_control().MG_end( event ); // ホイールマウスジェスチャ // 実行された場合は何もしない if( get_control().MG_wheel_end( event ) ) return true; if( mg != CONTROL::None && enable_mg() ){ operate_view( mg ); return true; } // ダブルクリックの処理のため一時的にtypeを切替える GdkEventType type_copy = event->type; if( m_dblclick ) event->type = GDK_2BUTTON_PRESS; // ポップアップメニュー if( get_control().button_alloted( event, CONTROL::PopupmenuButton ) ){ show_popupmenu( "", false ); } else if( is_under_mouse() ) operate_view( get_control().button_press( event ) ); event->type = type_copy; return true; } // // マウスモーション // bool ImageViewBase::slot_motion_notify( GdkEventMotion* event ) { /// マウスジェスチャ get_control().MG_motion( event ); return true; } // // マウスホイールイベント // bool ImageViewBase::slot_scroll_event( GdkEventScroll* event ) { // ホイールマウスジェスチャ int control = get_control().MG_wheel_scroll( event ); if( enable_mg() && control != CONTROL::None ){ operate_view( control ); return true; } return false; } // // マウスが入った // bool ImageViewBase::slot_enter_notify_event( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "ImageViewBase::slot_enter_notify_event\n"; #endif m_under_mouse = true; return true; } // // マウスが出た // bool ImageViewBase::slot_leave_notify_event( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "ImageViewBase::slot_leave_notify_event\n"; #endif m_under_mouse = false; return true; } // // 強制再読み込み // void ImageViewBase::slot_reload_force() { if( ! m_enable_menuslot ) return; if( ! SESSION::is_online() ){ CORE::core_set_command( "hide_popup" ); SKELETON::MsgDiag mdiag( get_parent_win(), "オフラインです" ); mdiag.run(); return; } // コードをリセットしてから再読み込みをかける m_img->reset(); m_img->set_code( HTTP_INIT ); m_img->set_type( DBIMG::T_UNKNOWN ); reload(); } // // モザイク解除 // void ImageViewBase::slot_cancel_mosaic() { if( ! m_enable_menuslot ) return; if( ! m_img->is_cached() ) return; if( ! m_img->get_mosaic() ) return; if( m_img->is_fake() ){ CORE::core_set_command( "hide_popup" ); std::string type = "本当の画像タイプは"; switch( DBIMG::get_type_real( get_url() ) ){ case DBIMG::T_JPG: type += "JPEG"; break; case DBIMG::T_PNG: type += "PNG"; break; case DBIMG::T_GIF: type += "GIF"; break; case DBIMG::T_BMP: type += "BMP"; break; } type += "です。"; SKELETON::MsgDiag mdiag( get_parent_win(), "拡張子が偽装されています。" + type + "\n\nモザイクを解除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); mdiag.set_default_response( Gtk::RESPONSE_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; } m_img->set_mosaic( false ); CORE::core_set_command( "redraw", get_url() ); } // // 大きい画像を表示 // void ImageViewBase::slot_show_large_img() { m_img->show_large_img(); } // // ウィンドウにサイズを合わせる // void ImageViewBase::slot_fit_win() { if( m_img->is_zoom_to_fit() ) SESSION::toggle_img_fit_mode(); m_img->set_zoom_to_fit( true ); CORE::core_set_command( "redraw", get_url() ); } // // ズームイン // void ImageViewBase::slot_zoom_in() { zoom_in_out( true ); } // // ズームアウト // void ImageViewBase::slot_zoom_out() { zoom_in_out( false ); } // // ズームイン、アウトの実行部 void ImageViewBase::zoom_in_out( bool zoomin ) { unsigned int size[] = SIZE_MENU; unsigned int size_current = m_img->get_size(); int size_zoomin = 0, size_zoomout = 0; // 現在のサイズから次のサイズを決定 if( size_current ){ size_zoomin = size_current + 100; size_zoomout = size_current - 100; unsigned int maxsize = sizeof( size )/sizeof( unsigned int ); for( unsigned int i = 1; i < maxsize ; ++i ){ if( zoomin && size[ i ] > size_current + 5 ){ size_zoomin = size[ i ]; break; } if( !zoomin && size[ i ] > size_current -5 ){ size_zoomout = size[ i -1 ]; break; } } } #ifdef _DEBUG std::cout << "ImageViewBase::zoom_in_out\n" << "size_current = " << size_current << std::endl << "zoomin = " << size_zoomin << std::endl << "zoomout = " << size_zoomout << std::endl; #endif if( zoomin ) slot_resize_image( size_zoomin ); else slot_resize_image( size_zoomout ); } // // 画像サイズ // void ImageViewBase::slot_resize_image( int size ) { unsigned int sizemenu[] = SIZE_MENU; int maxsize = sizemenu[ sizeof( sizemenu )/sizeof( unsigned int ) -1 ]; if( size <= 0 ) return; if( size > maxsize ) return; if( !m_img->is_zoom_to_fit() && m_img->get_size() == size ) return; m_img->set_zoom_to_fit( false ); m_img->set_size( size ); CORE::core_set_command( "redraw", get_url() ); } // // ロックする // void ImageViewBase::slot_lock() { if( ! m_enable_menuslot ) return; if( is_locked() ) unlock(); else lock(); } // // ブラウザで開く // void ImageViewBase::slot_open_browser() { if( ! m_enable_menuslot ) return; CORE::core_set_command( "open_url_browser", get_url() ); } // // キャッシュをブラウザで開く // void ImageViewBase::slot_open_cache_browser() { if( ! m_enable_menuslot ) return; if( ! m_img->is_cached() ) return; const std::string url = "file://" + m_img->get_cache_path(); CORE::core_set_command( "open_url_browser", url ); } // // 参照元を開く // void ImageViewBase::slot_open_ref() { if( ! m_enable_menuslot ) return; const std::string refurl = m_img->get_refurl(); int center, from, to; std::string num_str; const std::string url = DBTREE::url_dat( refurl, center, to, num_str ); if( url.empty() ) return; const int range = 10; from = MAX( 0, center - range ); to = center + range; std::stringstream ss; ss << from << "-" << to; CORE::core_set_command( "open_article_res" ,url, ss.str(), MISC::itostr( center ) ); } // // URLをクリップボードにコピー // void ImageViewBase::slot_copy_url() { if( ! m_enable_menuslot ) return; MISC::CopyClipboard( get_url() ); } // // 保存 // void ImageViewBase::slot_save() { if( ! m_enable_menuslot ) return; CORE::core_set_command( "hide_popup" ); m_img->save( IMAGE::get_admin()->get_win(), std::string() ); } // // すべて保存 // void ImageViewBase::slot_save_all() { if( ! m_enable_menuslot ) return; IMAGE::get_admin()->set_command( "save_all" ); } // // お気に入り // void ImageViewBase::slot_favorite() { if( ! m_enable_menuslot ) return; set_image_to_buffer(); CORE::core_set_command( "append_favorite", URL_FAVORITEVIEW ); } // // 画像キャッシュ保護 // void ImageViewBase::slot_toggle_protectimage() { if( ! m_enable_menuslot ) return; m_img->set_protect( ! m_img->is_protected( ) ); CORE::core_set_command( "redraw", get_url() ); // ステータス再描画 } // // 画像あぼーん // void ImageViewBase::slot_abone_img() { m_img->set_abone( true ); delete_view(); } // // 共有バッファセット // void ImageViewBase::set_image_to_buffer() { CORE::DATA_INFO info; info.type = TYPE_IMAGE; info.parent = IMAGE::get_admin()->get_win(); info.url = get_url(); info.name = get_url(); info.path = Gtk::TreePath( "0" ).to_string(); CORE::DATA_INFO_LIST list_info; list_info.push_back( info ); CORE::SBUF_set_list( list_info ); } // // ポップアップメニューを表示する前にメニューのアクティブ状態を切り替える // // SKELETON::View::show_popupmenu() を参照すること // void ImageViewBase::activate_act_before_popupmenu( const std::string& url ) { if( !m_img ) return; // toggle アクションを activeにするとスロット関数が呼ばれるので処理しないようにする m_enable_menuslot = false; Glib::RefPtr< Gtk::Action > act; Glib::RefPtr< Gtk::ToggleAction > tact; bool current_protect = m_img->is_protected(); // ロック act = action_group()->get_action( "LockTab" ); if( act ){ Glib::RefPtr< Gtk::ToggleAction > tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( is_locked() ) tact->set_active( true ); else tact->set_active( false ); } // 閉じる act = action_group()->get_action( "Quit" ); if( act ){ if( is_locked() ) act->set_sensitive( false ); else act->set_sensitive( true ); } // モザイク act = action_group()->get_action( "CancelMosaic" ); if( act ){ if( m_img->is_cached() && m_img->get_mosaic() ) act->set_sensitive( true ); else act->set_sensitive( false ); } // サイズの大きい画像を表示 act = action_group()->get_action( "ShowLargeImg" ); if( act ){ if( m_img->get_type() == DBIMG::T_LARGE ) act->set_sensitive( true ); else act->set_sensitive( false ); } // サイズ系メニュー、お気に入り、保存 std::string sizemenus[] = { "Size_Menu", "OrgSizeImage", "ZoomFitImage", "ZoomInImage", "ZoomOutImage", "AppendFavorite", "Save" }; for( int i = 0; i < 7; ++i ){ act = action_group()->get_action( sizemenus[ i ] ); if( act ){ if( m_img->is_cached() ) act->set_sensitive( true ); else act->set_sensitive( false ); } } // キャッシュをブラウザで開く act = action_group()->get_action( "OpenCacheBrowser" ); if( act ){ if( m_img->is_cached() ) act->set_sensitive( true ); else act->set_sensitive( false ); } // 参照元スレ act = action_group()->get_action( "OpenRef" ); if( act ){ if( ! m_img->get_refurl().empty() ) act->set_sensitive( true ); else act->set_sensitive( false ); } // 保護 act = action_group()->get_action( "ProtectImage" ); if( act ){ if( m_img->is_cached() ){ act->set_sensitive( true ); tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( tact ){ if( current_protect ) tact->set_active( true ); else tact->set_active( false ); } } else act->set_sensitive( false ); } // 削除 act = action_group()->get_action( "DeleteMenu" ); if( act ){ if( m_img->get_code() != HTTP_INIT && ! m_img->is_protected() ) act->set_sensitive( true ); else act->set_sensitive( false ); } // ロード停止 act = action_group()->get_action( "LoadStop" ); if( act ){ if( m_img->is_loading() ) act->set_sensitive( true ); else act->set_sensitive( false ); } // あぼーん act = action_group()->get_action( "AboneImage" ); if( act ){ if( ! m_img->is_protected() ) act->set_sensitive( true ); else act->set_sensitive( false ); } // ユーザコマンド // 選択不可かどうか判断して visible か sensitive にする const std::string url_article = DBTREE::url_dat( m_img->get_refurl() ); CORE::get_usrcmd_manager()->toggle_sensitive( action_group(), url_article, get_url(), "" ); m_enable_menuslot = true; } // // ユーザコマンド実行 // void ImageViewBase::slot_usrcmd( int num ) { int from, to; std::string num_str; const std::string url_article = DBTREE::url_dat( m_img->get_refurl(), from, to, num_str ); CORE::core_set_command( "exec_usr_cmd" , url_article, MISC::itostr( num ), get_url(), "", MISC::itostr( from ) ); } jd-2.8.7-140104/src/image/imageviewbase.h0000644000076400010400000001052711546077763014447 0ustar // ライセンス: GPL2 // // 画像ビューのベースクラス // #ifndef _IMAGEVIEWBASE_H #define _IMAGEVIEWBASE_H #include "skeleton/view.h" #include "skeleton/admin.h" #include "jdlib/constptr.h" #include #include namespace SKELETON { class Admin; } namespace DBIMG { class Img; } namespace IMAGE { class ImageAreaBase; // // ビューのベースクラス // class ImageViewBase : public SKELETON::View { JDLIB::ConstPtr< DBIMG::Img > m_img; // Gtk::manage で作っているのでdeleteしなくても良い JDLIB::ConstPtr< ImageAreaBase > m_imagearea; bool m_wait; bool m_loading; Gtk::EventBox m_event; bool m_dblclick; bool m_under_mouse; bool m_enable_menuslot; protected: // Viewが所属するAdminクラス virtual SKELETON::Admin* get_admin(); JDLIB::ConstPtr< DBIMG::Img >& get_img(){ return m_img;} JDLIB::ConstPtr< ImageAreaBase >& get_imagearea(){ return m_imagearea; } void set_imagearea( ImageAreaBase* imagearea ); void remove_imagearea(); const bool is_wait() const{ return m_wait; } void set_wait( const bool wait ){ m_wait = wait; } const bool is_loading() const{ return m_loading; } void set_loading( const bool loading ){ m_loading = loading; } Gtk::EventBox& get_event(){ return m_event; } public: ImageViewBase( const std::string& url, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() ); virtual ~ImageViewBase(); const bool is_under_mouse() const { return m_under_mouse; } // // SKELETON::View の関数のオーバロード // virtual void save_session(){} // 親ウィンドウを取得 virtual Gtk::Window* get_parent_win(); // キーを押した virtual const bool slot_key_press( GdkEventKey* event ); // コマンド virtual const bool set_command( const std::string& command, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() ); virtual void reload(); virtual void stop(); virtual void redraw_view(); virtual void close_view(); virtual void delete_view(); virtual const bool operate_view( const int control ); virtual void show_preference(); protected: void setup_common(); void set_image_to_buffer(); virtual void activate_act_before_popupmenu( const std::string& url ); void delete_view_impl( const bool show_diag ); void slot_cancel_mosaic(); void slot_save(); virtual bool slot_button_press( GdkEventButton* event ); bool slot_button_release( GdkEventButton* event ); virtual bool slot_motion_notify( GdkEventMotion* event ); virtual bool slot_scroll_event( GdkEventScroll* event ); bool slot_enter_notify_event( GdkEventCrossing* event ); bool slot_leave_notify_event( GdkEventCrossing* event ); private: virtual void show_status(){} virtual void update_status(){} virtual void add_image(){} virtual void switch_icon(){} // クリックした時の処理 virtual void clicked(); void zoom_in_out( bool zoomin ); void slot_move_head(); void slot_move_tail(); void slot_reload_force(); void slot_show_large_img(); void slot_fit_win(); void slot_zoom_in(); void slot_zoom_out(); void slot_resize_image( int size ); void slot_lock(); void slot_open_browser(); void slot_open_cache_browser(); void slot_open_ref(); void slot_copy_url(); void slot_save_all(); void slot_favorite(); void slot_toggle_protectimage(); void slot_abone_img(); void slot_close_other_views(); void slot_close_left_views(); void slot_close_right_views(); void slot_close_error_views(); void slot_close_notimeout_error_views(); void slot_close_all_error_views(); void slot_close_noerror_views(); void slot_close_all_views(); void slot_usrcmd( int num ); }; } #endif jd-2.8.7-140104/src/image/imageviewicon.cpp0000644000076400010400000001477011334022056015000 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imageadmin.h" #include "imageviewicon.h" #include "imageareaicon.h" #include "dbimg/img.h" #include "jdlib/miscutil.h" #include "control/controlid.h" #include "type.h" #include "dndmanager.h" #include "sharedbuffer.h" #include "cache.h" #include "command.h" #include "global.h" // 枠を描く #define DRAW_FRAME( color ) m_event_frame->modify_bg( Gtk::STATE_NORMAL, color ); using namespace IMAGE; ImageViewIcon::ImageViewIcon( const std::string& url ) : ImageViewBase( url ) { #ifdef _DEBUG std::cout << "ImageViewIcon::ImageViewIcon : " << get_url() << std::endl; #endif // コントロールモード設定 get_control().add_mode( CONTROL::MODE_IMAGEICON ); //枠を描くためにm_eventの外にもう一つEventBoxを作る ( Gtk::HBox は modify_fg() 無効なので ) m_event_frame = Gtk::manage( new Gtk::EventBox() ); pack_start( *m_event_frame ); m_event_frame->add( get_event() ); get_event().set_border_width( 1 ); DRAW_FRAME( Gdk::Color( "white" ) ); setup_common(); // D&D可能にする std::list< Gtk::TargetEntry > targets; targets.push_back( Gtk::TargetEntry( DNDTARGET_IMAGETAB, Gtk::TARGET_SAME_APP, 0 ) ); get_event().drag_dest_set( targets ); targets.push_back( Gtk::TargetEntry( DNDTARGET_FAVORITE, Gtk::TARGET_SAME_APP, 0 ) ); get_event().drag_source_set( targets, Gdk::BUTTON1_MASK ); get_event().signal_drag_begin().connect( sigc::mem_fun( *this, &ImageViewIcon::slot_drag_begin ) ); get_event().signal_drag_data_get().connect( sigc::mem_fun( *this, &ImageViewIcon::slot_drag_data_get ) ); get_event().signal_drag_data_received().connect( sigc::mem_fun( *this, &ImageViewIcon::slot_drag_data_received ) ); get_event().signal_drag_end().connect( sigc::mem_fun( *this, &ImageViewIcon::slot_drag_end ) ); } ImageViewIcon::~ImageViewIcon() { #ifdef _DEBUG std::cout << "ImageViewIcon::~ImageViewIcon : " << get_url() << std::endl; #endif // スレッドを止めるために明示的にクリアする get_imagearea().clear(); } // // クロック入力 // void ImageViewIcon::clock_in() { View::clock_in(); // 待ち状態 if( is_wait() && ! get_img()->is_wait() ){ set_wait( false ); set_loading( get_img()->is_loading() ); show_view(); } // ロード終了 else if( get_imagearea() && is_loading() && ! get_img()->is_loading() ){ set_loading( false ); show_view(); } } // // フォーカスイン // void ImageViewIcon::focus_view() { DRAW_FRAME( Gdk::Color( "red" ) ); get_event().grab_focus(); } // // フォーカスアウト // void ImageViewIcon::focus_out() { SKELETON::View::focus_out(); DRAW_FRAME( Gdk::Color( "white" ) ); } // // 表示 // void ImageViewIcon::show_view() { if( is_loading() ) return; if( is_wait() ) return; #ifdef _DEBUG std::cout << "ImageViewIcon::show_view url = " << get_url() << std::endl; #endif // 待ち状態 if( get_img()->is_wait() ) set_wait( true ); // 読み込み中 else if( get_img()->is_loading() ) set_loading( true ); // 画像が既に表示しているなら再描画 if( get_imagearea() ) get_imagearea()->show_image(); // 画像貼り付け // ロード中の時はclock_in()経由でもう一度 show_view()が呼び出される else{ set_imagearea( Gtk::manage( new ImageAreaIcon( get_url() ) ) ); get_imagearea()->show_image(); show_all_children(); } } // // アイコンが切り替わった // void ImageViewIcon::switch_icon() { DRAW_FRAME( Gdk::Color( "red" ) ); } // // ポップアップメニュー取得 // // SKELETON::View::show_popupmenu() を参照すること // Gtk::Menu* ImageViewIcon::get_popupmenu( const std::string& url ) { Gtk::Menu* menu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_icon" ) ); // タブ情報セット if( menu ){ // 一番上のitemのラベルを書き換える Gtk::Menu_Helpers::MenuList::iterator it_item = menu->items().begin(); Gtk::Label* label = dynamic_cast< Gtk::Label* >( (*it_item).get_child() ); if( label ) label->set_text_with_mnemonic( ITEM_NAME_GO + std::string( " [ タブ数 " ) + MISC::itostr( IMAGE::get_admin()->get_tab_nums() ) + " ](_M)" ); } return menu; } // // マウスホイールイベント // bool ImageViewIcon::slot_scroll_event( GdkEventScroll* event ) { // 回転したらタブ切り替え int control = CONTROL::None; if( event->direction == GDK_SCROLL_UP ) control = CONTROL::TabLeft; if( event->direction == GDK_SCROLL_DOWN ) control = CONTROL::TabRight; ImageViewBase::operate_view( control ); IMAGE::get_admin()->set_command( "switch_admin" ); return true; } // // D&D開始 // void ImageViewIcon::slot_drag_begin( const Glib::RefPtr& context ) { #ifdef _DEBUG std::cout << "ImageViewIcon::slot_drag_begin url = " << get_url() << std::endl; #endif CORE::DND_Begin(); } // // D&Dで受信側がデータ送信を要求してきた // void ImageViewIcon::slot_drag_data_get( const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time ) { #ifdef _DEBUG std::cout << "ImageViewIcon::on_drag_data_get target = " << selection_data.get_target() << " url = " << get_url() << std::endl;; #endif set_image_to_buffer(); selection_data.set( selection_data.get_target(), get_url() ); } // // 他の画像アイコンからドロップされた // void ImageViewIcon::slot_drag_data_received( const Glib::RefPtr& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time ) { const std::string url_from = selection_data.get_data_as_string(); #ifdef _DEBUG std::cout << "ImageViewIcon::slot_drag_data_received target = " << selection_data.get_target() << " url = " << get_url() << " url_from = " << url_from << std::endl; #endif IMAGE::get_admin()->set_command( "reorder", get_url(), url_from, get_url() ); } // // D&D終了 // void ImageViewIcon::slot_drag_end( const Glib::RefPtr< Gdk::DragContext >& context ) { #ifdef _DEBUG std::cout << "ImageViewIcon::slot_drag_end url = " << get_url() << std::endl; #endif CORE::DND_End(); } jd-2.8.7-140104/src/image/imageviewicon.h0000644000076400010400000000234111116750152014437 0ustar // ライセンス: GPL2 // // 画像アイコンクラス // #ifndef _IMAGEVIEWICON_H #define _IMAGEVIEWICON_H #include "imageviewbase.h" namespace IMAGE { class ImageViewIcon : public ImageViewBase { Gtk::EventBox* m_event_frame; public: ImageViewIcon( const std::string& url ); virtual ~ImageViewIcon(); virtual void clock_in(); virtual void focus_view(); virtual void focus_out(); virtual void show_view(); protected: virtual Gtk::Menu* get_popupmenu( const std::string& url ); virtual bool slot_scroll_event( GdkEventScroll* event ); private: virtual void switch_icon(); void slot_drag_begin( const Glib::RefPtr& context ); void slot_drag_data_get( const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time ); void slot_drag_data_received( const Glib::RefPtr& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time ); void slot_drag_end( const Glib::RefPtr< Gdk::DragContext >& context ); }; } #endif jd-2.8.7-140104/src/image/imageviewpopup.cpp0000644000076400010400000002160611334022056015207 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imageviewpopup.h" #include "imageareapopup.h" #include "dbimg/img.h" #include "config/globalconf.h" #include "control/controlid.h" #include "colorid.h" #include "cssmanager.h" using namespace IMAGE; ImageViewPopup::ImageViewPopup( const std::string& url ) : ImageViewBase( url ) , m_label( NULL ) , m_length_prev( 0 ) , m_clicked( false ) { #ifdef _DEBUG std::cout << "ImageViewPopup::ImageViewPopup url = " << get_url() << std::endl; #endif // コントロールモード設定 get_control().add_mode( CONTROL::MODE_IMAGEVIEW ); get_control().add_mode( CONTROL::MODE_IMAGEICON ); int border_width = 1; int margin = 0; std::string border_color = "black"; std::string bg_color = CONFIG::get_color( COLOR_BACK ); const int classid = CORE::get_css_manager()->get_classid( "imgpopup" ); if( classid >= 0 ){ CORE::CSS_PROPERTY css = CORE::get_css_manager()->get_property( classid ); border_width = css.border_left_width_px; margin = css.mrg_left_px; if( css.border_left_color >= 0 ) border_color = CORE::get_css_manager()->get_color( css.border_left_color ); if( css.bg_color > 0 ) bg_color = CORE::get_css_manager()->get_color( css.bg_color ); } //枠を描くためにm_eventの外にもう一つEventBoxを作る ( Gtk::HBox は modify_fg() 無効なので ) pack_start( m_event_frame ); m_event_frame.add( m_event_margin ); m_event_margin.add( get_event() ); // 枠の幅 m_event_margin.set_border_width( border_width ); // マージン get_event().set_border_width( margin ); // 枠色 m_event_frame.modify_bg( Gtk::STATE_NORMAL, Gdk::Color( border_color ) ); // 背景色 const Gdk::Color color_bg( bg_color ); m_event_margin.modify_bg( Gtk::STATE_NORMAL, color_bg ); get_event().modify_bg( Gtk::STATE_NORMAL, color_bg ); // 全ての領域を表示できないならカーソルの上に表示 set_popup_upside( true ); setup_common(); } ImageViewPopup::~ImageViewPopup() { #ifdef _DEBUG std::cout << "ImageViewPopup::~ImageViewPopup url = " << get_url() << std::endl; #endif } // // クロック入力 // void ImageViewPopup::clock_in() { View::clock_in(); // ロード中 if( is_loading() ){ // 読み込みサイズの表示更新 if( get_img()->is_loading() ) update_label(); } } // // 画像表示停止 // void ImageViewPopup::stop() { #ifdef _DEBUG std::cout << "ImageViewPopup::stop url = " << get_url() << std::endl; #endif if( get_imagearea() ){ get_imagearea()->stop(); get_imagearea()->wait(); } } // // ラベルを貼る // void ImageViewPopup::set_label( const std::string& status ) { if( !m_label ){ m_label = Gtk::manage( new Gtk::Label() ); assert( m_label ); get_event().add( *m_label ); m_label->set_text( status ); std::string text_color = CONFIG::get_color( COLOR_CHAR ); const int classid = CORE::get_css_manager()->get_classid( "imgpopup" ); if( classid >= 0 ){ CORE::CSS_PROPERTY css = CORE::get_css_manager()->get_property( classid ); if( css.color >= 0 ) text_color = CORE::get_css_manager()->get_color( css.color ); } const Gdk::Color color_text( text_color ); m_label->modify_fg( Gtk::STATE_NORMAL, color_text ); m_label->show(); } } // // ラベル削除 // void ImageViewPopup::remove_label() { if( m_label ){ get_event().remove(); delete m_label; m_label = NULL; } } // // 表示 // void ImageViewPopup::show_view() { #ifdef _DEBUG std::cout << "ImageViewPopup::show_view url = " << get_url() << std::endl; #endif // 待ち状態 if( is_wait() && ! get_img()->is_wait() ){ set_wait( false ); if( get_img()->is_loading() ){ set_loading( true ); set_label( "読み込み中" ); } else{ set_loading( false ); show_view_impl(); } } // ロード完了 else if( is_loading() && ! get_img()->is_loading() ){ set_loading( false ); // 画像表示 if( CONFIG::get_use_image_popup() ){ show_view_impl(); // リサイズ依頼 sig_resize_popup().emit(); } // ポップアップを閉じる else sig_hide_popup().emit(); } else show_view_impl(); } void ImageViewPopup::show_view_impl() { if( is_loading() ) return; if( is_wait() ) return; #ifdef _DEBUG std::cout << "ImageViewPopup::show_view_impl url = " << get_url() << std::endl; #endif // 画像を既に表示している if( get_imagearea() ){ // キャッシュされてるなら再描画 if( get_img()->is_cached() ){ #ifdef _DEBUG std::cout << "redraw\n"; #endif get_imagearea()->show_image(); } return; } // サーバから読み込み中 // 読み込みが終わったら show_view() が呼び出されて画像が表示される if( get_img()->is_loading() || get_img()->is_wait() ){ if( get_img()->is_wait() ){ #ifdef _DEBUG std::cout << "wait\n"; #endif set_wait( true ); set_loading( false ); set_label( "待機中" ); } else{ #ifdef _DEBUG std::cout << "loading\n"; #endif set_wait( false ); set_loading( true ); set_label( "読み込み中" ); } m_length_prev = 0; } // 画像張り付け else{ #ifdef _DEBUG std::cout << "not loading\n"; #endif // キャッシュがあったら画像貼り付け if( get_img()->is_cached() ){ ImageAreaBase* imagearea = Gtk::manage( new ImageAreaPopup( get_url() ) ); imagearea->show_image(); if( imagearea->get_errmsg().empty() ){ remove_label(); set_imagearea( imagearea ); } // エラー表示 else{ set_label( "" ); m_label->set_text( imagearea->get_errmsg() ); } } // キャッシュが無い else{ set_label( "" ); if( get_img()->get_str_code( ).empty() ) m_label->set_text( "キャッシュが存在しません" ); else m_label->set_text( get_img()->get_str_code( ) ); } } // マージンやボーダーの分を幅と高さに加える const int classid = CORE::get_css_manager()->get_classid( "imgpopup" ); if( classid >= 0 ){ CORE::CSS_PROPERTY css = CORE::get_css_manager()->get_property( classid ); const int border_width = css.border_left_width_px; const int margin = css.mrg_left_px; set_width_client( width_client() + margin*2 + border_width*2 ); set_height_client( height_client() + margin*2 + border_width*2 ); } show_all_children(); } // // ラベル表示更新 // void ImageViewPopup::update_label() { if( ! m_label ) return; if( m_length_prev != get_img()->current_length() ){ m_length_prev = get_img()->current_length(); char tmpstr[ 256 ]; snprintf( tmpstr, 256, "%zd k / %zd k", m_length_prev/1024, get_img()->total_length()/1024 ); m_label->set_text( tmpstr ); } } // クリックした時の処理 void ImageViewPopup::clicked() { #ifdef _DEBUG std::cout << "ImageViewPopup::clicked\n"; #endif // クリックしたらマウスボタンのリリース時に閉じる m_clicked = true; } // // ポップアップメニュー取得 // // SKELETON::View::show_popupmenu() を参照すること // Gtk::Menu* ImageViewPopup::get_popupmenu( const std::string& url ) { Gtk::Menu* popupmenu = dynamic_cast< Gtk::Menu* >( ui_manager()->get_widget( "/popup_menu_popup" ) ); return popupmenu; } // // 閉じる // void ImageViewPopup::close_view() { #ifdef _DEBUG std::cout << "ImageViewPopup::close_view\n"; #endif sig_hide_popup().emit(); } // // viewの操作 // const bool ImageViewPopup::operate_view( const int control ) { #ifdef _DEBUG std::cout << "ImageViewPopup::operate_view control = " << control << std::endl; #endif switch( control ){ case CONTROL::CancelMosaic: case CONTROL::CancelMosaicButton: slot_cancel_mosaic(); break; case CONTROL::Cancel: case CONTROL::CloseImageButton: case CONTROL::CloseImageTabButton: case CONTROL::Quit: close_view(); break; case CONTROL::Save: slot_save(); break; case CONTROL::Delete: delete_view_impl( true ); break; default: if( m_clicked ) close_view(); break; } m_clicked = false; return true; } jd-2.8.7-140104/src/image/imageviewpopup.h0000644000076400010400000000214111542415626014657 0ustar // ライセンス: GPL2 // // 画像ポップアップクラス // #ifndef _IMAGEVIEWPOPUP_H #define _IMAGEVIEWPOPUP_H #include "imageviewbase.h" namespace IMAGE { class ImageViewPopup : public ImageViewBase { Gtk::EventBox m_event_frame; Gtk::EventBox m_event_margin; Gtk::Label* m_label; size_t m_length_prev; bool m_clicked; public: ImageViewPopup( const std::string& url ); virtual ~ImageViewPopup(); virtual void clock_in(); // 親ウィンドウは無し virtual Gtk::Window* get_parent_win(){ return NULL; } virtual void stop(); virtual void show_view(); virtual void close_view(); virtual const bool operate_view( const int control ); protected: virtual Gtk::Menu* get_popupmenu( const std::string& url ); private: void show_view_impl(); // クリックした時の処理 virtual void clicked(); void update_label(); void set_label( const std::string& status ); void remove_label(); }; } #endif jd-2.8.7-140104/src/image/imagewin.cpp0000644000076400010400000000521511501147420013743 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imageadmin.h" #include "imagewin.h" #include "jdlib/miscgtk.h" #include "config/globalconf.h" #include "session.h" #include "command.h" using namespace IMAGE; ImageWin::ImageWin() : SKELETON::JDWindow( CONFIG::get_fold_image() ), m_tab( NULL ) { #ifdef _DEBUG std::cout << "ImageWin::ImageWin x y w h = " << get_x_win() << " " << get_y_win() << " " << get_width_win() << " " << get_height_win() << std::endl; #endif init_win(); pack_remove_end( false, get_statbar(), Gtk::PACK_SHRINK ); if( ! CONFIG::get_fold_image() ) set_transient_for( *CORE::get_mainwindow() ); show_all_children(); } ImageWin::~ImageWin() { #ifdef _DEBUG std::cout << "ImageWin::~ImageWin window size : x = " << get_x_win() << " y = " << get_y_win() << " w = " << get_width_win() << " h = " << get_height_win() << " max = " << is_maximized_win() << std::endl; #endif set_shown_win( false ); CORE::core_set_command( "restore_focus" ); } const int ImageWin::get_x_win() { return SESSION::get_x_win_img(); } const int ImageWin::get_y_win() { return SESSION::get_y_win_img(); } void ImageWin::set_x_win( const int x ) { SESSION::set_x_win_img( x ); } void ImageWin::set_y_win( const int y ) { SESSION::set_y_win_img( y ); } const int ImageWin::get_width_win() { return SESSION::get_width_win_img(); } const int ImageWin::get_height_win() { return SESSION::get_height_win_img(); } void ImageWin::set_width_win( const int width ) { SESSION::set_width_win_img( width ); } void ImageWin::set_height_win( const int height ) { SESSION::set_height_win_img( height ); } const bool ImageWin::is_focus_win() { return SESSION::is_focus_win_img(); } void ImageWin::set_focus_win( const bool set ) { SESSION::set_focus_win_img( set ); } const bool ImageWin::is_maximized_win() { return SESSION::is_maximized_win_img(); } void ImageWin::set_maximized_win( const bool set ) { SESSION::set_maximized_win_img( set ); } const bool ImageWin::is_iconified_win() { return SESSION::is_iconified_win_img(); } void ImageWin::set_iconified_win( const bool set ) { SESSION::set_iconified_win_img( set ); } const bool ImageWin::is_shown_win() { return SESSION::is_shown_win_img(); } void ImageWin::set_shown_win( const bool set ) { SESSION::set_shown_win_img( set ); } void ImageWin::switch_admin() { CORE::core_set_command( "switch_image" ); } void ImageWin::pack_remove_tab( bool unpack, Widget& tab ) { m_tab = &tab; get_vbox().pack_remove_start( unpack, tab, Gtk::PACK_SHRINK ); } jd-2.8.7-140104/src/image/imagewin.h0000644000076400010400000000247411501147420013414 0ustar // ライセンス: GPL2 // // 画像ウィンドウ // #ifndef _IMAGEWIN_H #define _IMAGEWIN_H #include #include "skeleton/window.h" namespace IMAGE { class ImageWin : public SKELETON::JDWindow { Gtk::Widget* m_tab; public: ImageWin(); virtual ~ImageWin(); void pack_remove_tab( bool unpack, Widget& tab ); protected: virtual void switch_admin(); virtual const int get_x_win(); virtual const int get_y_win(); virtual void set_x_win( const int x ); virtual void set_y_win( const int y ); virtual const int get_width_win(); virtual const int get_height_win(); virtual void set_width_win( const int width ); virtual void set_height_win( const int height ); virtual const bool is_focus_win(); virtual void set_focus_win( const bool set ); virtual const bool is_maximized_win(); virtual void set_maximized_win( const bool set ); virtual const bool is_iconified_win(); virtual void set_iconified_win( const bool set ); virtual const bool is_full_win(){ return false; } virtual void set_full_win( const bool set ){} virtual const bool is_shown_win(); virtual void set_shown_win( const bool set ); }; } #endif jd-2.8.7-140104/src/image/Makefile.am0000644000076400010400000000105012072045132013465 0ustar noinst_LIBRARIES = libimage.a libimage_a_SOURCES = \ imageadmin.cpp \ preference.cpp \ imagewin.cpp \ \ imageareabase.cpp \ imagearea.cpp \ imageareaicon.cpp \ imageareapopup.cpp \ \ imageviewbase.cpp \ imageview.cpp \ imageviewicon.cpp \ imageviewpopup.cpp noinst_HEADERS = \ imageadmin.h \ preference.h \ imagewin.h \ \ imageareabase.h \ imagearea.h \ imageareaicon.h \ imageareapopup.h \ \ imageviewbase.h \ imageview.h \ imageviewicon.h \ imageviewpopup.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/image/preference.cpp0000644000076400010400000000743611205672661014303 0ustar // ライセンス: GPL2 #include "preference.h" #include "dbtree/interface.h" #include "dbimg/imginterface.h" #include "jdlib/miscutil.h" #include "command.h" #include using namespace IMAGE; Preferences::Preferences( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url, true ) ,m_label_url( false, "URL:", get_url() ) ,m_label_cache( false, "ローカルキャッシュパス:", DBIMG::get_cache_path( url ) ) ,m_label_ref( false, "参照元スレ名:" ) ,m_label_url_ref( false, "参照元レス:" ) ,m_open_ref( "開く" ) ,m_label_wh( false, "大きさ : ", std::string() ) ,m_label_size( false, "サイズ( byte / Kbyte ) : ", std::string() ) ,m_label_type( false, "種類 : ", std::string() ) ,m_check_protect( "キャッシュを保護する" ) { // 一般 int num_from, num_to; std::string num_str; const std::string refurl = DBIMG::get_refurl( get_url() ); const std::string daturl = DBTREE::url_dat( refurl, num_from, num_to, num_str ); const std::string readcgi = DBTREE::url_readcgi( daturl, num_from, 0 ); m_label_ref.set_text( DBTREE::article_subject( daturl ) ); m_label_url_ref.set_text( readcgi ); m_open_ref.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_open_ref ) ); m_hbox_ref.pack_start( m_label_url_ref ); m_hbox_ref.pack_start( m_open_ref, Gtk::PACK_SHRINK ); m_label_wh.set_text( MISC::itostr( DBIMG::get_width( get_url() ) ) + " x " + MISC::itostr( DBIMG::get_height( get_url() ) ) ); int size = DBIMG::get_filesize( get_url() ); m_label_size.set_text( MISC::itostr( size ) + " / " + MISC::itostr( size/1024 ) ); std::string type; switch( DBIMG::get_type_real( get_url() ) ){ case DBIMG::T_JPG: type = "JPEG"; break; case DBIMG::T_PNG: type = "PNG"; break; case DBIMG::T_GIF: type = "GIF"; break; case DBIMG::T_BMP: type = "BMP"; break; } if( DBIMG::is_fake( get_url() ) ) type += " ※拡張子が偽装されています※"; m_label_type.set_text( type ); m_check_protect.set_active( DBIMG::is_protected( get_url() ) ); m_vbox_info.set_border_width( 16 ); m_vbox_info.set_spacing( 8 ); m_vbox_info.pack_start( m_label_url, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_cache, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_ref, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_hbox_ref, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_wh, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_size, Gtk::PACK_SHRINK ); m_vbox_info.pack_start( m_label_type, Gtk::PACK_SHRINK ); m_vbox_info.pack_end( m_check_protect, Gtk::PACK_SHRINK ); set_title( "画像のプロパティ" ); get_vbox()->pack_start( m_vbox_info ); resize( 600, 400 ); show_all_children(); } // // OK 押した // void Preferences::slot_ok_clicked() { if( m_check_protect.get_active() ) DBIMG::set_protect( get_url(), true ); else DBIMG::set_protect( get_url(), false ); // viewの再レイアウト CORE::core_set_command( "relayout_article", get_url() ); } // // 参照元を開く // // ImageViewBase::slot_open_ref() からのコピペ // void Preferences::slot_open_ref() { std::string refurl = DBIMG::get_refurl( get_url() ); int center, from, to; std::string num_str; const std::string url = DBTREE::url_dat( refurl, center, to, num_str ); if( url.empty() ) return; const int range = 10; from = MAX( 0, center - range ); to = center + range; std::stringstream ss; ss << from << "-" << to; CORE::core_set_command( "open_article_res" ,url, ss.str(), MISC::itostr( center ) ); response( Gtk::RESPONSE_CANCEL ); } jd-2.8.7-140104/src/image/preference.h0000644000076400010400000000160510655032354013735 0ustar // ライセンス: GPL2 #ifndef _IMAGE_PREFERENCES_H #define _IMAGE_PREFERENCES_H #include "skeleton/prefdiag.h" #include "skeleton/editview.h" #include "skeleton/label_entry.h" namespace IMAGE { class Preferences : public SKELETON::PrefDiag { // 情報 Gtk::VBox m_vbox_info; SKELETON::LabelEntry m_label_url; SKELETON::LabelEntry m_label_cache; SKELETON::LabelEntry m_label_ref; Gtk::HBox m_hbox_ref; SKELETON::LabelEntry m_label_url_ref; Gtk::Button m_open_ref; SKELETON::LabelEntry m_label_wh; SKELETON::LabelEntry m_label_size; SKELETON::LabelEntry m_label_type; Gtk::CheckButton m_check_protect; public: Preferences( Gtk::Window* parent, const std::string& url ); private: virtual void slot_ok_clicked(); void slot_open_ref(); }; } #endif jd-2.8.7-140104/src/iomonitor.cpp0000644000076400010400000002263611347455370013124 0ustar // License: GPL2 // // FIFOを使ったプロセス間通信を行うクラス // //#define _DEBUG #include "jddebug.h" #include "iomonitor.h" #include "command.h" #include "cache.h" #include "jdlib/miscmsg.h" #include #include #include #include #ifdef _WIN32 #define FIFO_TIMEOUT_MILI 100 #endif using namespace CORE; #define COMMAND_MAX_LENGTH 1024 /*-------------------------------------------------------------------*/ // コンストラクタ /*-------------------------------------------------------------------*/ IOMonitor::IOMonitor() #ifndef _WIN32 : m_fifo_fd( -1 ) , m_iochannel( NULL ) #else : m_slot_hd( INVALID_HANDLE_VALUE ) #endif // _WIN32 , m_fifo_file( CACHE::path_lock() ) , m_fifo_stat( FIFO_OK ) , m_main_process( false ) { #ifdef _WIN32 // create path to mailslot depends JD cache root std::string slot_tmp( CACHE::path_root() ); for( int i=slot_tmp.length()-1; i>=0; i-- ){ if( slot_tmp[ i ] == '/' || slot_tmp[ i ] == ':' ){ slot_tmp[ i ] = '_'; } } m_slot_name = "\\\\.\\mailslot\\" + slot_tmp; #endif // _WIN32 init(); } /*-------------------------------------------------------------------*/ // デストラクタ /*-------------------------------------------------------------------*/ IOMonitor::~IOMonitor() { #ifndef _WIN32 if( m_iochannel ) m_iochannel->close(); // close( m_fifo_fd ); // メインプロセスの終了時にFIFOを消去する if( m_main_process ) delete_fifo(); #else if( m_slot_hd != INVALID_HANDLE_VALUE ){ CloseHandle( m_slot_hd ); m_slot_hd = INVALID_HANDLE_VALUE; } if( m_main_process ){ m_thread.join(); } #endif // _WIN32 } /*-------------------------------------------------------------------*/ // このクラスの初期化( FIFO作成、FIFOオープン、Glib::IOChannelの作成 ) /*-------------------------------------------------------------------*/ void IOMonitor::init() { // 既にFIFOと同名のファイルが存在するか確認 const int status = CACHE::file_exists( m_fifo_file ); #ifndef _WIN32 // 同名のファイルがFIFOでなければ削除する if( status != CACHE::EXIST_ERROR && status != CACHE::EXIST_FIFO ) { delete_fifo(); } // FIFOを作成 int mkfifo_status = -1; do_makefifo: mkfifo_status = mkfifo( m_fifo_file.c_str(), O_RDWR | S_IRUSR | S_IWUSR ); // FIFO作成でエラーになった( 基本的に既にメインプロセスがある ) if( mkfifo_status != 0 ) { // FIFOが存在する if( errno == EEXIST ) { // FIFOを書き込み専用モードでオープン( ノンブロック ) if( ( m_fifo_fd = open( m_fifo_file.c_str(), O_WRONLY | O_NONBLOCK ) ) == -1 ) { // 反対側が既にオープンされていない( 異常終了などでメインプロセスがない ) if( ( errno & ENXIO ) != 0 ) { // 残っているFIFOを消す delete_fifo(); // 最初からやり直す goto do_makefifo; } // その他のエラー #ifdef _DEBUG std::cerr << "IOMonitor::init(): " << strerror( errno ) << std::endl; #endif m_fifo_stat = FIFO_OPEN_ERROR; } } // 何らかの問題で作成出来なかった else { MISC::ERRMSG( "IOMonitor::init(): fifo create failed." ); m_fifo_stat = FIFO_CREATE_ERROR; } } // メインプロセス else { // FIFOを読み込み専用モードでオープン( ノンブロック ) if( ( m_fifo_fd = open( m_fifo_file.c_str(), O_RDWR | O_NONBLOCK ) ) == -1 ) { // エラーなのでFIFOを消す delete_fifo(); #ifdef _DEBUG std::cerr << "IOMonitor::init(): " << strerror( errno ); #endif // _DEBUG m_fifo_stat = FIFO_OPEN_ERROR; return; } // メインプロセスである m_main_process = true; // Glib::IOChannel Glib::signal_io().connect( sigc::mem_fun( this, &IOMonitor::slot_ioin ), m_fifo_fd, Glib::IO_IN ); m_iochannel = Glib::IOChannel::create_from_fd( m_fifo_fd ); } #else // _WIN32 if( status != CACHE::EXIST_ERROR ) { // if lockfile exists, jd don't suggest working because cache isn't broken MISC::ERRMSG( "IOMonitor::init(): exists other lockfile." ); m_fifo_stat = FIFO_CREATE_ERROR; } #ifdef _DEBUG std::cerr << "Create slot name: " << m_slot_name << std::endl; #endif m_slot_hd = CreateMailslot( to_locale_cstr( m_slot_name.c_str() ), 0, FIFO_TIMEOUT_MILI, NULL ); if( m_slot_hd == INVALID_HANDLE_VALUE ){ if( GetLastError() == ERROR_ALREADY_EXISTS ){ // client m_slot_hd = CreateFile( to_locale_cstr( m_slot_name.c_str() ), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if( m_slot_hd == INVALID_HANDLE_VALUE ){ #ifdef _DEBUG std::cerr << "Open err: " << GetLastError() << std::endl; #endif MISC::ERRMSG( "IOMonitor::init(): Open client failed." ); m_fifo_stat = FIFO_OPEN_ERROR; } } else { #ifdef _DEBUG std::cerr << "Create err: " << GetLastError() << std::endl; #endif MISC::ERRMSG( "IOMonitor::init(): Create slot failed." ); m_fifo_stat = FIFO_CREATE_ERROR; } } else { // server if( ! m_thread.create( monitor_launcher, ( void* )this, JDLIB::NODETACH ) ) { MISC::ERRMSG( "IOMonitor::init(): Could not start thread." ); m_fifo_stat = FIFO_CREATE_ERROR; return; } m_main_process = true; } #endif // _WIN32 } /*-------------------------------------------------------------------*/ // FIFOを削除する /*-------------------------------------------------------------------*/ void IOMonitor::delete_fifo() { int del_stat = 0; if( ( del_stat = unlink( m_fifo_file.c_str() ) ) < 0 ) { MISC::ERRMSG( "IOMonitor::init(): fifo unlink failed." ); } g_assert( del_stat >= 0 ); } /*-------------------------------------------------------------------*/ // FIFOに書き込む // // 引数 1: 書き込む文字列 // // 戻り値: 全て書き込まれたか否か /*-------------------------------------------------------------------*/ bool IOMonitor::send_command( const char* command ) { if( ! command ) return false; const size_t command_length = strlen( command ); // 異常に長かったら書き込まない if( command_length > COMMAND_MAX_LENGTH ) return false; #ifndef _WIN32 g_assert( m_fifo_fd >= 0 ); int status = -1; status = write( m_fifo_fd, command, command_length ); return ( (size_t)status == command_length ); #else g_assert( m_slot_hd != INVALID_HANDLE_VALUE ); DWORD length = 0; BOOL rc = WriteFile( m_slot_hd, command, command_length, &length, NULL ); return rc != FALSE && ( size_t )length == command_length; #endif // _WIN32 } /*-------------------------------------------------------------------*/ // FIFOに書き込まれたら呼び出される( Glib::signal_io() ) // // 引数 1: Glib::IOCondition // // 戻り値: true /*-------------------------------------------------------------------*/ bool IOMonitor::slot_ioin( Glib::IOCondition io_condition ) { if( ( io_condition & ( Glib::IO_IN | Glib::IO_PRI ) ) == 0 ) { MISC::ERRMSG( "IOMonitor::slot_ioin(): Invalid fifo response." ); return false; } Glib::ustring buffer; #ifndef _WIN32 // 最大で COMMAND_MAX_LENGTH まで読み出す Glib::IOStatus io_status = m_iochannel->read( buffer, COMMAND_MAX_LENGTH ); if( io_status == Glib::IO_STATUS_ERROR ) { MISC::ERRMSG( "IOMonitor::slot_ioin(): read error." ); } #else char msg[ COMMAND_MAX_LENGTH ]; memset( msg, 0, sizeof( msg ) ); DWORD length = 0; BOOL rc = ReadFile( m_slot_hd, msg, COMMAND_MAX_LENGTH - 1, &length, NULL ); if( rc == FALSE ){ DWORD error = GetLastError(); if( error == ERROR_SEM_TIMEOUT ){ return true; } #ifdef _DEBUG std::cout << "read err: " << error << std::endl; #endif MISC::ERRMSG( "IOMonitor::slot_ioin(): read error." ); return false; } if( length == 0 ){ return true; } buffer += msg; #endif // _WIN32 #ifdef _DEBUG std::cout << "入力文字: " << buffer << std::endl; if( buffer == "Q" ) Gtk::Main::quit(); #endif // _DEBUG // FIFOに書き込まれたURLを開く // "現在のタブ/新しいタブ"など、開き方を選ぶ必要があるかも知れない //core_set_command( "open_article", buffer, "left", "auto" ); core_set_command( "open_url", buffer ); return true; } #ifdef _WIN32 /*-------------------------------------------------------------------*/ // monitor_launcher /*-------------------------------------------------------------------*/ // static void* IOMonitor::monitor_launcher( void* dat ) { CORE::IOMonitor* iom = ( CORE::IOMonitor* )dat; while( iom->m_slot_hd != INVALID_HANDLE_VALUE ){ if( ! iom->slot_ioin( Glib::IO_IN ) ){ break; } } return 0; } #endif // _WIN32 jd-2.8.7-140104/src/iomonitor.h0000644000076400010400000000270511347455370012564 0ustar // License: GPL2 // // FIFOを使ったプロセス間通信を行うクラス // #ifndef _IOMONITOR_H #define _IOMONITOR_H #include #ifdef _WIN32 #include "jdlib/jdthread.h" #include #endif namespace CORE { enum { FIFO_OK = 0, FIFO_OPEN_ERROR, FIFO_CREATE_ERROR }; class IOMonitor { #ifndef _WIN32 // FIFOのファイルディスクリプタ int m_fifo_fd; // I/Oの架け橋 Glib::RefPtr< Glib::IOChannel > m_iochannel; #else HANDLE m_slot_hd; std::string m_slot_name; JDLIB::Thread m_thread; #endif // FIFOファイル名 std::string m_fifo_file; // FIFOの状態 int m_fifo_stat; // メインプロセスか否か bool m_main_process; private: // 初期化 void init(); // FIFOを削除する void delete_fifo(); // FIFOに書き込まれたら呼び出される bool slot_ioin( Glib::IOCondition io_condition ); #ifdef _WIN32 static void* monitor_launcher( void* dat ); #endif public: IOMonitor(); ~IOMonitor(); // FIFOの状態を取得 int get_fifo_stat(){ return m_fifo_stat; } // メインプロセスか否かを取得 bool is_main_process(){ return m_main_process; } // FIFOに書き込み bool send_command( const char* command ); }; } #endif jd-2.8.7-140104/src/jddebug.h0000644000076400010400000000163712006761301012137 0ustar // ライセンス: GPL2 #ifndef _JDDEBUG_H #define _JDDEBUG_H #ifndef _DEBUG #define NDEBUG #else #include #endif #ifdef _DEBUG_CARETMOVE #include #endif #include #ifdef _DEBUG_SHOW_VMSIZE #include #include // プロセスのvmsizeを表示 #define show_vmsize( msg ) { \ std::stringstream com; \ com << "grep VmSize /proc/" << getpid() << "/status | sed -e \"s/V[^0-9]*//\""; \ std::cerr << msg << ": "; \ system( com.str().c_str() ); \ } while(0) #else #define show_vmsize( msg ) while(0) #endif // from GTK_CHECK_VERSION in gtk/gtkversion.h #ifndef GTKMM_CHECK_VERSION #define GTKMM_CHECK_VERSION(major,minor,micro) \ (GTKMM_MAJOR_VERSION > (major) || \ (GTKMM_MAJOR_VERSION == (major) && GTK_MINOR_VERSION > (minor)) || \ (GTKMM_MAJOR_VERSION == (major) && GTK_MINOR_VERSION == (minor) && \ GTKMM_MICRO_VERSION >= (micro))) #endif #endif jd-2.8.7-140104/src/jdlib/0000755000076400010400000000000012261751612011446 5ustar jd-2.8.7-140104/src/jdlib/confloader.cpp0000644000076400010400000001317211215464761014276 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "confloader.h" #include "miscutil.h" #include "cache.h" #include #include using namespace JDLIB; // // file : 設定ファイル // str_conf : 設定文字列 // // もしstr_confがemptyの時はfileから読み込む // ConfLoader::ConfLoader( const std::string& file, std::string str_conf ) : m_file( file ), m_broken( false ) { if( str_conf.empty() ) CACHE::load_rawdata( m_file, str_conf ); #ifdef _DEBUG std::cout << "ConfLoader::ConfLoader " << m_file << std::endl; std::cout << str_conf << std::endl; #endif // 行ごとに分割してConfDataに登録 if( ! str_conf.empty() ){ std::list< std::string > lines = MISC::get_lines( str_conf ); if( lines.size() == 0 ) return; std::list < std::string >::iterator it = lines.begin(); for( ; it != lines.end(); ++it ){ std::string line = MISC::remove_space( ( *it ) ); size_t i = line.find( "=" ); if( i != std::string::npos ){ ConfData data; data.name = MISC::remove_space( line.substr( 0, i ) ); data.value = MISC::remove_space( line.substr( i +1 ) ); m_data.push_back( data ); #ifdef _DEBUG std::cout << data.name << " = " << data.value << std::endl; #endif } } } } const bool ConfLoader::empty() { return !( m_data.size() ); } // 保存 void ConfLoader::save() { if( m_file.empty() ) return; std::string str_conf; std::list < ConfData >::iterator it = m_data.begin(); for( ; it != m_data.end(); ++it ) str_conf += (*it).name + " = " + (*it).value + "\n"; #ifdef _DEBUG std::cout << "ConfLoader::save " << m_file << std::endl; std::cout << str_conf << std::endl; #endif if( !str_conf.empty() ) CACHE::save_rawdata( m_file, str_conf ); } // 値を変更 (string型) // name が無い場合は綱目を追加 void ConfLoader::update( const std::string& name, const std::string& value ) { if( name.empty() ) return; std::list < ConfData >::iterator it = m_data.begin(); for( ; it != m_data.end(); ++it ){ if( (*it).name == name ){ (*it).value = value; return; } } // 追加 ConfData data; data.name = name; data.value = value; m_data.push_back( data ); } // 値を変更 (bool型) void ConfLoader::update( const std::string& name, const bool value ) { std::string str_value = value ? "1" : "0"; update( name, str_value ); } // 値を変更 (int型) void ConfLoader::update( const std::string& name, const int value ) { const int buflng = 256; char str_value[ buflng ]; snprintf( str_value, buflng, "%d", value ); update( name, std::string( str_value ) ); } // 値を変更 (double型) void ConfLoader::update( const std::string& name, const double value ) { const int buflng = 256; char str_value[ buflng ]; #ifdef _WIN32 // not support to 'l' flag, error occurred if using snprintf( str_value, buflng, "%f", value ); #else snprintf( str_value, buflng, "%lf", value ); #endif update( name, std::string( str_value ) ); } // // string 型 // // dflt はデフォルト値, デフォルト引数 maxlength = 0 const std::string ConfLoader::get_option_str( const std::string& name, const std::string& dflt, const size_t maxlength ) { if( name.empty() ) return std::string(); std::list < ConfData >::iterator it = m_data.begin(); for( ; it != m_data.end(); ++it ) { if( (*it).name == name ) { // maxlengthが設定されている場合は文字数制限をする if( maxlength > 0 && (*it).value.length() > maxlength ) { m_broken = true; #ifdef _DEBUG std::cout << "ConfLoader::get_option_str: " << name << "=" << (*it).value << std::endl; #endif break; } return (*it).value; } } return dflt; } // // bool型 // const bool ConfLoader::get_option_bool( const std::string& name, const bool dflt ) { std::string val_str = get_option_str( name, std::string() ); if( val_str.empty() ) return dflt; if( val_str == "1" ) return true; if( val_str == "0" ) return false; val_str = MISC::toupper_str( val_str ); if( val_str == "TRUE" || val_str == "T" ) return true; if( val_str == "FALSE" || val_str == "F" ) return false; m_broken = true; #ifdef _DEBUG std::cout << "ConfLoader::get_option_bool: " << name << "=" << val_str << std::endl; #endif return dflt; } // // int 型 // const int ConfLoader::get_option_int( const std::string& name, const int dflt, const int min, const int max ) { std::string val_str = get_option_str( name, std::string() ); if( val_str.empty() ) return dflt; int val_int = atoi( val_str.c_str() ); if( val_int < min || val_int > max ) { val_int = dflt; m_broken = true; #ifdef _DEBUG std::cout << "ConfLoader::get_option_int: " << name << "=" << val_int << std::endl; #endif } return val_int; } // // double 型 // const double ConfLoader::get_option_double( const std::string& name, const double dflt, const double min, const double max ) { std::string val_str = get_option_str( name, std::string() ); if( val_str.empty() ) return dflt; double val_double = atof( val_str.c_str() ); if( val_double < min || val_double > max ) { val_double = dflt; m_broken = true; #ifdef _DEBUG std::cout << "ConfLoader::get_option_double: " << name << "=" << val_double << std::endl; #endif } return val_double; } jd-2.8.7-140104/src/jdlib/confloader.h0000644000076400010400000000304511211233540013722 0ustar // ライセンス: GPL2 // // コンフィグファイルのローダ // #ifndef _CONFLOADER_H #define _CONFLOADER_H #include #include #include "config/defaultconf.h" namespace JDLIB { struct ConfData { std::string name; std::string value; }; class ConfLoader { std::string m_file; std::list< ConfData > m_data; bool m_broken; public: // file : 設定ファイル // str_conf : 設定文字列 // もしstr_confがemptyの時はfileから読み込む ConfLoader( const std::string& file, std::string str_conf ); const bool empty(); const bool is_broken(){ return m_broken; } // 保存 void save(); // 値を変更 // name が無い場合は綱目を追加 void update( const std::string& name, const std::string& value ); void update( const std::string& name, const bool value ); void update( const std::string& name, const int value ); void update( const std::string& name, const double value ); // 値取得 const std::string get_option_str( const std::string& name, const std::string& dflt, const size_t maxlength = 0 ); const bool get_option_bool( const std::string& name, const bool dflt ); const int get_option_int( const std::string& name, const int dflt, const int min, const int max ); const double get_option_double( const std::string& name, const double dflt, const double min , const double max ); }; } #endif jd-2.8.7-140104/src/jdlib/constptr.h0000644000076400010400000000232410540252733013472 0ustar // ライセンス: GPL2 // // constなスマートポインタ // #ifndef _CONSTPTR_H #define _CONSTPTR_H namespace JDLIB { template < typename T > class ConstPtr { T *m_p; public: T* operator -> (){ return m_p; } bool operator == ( const T *p ) const { return( m_p == p ); } bool operator != ( const T *p ) const { return( m_p != p ); } bool operator ! () const { return ( m_p == NULL ); } T& operator * () const { return *m_p; } operator bool () const { return ( m_p != NULL ); } T& operator [] ( const int i ){ return m_p[ i ]; } ConstPtr< T >& operator = ( const ConstPtr< T >& a ){ m_p = a.m_p; return *this; } ConstPtr< T >& operator = ( ConstPtr< T >& a ){ m_p = a.m_p; return *this; } ConstPtr< T >& operator = ( const T *p ){ m_p = p; return *this; } ConstPtr< T >& operator = ( T *p ){ m_p = p; return *this; } void reset() { m_p = NULL; } // clear は deleteも実行 void clear(){ if( m_p ) delete m_p; reset(); } ConstPtr() : m_p (0){} ConstPtr( T *p ) : m_p (p){} ConstPtr( const T *p ) : m_p (p){} }; } #endif jd-2.8.7-140104/src/jdlib/hash_set.cpp0000644000076400010400000000323311361360531013745 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "hash_set.h" #include "dbtree/interface.h" #include using namespace JDLIB; simple_hash_set::simple_hash_set( const int hash_size ) : m_hash_size( hash_size ) {} simple_hash_set::~simple_hash_set() { #ifdef _DEBUG std::cout << "simple_hash_set::~simple_hash_set\n"; for( size_t i = 0; i < m_hash.size(); ++i ) if( m_hash[ i ].size() ) std::cout << "[" << i << "] " << m_hash[ i ].size() << std::endl; #endif } void simple_hash_set::clear() { m_hash.clear(); } void simple_hash_set::insert( const std::string& item ) { if( ! m_hash.size() ) m_hash.resize( m_hash_size ); const int key = get_key( item ); m_hash[ key ].insert( item ); } void simple_hash_set::erase( const std::string& item ) { if( ! m_hash.size() ) return; const int key = get_key( item ); m_hash[ key ].erase( item ); } const bool simple_hash_set::find_if( const std::string& item ) { if( ! m_hash.size() ) return false; const int key = get_key( item ); return ( m_hash[ key ].find( item ) != m_hash[ key ].end() ); } ////////////////////////////// // スレッドのアドレス用 hash_set enum { HASH_TBLSIZE = 1024 }; hash_set_thread::hash_set_thread() : JDLIB::simple_hash_set( HASH_TBLSIZE ) {} const int hash_set_thread::get_key( const std::string& url ) { const int lng = DBTREE::url_datbase( url ).length(); const int key = atoi( url.substr( lng < (int) url.length() ? lng : 0 ).c_str() ) % size(); #ifdef _DEBUG std::cout << "hash_set_thread::get_key url = " << url << " key = " << key << std::endl; #endif return key ; } jd-2.8.7-140104/src/jdlib/hash_set.h0000644000076400010400000000200011351667604013413 0ustar // ライセンス: GPL2 // 簡易 hash_set #ifndef _HASH_SET_H #define _HASH_SET_H #include #include #include namespace JDLIB { typedef std::set< std::string > HASH_SET_ITEM; class simple_hash_set { int m_hash_size; std::vector< HASH_SET_ITEM > m_hash; public: simple_hash_set( const int hash_size ); virtual ~simple_hash_set(); const int size() const { return m_hash_size; } void clear(); void insert( const std::string& item ); void erase( const std::string& item ); const bool find_if( const std::string& item ); private: virtual const int get_key( const std::string& item ) = 0; }; ///////////////////////////////////// // スレッドのアドレス用 hash_set class hash_set_thread : public JDLIB::simple_hash_set { public: hash_set_thread(); private: virtual const int get_key( const std::string& url ); }; } #endif jd-2.8.7-140104/src/jdlib/heap.cpp0000644000076400010400000000255511013324557013074 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "heap.h" #include #include using namespace JDLIB; HEAP::HEAP( long blocksize ) : m_max( blocksize ), m_used( 0 ), m_total_size( 0 ) { #ifdef _DEBUG std::cout << "HEAP::HEAP : max = " << m_max << std::endl; #endif } HEAP::~HEAP() { #ifdef _DEBUG std::cout << "HEAP::~HEAP : size " << m_total_size << " max =" << m_max << std::endl; #endif clear(); } void HEAP::clear() { #ifdef _DEBUG std::cout << "HEAP::crear max = " << m_max << " total = " << m_total_size << std::endl; #endif m_total_size = 0; m_used = 0; std::list< unsigned char* >::iterator it; for( it = m_heap_list.begin(); it != m_heap_list.end(); ++it ){ free( (*it) ); } m_heap_list.clear(); } unsigned char* HEAP::heap_alloc( long n ) { assert( n > 0 && n <= m_max ); if( m_used == 0 || m_used + n > m_max ){ m_heap_list.push_back( ( unsigned char* )malloc( m_max ) ); memset( m_heap_list.back(), 0, m_max ); m_used = 0; #ifdef _DEBUG std::cout << "HEAP::heap_alloc malloc max = " << m_max << " total = " << m_total_size + n + 4 << std::endl; #endif } unsigned char* heap = m_heap_list.back() + m_used; m_used += n + 4; m_total_size += n + 4; return heap; } jd-2.8.7-140104/src/jdlib/heap.h0000644000076400010400000000100010540252733012521 0ustar // ライセンス: GPL2 // ヒープクラス #ifndef _HEAP_H #define _HEAP_H #include #include namespace JDLIB { class HEAP { std::list< unsigned char* >m_heap_list; long m_max; // ブロックサイズ long m_used; // ブロック内の使用量 long m_total_size; // トータルサイズ public: HEAP( long blocksize ); ~HEAP(); void clear(); unsigned char* heap_alloc( long n ); }; } #endif jd-2.8.7-140104/src/jdlib/hkana.h0000644000076400010400000000351311405713530012677 0ustar // ライセンス: GPL2 // 半角カナ -> 全角カナ変換テーブル #ifndef _HKANA_H_ #define _HKANA_H_ unsigned char hkana_table1[][2][8] = { { "。", "。" }, { "「", "「" }, { "」", "」" }, { "、", "、" }, { "・", "・" }, { "ヲ", "ヲ" }, { "ァ", "ァ" }, { "ィ", "ィ" }, { "ゥ", "ゥ" }, { "ェ", "ェ" }, { "ォ", "ォ" }, { "ャ", "ャ" }, { "ュ", "ュ" }, { "ョ", "ョ" }, { "ッ", "ッ" }, { "ー", "ー" }, { "ア", "ア" }, { "イ", "イ" }, { "ウ", "ウ" }, { "エ", "エ" }, { "オ", "オ" }, { "カ", "カ" }, { "キ", "キ" }, { "ク", "ク" }, { "ケ", "ケ" }, { "コ", "コ" }, { "サ", "サ" }, { "シ", "シ" }, { "ス", "ス" }, { "セ", "セ" }, { "ソ", "ソ" }, { "タ", "タ" }, { "チ", "チ" }, { "ツ", "ツ" }, { "テ", "テ" }, { "ト", "ト" }, { "ナ", "ナ" }, { "ニ", "ニ" }, { "ヌ", "ヌ" }, { "ネ", "ネ" }, { "ノ", "ノ" }, { "ハ", "ハ" }, { "ヒ", "ヒ" }, { "フ", "フ" }, { "ヘ", "ヘ" }, { "ホ", "ホ" }, { "マ", "マ" }, { "ミ", "ミ" }, { "ム", "ム" }, { "メ", "メ" }, { "モ", "モ" }, { "ヤ", "ヤ" }, { "ユ", "ユ" }, { "ヨ", "ヨ" }, { "ラ", "ラ" }, { "リ", "リ" }, { "ル", "ル" }, { "レ", "レ" }, { "ロ", "ロ" }, { "ワ", "ワ" }, { "ン", "ン" }, // 濁点 { "ウ", "ヴ" }, { "カ", "ガ" }, { "キ", "ギ" }, { "ク", "グ" }, { "ケ", "ゲ" }, { "コ", "ゴ" }, { "サ", "ザ" }, { "シ", "ジ" }, { "ス", "ズ" }, { "セ", "ゼ" }, { "ソ", "ゾ" }, { "タ", "ダ" }, { "チ", "ヂ" }, { "ツ", "ヅ" }, { "テ", "デ" }, { "ト", "ド" }, { "ハ", "バ" }, { "ヒ", "ビ" }, { "フ", "ブ" }, { "ヘ", "ベ" }, { "ホ", "ボ" }, // 半濁点 { "ハ", "パ" }, { "ヒ", "ピ" }, { "フ", "プ" }, { "ヘ", "ペ" }, { "ホ", "ポ" }, { "", "" } }; #endif jd-2.8.7-140104/src/jdlib/imgloader.cpp0000644000076400010400000002110212006761301014102 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _VERBOSE #include "jddebug.h" #include "gtkmmversion.h" #include "imgloader.h" #include "cache.h" #include "config/globalconf.h" using namespace JDLIB; /**********************************************************/ /* constructions ******************************************/ ImgLoader::ImgLoader( const std::string& file ) : m_file( file ), m_width( 0 ), m_height( 0 ), m_stop( false ), m_y( 0 ), m_loadedlevel( LOADLEVEL_INIT ) { #ifdef _DEBUG std::cout << "ImgLoader::ImgLoader file = " << m_file << std::endl; #endif } ImgLoader::~ImgLoader() { #ifdef _DEBUG std::cout << "ImgLoader::~ImgLoader file = " << m_file << std::endl; #endif } // static // いつまでもImgLoaderを保持していると、キャッシュアウトしても解放されないため、 // ImgLoaderは不要になった時点で、ただちに解放(.clear()または他の値代入)すること Glib::RefPtr< ImgLoader > ImgLoader::get_loader( const std::string& file ) { ImgProvider& provider = ImgProvider::get_provider(); Glib::Mutex::Lock lock( provider.m_provider_lock ); Glib::RefPtr< ImgLoader > loader = provider.get_loader( file ); if( ! loader ) { loader = Glib::RefPtr< ImgLoader >( new ImgLoader( file ) ); provider.set_loader( loader ); } return loader; } /**********************************************************/ /* external interface to PixbufLoader *********************/ // 画像サイズ取得 bool ImgLoader::get_size( int& width, int& height ) { Glib::Mutex::Lock lock( m_loader_lock ); bool ret = load_imgfile( LOADLEVEL_SIZEONLY ); width = m_width; height = m_height; return ret; } Glib::RefPtr< Gdk::Pixbuf > ImgLoader::get_pixbuf( const bool pixbufonly ) { Glib::RefPtr< Gdk::Pixbuf > ret; Glib::Mutex::Lock lock( m_loader_lock ); if( load_imgfile( pixbufonly ? LOADLEVEL_PIXBUFONLY : LOADLEVEL_NORMAL ) ) { ret = m_loader->get_pixbuf(); } return ret; } Glib::RefPtr< Gdk::PixbufAnimation > ImgLoader::get_animation() { Glib::RefPtr< Gdk::PixbufAnimation > ret; Glib::Mutex::Lock lock( m_loader_lock ); if( load_imgfile( LOADLEVEL_NORMAL ) ) { ret = m_loader->get_animation(); } return ret; } // 画像読み込み // 動画でpixbufonly = true の時はアニメーションさせない const bool ImgLoader::load( const bool pixbufonly ) { Glib::Mutex::Lock lock( m_loader_lock ); return load_imgfile( pixbufonly ? LOADLEVEL_PIXBUFONLY : LOADLEVEL_NORMAL ); } /**********************************************************/ /* create PixbufLoader ************************************/ // private, NOT thread safe const bool ImgLoader::load_imgfile( const int loadlevel ) { if( m_loader ) { // キャッシュに読み込んだデータが十分かどうか if( m_loadedlevel <= loadlevel ) { #ifdef _DEBUG std::cout << "ImgLoader use cache loadlevel / loadedlevel = " << loadlevel << " / " << m_loadedlevel << " file = " << m_file << std::endl; #endif return true; } // リロード m_width = 0; m_height = 0; m_stop = false; m_y = 0; } m_loadlevel = loadlevel; #ifdef _DEBUG std::cout << "ImgLoader::load_imgfile start loadlevel = " << loadlevel << " loadedlevel = " << m_loadedlevel << " file = " << m_file << std::endl; size_t total = 0; #endif bool ret = true; FILE* f = NULL; const size_t bufsize = 8192; size_t readsize = 0; guint8 data[ bufsize ]; #if !GTKMM_CHECK_VERSION(2,5,0) bool size_prepared = false; #endif f = fopen( to_locale_cstr( m_file ), "rb" ); if( ! f ){ m_errmsg = "cannot file open"; return false; } try { m_loader = Gdk::PixbufLoader::create(); #if GTKMM_CHECK_VERSION(2,5,0) m_loader->signal_size_prepared().connect( sigc::mem_fun( *this, &ImgLoader::slot_size_prepared ) ); #endif m_loader->signal_area_updated().connect( sigc::mem_fun( *this, &ImgLoader::slot_area_updated ) ); while( ! m_stop ){ readsize = fread( data, 1, bufsize, f ); if( readsize ) m_loader->write( data, readsize ); #ifdef _DEBUG total += readsize; // std::cout << readsize << " / " << total << std::endl; #endif if( feof( f ) ){ // 画像データ全体を読み込み完了 m_loadedlevel = LOADLEVEL_NORMAL; break; } #if !GTKMM_CHECK_VERSION(2,5,0) // gdkのバージョンが古い場合はpixbufを取得してサイズを得る if( ! size_prepared && m_loader->get_pixbuf() ){ size_prepared = true; m_width = m_loader->get_pixbuf()->get_width(); m_height = m_loader->get_pixbuf()->get_height(); if( loadlevel == LOADLEVEL_SIZEONLY ) m_stop = true; } #endif } m_loader->close(); } catch( Glib::Error& err ) { #ifdef _DEBUG std::string stop_s = m_stop ? "true" : "false"; std::cout << "ImgLoader stop = (" << stop_s << ") : " << m_file << std::endl; #endif if( ! m_stop ){ m_errmsg = err.what(); m_loader.clear(); ret = false; } } fclose( f ); #ifdef _DEBUG std::cout << "ImgLoader::load_imgfile fisished read = " << total << " w = " << m_width << " h = " << m_height << " loadedlevel = " << m_loadedlevel << std::endl; #endif return ret; } // PixbufLoaderが生成する画像の大きさを計算するのに必要な量のデータを受け取った時のシグナルハンドラ void ImgLoader::slot_size_prepared( int w, int h ) { #ifdef _DEBUG std::cout << "ImgLoader::slot_size_prepared w = " << w << " h = " << h << std::endl; #endif m_width = w; m_height = h; if( m_loadedlevel > LOADLEVEL_SIZEONLY ) m_loadedlevel = LOADLEVEL_SIZEONLY; if( m_loadlevel >= LOADLEVEL_SIZEONLY ) request_stop(); } // 画像の一部分が更新された時のシグナルハンドラ void ImgLoader::slot_area_updated(int x, int y, int w, int h ) { if( m_loadlevel >= LOADLEVEL_PIXBUFONLY ){ #if defined( _DEBUG ) && defined( _VERBOSE ) std::cout << "ImgLoader::slot_area_updated x = " << x << " y = " << y << " w = " << w << " h = " << h << std::endl; #endif // アニメーション画像を表示する際、幅や高さが元の値と異なる時に、全ての画像データを // 読み込まなくても pixbuf だけ取り出せれば良いので、pixbufを取り出せるようになった時点で // 画像データの読み込みを途中で止めて表示待ち時間を短縮する if( y < m_y ){ m_loadedlevel = LOADLEVEL_PIXBUFONLY; request_stop(); } m_y = y; } } /**********************************************************/ /* interface inner behavior *******************************/ // 読み込み中断のリクエスト void ImgLoader::request_stop() { #ifndef _WIN32 // 中断をリクエストされても実際には読み込みが完了していることがある // windowsでは読み込みを中断すると、通常の画像でpixbufが壊れてしまうことがある m_stop = true; #endif } bool ImgLoader::equals( const std::string& file ) const { return m_file == file; } /**********************************************************/ /* ImgProvider has relational from ImgLoader ********/ ImgProvider::ImgProvider() { } // static ImgProvider& ImgProvider::get_provider() { // singleton provider static ImgProvider instance; return instance; } // NOT thread safe Glib::RefPtr< ImgLoader > ImgProvider::get_loader( const std::string& file ) { // ImgLoaderキャッシュをサーチ for( std::list< Glib::RefPtr< ImgLoader > >::iterator it = m_cache.begin(); it != m_cache.end(); it++ ) { if( (*it)->equals( file ) ) { Glib::RefPtr< ImgLoader > ret = *it; // LRU: キャッシュをlistの先頭に移動 if( it != m_cache.begin() ) { m_cache.erase( it ); m_cache.push_front( ret ); } return ret; } } return Glib::RefPtr< ImgLoader >(); //null } // NOT thread safe void ImgProvider::set_loader( Glib::RefPtr< ImgLoader > loader ) { int size = CONFIG::get_imgcache_size(); if( size ) { if( m_cache.size() >= (size_t)size ) { m_cache.pop_back(); } m_cache.push_front( loader ); } } jd-2.8.7-140104/src/jdlib/imgloader.h0000644000076400010400000000416311313421664013564 0ustar // ライセンス: GPL2 // // 画像ローダ // #ifndef _IMGLOADER_H #define _IMGLOADER_H #include namespace JDLIB { // 画像ロードレベル、必要なデータ量順に定義 enum { LOADLEVEL_NORMAL = 0, // 画像データ全体を読み込む LOADLEVEL_PIXBUFONLY, // pixbufを作るのに十分なデータを読み込む LOADLEVEL_SIZEONLY, // サイズを計算するのに十分なデータを読み込む LOADLEVEL_INIT }; class ImgLoader : public Glib::Object { Glib::RefPtr< Gdk::PixbufLoader > m_loader; Glib::Mutex m_loader_lock; std::string m_file; std::string m_errmsg; int m_width; int m_height; bool m_stop; int m_y; int m_loadlevel; int m_loadedlevel; public: virtual ~ImgLoader(); static Glib::RefPtr< ImgLoader > get_loader( const std::string& file ); const std::string& get_errmsg() const { return m_errmsg; } bool get_size( int& width, int& height ); void request_stop(); const bool load( const bool pixbufonly = false ); Glib::RefPtr get_pixbuf( const bool pixbufonly = false ); Glib::RefPtr get_animation(); bool equals( const std::string& file ) const; private: ImgLoader( const std::string& file ); const bool load_imgfile( const int loadlevel ); void slot_size_prepared( int w, int h ); void slot_area_updated(int x, int y, int w, int h ); }; class ImgProvider { std::list< Glib::RefPtr< ImgLoader > > m_cache; public: Glib::Mutex m_provider_lock; // ImgProvider操作時の必須ロック public: virtual ~ImgProvider(){} static ImgProvider& get_provider(); Glib::RefPtr< ImgLoader > get_loader( const std::string& file ); void set_loader( Glib::RefPtr< ImgLoader > loader ); private: ImgProvider(); }; } #endif jd-2.8.7-140104/src/jdlib/jdiconv.cpp0000644000076400010400000001440511455622660013616 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jdiconv.h" #include "miscmsg.h" #include "miscutil.h" #include #include #include #include using namespace JDLIB; Iconv::Iconv( const std::string& coding_from, const std::string& coding_to ) : m_buf_in( 0 ), m_buf_out( 0 ), m_coding_from( coding_from ) { #ifdef _DEBUG std::cout << "Iconv::Iconv coding = " << m_coding_from << " to " << coding_to << std::endl; #endif m_buf_in = ( char* )malloc( BUF_SIZE_ICONV_IN ); m_buf_out = ( char* )malloc( BUF_SIZE_ICONV_OUT ); m_cd = iconv_open( coding_to.c_str(), m_coding_from.c_str() ); // MS932で失敗したらCP932で試してみる if( m_cd == ( iconv_t ) -1 ){ if( coding_to == "MS932" ) m_cd = iconv_open( "CP932", m_coding_from.c_str() ); else if( coding_from == "MS932" ) m_cd = iconv_open( coding_to.c_str(), "CP932" ); } // "EUCJP-*"で失敗したら"EUCJP"で試してみる if( m_cd == ( iconv_t ) - 1 && ( errno & EINVAL ) != 0 ) { if( coding_to.find( "EUCJP-", 0 ) == 0 ) { m_cd = iconv_open( "EUCJP//TRANSLIT", coding_from.c_str() ); } else if( coding_from.find( "EUCJP-", 0 ) == 0 ) { const std::string coding_to_translit = coding_to + "//TRANSLIT"; m_cd = iconv_open( coding_to_translit.c_str(), "EUCJP" ); } } if( m_cd == ( iconv_t ) -1 ){ MISC::ERRMSG( "can't open iconv coding = " + m_coding_from + " to " + coding_to ); } m_byte_left_in = 0; } Iconv::~Iconv() { #ifdef _DEBUG std::cout << "Iconv::~Iconv\n"; #endif if( m_buf_in ) free( m_buf_in ); if( m_buf_out ) free( m_buf_out ); if( m_cd != ( iconv_t ) -1 ) iconv_close( m_cd ); } const char* Iconv::convert( char* str_in, int size_in, int& size_out ) { #ifdef _DEBUG std::cout << "Iconv::convert size_in = " << size_in <<" left = " << m_byte_left_in << std::endl; #endif assert( m_byte_left_in + size_in < BUF_SIZE_ICONV_IN ); if( m_cd == ( iconv_t ) -1 ) return NULL; size_t byte_left_out = BUF_SIZE_ICONV_OUT; char* buf_out = m_buf_out; // 前回の残りをコピー if( m_byte_left_in ){ memcpy( m_buf_in, m_buf_in_tmp, m_byte_left_in ); m_buf_in_tmp = m_buf_in; memcpy( m_buf_in + m_byte_left_in , str_in, size_in ); } else m_buf_in_tmp = str_in; m_byte_left_in += size_in; // iconv 実行 do{ #ifdef _DEBUG std::cout << "m_byte_left_in = " << m_byte_left_in << std::endl; std::cout << "byte_left_out = " << byte_left_out << std::endl; #endif const int ret = iconv( m_cd, ( ICONV_CONST char**)&m_buf_in_tmp, &m_byte_left_in, &buf_out, &byte_left_out ); #ifdef _DEBUG std::cout << "--> ret = " << ret << std::endl; std::cout << "m_byte_left_in = " << m_byte_left_in << std::endl; std::cout << "byte_left_out = " << byte_left_out << std::endl; #endif assert( byte_left_out >= 0 ); // エラー if( ret == -1 ){ if( errno == EILSEQ ){ char str_tmp[256]; const unsigned char code0 = *m_buf_in_tmp; const unsigned char code1 = *(m_buf_in_tmp+1); const unsigned char code2 = *(m_buf_in_tmp+2); if( m_coding_from == "MS932" ) { // 空白(0xa0) if( code0 == 0xa0 ){ *m_buf_in_tmp = 0x20; continue; } // <>の誤判別 ( 開発スレ 489 を参照 ) if( code1 == 0x3c && code2 == 0x3e ){ *m_buf_in_tmp = '?'; snprintf( str_tmp, 256, "iconv 0x%x%x> -> ?<>", code0, code1 ); MISC::MSG( str_tmp ); continue; } // マッピング失敗 // □(0x81a0)を表示する if( ( code0 >= 0x81 && code0 <=0x9F ) || ( code0 >= 0xe0 && code0 <=0xef ) ){ *m_buf_in_tmp = 0x81; *(m_buf_in_tmp+1) = 0xa0; snprintf( str_tmp, 256, "iconv 0x%x%x -> □ (0x81a0) ", code0, code1 ); MISC::MSG( str_tmp ); continue; } } // unicode 文字からの変換失敗 // 数値文字参照(&#????;)形式にする if( m_coding_from == "UTF-8" ){ int byte; const int ucs2 = MISC::utf8toucs2( m_buf_in_tmp, byte ); if( byte != 1 ){ const std::string ucs2_str = MISC::itostr( ucs2 ); #ifdef _DEBUG std::cout << "ucs2 = " << ucs2_str << " byte = " << byte << std::endl; #endif m_buf_in_tmp += byte; m_byte_left_in -= byte; *(buf_out++) = '&'; *(buf_out++) = '#'; memcpy( buf_out, ucs2_str.c_str(), ucs2_str.size() ); buf_out += ucs2_str.size(); *(buf_out++) = ';'; byte_left_out -= ucs2_str.size() + 3; continue; } } // 時々空白(0x20)で EILSEQ が出るときがあるのでもう一度トライする if( code0 == 0x20 ) continue; //その他、1文字を空白にして続行 snprintf( str_tmp, 256, "iconv EILSEQ left = %zd code = %x %x %x", m_byte_left_in, code0, code1, code2 ); MISC::ERRMSG( str_tmp ); *m_buf_in_tmp = 0x20; } else if( errno == EINVAL ){ MISC::ERRMSG( "iconv EINVAL\n" ); break; } else if( errno == E2BIG ){ MISC::ERRMSG( "iconv E2BIG\n" ); break; } } } while( m_byte_left_in > 0 ); size_out = BUF_SIZE_ICONV_OUT - byte_left_out; m_buf_out[ size_out ] = '\0'; return m_buf_out; } jd-2.8.7-140104/src/jdlib/jdiconv.h0000644000076400010400000000136110724250034013246 0ustar // ライセンス: GPL2 #ifndef _JDICONV_H #define _JDICONV_H #include #include // iconv の内部で確保するバッファサイズ(バイト) // BUF_SIZE_ICONV_IN を超える入力は扱えないので注意 enum { BUF_SIZE_ICONV_IN = 1024 * 1024, BUF_SIZE_ICONV_OUT = BUF_SIZE_ICONV_IN /2 * 3 }; namespace JDLIB { class Iconv { iconv_t m_cd; size_t m_byte_left_in; char* m_buf_in; char* m_buf_in_tmp; char* m_buf_out; std::string m_coding_from; public: Iconv( const std::string& coding_from, const std::string& coding_to ); ~Iconv(); const char* convert( char* str_in, int size_in, int& size_out ); }; } #endif jd-2.8.7-140104/src/jdlib/jdmigemo.cpp0000644000076400010400000000334410753065065013755 0ustar // ライセンス: GPL2 // // Thanks to 「テスト運用中」スレの18氏 // // http://jd4linux.sourceforge.jp/cgi-bin/bbs/test/read.cgi/support/1149945056/18 // #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_MIGEMO_H //#define _DEBUG #include "jddebug.h" #include "jdmigemo.h" #include #include #include migemo *migemo_object; int jd_migemo_regcomp(regex_t *preg,const char *regex,int cflags) { migemo *m; int retval,i; size_t len; unsigned char *p,*utmp; char *ctmp; m=migemo_object; if(!m){ return -1; } //migemo_load(m,MIGEMO_DICTID_MIGEMO,JD_MIGEMO_DICTNAME); if(!migemo_is_enable(m)){ return -1; } utmp=(unsigned char *)calloc(sizeof(unsigned char),strlen(regex)+1); memcpy(utmp,regex,strlen(regex)); for(i=0;utmp[i]!='\0';i++){ if(utmp[i]=='\n'){ utmp[i]='\0'; break; } } p=migemo_query(m,utmp); free(utmp); for(len=0;p[len]!='\0';len++); ctmp=(char *)calloc(sizeof(char),len+1); memcpy(ctmp,p,len); #ifdef _DEBUG std::cout << "migemo comp:" << ctmp << std::endl; #endif retval=regcomp(preg,ctmp,cflags); free(ctmp); if(retval!=0){ regfree(preg); } migemo_release(m,p); return retval; } int jd_migemo_init(const char *filename) { #ifdef _DEBUG std::cout << "migemo-dict: " << filename << std::endl; #endif migemo_object=migemo_open(filename); if(migemo_is_enable(migemo_object)){ return 1; }else{ migemo_close(migemo_object); migemo_object=NULL; return 0; } } int jd_migemo_close(void) { migemo_close(migemo_object); migemo_object=NULL; return 1; } #endif jd-2.8.7-140104/src/jdlib/jdmigemo.h0000644000076400010400000000120011122725162013377 0ustar // ライセンス: GPL2 // // Thanks to 「テスト運用中」スレの18氏 // // http://jd4linux.sourceforge.jp/cgi-bin/bbs/test/read.cgi/support/1149945056/18 // #ifndef __JD_MIGEMO_H__ #define __JD_MIGEMO_H__ #ifdef HAVE_MIGEMO_H #include #include "jdregex.h" #ifdef __cplusplus extern "C" { #endif int jd_migemo_regcomp(regex_t *preg,const char *regex,int cflags); int jd_migemo_init(const char *filename); int jd_migemo_close(void); #ifdef __cplusplus } #endif #define JD_MIGEMO_DICTNAME ("/usr/share/migemo/utf-8/migemo-dict") #endif /* #ifdef HAVE_MIGEMO_H */ #endif /* #ifndef __JD_MIGEMO_H__ */ jd-2.8.7-140104/src/jdlib/jdregex.cpp0000644000076400010400000001314212127277600013604 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "jdregex.h" #include "miscutil.h" #ifdef HAVE_MIGEMO_H #include "jdmigemo.h" #endif #include enum { MAX_TARGET_SIZE = 64 * 1024, // 全角半角変換のバッファサイズ REGEX_MAX_NMATCH = 32 }; using namespace JDLIB; Regex::Regex() : m_compiled(false), m_target_asc( NULL ), m_table_pos( NULL ) { m_results.clear(); m_pos.clear(); } Regex::~Regex() { dispose(); if( m_target_asc ) free( m_target_asc ); if( m_table_pos ) free( m_table_pos ); } void Regex::dispose() { if ( m_compiled ) { regfree( &m_reg ); m_compiled = false; } } // icase : 大文字小文字区別しない // newline : . に改行をマッチさせない // usemigemo : migemo使用 (コンパイルオプションで指定する必要あり) // wchar : 全角半角の区別をしない const bool Regex::compile( const std::string reg, const bool icase, const bool newline, const bool use_migemo, const bool wchar ) { #ifdef _DEBUG if( wchar ){ std::cout << "Regex::compile\n"; std::cout << reg << std::endl; } #endif dispose(); if( reg.empty() ) return false; #ifdef USE_PCRE int cflags = REG_UTF8; if( ! newline ) cflags |= REG_DOTALL; // . を改行にマッチさせる #else int cflags = REG_EXTENDED; #endif if( newline ) cflags |= REG_NEWLINE; if( icase ) cflags |= REG_ICASE; m_newline = newline; m_wchar = wchar; const char* asc_reg = reg.c_str(); // 全角英数字 → 半角英数字、半角カナ → 全角カナ if( m_wchar && MISC::has_widechar( asc_reg ) ){ if( ! m_target_asc ) m_target_asc = ( char* )malloc( MAX_TARGET_SIZE ); if( ! m_table_pos ) m_table_pos = ( int* )malloc( MAX_TARGET_SIZE ); MISC::asc( asc_reg, m_target_asc, m_table_pos, MAX_TARGET_SIZE ); asc_reg = m_target_asc; #ifdef _DEBUG std::cout << m_target_asc << std::endl; #endif } #ifdef HAVE_MIGEMO_H if( use_migemo ){ if( jd_migemo_regcomp( &m_reg, asc_reg, cflags ) != 0 ){ if( regcomp( &m_reg, asc_reg, cflags ) != 0 ){ regfree( &m_reg ); return false; } } } else{ #endif if( regcomp( &m_reg, asc_reg, cflags ) != 0 ){ regfree( &m_reg ); return false; } #ifdef HAVE_MIGEMO_H } #endif m_compiled = true; return true; } const bool Regex::exec( const std::string& target, const size_t offset ) { regmatch_t pmatch[ REGEX_MAX_NMATCH ]; memset(pmatch, 0, sizeof(pmatch)); if ( ! m_compiled ) return false; if( target.empty() ) return false; if( target.length() <= offset ) return false; m_pos.clear(); m_results.clear(); const char* asc_target = target.c_str() + offset; bool exec_asc = false; // 全角英数字 → 半角英数字、半角カナ → 全角カナ if( m_wchar && MISC::has_widechar( asc_target ) ){ #ifdef _DEBUG std::cout << "Regex::exec offset = " << offset << std::endl; std::cout << target << std::endl; #endif if( ! m_target_asc ) m_target_asc = ( char* )malloc( MAX_TARGET_SIZE ); if( ! m_table_pos ) m_table_pos = ( int* )malloc( MAX_TARGET_SIZE ); MISC::asc( asc_target, m_target_asc, m_table_pos, MAX_TARGET_SIZE ); exec_asc = true; asc_target = m_target_asc; #ifdef _DEBUG std::cout << m_target_asc << std::endl; #endif } #ifdef USE_ONIG // 鬼車はnewlineを無視するようなので、文字列のコピーを取って // 改行をスペースにしてから実行する if( ! m_newline ){ std::string target_copy = asc_target; for( size_t i = 0; i < target_copy.size(); ++i ) if( target_copy[ i ] == '\n' ) target_copy[ i ] = ' '; if( regexec( &m_reg, target_copy.c_str(), REGEX_MAX_NMATCH, pmatch, 0 ) != 0 ){ return false; } } else #endif if( regexec( &m_reg, asc_target, REGEX_MAX_NMATCH, pmatch, 0 ) != 0 ){ return false; } for( int i = 0; i < REGEX_MAX_NMATCH; ++i ){ int so = pmatch[ i ].rm_so; int eo = pmatch[ i ].rm_eo; if( exec_asc && so >= 0 && eo >= 0 ){ #ifdef _DEBUG std::cout << "so = " << so << " eo = " << eo; #endif so = m_table_pos[ so ]; eo = m_table_pos[ eo ]; #ifdef _DEBUG std::cout << " -> so = " << so << " eo = " << eo << std::endl; #endif } so += offset; eo += offset; m_pos.push_back( so ); if( so >= 0 && eo >= 0 ) m_results.push_back( target.substr( so, eo - so ) ); else m_results.push_back( std::string() ); } return true; } // icase : 大文字小文字区別しない // newline : . に改行をマッチさせない // usemigemo : migemo使用 (コンパイルオプションで指定する必要あり) // wchar : 全角半角の区別をしない const bool Regex::exec( const std::string reg, const std::string& target, const size_t offset, const bool icase, const bool newline, const bool use_migemo, const bool wchar ) { if ( ! compile(reg, icase, newline, use_migemo, wchar ) ) return false; if ( ! exec(target, offset) ){ dispose(); return false; } dispose(); return true; } const std::string Regex::str( const size_t num ) { if( m_results.size() > num ) return m_results[ num ]; return std::string(); } const int Regex::pos( const size_t num ) { if( m_results.size() > num ) return m_pos[ num ]; return -1; } jd-2.8.7-140104/src/jdlib/jdregex.h0000644000076400010400000000265411724326274013263 0ustar // ライセンス: GPL2 #ifndef _JDREGEX_H #define _JDREGEX_H #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef USE_ONIG #include #elif defined( USE_PCRE ) #include #else #include #endif /** USE_ONIG **/ namespace JDLIB { class Regex { std::vector< int > m_pos; std::vector< std::string > m_results; regex_t m_reg; bool m_compiled; bool m_newline; bool m_wchar; char *m_target_asc; int *m_table_pos; public: Regex(); ~Regex(); void dispose(); // icase : 大文字小文字区別しない // newline : . に改行をマッチさせない // usemigemo : migemo使用 (コンパイルオプションで指定する必要あり) // wchar : 全角半角の区別をしない const bool compile( const std::string reg , const bool icase, const bool newline, const bool usemigemo, const bool wchar ); const bool exec( const std::string& target, const size_t offset ); const bool exec( const std::string reg, const std::string& target, const size_t offset , const bool icase, const bool newline, const bool usemigemo, const bool wchar ); const int pos( const size_t num ); const std::string str( const size_t num ); }; } #endif jd-2.8.7-140104/src/jdlib/jdthread.cpp0000644000076400010400000000516711235623006013743 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "jdthread.h" #include "miscmsg.h" #include #include using namespace JDLIB; Thread::Thread() { JDTH_CLEAR( m_thread ); #ifdef USE_GTHREAD if( !Glib::thread_supported() ) Glib::thread_init(); #endif } Thread::~Thread() { #ifdef _DEBUG std::cout << "Thread::~Thread\n"; assert( ! is_running() ); #endif join(); } #ifdef USE_GTHREAD void Thread::slot_wrapper( STARTFUNC func, void* arg ) { func( arg ); } #endif // スレッド作成 const bool Thread::create( STARTFUNC func , void* arg, const bool detach, const int stack_kbyte ) { if( JDTH_ISRUNNING( m_thread ) ){ MISC::ERRMSG( "Thread::create : thread is already running" ); return false; } #ifdef USE_GTHREAD // gthread 使用 #ifdef _DEBUG std::cout << "Thread::create (gthread)\n"; #endif try { m_thread = Glib::Thread::create( sigc::bind( sigc::ptr_fun( Thread::slot_wrapper ), func, arg ), stack_kbyte * 1024, ! detach, true, Glib::THREAD_PRIORITY_NORMAL ); } catch( Glib::ThreadError& err ) { MISC::ERRMSG( err.what() ); return false; } if( detach ){ #ifdef _DEBUG std::cout << "detach\n"; #endif JDTH_CLEAR( m_thread ); } #else // pthread 使用 #ifdef _DEBUG std::cout << "Thread::create (pthread)\n"; #endif int status; pthread_attr_t attr; size_t stacksize = PTHREAD_STACK_MIN + stack_kbyte * 1024; pthread_attr_init( &attr ); pthread_attr_setstacksize( &attr, stacksize ); status = pthread_create( &m_thread, &attr, func, arg ); pthread_attr_destroy( &attr ); if( status ){ MISC::ERRMSG( std::string( "Thread::create : " ) + strerror( status ) ); return false; } if( detach ){ #ifdef _DEBUG std::cout << "detach\n"; #endif pthread_detach( m_thread ); JDTH_CLEAR( m_thread ); } #endif // USE_GTHREAD #ifdef _DEBUG std::cout << "thread = " << m_thread << std::endl; #endif return true; } const bool Thread::join() { if( ! JDTH_ISRUNNING( m_thread ) ) return true; #ifdef _DEBUG std::cout << "Thread:join thread = " << m_thread << std::endl; #endif #ifdef USE_GTHREAD // gthread 使用 if( m_thread->joinable() ){ m_thread->join(); } JDTH_CLEAR( m_thread ); #else // pthread 使用 int status = pthread_join( m_thread, NULL ); JDTH_CLEAR( m_thread ); if( status ){ MISC::ERRMSG( std::string( "Thread::join : " ) + strerror( status ) ); return false; } #endif // USE_GTHREAD return true; } jd-2.8.7-140104/src/jdlib/jdthread.h0000644000076400010400000000210011235623006013370 0ustar // ライセンス: GPL2 // スレッドクラス #ifndef _JDTHREAD_H #define _JDTHREAD_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef USE_GTHREAD #include #define JDTH_TYPE Glib::Thread* #define JDTH_ISRUNNING( pth ) ( ( pth ) != NULL ) #define JDTH_CLEAR( pth ) ( ( pth ) = NULL ) #else #include #define JDTH_TYPE pthread_t #define JDTH_ISRUNNING( pth ) ( pth ) #define JDTH_CLEAR( pth ) ( pth = 0 ) #endif typedef void* ( *STARTFUNC )( void * ); enum { DEFAULT_STACKSIZE = 64 }; namespace JDLIB { enum { DETACH = true, NODETACH = false }; class Thread { JDTH_TYPE m_thread; #ifdef USE_GTHREAD static void slot_wrapper( STARTFUNC func, void* arg ); #endif public: Thread(); virtual ~Thread(); const bool is_running() const { return JDTH_ISRUNNING( m_thread ); } // スレッド作成 const bool create( STARTFUNC func , void * arg, const bool detach, const int stack_kbyte = DEFAULT_STACKSIZE ); const bool join(); }; } #endif jd-2.8.7-140104/src/jdlib/loader.cpp0000644000076400010400000012760711636104156013435 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _DEBUG_CHUNKED //#define _DEBUG_TIME #ifdef _WIN32 #define STRICT #endif #include "jddebug.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "loader.h" #include "miscmsg.h" #include "miscutil.h" #include "ssl.h" #ifdef _DEBUG_TIME #include "misctime.h" #endif #include "config/globalconf.h" #include "skeleton/loadable.h" #include "httpcode.h" #include #include #include #include #ifdef _WIN32 #include #else #include #include #endif #include #include enum { MAX_LOADER = 10, // 最大スレッド数 MAX_LOADER_SAMEHOST = 2, // 同一ホストに対して実行できる最大スレッド数 LNG_BUF_MIN = 1 * 1024, // 読み込みバッファの最小値 (byte) TIMEOUT_MIN = 1 // タイムアウトの最小値 (秒) }; #ifdef _WIN32 bool initialized_loader = false; #endif // // トークンとスレッド起動待ちキュー // // 起動しているローダが MAX_LOADER 個を越えたらローダをスレッド待ちキューに入れる // namespace JDLIB { const bool get_token( JDLIB::Loader* loader ); void return_token( JDLIB::Loader* loader ); void push_loader_queue( JDLIB::Loader* loader ); const bool remove_loader_queue( JDLIB::Loader* loader ); void pop_loader_queue(); } Glib::StaticMutex mutex_token = GLIBMM_STATIC_MUTEX_INIT; Glib::StaticMutex mutex_queue = GLIBMM_STATIC_MUTEX_INIT; std::list< JDLIB::Loader* > queue_loader; // スレッド起動待ちの Loader のキュー int token_loader = 0; std::vector< JDLIB::Loader* > vec_loader( MAX_LOADER ); bool disable_pop = false; // トークン取得 const bool JDLIB::get_token( JDLIB::Loader* loader ) { Glib::Mutex::Lock lock( mutex_token ); #ifdef _DEBUG std::cout << "JDLIB::get_token : url = " << loader->data().url << " token = " << token_loader << std::endl; #endif if( token_loader >= MAX_LOADER ) return false; int count = 0; std::vector< JDLIB::Loader* >::iterator it = vec_loader.begin(); for( ; it != vec_loader.end(); ++it ) if( ( *it ) && ( *it )->data().host == loader->data().host ) ++count; #ifdef _DEBUG std::cout << "count = " << count << std::endl; #endif const int max_loader = MIN( MAX_LOADER_SAMEHOST, MAX( 1, CONFIG::get_connection_num() ) ); if( count >= max_loader ) return false; #ifdef _DEBUG std::cout << "got token\n"; #endif ++token_loader; it = vec_loader.begin(); for( ; it != vec_loader.end(); ++it ) if( ! ( *it ) ){ ( *it ) = loader; break; } return true; } // トークン返す void JDLIB::return_token( JDLIB::Loader* loader ) { Glib::Mutex::Lock lock( mutex_token ); --token_loader; assert( token_loader >= 0 ); std::vector< JDLIB::Loader* >::iterator it = vec_loader.begin(); for( ; it != vec_loader.end(); ++it ) if( ( *it ) == loader ) ( *it ) = NULL; #ifdef _DEBUG std::cout << "JDLIB::return_token : url = " << loader->data().url << " token = " << token_loader << std::endl; #endif } // スレッド起動待ちキューに Loader を登録 void JDLIB::push_loader_queue( JDLIB::Loader* loader ) { Glib::Mutex::Lock lock( mutex_queue ); if( ! loader ) return; if( loader->get_low_priority() ) queue_loader.push_back( loader ); else{ std::list< JDLIB::Loader* >::iterator pos = queue_loader.begin(); for( ; pos != queue_loader.end(); ++pos ) if( ( *pos )->get_low_priority() ) break; queue_loader.insert( pos, loader ); } #ifdef _DEBUG std::cout << "JDLIB::push_loader_queue url = " << loader->data().url << " size = " << queue_loader.size() << std::endl; #endif } // キューから Loader を取り除いたらtrueを返す const bool JDLIB::remove_loader_queue( JDLIB::Loader* loader ) { Glib::Mutex::Lock lock( mutex_queue ); if( ! queue_loader.size() ) return false; if( std::find( queue_loader.begin(), queue_loader.end(), loader ) == queue_loader.end() ) return false; queue_loader.remove( loader ); #ifdef _DEBUG std::cout << "JDLIB::remove_loader_queue url = " << loader->data().url << " size = " << queue_loader.size() << std::endl; #endif return true; } // キューに登録されたスレッドを起動する void JDLIB::pop_loader_queue() { Glib::Mutex::Lock lock( mutex_queue ); if( disable_pop ) return; if( ! queue_loader.size() ) return; #ifdef _DEBUG std::cout << "JDLIB::pop_loader_queue size = " << queue_loader.size() << std::endl; #endif std::list< JDLIB::Loader* >::iterator it = queue_loader.begin(); for( ; it != queue_loader.end(); ++it ) if( JDLIB::get_token( *it ) ) break; if( it == queue_loader.end() ) return; JDLIB::Loader* loader = *it; queue_loader.remove( loader ); #ifdef _DEBUG std::cout << "pop " << loader->data().url << std::endl; #endif loader->create_thread(); } // // ローダの起動待ちキューにあるスレッドを実行しない // // アプリ終了時にこの関数を呼び出さないとキューに登録されたスレッドが起動してしまうので注意 // void JDLIB::disable_pop_loader_queue() { Glib::Mutex::Lock lock( mutex_queue ); #ifdef _DEBUG std::cout << "JDLIB::disable_pop_loader_queue\n"; #endif disable_pop = true; } // // mainの最後でローダが動いていないかチェックする関数 // void JDLIB::check_loader_alive() { #ifdef _DEBUG std::cout << "JDLIB::check_loader_alive loader = " << token_loader << " queue = " << queue_loader.size() << std::endl; #endif if( token_loader ){ MISC::ERRMSG( "loaders are still moving." ); assert( false ); } if( queue_loader.size() ){ MISC::ERRMSG( "queue of loaders are not empty." ); assert( false ); } #ifdef _WIN32 if ( initialized_loader ){ WSACleanup(); } #endif } /////////////////////////////////////////////////// using namespace JDLIB; // // low_priority = true の時はスレッド起動待ち状態になった時に、起動順のプライオリティを下げる // Loader::Loader( const bool low_priority ) : m_addrinfo( 0 ), m_stop( false ), m_loading( false ), m_low_priority( low_priority ), m_buf( 0 ), m_buf_zlib_in ( 0 ), m_buf_zlib_out ( 0 ), m_use_zlib ( 0 ) { #ifdef _DEBUG std::cout << "Loader::Loader : loader was created.\n"; #endif #ifdef _WIN32 if ( !initialized_loader ){ WSADATA wsaData; if ( WSAStartup(MAKEWORD(2,0), &wsaData) != 0 ){ MISC::ERRMSG( "could not startup winsock2" ); } initialized_loader = true; } #endif clear(); } Loader::~Loader() { #ifdef _DEBUG std::cout << "Loader::~Loader : url = " << m_data.url << std::endl; #endif clear(); // assert( ! m_loading ); } void Loader::clear() { #ifdef _DEBUG std::cout << "Loader::clear\n"; #endif stop(); wait(); m_loadable = NULL; m_use_chunk = false; if( m_buf ) free( m_buf ); m_buf = NULL; if( m_buf_zlib_in ) free( m_buf_zlib_in ); m_buf_zlib_in = NULL; if( m_buf_zlib_out ) free( m_buf_zlib_out ); m_buf_zlib_out = NULL; if( m_use_zlib ) inflateEnd( &m_zstream ); m_use_zlib = false; } void Loader::wait() { m_thread.join(); } void Loader::stop() { if( ! m_loading ) return; #ifdef _DEBUG std::cout << "Loader::stop : url = " << m_data.url << std::endl; #endif m_stop = true; // スレッド起動待ち状態の時は SKELETON::Loadable にメッセージを送る if( JDLIB::remove_loader_queue( this ) ){ m_data.code = HTTP_TIMEOUT; m_data.modified = std::string(); m_data.str_code = "stop loading"; finish_loading(); } } // // ダウンロード開始 // // data_in でセットする必要がある項目 ( url は必須 ) // // url // head ( true なら HEAD 送信 ) // port ( == 0 ならプロトコルを見て自動認識 ) // str_post( != empty なら POST する。UTF-8であること ) // modified // byte_readfrom ( != 0 ならその位置からレジューム) // agent // referer // cookie_for_write // host_proxy ( != empty ならproxy使用 ) // port_proxy ( == 0 なら 8080 ) // basicauth_proxy // size_buf ( バッファサイズ, k 単位で指定。 == 0 ならデフォルトサイズ(LNG_BUF_MIN)使用) // timeout ( タイムアウト秒。==0 ならデフォルト( TIMEOUT )使用 ) // basicauth // bool Loader::run( SKELETON::Loadable* cb, const LOADERDATA& data_in ) { assert( ! data_in.url.empty() ); #ifdef _DEBUG std::cout << "Loader::run : url = " << data_in.url << std::endl; #endif if( m_loading ){ MISC::ERRMSG( "now loading : " + data_in.url ); return false; } clear(); m_loadable = cb; m_data.init(); m_stop = false; // バッファサイズ設定 m_data.size_buf = data_in.size_buf; m_lng_buf = MAX( LNG_BUF_MIN, m_data.size_buf * 1024 ); m_lng_buf_zlib_in = m_lng_buf * 2; m_lng_buf_zlib_out = m_lng_buf * 10; // 小さいとパフォーマンスが落ちるので少し多めに10倍位 // protocol と host と path 取得 m_data.url = data_in.url; size_t i = m_data.url.find( "://", 0 ); // "http://" とつけるのは呼び出し側の責任で if( i == std::string::npos ){ m_data.code = HTTP_ERR; m_data.str_code = "could nod get protocol : " + m_data.url; MISC::ERRMSG( m_data.str_code ); return false; } i += 3; m_data.protocol = data_in.url.substr( 0, i ); size_t i2 = m_data.url.find( "/", i ); if( i2 == std::string::npos ){ m_data.code = HTTP_ERR; m_data.str_code = "could not get hostname and path : " + m_data.url; MISC::ERRMSG( m_data.str_code ); return false; } m_data.host = m_data.url.substr( i, i2 - i ); i = i2; m_data.path = m_data.url.substr( i2 ); // ポートセット // ホスト名の後に指定されている if( ( i = m_data.host.find( ":" ) ) != std::string::npos ){ m_data.port = atoi( m_data.host.substr( i+1 ).c_str() ); m_data.host = m_data.host.substr( 0, i ); } // 明示的に指定 else if( data_in.port != 0 ) m_data.port = data_in.port; // プロトコルを見て自動決定 else{ // http if( m_data.protocol.find( "http://" ) != std::string::npos ) m_data.port = 80; // https else if( m_data.protocol.find( "https://" ) != std::string::npos ){ m_data.use_ssl = true; m_data.async = false; m_data.port = 443; } // その他 else{ m_data.code = HTTP_ERR; m_data.str_code = "unknown protocol : " + m_data.url; MISC::ERRMSG( m_data.str_code ); return false; } } // 明示的にssl使用指定 if( data_in.use_ssl ){ m_data.use_ssl = true; m_data.async = false; m_data.port = 443; } // プロキシ m_data.host_proxy = data_in.host_proxy; // 先頭に *tp:// が付いていたら取り除く if( ! m_data.host_proxy.empty() && m_data.host_proxy.find( "tp://" ) != std::string::npos ){ const bool protocol = false; m_data.host_proxy = MISC::get_hostname( m_data.host_proxy , protocol ); } if( ! m_data.host_proxy.empty() ){ m_data.port_proxy = data_in.port_proxy; if( m_data.port_proxy == 0 ) m_data.port_proxy = 8080; m_data.basicauth_proxy = data_in.basicauth_proxy; } // その他 m_data.head = data_in.head; m_data.str_post = data_in.str_post; m_data.modified = data_in.modified; m_data.byte_readfrom = data_in.byte_readfrom; m_data.contenttype = data_in.contenttype; m_data.agent = data_in.agent; m_data.referer = data_in.referer; m_data.cookie_for_write = data_in.cookie_for_write; m_data.timeout = MAX( TIMEOUT_MIN, data_in.timeout ); m_data.ex_field = data_in.ex_field; m_data.basicauth = data_in.basicauth; m_data.use_ipv6 = data_in.use_ipv6; #ifdef _DEBUG std::cout << "host: " << m_data.host << std::endl; std::cout << "protocol: " << m_data.protocol << std::endl; std::cout << "path: " << m_data.path << std::endl; std::cout << "port: " << m_data.port << std::endl; std::cout << "modified: " << m_data.modified << std::endl; std::cout << "byte_readfrom: " << m_data.byte_readfrom << std::endl; std::cout << "contenttype: " << m_data.contenttype << std::endl; std::cout << "agent: " << m_data.agent << std::endl; std::cout << "referer: " << m_data.referer << std::endl; std::cout << "cookie: " << m_data.cookie_for_write << std::endl; std::cout << "proxy: " << m_data.host_proxy << std::endl; std::cout << "port of proxy: " << m_data.port_proxy << std::endl; std::cout << "proxy basicauth : " << m_data.basicauth_proxy << std::endl; std::cout << "buffer size: " << m_lng_buf / 1024 << " Kb" << std::endl; std::cout << "timeout : " << m_data.timeout << " sec" << std::endl; std::cout << "ex_field : " << m_data.ex_field << std::endl; std::cout << "basicauth : " << m_data.basicauth << std::endl; std::cout << "\n"; #endif m_loading = true; // トークンを取得出来なかったら、他のスレッドが終了した時に // 改めて create_thread() を呼び出す if( get_token( this ) ) create_thread(); else JDLIB::push_loader_queue( this ); return true; } // // スレッド起動 // void Loader::create_thread() { #ifdef _DEBUG std::cout << "Loader::create_thread : url = " << m_data.url << std::endl; #endif if( ! m_thread.create( ( STARTFUNC ) launcher, ( void * ) this, JDLIB::NODETACH ) ){ m_data.code = HTTP_ERR; m_data.str_code = "Loader::run : could not start thread"; MISC::ERRMSG( m_data.str_code ); finish_loading(); return; } } // // スレッドのランチャ (static) // void* Loader::launcher( void* dat ) { Loader* tt = ( Loader * ) dat; tt->run_main(); return 0; } // // 実際の処理部 // void Loader::run_main() { // エラーメッセージ std::string errmsg; #ifdef _WIN32 SOCKET soc; // ソケットID #else int soc = -1; // ソケットID #endif bool use_proxy = ( ! m_data.host_proxy.empty() ); JDLIB::JDSSL* ssl = NULL; // 送信メッセージ作成 const std::string msg_send = create_msg_send(); #ifdef _DEBUG std::cout << "Loader::run_main : start loading thread : " << m_data.url << std::endl;; if( use_proxy ) std::cout << "use_proxy : " << m_data.host_proxy << std::endl; std::cout <<"send :----------\n" << msg_send << "\n---------------\n"; #endif // addrinfo 取得 if( m_data.host_proxy.empty() ){ m_addrinfo = get_addrinfo( m_data.host, m_data.port ); if( ! m_addrinfo ){ m_data.code = HTTP_ERR; errmsg = "getaddrinfo failed : " + m_data.url; goto EXIT_LOADING; } } else{ m_addrinfo = get_addrinfo( m_data.host_proxy, m_data.port_proxy ); if( ! m_addrinfo ){ m_data.code = HTTP_ERR; errmsg = "getaddrinfo failed : " + m_data.host_proxy; goto EXIT_LOADING; } } // ソケット作成 soc = socket( m_addrinfo ->ai_family, m_addrinfo ->ai_socktype, m_addrinfo ->ai_protocol ); #ifdef _WIN32 if ( soc == INVALID_SOCKET ){ #else if ( soc < 0 ){ #endif m_data.code = HTTP_ERR; errmsg = "socket failed : " + m_data.url; goto EXIT_LOADING; } // ソケットを非同期に設定 if( m_data.async ){ #ifdef _WIN32 u_long flags = 0; if ( ioctlsocket( soc, FIONBIO, &flags) != 0 ){ #else int flags; flags = fcntl( soc, F_GETFL, 0); if( flags == -1 || fcntl( soc, F_SETFL, flags | O_NONBLOCK ) < 0 ){ #endif m_data.code = HTTP_ERR; errmsg = "fcntl failed"; goto EXIT_LOADING; } } // サーバにconnect int ret; ret = connect( soc, m_addrinfo ->ai_addr, m_addrinfo ->ai_addrlen ); if( ret != 0 ){ // ノンブロックでまだ接続中 #ifdef _WIN32 if ( !( m_data.async && WSAGetLastError() == WSAEWOULDBLOCK ) ){ #else if ( !( m_data.async && errno == EINPROGRESS ) ){ #endif m_data.code = HTTP_ERR; if( ! use_proxy ) errmsg = "connect failed : " + m_data.host; else errmsg = "connect failed : " + m_data.host_proxy; goto EXIT_LOADING; } } // connect待ち if( m_data.async ){ if( ! wait_recv_send( soc, false ) ){ // タイムアウト m_data.code = HTTP_TIMEOUT; errmsg = "connect timeout"; goto EXIT_LOADING; } // connectが成功したかチェック int optval; socklen_t optlen = sizeof( int ); #ifdef _WIN32 if( getsockopt( soc, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen ) != 0 ){ #else if( getsockopt( soc, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen ) < 0 ){ #endif m_data.code = HTTP_ERR; errmsg = "getsockopt failed"; goto EXIT_LOADING; } if( optval != 0 ){ m_data.code = HTTP_ERR; errmsg = "connect(getsockopt) failed"; goto EXIT_LOADING; } #ifdef _DEBUG std::cout << "connect ok\n"; #endif } // ssl 初期化とコネクト if( m_data.use_ssl ){ ssl = new JDLIB::JDSSL(); if( ! ssl->connect( soc ) ){ m_data.code = HTTP_ERR; errmsg = ssl->get_errmsg() + " : " + m_data.url; goto EXIT_LOADING; } } // SEND 又は POST // 通常 if( !ssl ){ size_t send_size = strlen( msg_send.data() ); while( send_size > 0 && !m_stop ){ // writefds 待ち if( ! wait_recv_send( soc, false ) ){ // タイムアウト m_data.code = HTTP_TIMEOUT; errmsg = "send timeout"; goto EXIT_LOADING; } // SEND 又は POST #ifdef _WIN32 ssize_t tmpsize = send( soc, msg_send.data(), send_size,0); int lastError = WSAGetLastError(); #else #ifdef MSG_NOSIGNAL ssize_t tmpsize = send( soc, msg_send.data(), send_size, MSG_NOSIGNAL ); #else // SolarisにはMSG_NOSIGNALが無いのでSIGPIPEをIGNOREする (FreeBSD4.11Rにもなかった) signal( SIGPIPE , SIG_IGN ); /* シグナルを無視する */ ssize_t tmpsize = send( soc, msg_send.data(), send_size,0); signal(SIGPIPE,SIG_DFL); /* 念のため戻す */ #endif // MSG_NOSIGNAL #endif // _WIN32 #ifdef _WIN32 if( tmpsize == 0 || ( tmpsize < 0 && !( lastError == WSAEWOULDBLOCK || errno == WSAEINTR ) ) ){ #else if( tmpsize == 0 || ( tmpsize < 0 && !( errno == EWOULDBLOCK || errno == EINTR ) ) ){ #endif m_data.code = HTTP_ERR; errmsg = "send failed : " + m_data.url; goto EXIT_LOADING; } if( tmpsize > 0 ) send_size -= tmpsize; } if( m_stop ) goto EXIT_LOADING; #ifdef _DEBUG std::cout << "send ok\n"; #endif } // SSL使用 else{ if( ssl->write( msg_send.data(), strlen( msg_send.data() ) ) < 0 ){ m_data.code = HTTP_ERR; errmsg = ssl->get_errmsg() + " : " + m_data.url; goto EXIT_LOADING; } } // 受信用バッファを作ってメッセージ受信 size_t mrg; mrg = 64; // 一応オーバーフロー避けのおまじない assert( m_buf == NULL ); m_buf = ( char* )malloc( m_lng_buf + mrg ); bool receiving_header; #ifdef _DEBUG_TIME MISC::start_measurement( 1 ); #endif // 受信開始 receiving_header = true; m_data.length_current = 0; m_data.size_data = 0; do{ // 読み込み size_t read_size = 0; while( read_size < m_lng_buf - mrg && !m_stop ){ ssize_t tmpsize; // 通常 if( !ssl ){ #ifdef _DEBUG_TIME MISC::start_measurement( 0 ); #endif // readfds 待ち if( !wait_recv_send( soc, true ) ){ // タイムアウト m_data.code = HTTP_TIMEOUT; errmsg = "read timeout"; goto EXIT_LOADING; } tmpsize = recv( soc, m_buf + read_size, m_lng_buf - read_size - mrg, 0 ); if( tmpsize < 0 && errno != EINTR ){ m_data.code = HTTP_ERR; errmsg = "recv() failed"; goto EXIT_LOADING; } #ifdef _DEBUG_TIME std::cout << "size = " << tmpsize << " time = " << MISC::measurement( 0 ) << std::endl; #endif } // SSL else{ tmpsize = ssl->read( m_buf + read_size, m_lng_buf - read_size - mrg ); if( tmpsize < 0 ){ m_data.code = HTTP_ERR; errmsg = ssl->get_errmsg() + " : " + m_data.url; goto EXIT_LOADING; } } if( tmpsize == 0 ) break; if( tmpsize > 0 ){ read_size += tmpsize; // ヘッダ取得 if( receiving_header ){ const int ret = receive_header( m_buf, read_size ); if( ret == HTTP_ERR ){ m_data.code = HTTP_ERR; errmsg = "invalid header : " + m_data.url; goto EXIT_LOADING; } else if( ret == HTTP_OK ) receiving_header = false; } if( m_data.length && m_data.length <= m_data.length_current + read_size ) break; } } m_buf[ read_size ] = '\0'; // 停止指定 if( m_stop ) break; // サーバ側がcloseした if( read_size == 0 ){ // ヘッダを取得する前にcloseしたらエラー if( receiving_header && m_data.size_data == 0 ){ m_data.code = HTTP_ERR; errmsg = "no data"; goto EXIT_LOADING; } // コード304等の場合は終了 break; } // ヘッダ取得失敗 if( receiving_header ){ m_data.code = HTTP_ERR; errmsg = "no http header"; goto EXIT_LOADING; } m_data.length_current += read_size; // chunkedな場合 if( m_use_chunk ){ if( !skip_chunk( m_buf, read_size ) ){ m_data.code = HTTP_ERR; errmsg = "skip_chunk() failed : " + m_data.url; goto EXIT_LOADING; } if( ! read_size ) continue; } // 圧縮されていない時はそのままコールバック呼び出し if( !m_use_zlib ) { m_data.size_data += read_size; // コールバック呼び出し if( m_loadable ) m_loadable->receive( m_buf, read_size ); } // 圧縮されているときは unzip してからコールバック呼び出し else if( !unzip( m_buf, read_size ) ){ m_data.code = HTTP_ERR; errmsg = "unzip() failed : " + m_data.url; goto EXIT_LOADING; } if( m_data.length && m_data.length <= m_data.length_current ) break; } while( !m_stop ); #ifdef _DEBUG_TIME std::cout << "loadingl time = " << MISC::measurement( 1 ) << std::endl; #endif // 終了処理 EXIT_LOADING: // ssl クローズ if( ssl ){ ssl->close(); delete ssl; ssl = NULL; } if( soc >= 0 ){ // writefds待ち // 待たないとclose()したときにfinパケットが消える? if( ! wait_recv_send( soc, false ) ){ // タイムアウト m_data.code = HTTP_TIMEOUT; errmsg = "send timeout"; } // 送信禁止 #ifdef _WIN32 shutdown( soc, SD_SEND ); #else shutdown( soc, SHUT_WR ); #endif } // 強制停止した場合 if( m_stop ){ #ifdef _DEBUG std::cout << "Loader::run_main : stop loading\n"; #endif m_data.code = HTTP_TIMEOUT; m_data.modified = std::string(); m_data.str_code = "stop loading"; } // エラーあり else if( ! errmsg.empty() ){ m_data.modified = std::string(); MISC::ERRMSG( errmsg ); m_data.str_code = errmsg; } // ソケットクローズ if( soc >= 0 ) close( soc ); // addrinfo開放 if( m_addrinfo ) freeaddrinfo( m_addrinfo ); m_addrinfo = NULL; // トークン返す return_token( this ); finish_loading(); #ifdef _DEBUG std::cout << "Loader::run_main : finish loading : " << m_data.url << std::endl;; std::cout << "read size : " << m_data.length_current << " / " << m_data.length << std::endl;; std::cout << "data size : " << m_data.size_data << std::endl;; std::cout << "code : " << m_data.code << std::endl << std::endl; #endif } // // addrinfo 取得 // struct addrinfo* Loader::get_addrinfo( const std::string& hostname, const int port ) { if( port < 0 || port > 65535 ) return NULL; if( hostname.empty() ) return NULL; int ret; struct addrinfo hints, *res; const int poststrlng = 256; char port_str[ poststrlng ]; memset( &hints, 0, sizeof( addrinfo ) ); if( m_data.use_ipv6 ) hints.ai_family = AF_UNSPEC; else hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; snprintf( port_str, poststrlng, "%d", port ); ret = getaddrinfo( hostname.c_str(), port_str, &hints, &res ); if( ret ) { MISC::ERRMSG( m_data.str_code ); return NULL; } #ifdef _DEBUG std::cout << "host = " << hostname << " ipv6 = " << m_data.use_ipv6 << ", ip =" << inet_ntoa( ( ( sockaddr_in* )( res->ai_addr ) )->sin_addr ) << std::endl; #endif return res; } // // 送信メッセージ作成 // const std::string Loader::create_msg_send() { bool post_msg = ( !m_data.str_post.empty() && !m_data.head ); bool use_proxy = ( ! m_data.host_proxy.empty() ); std::ostringstream msg; msg.clear(); if( m_data.head ) msg << "HEAD "; else if( ! post_msg ) msg << "GET "; else msg << "POST "; if( ! use_proxy ) msg << m_data.path << " HTTP/1.1\r\n"; else { msg << m_data.protocol << m_data.host << ":" << m_data.port << m_data.path << " HTTP/1.1\r\n"; } msg << "Host: " << m_data.host << "\r\n"; if( ! m_data.contenttype.empty() ) msg << "Content-Type: " << m_data.contenttype << "\r\n"; if( ! m_data.agent.empty() ) msg << "User-Agent: " << m_data.agent << "\r\n"; if( ! m_data.referer.empty() ) msg << "Referer: " << m_data.referer << "\r\n"; // basic認証 if( ! m_data.basicauth.empty() ) msg << "Authorization: Basic " << MISC::base64( m_data.basicauth ) << "\r\n"; // proxy basic認証 if( use_proxy && ! m_data.basicauth_proxy.empty() ) msg << "Proxy-Authorization: Basic " << MISC::base64( m_data.basicauth_proxy ) << "\r\n"; if( ! m_data.cookie_for_write.empty() ) msg << "Cookie: " << m_data.cookie_for_write << "\r\n"; if( ! m_data.modified.empty() ) msg << "If-Modified-Since: " << m_data.modified << "\r\n"; // レジュームするときは gzip は受け取らない if( m_data.byte_readfrom ){ msg << "Range: bytes=" << m_data.byte_readfrom << "-\r\n"; // プロキシ使う場合は no-cache 指定 if( use_proxy ) msg << "Cache-Control: no-cache\r\n"; } else msg << "Accept-Encoding: gzip\r\n"; // レジュームしないなら gzip 受け取り可能 // その他のフィールド if( ! m_data.ex_field.empty() ) msg << m_data.ex_field; msg << "Connection: close\r\n"; // POST する文字列 if( post_msg ){ msg << "Content-Length: " << m_data.str_post.length() << "\r\n"; msg << "\r\n"; msg << m_data.str_post; msg << "\r\n"; } msg << "\r\n"; return msg.str(); } // // サーバから送られてきた生データからヘッダ取得 // // 戻り値 : 成功 HTTP_OK、失敗 HTTP_ERR、未処理 HTTP_INIT // // 入力 // buf : 生データ // readsize: 生データサイズ // // 出力 // buf : ヘッダが取り除かれたデータ // readsize: 出力データサイズ // const int Loader::receive_header( char* buf, size_t& read_size ) { #ifdef _DEBUG std::cout << "Loader::receive_header : read_size = " << read_size << std::endl; #endif buf[ read_size ] = '\0'; m_data.str_header = buf; size_t lng_header = m_data.str_header.find( "\r\n\r\n" ); if( lng_header != std::string::npos ) lng_header += 4; else{ lng_header = m_data.str_header.find( "\n\n" ); if( lng_header != std::string::npos ) lng_header +=2; else return HTTP_INIT; } m_data.str_header.resize( lng_header ); #ifdef _DEBUG std::cout << "header : size = " << lng_header << " byte\n"; std::cout << m_data.str_header << std::endl; #endif if( ! analyze_header() ) return HTTP_ERR; // 残りのデータを前に移動 read_size -= lng_header; if( read_size ){ memmove( buf, buf+ lng_header, read_size ); buf[ read_size ] = '\0'; } return HTTP_OK; } // // ヘッダ解析 // bool Loader::analyze_header() { // コード std::string str_tmp = analyze_header_option( "HTTP/1.1 " ); if( ! str_tmp.empty() ){ m_data.str_code = "HTTP/1.1 " + str_tmp; } else{ str_tmp = analyze_header_option( "HTTP/1.0 " ); if( ! str_tmp.empty() ) m_data.str_code = "HTTP/1.0 " + str_tmp; } if( str_tmp.empty() ){ MISC::ERRMSG( "could not find HTTP/1.1" ); return false; } size_t i = str_tmp.find( " " ); if( i == std::string::npos ) m_data.code = atoi( str_tmp.c_str() ); else m_data.code = atoi( str_tmp.substr( 0, i ).c_str() ); if( m_data.code == 0 ){ MISC::ERRMSG( "could not get http status code" ); return false; } // サイズ m_data.length = 0; str_tmp = analyze_header_option( "Content-Length: " ); if( ! str_tmp.empty() ) m_data.length = atoi( str_tmp.c_str() ); // date m_data.date = analyze_header_option( "Date: " ); // modified m_data.modified = analyze_header_option( "Last-Modified: " ); // cookie m_data.list_cookies = analyze_header_option_list( "Set-Cookie: " ); // Location if( m_data.code == HTTP_REDIRECT || m_data.code == HTTP_MOVED_PERM ) m_data.location = analyze_header_option( "Location: " ); else m_data.location = std::string(); // Content-Type m_data.contenttype = analyze_header_option( "Content-Type: " ); // chunked か m_use_chunk = false; str_tmp = analyze_header_option( "Transfer-Encoding: " ); if( str_tmp.find( "chunked" ) != std::string::npos ){ m_use_chunk = true; m_status_chunk = 0; m_pos_sizepart = m_str_sizepart; } // gzip か m_use_zlib = false; str_tmp = analyze_header_option( "Content-Encoding: " ); if( str_tmp.find( "gzip" ) != std::string::npos ){ if( !init_unzip() ) return false; } #ifdef _DEBUG std::cout << "code = " << m_data.code << std::endl; std::cout << "length = " << m_data.length << std::endl; std::cout << "date = " << m_data.date << std::endl; std::cout << "modified = " << m_data.modified << std::endl; std::list< std::string >::iterator it = m_data.list_cookies.begin(); for( ; it != m_data.list_cookies.end(); ++it ) std::cout << "cookie = " << (*it) << std::endl; std::cout << "location = " << m_data.location << std::endl; std::cout << "contenttype = " << m_data.contenttype<< std::endl; if( m_use_chunk ) std::cout << "m_use_chunk = true\n"; if( m_use_zlib ) std::cout << "m_use_zlib = true\n"; std::cout << "authenticate = " << analyze_header_option( "WWW-Authenticate: " ) << std::endl; std::cout << "\n"; #endif return true; } // // analyze_header() から呼ばれるオプションの値を取り出す関数 // std::string Loader::analyze_header_option( const std::string& option ) { size_t i = 0, i2 = 0; i = m_data.str_header.find( option, 0 ); if( i != std::string::npos ){ const size_t option_length = option.length(); i2 = m_data.str_header.find( "\r\n", i ); if( i2 == std::string::npos ) i2 = m_data.str_header.find( "\n", i ); if( i2 != std::string::npos ) return m_data.str_header.substr( i + option_length, i2 - ( i + option_length ) ); } return std::string(); } // // analyze_header() から呼ばれるオプションの値を取り出す関数(リスト版) // std::list< std::string > Loader::analyze_header_option_list( const std::string& option ) { std::list< std::string > str_list; size_t i = 0, i2 = 0; const size_t option_length = option.length(); for(;;){ i = m_data.str_header.find( option, i2 ); if( i == std::string::npos ) break; i2 = m_data.str_header.find( "\r\n", i ); if( i2 == std::string::npos ) i2 = m_data.str_header.find( "\n", i ); if( i2 == std::string::npos ) break; str_list.push_back( m_data.str_header.substr( i + option_length, i2 - ( i + option_length ) ) ); } return str_list; } // // chunked なデータを切りつめる関数 // // 入力 // buf : 生データ // readsize: 生データサイズ // // 出力 // buf : 切りつめられたデータ // readsize: 出力データサイズ // bool Loader::skip_chunk( char* buf, size_t& read_size ) { #ifdef _DEBUG_CHUNKED std::cout << "\n[[ skip_chunk : start read_size = " << read_size << " ]]\n"; #endif size_t pos_chunk = 0; size_t pos_data_chunk_start = 0; size_t buf_size = 0; for(;;){ // サイズ部 if( m_status_chunk == 0 ){ // \nが来るまで m_str_sizepart[] に文字をコピーしていく for( ; pos_chunk < read_size; ++pos_chunk, ++m_pos_sizepart ){ // バッファオーバーフローのチェック if( ( long )( m_pos_sizepart - m_str_sizepart ) >= 64 ){ MISC::ERRMSG( "buffer over flow at skip_chunk" ); return false; } *( m_pos_sizepart ) = buf[ pos_chunk ]; // \n が来たらデータ部のサイズを取得 if( buf[ pos_chunk ] == '\n' ){ ++pos_chunk; *( m_pos_sizepart ) = '\0'; if( *( m_pos_sizepart -1 ) == '\r' ) *( m_pos_sizepart -1 ) = '\0'; // "\r\n"の場合 m_lng_leftdata = strtol( m_str_sizepart, NULL, 16 ); m_pos_sizepart = m_str_sizepart; #ifdef _DEBUG_CHUNKED std::cout << "[[ skip_chunk : size chunk finished : str = 0x" << m_str_sizepart << " ]]\n"; std::cout << "[[ skip_chunk : enter the data chunk, data size = " << m_lng_leftdata << " ]]\n"; #endif pos_data_chunk_start = pos_chunk; m_status_chunk = 1; break; } } } // データ部 if( m_status_chunk == 1 ){ // データを前に詰める if( m_lng_leftdata ){ for( ; m_lng_leftdata > 0 && pos_chunk < read_size; --m_lng_leftdata, ++pos_chunk ); size_t buf_size_tmp = pos_chunk - pos_data_chunk_start; if( buf_size != pos_data_chunk_start && buf_size_tmp ) memmove( buf + buf_size , buf + pos_data_chunk_start, buf_size_tmp ); buf_size += buf_size_tmp; } // データを全部読み込んだらデータ部終わり if( m_lng_leftdata == 0 ) m_status_chunk = 2; } // データ部→サイズ部切り替え中( "\r" と "\n" の間でサーバからの入力が分かれる時がある) if( m_status_chunk == 2 ){ unsigned char c = buf[ pos_chunk ]; if( c != '\r' && c != '\n' ){ MISC::ERRMSG( "broken chunked data." ); return false; } // \r\nが来たらサイズ部に戻る if( c == '\r' ) ++pos_chunk; else break; if( buf[ pos_chunk ] == '\n' ) ++pos_chunk; else break; #ifdef _DEBUG_CHUNKED std::cout << "[[ skip_chunk : data chunk finished. ]]\n"; #endif m_status_chunk = 0; } // バッファ終わり if( pos_chunk == read_size ){ read_size = buf_size; buf[ read_size ] = '\0'; #ifdef _DEBUG_CHUNKED std::cout << "[[ skip_chunk : output = " << read_size << " ]]\n\n"; #endif return true; } } return true; } // // zlib 初期化 // bool Loader::init_unzip() { #ifdef _DEBUG std::cout << "Loader::init_unzip\n"; #endif m_use_zlib = true; #ifdef USE_OLDZLIB m_check_gzheader = true; #endif // zlib 初期化 m_zstream.zalloc = Z_NULL; m_zstream.zfree = Z_NULL; m_zstream.opaque = Z_NULL; m_zstream.next_in = Z_NULL; m_zstream.avail_in = 0; #ifdef USE_OLDZLIB #ifdef _DEBUG std::cout << "use old zlib\n"; #endif if ( inflateInit2( &m_zstream, -MAX_WBITS ) != Z_OK ) #else #ifdef _DEBUG std::cout << "use zlib12\n"; #endif if ( inflateInit2( &m_zstream, 15 + 32 ) != Z_OK ) // デフォルトの15に+32する( windowBits = 47 )と自動でヘッダ認識 #endif { MISC::ERRMSG( "inflateInit2 failed." ); return false; } assert( m_buf_zlib_in == NULL ); assert( m_buf_zlib_out == NULL ); m_buf_zlib_in = ( Bytef* )malloc( m_lng_buf_zlib_in + 64 ); m_buf_zlib_out = ( Bytef* )malloc( m_lng_buf_zlib_out + 64 ); return true; } #ifdef USE_OLDZLIB // // gzip のヘッダチェック // // 戻り値 : ヘッダのサイズ(エラーなら-1) // // TODO: size がヘッダサイズよりも小さいと必ず失敗する // int Loader::check_gzheader( char* buf, size_t& size ) { #ifdef _DEBUG std::cout << "Loader::check_gzheader\n"; #endif m_check_gzheader = false; unsigned int pos = 0; if( ( ( unsigned char* )buf )[ pos++ ] != 0x1f || ( ( unsigned char* )buf )[ pos++ ] != 0x8b ) return -1; // CM(1byte) if( buf[ pos++ ] != 0x08 ) return false; // FLG(1byte) unsigned char flag =( ( unsigned char* )buf )[ pos++ ]; #ifdef _DEBUG std::cout << "flag = " << std::hex << ( unsigned int )flag << std::dec << std::endl; #endif if( flag & 0xe0 ) return -1; // MTIME(4byte), XFL(1byte), OS(1byte)を飛ばす pos += 6; // XLEN(2byte) + 拡張フィールド if( flag & 4 ){ unsigned short lngext; memcpy( &lngext, buf + pos, sizeof( unsigned short ) ); #ifdef _DEBUG std::cout << "FEXTRA lng = " << lngext << std::endl; #endif pos += sizeof( unsigned short ) + lngext; } // NAME if( flag & 8 ){ int i = 0; char tmp_str[ 256 ]; while( pos < size && i < 256 && buf[ pos ] != '\0' ) tmp_str[ i++ ] = buf[ pos++ ]; tmp_str[ i ] = buf[ pos++ ]; if( tmp_str[ i ] != '\0' ) return -1; #ifdef _DEBUG std::cout << "NAME = " << tmp_str << std::endl; #endif } // COMMENT if( flag & 16 ){ int i = 0; char tmp_str[ 256 ]; while( pos < size && i < 256 && buf[ pos ] != '\0' ) tmp_str[ i++ ] = buf[ pos++ ]; tmp_str[ i ] = buf[ pos++ ]; if( tmp_str[ i ] != '\0' ) return -1; #ifdef _DEBUG std::cout << "COMMENT = " << tmp_str << std::endl; #endif } // CRC16 if(flag & 2 ){ pos += 2; #ifdef _DEBUG std::cout << "CRC16\n"; #endif } if( pos >= size ) return -1; #ifdef _DEBUG std::cout << "header size = " << pos << std::endl; #endif return pos; } #endif // // unzipしてコールバック呼び出し // bool Loader::unzip( char* buf, size_t& read_size ) { #ifdef USE_OLDZLIB // gzip のヘッダを飛ばす if( m_check_gzheader ){ int headsize = check_gzheader( buf, read_size ); if( headsize < 0 ){ MISC::ERRMSG( "invalid gzip header : " + m_data.url ); return false; } buf += headsize; read_size -= headsize; } #endif // zlibの入力バッファに値セット if( m_zstream.avail_in + read_size > m_lng_buf_zlib_in ){ // オーバーフローのチェック MISC::ERRMSG( "buffer over flow at zstream_in : " + m_data.url ); return false; } memcpy( m_buf_zlib_in + m_zstream.avail_in , buf, read_size ); m_zstream.avail_in += read_size; m_zstream.next_in = m_buf_zlib_in; size_t byte_out = 0; do{ // 出力バッファセット m_zstream.next_out = m_buf_zlib_out; m_zstream.avail_out = m_lng_buf_zlib_out; byte_out = 0; // 解凍 int ret = inflate( &m_zstream, Z_NO_FLUSH ); if( ret == Z_OK || ret == Z_STREAM_END ){ byte_out = m_lng_buf_zlib_out - m_zstream.avail_out; m_buf_zlib_out[ byte_out ] = '\0'; m_data.size_data += byte_out; #ifdef _DEBUG std::cout << "inflate ok byte = " << byte_out << std::endl; #endif // コールバック呼び出し if( byte_out && m_loadable ) m_loadable->receive( ( char* )m_buf_zlib_out, byte_out ); #ifdef USE_OLDZLIB if( ret == Z_STREAM_END ){ m_zstream.avail_in = 0; // CRC32(4byte)とISIZE(4byte)の分を引く return true; } #endif } else return true; } while ( byte_out ); // 入力バッファに使ってないデータが残っていたら前に移動 if( m_zstream.avail_in ) memmove( m_buf_zlib_in, m_buf_zlib_in + ( read_size - m_zstream.avail_in ), m_zstream.avail_in ); return true; } // // sent, recv待ち // const bool Loader::wait_recv_send( const int fd, const bool recv ) { if( !fd ) return true; // 同期している場合は何もしない if( !m_data.async ) return true; int count = 0; for(;;){ errno = 0; int ret; fd_set fdset; FD_ZERO( &fdset ); FD_SET( fd , &fdset ); timeval timeout; memset( &timeout, 0, sizeof( timeval ) ); timeout.tv_sec = 1; if( recv ) ret = select( fd+1 , &fdset , NULL , NULL , &timeout ); else ret = select( fd+1 , NULL, &fdset , NULL , &timeout ); #ifdef _DEBUG if( errno == EINTR && ret < 0 ) std::cout << "Loader::wait_recv_send : errno = EINTR " << errno << std::endl; #endif if( errno != EINTR && ret < 0 ){ #ifdef _DEBUG std::cout << "Loader::wait_recv_send : errno = " << errno << std::endl; #endif MISC::ERRMSG( "select failed" ); break; } if( errno != EINTR && FD_ISSET( fd, &fdset ) ) return true; if( m_stop ) break; if( ++count >= m_data.timeout ) break; #ifdef _DEBUG std::cout << "Loader::wait_recv_send ret = " << ret << " errno = " << errno << " timeout = " << count << std::endl; #endif } return false; } // // ローディング終了処理 // void Loader::finish_loading() { #ifdef _DEBUG std::cout << "Loader::finish_loading : url = " << m_data.url << std::endl; #endif // SKELETON::Loadable に終了を知らせる if( m_loadable ) m_loadable->finish(); m_loading = false; JDLIB::pop_loader_queue(); } jd-2.8.7-140104/src/jdlib/loader.h0000644000076400010400000000713711275071177013102 0ustar // ライセンス: GPL2 // // ファイルローダ // // SKELETON::Loadable と組み合わせて使用する // #ifndef _LOADER_H #define _LOADER_H #include "loaderdata.h" #include "jdthread.h" #include #include #include #ifdef _WIN32 // set Windows XP or 2003 Server for addrinfo before include windows.h #ifdef WINVER #undef WINVER #endif #define WINVER 0x0501 #include #include #include #else #include #endif // zlibが1.2よりバージョンが低いか判定する #ifndef ZLIB_VERNUM #define ZLIB_VERNUM 0x1000 #endif #if ZLIB_VERNUM < 0x1200 #define USE_OLDZLIB #endif namespace SKELETON { class Loadable; } namespace JDLIB { class Loader { LOADERDATA m_data; struct addrinfo* m_addrinfo; bool m_stop; // = true にするとスレッド停止 bool m_loading; JDLIB::Thread m_thread; SKELETON::Loadable* m_loadable; // スレッド起動待ち状態になった時に、起動順のプライオリティを下げる bool m_low_priority; // 読み込みバッファ unsigned long m_lng_buf; char* m_buf; // zlib 用のバッファ unsigned long m_lng_buf_zlib_in; unsigned long m_lng_buf_zlib_out;; Bytef* m_buf_zlib_in; Bytef* m_buf_zlib_out; // chunk 用変数 bool m_use_chunk; long m_status_chunk; char m_str_sizepart[ 64 ]; // サイズ部のバッファ。64byte以下と仮定(超えるとエラー) char* m_pos_sizepart; size_t m_lng_leftdata; // zlib 用変数 bool m_use_zlib; z_stream m_zstream; #ifdef USE_OLDZLIB bool m_check_gzheader; #endif public: // low_priority = true の時はスレッド起動待ち状態になった時に、起動順のプライオリティを下げる Loader( const bool low_priority ); ~Loader(); const bool is_loading() const { return m_loading; } const LOADERDATA& data() const { return m_data; } bool run( SKELETON::Loadable* cb, const LOADERDATA& data_in ); void wait(); void stop(); const bool get_low_priority() const { return m_low_priority; } void create_thread(); private: static void* launcher( void* ); void clear(); void run_main(); struct addrinfo* get_addrinfo( const std::string& hostname, const int port ); const std::string create_msg_send(); const bool wait_recv_send( const int fd, const bool recv ); // ローディング終了処理 void finish_loading(); // ヘッダ用 const int receive_header( char* buf, size_t& read_size ); bool analyze_header(); std::string analyze_header_option( const std::string& option ); std::list< std::string > analyze_header_option_list( const std::string& option ); // chunk用 bool skip_chunk( char* buf, size_t& read_size ); // unzip 用 bool init_unzip(); bool unzip( char* buf, size_t& read_size ); #ifdef USE_OLDZLIB int check_gzheader( char* buf, size_t& size ); #endif }; // ローダの起動待ちキューにあるスレッドを実行しない // アプリ終了時にこの関数を呼び出さないとキューに登録されたスレッドが起動してしまうので注意 void disable_pop_loader_queue(); // mainの最後でローダが動いていないかチェックする関数 void check_loader_alive(); } #endif jd-2.8.7-140104/src/jdlib/loaderdata.cpp0000644000076400010400000000260611157077436014266 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "loader.h" #include "config/globalconf.h" #include "httpcode.h" using namespace JDLIB; LOADERDATA::LOADERDATA() { init(); } void LOADERDATA::init() { head = false; length = 0; length_current = 0; size_data = 0; url.clear(); protocol.clear(); host.clear(); path.clear(); port = 0; use_ssl = false; async = true; use_ipv6 = CONFIG::get_use_ipv6(); str_post.clear(); host_proxy.clear(); port_proxy = 0; basicauth_proxy.clear(); agent.clear(); referer.clear(); ex_field.clear(); str_header.clear(); code = HTTP_INIT; str_code.clear(); date.clear(); modified.clear(); byte_readfrom = 0; cookie_for_write.clear(); list_cookies.clear(); contenttype.clear(); basicauth.clear(); size_buf = 0; timeout = 0; } // 一般データのダウンロード用初期化 void LOADERDATA::init_for_data() { agent = CONFIG::get_agent_for_data(); if( CONFIG::get_use_proxy_for_data() ) host_proxy = CONFIG::get_proxy_for_data(); else host_proxy = std::string(); port_proxy = CONFIG::get_proxy_port_for_data(); basicauth_proxy = CONFIG::get_proxy_basicauth_for_data(); size_buf = CONFIG::get_loader_bufsize(); timeout = CONFIG::get_loader_timeout_data(); } jd-2.8.7-140104/src/jdlib/loaderdata.h0000644000076400010400000000317711157077436013737 0ustar // ライセンス: GPL2 // // ファイルローダに渡すデータクラス // #ifndef _LOADERDATA_H #define _LOADERDATA_H #include #include namespace JDLIB { class LOADERDATA { public: bool head; size_t length; // Content-Length の値 size_t length_current; // 解凍前の現在までに読み込んでいるサイズ。よって length_current <= length size_t size_data; // 解凍したあとの純粋なデータサイズ。よって length < size_data となる場合もある std::string url; std::string protocol; std::string host; std::string path; long port; bool use_ssl; // https bool async; // 非同期ソケット使用 bool use_ipv6; // ipv6使用 std::string str_post; std::string host_proxy; long port_proxy; std::string basicauth_proxy; // proxy 認証 std::string agent; std::string referer; std::string ex_field; // 送信時にヘッダに追加するフィールド std::string str_header; long code; std::string str_code; std::string date; std::string modified; size_t byte_readfrom; std::string cookie_for_write; std::list< std::string > list_cookies; std::string location; std::string contenttype; std::string basicauth; size_t size_buf; long timeout; LOADERDATA(); void init(); // 一般データのダウンロード用初期化 void init_for_data(); }; } #endif jd-2.8.7-140104/src/jdlib/Makefile.am0000644000076400010400000000143412072045132013475 0ustar noinst_LIBRARIES = libjdlib.a libjdlib_a_SOURCES = \ miscutil.cpp \ miscmsg.cpp \ misctime.cpp \ misctrip.cpp \ miscx.cpp \ miscgtk.cpp \ jdthread.cpp \ misccharcode.cpp \ heap.cpp \ jdiconv.cpp \ loader.cpp \ imgloader.cpp \ ssl.cpp \ loaderdata.cpp \ confloader.cpp \ jdregex.cpp \ jdmigemo.cpp \ tfidf.cpp \ hash_set.cpp \ timeout.cpp noinst_HEADERS = \ miscutil.h \ miscmsg.h \ misctime.h \ misctrip.h \ miscx.h \ miscgtk.h \ jdthread.h \ misccharcode.h \ constptr.h \ refptr_lock.h \ heap.h \ jdiconv.h \ loader.h \ imgloader.h \ ssl.h \ loaderdata.h \ confloader.h \ jdregex.h \ jdmigemo.h \ tfidf.h \ hash_set.h \ timeout.h \ hkana.h AM_CXXFLAGS = @GTKMM_CFLAGS@ @GNUTLS_CFLAGS@ @OPENSSL_CFLAGS@ @X11_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/jdlib/misccharcode.cpp0000644000076400010400000001650010753065065014604 0ustar // License: GPL2 //#define _DEBUG #include "jddebug.h" #include "misccharcode.h" #include // チェックする最大バイト数 #define CHECK_LIMIT 1024 /*--- 制御文字とASCII -----------------------------------------------*/ // [ 制御文字 ] 0x00〜0x1F 0x7F #define CTRL_RNAGE( target ) ( target < 0x20 || target == 0x7F ) // [ ASCII ] 0x20〜0x7E #define ASCII_RANGE( target ) ( (unsigned char)( target - 0x20 ) < 0x5F ) // [ 制御文字とASCII ] 0x00〜0x7F #define CTRL_AND_ASCII_RANGE( target ) ( (unsigned char)target < 0x80 ) /*---- EUC-JP -------------------------------------------------------*/ // // [ カナ ] // 1バイト目 0x8E #define EUC_CODE_KANA( target ) ( (unsigned char)target == 0x8E ) // 2バイト目 0xA1〜0xDF #define EUC_RANGE_KANA( target ) ( (unsigned char)( target - 0xA1 ) < 0x3F ) // // [ 補助漢字 ] // 1バイト目 0x8F #define EUC_CODE_SUB_KANJI( target ) ( (unsigned char)target == 0x8F ) // // [ 漢字 ] // 1バイト目 0xA1〜0xFE // 2バイト目 0xA1〜0xFE #define EUC_RANGE_MULTI( target ) ( (unsigned char)( target - 0xA1 ) < 0x5E ) // bool MISC::is_euc( const char* input, size_t& read_byte ) { if( ! input ) return false; size_t byte = read_byte; const size_t input_length = strlen( input ); while( byte < input_length && byte < CHECK_LIMIT ) { // 制御文字かアスキー if( CTRL_AND_ASCII_RANGE( input[ byte ] ) ) { ++byte; } // カナ else if( EUC_CODE_KANA( input[ byte ] ) && EUC_RANGE_KANA( input[ byte + 1 ] ) ) { byte += 2; } // 補助漢字 else if( EUC_CODE_SUB_KANJI( input[ byte ] ) && EUC_RANGE_MULTI( input[ byte + 1 ] ) && EUC_RANGE_MULTI( input[ byte + 2 ] ) ) { byte += 3; } // 漢字 else if( EUC_RANGE_MULTI( input[ byte ] ) && EUC_RANGE_MULTI( input[ byte + 1 ] ) ) { byte += 2; } // その他 else { return false; } } return true; } /*---- ISO-2022-JP --------------------------------------------------*/ // // エスケープシーケンスの開始文字 ESC(0x1B) #define JIS_ESC_SEQ_START( target ) ( target == 0x1B ) // bool MISC::is_jis( const char* input, size_t& byte ) { if( ! input ) return false; const size_t input_length = strlen( input ); while( byte < input_length && byte < CHECK_LIMIT ) { // ESCが出現したか否かだけで判断 if( JIS_ESC_SEQ_START( input[ byte ] ) ) return true; // JISに該当しないコード 0x80〜 else if( ! CTRL_AND_ASCII_RANGE( input[ byte ] ) ) return false; ++byte; } // ループが終了していたら制御文字かアスキー return false; } /*---- Shift_JIS ----------------------------------------------------*/ // // [ カナ ] 0xA1〜0xDF #define SJIS_RANGE_KANA( target ) ( (unsigned char)( target - 0xA1 ) < 0x3F ) // // [ 漢字 ] // 1バイト目 0x81〜0x9F 0xE0〜0xFC( 0xEF ) //#define SJIS_RANGE_1( target ) ( (unsigned char)( target ^ 0x20 ) - 0xA1 < 0x2F ) #define SJIS_RANGE_1( target ) ( ( (unsigned char)target ^ 0x20 ) - 0xA1 < 0x3C ) // 0x81〜0x9F #define SJIS_RANGE_1_H( target ) ( (unsigned char)( target - 0x81 ) < 0x1F ) // 0xE0〜0xFC #define SJIS_RANGE_1_T( target ) ( (unsigned char)( target - 0xE0 ) < 0x1D ) // // 2バイト目 0x40〜0x7E 0x80〜0xFC #define SJIS_RANGE_2( target ) ( (unsigned char)( target - 0x40 ) < 0xBD && target != 0x7F ) // 0x40〜0x7E #define SJIS_RANGE_2_H( target ) ( (unsigned char)( target - 0x40 ) < 0x3F ) // 0x80〜0xFC #define SJIS_RANGE_2_T( target ) ( (unsigned char)( target - 0x80 ) < 0x7D ) // bool MISC::is_sjis( const char* input, size_t& read_byte ) { if( ! input ) return false; size_t byte = read_byte; const size_t input_length = strlen( input ); while( byte < input_length && byte < CHECK_LIMIT ) { // 制御文字かアスキー if( CTRL_AND_ASCII_RANGE( input[ byte ] ) ) { ++byte; } // カナ else if( SJIS_RANGE_KANA( input[ byte ] ) ) { ++byte; } // 漢字(MS932) else if( SJIS_RANGE_1( input[ byte ] ) && SJIS_RANGE_2( input[ byte + 1 ] ) ) { byte += 2; } // その他 else { return false; } } return true; } /*---- UTF ---------------------------------------------------------*/ // // 0xC0・0xC1はセキュリティ上の問題で使用が禁止されている // // [ 1バイト目の範囲 ] 0xC2〜0xFD [ RFC2279(破棄) ] // [ 1バイト目の範囲 ] 0xC2〜0xF4 [ RFC6329 ] #define UTF_RANGE_1( target ) ( (unsigned char)( target - 0xC2 ) < 0x33 ) // // [ 1バイト目 (2バイト文字) ] 先頭2ビットが1 #define UTF_FLAG_2( target ) ( ( target & 0xC0 ) == 0xC0 ) // // [ 1バイト目 (3バイト文字) ] 先頭3ビットが1 #define UTF_FLAG_3( target ) ( ( target & 0xE0 ) == 0xE0 ) // // [ 1バイト目 (4バイト文字) ] 先頭4ビットが1 #define UTF_FLAG_4( target ) ( ( target & 0xF0 ) == 0xF0 ) // // [ 2バイト目以降 ] 0x80〜0xBF #define UTF_RANGE_MULTI_BYTE( target ) ( (unsigned char)( target - 0x80 ) < 0x40 ) // bool MISC::is_utf( const char* input, size_t& read_byte ) { if( ! input ) return false; bool valid = true; size_t byte = read_byte; const size_t input_length = strlen( input ); while( byte < input_length && byte < CHECK_LIMIT ) { // 制御文字かアスキー if( CTRL_AND_ASCII_RANGE( input[ byte ] ) ) { ++byte; continue; } // UTF-8の1バイト目の範囲ではない else if( ! UTF_RANGE_1( input[ byte ] ) ) { byte = 0; return false; } int byte_count = 1; // 4,3,2バイト if( UTF_FLAG_4( input[ byte ] ) ) byte_count = 4; else if( UTF_FLAG_3( input[ byte ] ) ) byte_count = 3; else if( UTF_FLAG_2( input[ byte ] ) ) byte_count = 2; ++byte; // 2バイト目以降 while( byte_count > 1 ) { if( UTF_RANGE_MULTI_BYTE( input[ byte ] ) ) { ++byte; } else { valid = false; break; } --byte_count; } } return valid; } // // 日本語文字コードの判定 // // 各コードの判定でtrueの間は文字数分繰り返されるので // 速度の求められる繰り返し処理などで使わない事 // int MISC::judge_char_code( const std::string& str ) { int code = CHARCODE_UNKNOWN; if( str.empty() ) return code; size_t read_byte = 0; // JISの判定 if( is_jis( str.c_str(), read_byte ) ) code = CHARCODE_JIS; // JISの判定で最後まで進んでいたら制御文字かアスキー else if( read_byte == str.length() ) code = CHARCODE_ASCII; // UTF-8の範囲 else if( is_utf( str.c_str(), read_byte ) ) code = CHARCODE_UTF; // EUC-JPの範囲 else if( is_euc( str.c_str(), read_byte ) ) code = CHARCODE_EUC_JP; // Shift_JISの範囲 else if( is_sjis( str.c_str(), read_byte ) ) code = CHARCODE_SJIS; return code; } jd-2.8.7-140104/src/jdlib/misccharcode.h0000644000076400010400000000114410740444676014254 0ustar // License: GPL2 // 日本語文字コードの判定 #ifndef _MISCCHARCODE_H #define _MISCCHARCODE_H #include namespace MISC { enum CodeSet { CHARCODE_UNKNOWN = -1, CHARCODE_ASCII = 0, CHARCODE_EUC_JP, CHARCODE_JIS, CHARCODE_SJIS, CHARCODE_UTF }; bool is_euc( const char* input, size_t& read_byte ); bool is_jis( const char* input, size_t& read_byte ); bool is_sjis( const char* input, size_t& read_byte ); bool is_utf( const char* input, size_t& read_byte ); int judge_char_code( const std::string& str ); } #endif jd-2.8.7-140104/src/jdlib/miscgtk.cpp0000644000076400010400000001062611275071177013625 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "miscgtk.h" #include "imgloader.h" enum { CHAR_BUF = 256 // char の初期化用 }; // Gdk::Color -> 16進数表記の文字列 std::string MISC::color_to_str( const Gdk::Color& color ) { // R,G,Bを取得 int l_rgb[3]; l_rgb[0] = color.get_red(); l_rgb[1] = color.get_green(); l_rgb[2] = color.get_blue(); return color_to_str( l_rgb ); } // int[3] -> 16進数表記の文字列 std::string MISC::color_to_str( const int* l_rgb ) { // 16進数表記で各色の文字列を連結して格納 char str_value[ CHAR_BUF ]; snprintf( str_value, CHAR_BUF, "#%04x%04x%04x", l_rgb[ 0 ], l_rgb[ 1 ], l_rgb[ 2 ] ); #ifdef _DEBUG std::cout << "MISC::color_to_str" << std::endl; std::cout << l_rgb[0] << ", " << l_rgb[1] << ", " << l_rgb[2] << "->" << str_value << std::endl; #endif return str_value; } // htmlカラー (#ffffffなど) -> 16進数表記の文字列 std::string MISC::htmlcolor_to_str( const std::string& _htmlcolor ) { std::string htmlcolor = _htmlcolor; int rgb[ 3 ]; if( htmlcolor == "red" ) htmlcolor = "#ff0000"; else if( htmlcolor == "fuchsia" ) htmlcolor = "#ff00ff"; else if( htmlcolor == "purple" ) htmlcolor = "#800080"; else if( htmlcolor == "maroon" ) htmlcolor = "#800000"; else if( htmlcolor == "yellow" ) htmlcolor = "#ffff00"; else if( htmlcolor == "lime" ) htmlcolor = "#00ff00"; else if( htmlcolor == "green" ) htmlcolor = "#008000"; else if( htmlcolor == "olive" ) htmlcolor = "#808000"; else if( htmlcolor == "blue" ) htmlcolor = "#0000ff"; else if( htmlcolor == "aqua" ) htmlcolor = "#00ffff"; else if( htmlcolor == "teal" ) htmlcolor = "#008080"; else if( htmlcolor == "navy" ) htmlcolor = "#000080"; else if( htmlcolor == "white" ) htmlcolor = "#ffffff"; else if( htmlcolor == "silver" ) htmlcolor = "#c0c0c0"; else if( htmlcolor == "gray" ) htmlcolor = "#808080"; else if( htmlcolor == "black" ) htmlcolor = "#000000"; int offset = 0; if( htmlcolor.find( "#" ) == 0 ) offset = 1; std::string tmpstr = htmlcolor.substr( offset, 2 ); rgb[ 0 ] = strtol( std::string( "0x" + tmpstr + tmpstr ).c_str(), NULL, 16 ); tmpstr = htmlcolor.substr( 2 + offset, 2 ); rgb[ 1 ] = strtol( std::string( "0x" + tmpstr + tmpstr ).c_str(), NULL, 16 ); tmpstr = htmlcolor.substr( 4 + offset, 2 ); rgb[ 2 ] = strtol( std::string( "0x" + tmpstr + tmpstr ).c_str(), NULL, 16 ); #ifdef _DEBUG std::cout << "MISC::htmlcolor_to_gdkcolor color = " << htmlcolor << " r = " << rgb[ 0 ] << " g = " << rgb[ 1 ] << " b = " << rgb[ 2 ] << std::endl; #endif return color_to_str( rgb ); } // Gdk::Color -> int 変換 guint32 MISC::color_to_int( const Gdk::Color& color ) { guint32 red = color.get_red() >> 8; guint32 green = color.get_green() >> 8; guint32 blue = color.get_blue() >> 8; return ( red << 24 ) + ( green << 16 ) + ( blue << 8 ); } // 使用可能なフォントの一覧を取得 std::set< std::string > MISC::get_font_families() { std::set< std::string > set_out; Gtk::DrawingArea dummy; std::list< Glib::RefPtr< Pango::FontFamily > > list_families = dummy.get_pango_context()->list_families(); std::list< Glib::RefPtr< Pango::FontFamily > >::iterator it = list_families.begin(); for(; it != list_families.end(); ++it ){ #ifdef _DEBUG std::cout << (*it)->get_name() << std::endl; #endif set_out.insert( (*it)->get_name() ); } return set_out; } // gtk::entryのフォント名を取得 std::string MISC::get_entry_font() { Gtk::Entry entry; return entry.get_style()->get_font().to_string(); } // gtk::entryの文字色を16進数表記の文字列で取得 std::string MISC::get_entry_color_text() { Gtk::Entry entry; return color_to_str( entry.get_style()->get_text( Gtk::STATE_NORMAL ) ); } // gtk::entryの背景色を16進数表記の文字列で取得 std::string MISC::get_entry_color_base() { Gtk::Entry entry; return color_to_str( entry.get_style()->get_base( Gtk::STATE_NORMAL ) ); } // str をクリップボードにコピー void MISC::CopyClipboard( const std::string& str ) { Glib::RefPtr< Gtk::Clipboard > clip = Gtk::Clipboard::get(); clip->set_text( str ); clip = Gtk::Clipboard::get( GDK_SELECTION_PRIMARY ); clip->set_text( str ); } jd-2.8.7-140104/src/jdlib/miscgtk.h0000644000076400010400000000206511275071177013270 0ustar // ライセンス: GPL2 // gtk, gdk 関係の関数 #ifndef _MISCGTK_H #define _MISCGTK_H #include #include namespace MISC { // Gdk::Color -> 16進数表記の文字列 std::string color_to_str( const Gdk::Color& color ); // int[3] -> 16進数表記の文字列 std::string color_to_str( const int* l_rgb ); // htmlカラー (#ffffffなど) -> 16進数表記の文字列 std::string htmlcolor_to_str( const std::string& htmlcolor ); // Gdk::Color -> int 変換 guint32 color_to_int( const Gdk::Color& color ); // 使用可能なフォントの一覧を取得 std::set< std::string > get_font_families(); // gtk::entryのフォント名を取得 std::string get_entry_font(); // gtk::entryの文字色を16進数表記の文字列で取得 std::string get_entry_color_text(); // gtk::entryの背景色を16進数表記の文字列で取得 std::string get_entry_color_base(); // str をクリップボードにコピー void CopyClipboard( const std::string& str ); } #endif jd-2.8.7-140104/src/jdlib/miscmsg.cpp0000644000076400010400000000150711362077452013623 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "miscmsg.h" #include #include #ifdef _WIN32 // not exist _r suffix functions in mingw time.h #include #define ctime_r( _clock, _buf ) \ ( strcpy( (_buf), ctime( (_clock) ) ), (_buf) ) #endif namespace MISC { int id_err = 0; int id_msg = 0; } // // エラー出力 // void MISC::ERRMSG( const std::string& err ) { time_t current; time( ¤t ); char buf[ 256 ]; std::string str_date = ctime_r( ¤t, buf ); str_date.resize( str_date.length() -1 ); std::cerr << str_date << " (ER " << id_err << ") : " << err << std::endl; ++id_err; } // // メッセージ // void MISC::MSG( const std::string& msg ) { std::cout << "(MSG " << id_msg << "): " << msg << std::endl; ++id_msg; } jd-2.8.7-140104/src/jdlib/miscmsg.h0000644000076400010400000000042110540252733013254 0ustar // ライセンス: GPL2 // メッセージ表示関数 #ifndef _MISCMSG_H #define _MISCMSG_H #include namespace MISC { // エラー出力 void ERRMSG( const std::string& err ); // メッセージ void MSG( const std::string& msg ); } #endif jd-2.8.7-140104/src/jdlib/misctime.cpp0000644000076400010400000001374511724165466014007 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "misctime.h" #include "miscmsg.h" #include #include #include #include #include #ifdef _WIN32 #include // not exist _r suffix functions in mingw time.h #define localtime_r( _clock, _result ) \ ( *(_result) = *localtime( (_clock) ), \ (_result) ) #endif // // gettimeofday()の秒を文字列で取得 // const std::string MISC::get_sec_str() { std::ostringstream sec_str; struct timeval tv; struct timezone tz; gettimeofday( &tv, &tz ); sec_str << tv.tv_sec; return sec_str.str(); } // // timeval を str に変換 // const std::string MISC::timevaltostr( const struct timeval& tv ) { std::ostringstream sstr; sstr << ( tv.tv_sec >> 16 ) << " " << ( tv.tv_sec & 0xffff ) << " " << tv.tv_usec; return sstr.str(); } // // 時刻を紀元からの経過秒に直す // const time_t MISC::datetotime( const std::string& date ) { if( date.empty() ) return 0; struct tm tm_out; memset( &tm_out, 0, sizeof( struct tm ) ); #ifdef _WIN32 int rc; char month[4]; char monthes[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; char tzone[4]; rc = sscanf(date.c_str(), "%*3s, %2d %3s %4d %2d:%2d:%2d %3s", &tm_out.tm_mday, month, &tm_out.tm_year, &tm_out.tm_hour, &tm_out.tm_min, &tm_out.tm_sec, tzone); if ( rc != 7 ) { ERRMSG( "MISC::datetotime : unknown format = " + date ); return 0; } tm_out.tm_year -= 1900; for (int i=0; i<12; i++) { if (strcasecmp(monthes[i], month) == 0) { tm_out.tm_mon = i; break; } } // 通常はTZにGMTが渡される std::string env = "TZ="; putenv( (env + tzone).c_str() ); tzset(); time_t t_ret = mktime( &tm_out ); putenv( "TZ=" ); tzset(); #else // _WIN32 // (注意) LC_TIMEが"C"でないと環境によってはstrptime()が失敗する std::string lcl; char *lcl_tmp = setlocale( LC_TIME, NULL ); if( lcl_tmp ) lcl = lcl_tmp; #ifdef _DEBUG std::cout << "locale = " << lcl << std::endl; #endif if( ! lcl.empty() ) setlocale( LC_TIME, "C" ); char *ret = strptime( date.c_str(), "%a, %d %b %Y %T %Z", &tm_out ); if( ! lcl.empty() ) setlocale( LC_TIME, lcl.c_str() ); if( ret == NULL ) return 0; #ifdef USE_MKTIME time_t t_ret = mktime( &tm_out ); #else time_t t_ret = timegm( &tm_out ); #endif #endif // _WIN32 #ifdef _DEBUG std::cout << "MISC::datetotime " << date << " -> " << t_ret << std::endl; #endif return t_ret; } // // time_t を月日の文字列に変換 // const std::string MISC::timettostr( const time_t& time_from, const int mode ) { const int lng = 64; struct tm tm_tmp; char str_ret[ lng ]; str_ret[ 0 ] = '\0'; if( mode == MISC::TIME_NORMAL ){ if( localtime_r( &time_from, &tm_tmp ) ) snprintf( str_ret, lng, "%d/%02d/%02d %02d:%02d", ( 1900 + tm_tmp.tm_year ), ( 1 + tm_tmp.tm_mon ), tm_tmp.tm_mday, tm_tmp.tm_hour, tm_tmp.tm_min ); } else if( mode == MISC::TIME_NO_YEAR ){ if( localtime_r( &time_from, &tm_tmp ) ) snprintf( str_ret, lng, "%02d/%02d %02d:%02d", ( 1 + tm_tmp.tm_mon ), tm_tmp.tm_mday, tm_tmp.tm_hour, tm_tmp.tm_min ); } else if( mode == MISC::TIME_WEEK ){ const char week[][32] = { "日","月","火","水","木","金","土" }; if( localtime_r( &time_from, &tm_tmp ) ) snprintf( str_ret, lng, "%d/%02d/%02d(%s) %02d:%02d:%02d", ( 1900 + tm_tmp.tm_year ), ( 1 + tm_tmp.tm_mon ), tm_tmp.tm_mday, week[ tm_tmp.tm_wday ], tm_tmp.tm_hour, tm_tmp.tm_min, tm_tmp.tm_sec ); } else if( mode == MISC::TIME_SECOND ){ if( localtime_r( &time_from, &tm_tmp ) ) snprintf( str_ret, lng, "%d/%02d/%02d %02d:%02d:%02d", ( 1900 + tm_tmp.tm_year ), ( 1 + tm_tmp.tm_mon ), tm_tmp.tm_mday, tm_tmp.tm_hour, tm_tmp.tm_min, tm_tmp.tm_sec ); } else if( mode == MISC::TIME_PASSED ){ const time_t tmp_t = time( NULL ) - time_from; if( tmp_t < 0 ) snprintf( str_ret, lng, "未来" ); else if( tmp_t < 60 ) snprintf( str_ret, lng, "%d 秒前", (int) tmp_t ); else if( tmp_t < 60 * 60 ) snprintf( str_ret, lng, "%d 分前", (int)tmp_t / 60 ); else if( tmp_t < 60 * 60 * 24 ) snprintf( str_ret, lng, "%d 時間前", (int)tmp_t / ( 60 * 60 ) ); else if( tmp_t < 60 * 60 * 24 * 365 ) snprintf( str_ret, lng, "%d 日前", (int)tmp_t / ( 60 * 60 * 24 ) ); else snprintf( str_ret, lng, "%d 年前", (int)tmp_t / ( 60 * 60 * 24 * 365 ) ); } #ifdef _DEBUG std::cout << "MISC::timettostr " << time_from << " -> " << str_ret << std::endl; #endif return str_ret; } #ifdef NO_TIMEGM // // timegm // // Solarisの場合はtimegmが存在しないため、代替コードを宣言する(by kohju) // 原典:linux の man timegm // time_t timegm (struct tm *tm) { time_t ret; char *tz; tz = getenv("TZ"); setenv("TZ", "", 1); tzset(); ret = mktime(tm); if (tz) setenv("TZ", tz, 1); else unsetenv("TZ"); tzset(); return ret; } #endif // 実行時間測定用 std::vector< struct timeval > tv_measurement; void MISC::start_measurement( const int id ) { while( (int)tv_measurement.size() <= id ){ struct timeval tv; tv_measurement.push_back( tv ); } gettimeofday( &tv_measurement[ id ], NULL ); } const int MISC::measurement( const int id ) { if( id >= (int)tv_measurement.size() ) return 0; struct timeval tv; gettimeofday( &tv, NULL ); int ret = ( tv.tv_sec * 1000000 + tv.tv_usec ) - ( tv_measurement[ id ].tv_sec * 1000000 + tv_measurement[ id ].tv_usec ); tv_measurement[ id ] = tv; return ret; } jd-2.8.7-140104/src/jdlib/misctime.h0000644000076400010400000000232111724165466013440 0ustar // ライセンス: GPL2 // 時間関係の関数 #ifndef _MISCTIME_H #define _MISCTIME_H #include #include #include namespace MISC { // timetostr のモード enum { TIME_NORMAL = 0, // 年/月/日 時:分 TIME_NO_YEAR, // 月/日 時:分 TIME_WEEK, // 年/月/日(曜日) 時:分:秒 TIME_PASSED, // ~前 TIME_SECOND, // 年/月/日 時:分:秒 // この値が設定ファイルに保存されているので、最後に追加 TIME_NUM }; // gettimeofday()の秒を文字列で取得 const std::string get_sec_str(); // timeval を str に変換 const std::string timevaltostr( const struct timeval& tv ); // 時刻の文字列を紀元からの経過秒に直す // (例) Tue, 27 Dec 2005 14:28:10 GMT -> 1135693690 const time_t datetotime( const std::string& date ); // time_t を月日の文字列に変換 // (例) mode == TIME_NORMAL なら 1135785252 -> 2005/12/29 0:54 const std::string timettostr( const time_t& time_from, const int mode ); // 実行時間測定用 void start_measurement( const int id ); const int measurement( const int id ); } #endif jd-2.8.7-140104/src/jdlib/misctrip.cpp0000644000076400010400000001627511220665664014024 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "misctrip.h" #include "miscutil.h" #include #include #include #include // crypt #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef USE_OPENSSL #include #else // defined USE_GNUTLS #include #endif #ifdef _WIN32 #include #endif /*--------------------------------------------------------------------*/ // ローカル関数の宣言 // SHA1を計算 const std::string create_sha1( const std::string& key ); // トリップを計算(新方式) const std::string create_trip_newtype( const std::string& key ); // トリップを計算(従来方式) const std::string create_trip_conventional( const std::string& key ); /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ // SHA1を計算 // // param1: 元となる文字列 // return: SHA1文字列 /*--------------------------------------------------------------------*/ const std::string create_sha1( const std::string& key ) { if( key.empty() ) return std::string(); #ifdef USE_OPENSSL const unsigned int digest_length = SHA_DIGEST_LENGTH; unsigned char digest[ digest_length ]; // unsigned char *SHA1( const unsigned char *, size_t, unsigned char * ); SHA1( (const unsigned char *)key.c_str(), key.length(), digest ); #else // defined USE_GNUTLS const unsigned int digest_length = gcry_md_get_algo_dlen( GCRY_MD_SHA1 ); unsigned char digest[ digest_length ]; gcry_md_hash_buffer( GCRY_MD_SHA1, digest, key.c_str(), key.length() ); #endif std::stringstream sha1; #ifdef _DEBUG std::cout << "create_sha1 : SHA1 = "; #endif unsigned int n; for( n = 0; n < digest_length; ++n ) { sha1 << digest[n]; #ifdef _DEBUG std::cout << std::hex << (unsigned int)digest[n]; #endif } #ifdef _DEBUG std::cout << std::endl; #endif return sha1.str(); } /*--------------------------------------------------------------------*/ // トリップを計算(新方式) 2009/06の仕様 // param1: 元となる文字列 // return: トリップ文字列 /*--------------------------------------------------------------------*/ const std::string create_trip_newtype( const std::string& key ) { if( key.empty() ) return std::string(); const size_t key_length = key.length(); // キーは1024文字以内に限定される if( key_length > 1024 ) return std::string(); std::string trip = "???"; // "#"で始まる if( key[0] == '#' ) { // 全体が17〜19文字 ^#[0-9A-Fa-f]{16}[./0-9A-Za-z]{0,2}$ if( key_length > 16 && key_length < 20 ) { // 16進数文字列部分 const std::string hex_part = key.substr( 1, 16 ); char key_binary[17] = { 0 }; // 16進数文字列を全てバイナリに変換出来た [0-9A-Za-z]{16} if( MISC::chrtobin( hex_part.c_str(), key_binary ) == 16 ) { char salt[5] = { 0 }; bool is_salt_suitable = true; size_t n; // salt 候補の17〜18文字目を検証 for( n = 17; key[n] && n < 19; ++n ) { // [./0-9A-Za-z] if( isalnum( key[n] ) != 0 || (unsigned char)( key[n] - 0x2e ) < 2 ) { strncat( salt, &key[n], 1 ); } else { is_salt_suitable = false; break; } } // salt が適切(空も含む) if( is_salt_suitable == true ) { // salt に".."を足す strncat( salt, "..", 2 ); // crypt (key は先頭8文字しか使われない) const char *crypted = crypt( key_binary, salt ); // 末尾から10文字(cryptの戻り値はNULLでなければ必ず13文字) if( crypted ) trip = std::string( crypted + 3 ); else trip.clear(); } } } } // "$"で始まる else if( key[0] == '$' ) { // 現在は"???"を返す } // SHA1パターン else { const std::string sha1 = create_sha1( key ); if( ! sha1.empty() ) { // BASE64エンコード const std::string encoded = MISC::base64( sha1 ); // 先頭から12文字 trip = encoded.substr( 0, 12 ); } } return trip; } /*--------------------------------------------------------------------*/ // トリップを計算(従来方式) 2003/11/15の仕様らしい // 新方式導入に伴い、特殊文字の置換が不要になったようだ // // param1: 元となる文字列 // return: トリップ文字列 /*--------------------------------------------------------------------*/ const std::string create_trip_conventional( const std::string& key ) { if( key.empty() ) return std::string(); // key の2,3バイト目を salt として取り出す std::string salt = key.substr( 1, 2 ); // 仕様に合わせて salt を変換 const size_t salt_length = salt.length(); size_t n; for( n = 0; n < salt_length; n++ ) { // 0x2e〜0x7aの範囲にないものは '.'(0x2e) if( (unsigned char)( salt[n] - 0x2E ) > 0x4C ) { salt[n] = 0x2e; } // :;<=>?@ (0x3a〜0x40) は A〜G (0x41〜0x47) else if( (unsigned char)( salt[n] - 0x3A ) < 0x07 ) { salt[n] += 7; } // [\]^_` (0x5b〜0x60) は a〜f (0x61〜0x66) else if( (unsigned char)( salt[n] - 0x5B ) < 0x06 ) { salt[n] += 6; } } // salt の末尾に"H."を足す salt.append( "H." ); // crypt (key は先頭8文字しか使われない) const char *crypted = crypt( key.c_str(), salt.c_str() ); std::string trip; // 末尾10(cryptの戻り値はNULLでなければ必ず13文字) if( crypted ) trip = std::string( crypted + 3 ); return trip; } /*--------------------------------------------------------------------*/ // トリップを取得 // // param1: 元となる文字列(最初の"#"を含まない。UTF-8 であること) // param2: 書き込む掲示板の文字コード // return: トリップ文字列 /*--------------------------------------------------------------------*/ const std::string MISC::get_trip( const std::string& str, const std::string& charset ) { if( str.empty() ) return std::string(); // str の文字コードを UTF-8 から charset に変更して key に代入する std::string key = MISC::Iconv( str, "UTF-8", charset ); std::string trip; // key が12文字以上の場合は新方式 if( key.length() > 11 ) { trip = create_trip_newtype( key ); } // 従来方式 else { trip = create_trip_conventional( key ); } #ifdef _DEBUG std::cout << "MISC::get_trip : " << str << " -> " << trip << std::endl; #endif return trip; } jd-2.8.7-140104/src/jdlib/misctrip.h0000644000076400010400000000044111220425613013441 0ustar // ライセンス: GPL2 // トリップ関係の関数 #ifndef _MISCTRIP_H #define _MISCTRIP_H #include namespace MISC { // トリップを取得 (SHA1等の新方式対応) const std::string get_trip( const std::string& str, const std::string& charset ); }; #endif jd-2.8.7-140104/src/jdlib/miscutil.cpp0000644000076400010400000013420512116546561014014 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "miscutil.h" #include "miscmsg.h" #include "jdiconv.h" #include "jdregex.h" #include "hkana.h" #include "dbtree/spchar_decoder.h" #include "dbtree/node.h" #include #include #include #include // // str を "\n" ごとに区切ってlistにして出力 // const std::list< std::string > MISC::get_lines( const std::string& str ){ std::list< std::string > lines; size_t i = 0, i2 = 0, r = 0; while ( ( i2 = str.find( "\n", i ) ) != std::string::npos ){ r = 0; if( str[ i2 - 1 ] == '\r' ) r = 1; if( i2 - i > 0 ){ lines.push_back( str.substr( i, i2 - i - r ) ); } i = i2 + 1; } // 最後の行 if( i != str.length() +1 ) lines.push_back( str.substr( i ) ); return lines; } // // emacs lisp のリスト型を要素ごとにlistにして出力 // const std::list< std::string > MISC::get_elisp_lists( const std::string& str ) { #ifdef _DEBUG std::cout << "MISC::get_elisp_lists\n"; #endif std::list< std::string > lists; size_t pos = 0, length = 0; std::string str2 = remove_space( str ); const char* data = str2.c_str(); if( data[ 0 ] != '(' ) return lists; pos = 1; while( data[ pos ] != '\0' ){ // 空白削除 while( data[ pos ] == ' ' && data[ pos ] != '\0' ) ++pos; if( data[ pos ] == '\0' ) break; length = 1; // (が現れた if( data[ pos ] == '(' ){ int count = 1; while( data[ pos + length ] != '\0' ){ if( data[ pos + length ] == ')' ) --count; else if( data[ pos + length ] == '(' ) ++count; ++length; if( ! count ) break; } } // 改行 or データが壊れてる else if( data[ pos ] == '\n' || data[ pos ] == ')' ){ ++pos; continue; } // 通常データ else{ //空白 or ) を探す while( data[ pos + length ] != ' ' && data[ pos + length ] != ')' && data[ pos + length ] != '\0' ) ++length; } #ifdef _DEBUG std::cout << "pos = " << pos << " length = " << length << std::endl; #endif lists.push_back( str2.substr( pos, length ) ); pos += length; } #ifdef _DEBUG std::list < std::string >::iterator it; for( it = lists.begin(); it != lists.end(); ++it ) std::cout << "[" << *it << "]" << std::endl; #endif return lists; } // // strを空白または "" 単位で区切って list で出力 // const std::list< std::string > MISC::split_line( const std::string& str ) { std::string str_space = " "; size_t lng_space = str_space.length(); bool dquote; std::list< std::string > list_str; size_t i = 0, i2 = 0, lng = str.length(); for(;;){ // 空白を取る while( 1 ){ // 半角 if( str[ i ] == ' ' ) ++i; // 全角 else if( str[ i ] == str_space[ 0 ] && str[ i +1 ] == str_space[ 1 ] && ( lng_space == 2 || str[ i +2 ] == str_space[ 2 ] ) ) i += lng_space; else break; } // " から始まる ( \"は除く ) dquote = false; if( str[ i ] == '\"' && str[ i -1 ] != '\\' ){ dquote = true; ++i; } // 空白か " を探す i2 = i; size_t lng_tmp = 1; while( i2 < lng ){ // " 発見( \"は除く ) if( dquote ){ if( str[ i2 ] == '\"' && str[ i2-1 ] != '\\' ) break; } else{ // 半角 if( str[ i2 ] == ' ' ) break; // 全角 else if( str[ i2 ] == str_space[ 0 ] && str[ i2 +1 ] == str_space[ 1 ] && ( lng_space == 2 || str[ i2 +2 ] == str_space[ 2 ] ) ){ lng_tmp = lng_space; break; } } ++i2; } if( i2 - i ) list_str.push_back( str.substr( i, i2 - i ) ); if( i2 >= lng ) break; i = i2 + lng_tmp; } return list_str; } // strを delimで区切って list で出力 const std::list< std::string > MISC::StringTokenizer( const std::string& str, const char delim ) { std::list< std::string > list_str; size_t i = 0, i2 = 0, lng = str.length(); for(;;){ while( i2 < lng && str[ i2++ ] != delim ); int tmp = ( str[ i2-1 ] == delim || str[ i2 -1 ] == '\n' ) ? 1 : 0; if( i2 - i ) list_str.push_back( str.substr( i, i2 - i - tmp ) ); if( i2 >= lng ) break; i = i2; } return list_str; } // // list_inから空白行を除いてリストを返す // const std::list< std::string > MISC::remove_nullline_from_list( const std::list< std::string >& list_in ) { std::list< std::string > list_ret; std::list< std::string >::const_iterator it; for( it = list_in.begin(); it != list_in.end(); ++it ){ std::string tmp_str = MISC::remove_space( (*it) ); if( ! tmp_str.empty() ) list_ret.push_back( *it ); } return list_ret; } // // list_inの各行から前後の空白を除いてリストを返す // const std::list< std::string > MISC::remove_space_from_list( const std::list< std::string >& list_in ) { std::list< std::string > list_ret; std::list< std::string >::const_iterator it; for( it = list_in.begin(); it != list_in.end(); ++it ){ std::string tmp_str = MISC::remove_space( (*it) ); list_ret.push_back( tmp_str ); } return list_ret; } // // list_inからコメント行(#)を除いてリストを返す // const std::list< std::string > MISC::remove_commentline_from_list( const std::list< std::string >& list_in ) { const char commentchr = '#'; std::list< std::string > list_ret; std::list< std::string >::const_iterator it; for( it = list_in.begin(); it != list_in.end(); ++it ){ std::string tmp_str = MISC::remove_space( (*it) ); if( tmp_str.c_str()[ 0 ] != commentchr ) list_ret.push_back( *it ); } return list_ret; } // // 空白と""で区切られた str_in の文字列をリストにして出力 // // \"は " に置換される // // (例) "aaa" "bbb" "\"ccc\"" → aaa と bbb と "ccc" // const std::list< std::string > MISC::strtolist( const std::string& str_in ) { std::list< std::string > list_tmp; std::list< std::string > list_ret; list_tmp = MISC::split_line( str_in ); std::list< std::string >::iterator it = list_tmp.begin(); for( ; it != list_tmp.end(); ++it ){ if( !( *it ).empty() ) list_ret.push_back( MISC::recover_quot( ( *it ) ) ); } return list_ret; } // // list_in の文字列リストを空白と""で区切ってストリングにして出力 // // "は \" に置換される // // (例) "aaa" "bbb" "\"ccc\"" // const std::string MISC::listtostr( const std::list< std::string >& list_in ) { std::string str_out; std::list< std::string >::const_iterator it = list_in.begin(); for( ; it != list_in.end(); ++it ){ if( ! ( *it ).empty() ) str_out += " \"" + MISC::replace_quot( ( *it ) ) + "\""; } return str_out; } // // strの前後の空白削除 // const std::string MISC::remove_space( const std::string& str ) { std::string str_space = " "; size_t lng_space = str_space.length(); size_t lng = str.length(); if( lng == 0 ) return str; if( str.find( " " ) == std::string::npos ) return str; // 前 size_t i = 0; while( 1 ){ // 半角 if( str[ i ] == ' ' ) ++i; // 全角 else if( str[ i ] == str_space[ 0 ] && str[ i +1 ] == str_space[ 1 ] && ( lng_space == 2 || str[ i +2 ] == str_space[ 2 ] ) ) i += lng_space; else break; } // 後 size_t i2 = lng -1; while( 1 ){ // 半角 if( str[ i2 ] == ' ' ) --i2; // 全角 else if( str[ i2 - lng_space +1 ] == str_space[ 0 ] && str[ i2 - lng_space +2 ] == str_space[ 1 ] && ( lng_space == 2 || str[ i2 - lng_space +3 ] == str_space[ 2 ] ) ) i2 -= lng_space; else break; } return str.substr( i, i2 - i + 1 ); } // // str前後の改行、タブ、スペースを削除 // const std::string MISC::remove_spaces( const std::string& str ) { if( str.empty() ) return std::string(); size_t l = 0, r = str.length(); while( l < r && ( str[l] == '\n' || str[l] == '\r' || str[l] == '\t' || str[l] == ' ' ) ) ++l; // 最後の文字の位置は文字数より1少ない size_t p = r - 1; while( p > 0 && ( str[p] == '\n' || str[p] == '\r' || str[p] == '\t' || str[p] == ' ' ) ){ --p; --r; } return str.substr( l, r - l ); } // // str1からstr2で示された文字列を除く // const std::string MISC::remove_str( const std::string& str1, const std::string& str2 ) { return MISC::replace_str( str1, str2, "" ); } // // start 〜 end の範囲をstrから取り除く ( /* コメント */ など ) // const std::string MISC::remove_str( const std::string& str, const std::string& start, const std::string& end ) { std::string str_out = str; size_t l_pos = 0, r_pos = 0; const size_t start_length = start.length(); const size_t end_length = end.length(); while( ( l_pos = str_out.find( start, l_pos ) ) != std::string::npos && ( r_pos = str_out.find( end, l_pos + start_length ) ) != std::string::npos ) { str_out.erase( l_pos, r_pos - l_pos + end_length ); } return str_out; } // // 正規表現を使ってstr1からqueryで示された文字列を除く // const std::string MISC::remove_str_regex( const std::string& str1, const std::string& query ) { JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( ! regex.exec( query, str1, offset, icase, newline, usemigemo, wchar ) ) return std::string(); return MISC::remove_str( str1, regex.str( 0 ) ); } // // str1, str2 に囲まれた文字列を切り出す // const std::string MISC::cut_str( const std::string& str, const std::string& str1, const std::string& str2 ) { size_t i = str.find( str1 ); if( i == std::string::npos ) return std::string(); i += str1.length(); size_t i2 = str.find( str2, i ); if( i2 == std::string::npos ) return std::string(); return str.substr( i, i2 - i ); } // // str1 を str2 に置き換え // const std::string MISC::replace_str( const std::string& str, const std::string& str1, const std::string& str2 ) { std::string str_out; str_out.reserve( str.length() ); size_t i, pos = 0; while( ( i = str.find( str1 , pos ) ) != std::string::npos ){ str_out.append( str, pos, ( i - pos ) ); str_out.append( str2 ); pos = i + str1.length(); } str_out.append( str, pos, str.length() ); return str_out; } // // list_inから str1 を str2 に置き換えてリストを返す // const std::list< std::string > MISC::replace_str_list( const std::list< std::string >& list_in, const std::string& str1, const std::string& str2 ) { std::list< std::string > list_out; std::list< std::string >::const_iterator it = list_in.begin(); for( ; it != list_in.end(); ++it ) list_out.push_back( replace_str( *it, str1, str2 ) ); return list_out; } // // str_in に含まれる改行文字を replace に置き換え // const std::string MISC::replace_newlines_to_str( const std::string& str_in, const std::string& replace ) { if( str_in.empty() || replace.empty() ) return str_in; std::string str_out; str_out.reserve( str_in.length() ); size_t pos = 0, found = 0; while( ( found = str_in.find_first_of( "\r\n", pos ) ) != std::string::npos ) { str_out.append( str_in, pos, ( found - pos ) ); str_out.append( replace ); pos = found + 1; if( str_in[ found ] == '\r' && str_in[ found + 1 ] == '\n' ) ++pos; } str_out.append( str_in, pos, str_in.length() ); return str_out; } // // " を \" に置き換え // const std::string MISC::replace_quot( const std::string& str ) { return MISC::replace_str( str, "\"", "\\\"" ); } // // \" を " に置き換え // const std::string MISC::recover_quot( const std::string& str ) { return MISC::replace_str( str, "\\\"", "\"" ); } // // str 中に含まれている str2 の 数を返す // const int MISC::count_str( const std::string& str, const std::string& str2 ) { int count = 0; size_t found, pos = 0; while( ( found = str.find( str2, pos ) ) != std::string::npos ) { ++count; pos = found + 1; } return count; } // // str 中に含まれている chr の 数を返す // const int MISC::count_chr( const std::string& str, const char chr ) { int count = 0; const int size = str.size(); for( int i = 0; i < size; ++i ) if( str.c_str()[i] == chr ) ++count; return count; } // // 文字列(utf-8も) -> 整数変換 // // (例) "123" -> 123 // // 入力: // str // // 出力: // dig: 桁数、0なら失敗 // n : str から何バイト読み取ったか // // 戻り値: 数値 // const int MISC::str_to_uint( const char* str, size_t& dig, size_t& n ) { int out = 0; dig = 0; n = 0; while( *str != '\0' ){ const unsigned char in = (*str); if( '0' <= in && in <= '9' ){ out = out*10 + ( in - '0' ); ++dig; ++str; ++n; } else{ const unsigned char in2 = (* ( str +1 )); const unsigned char in3 = (* ( str +2 )); // utf-8 if( in == 0xef && in2 == 0xbc && ( 0x90 <= in3 && in3 <= 0x99 ) ){ out = out*10 + ( in3 - 0x90 ); ++dig; str += 3; n += 3; } else break; } } return out; } // // 数字 -> 文字変換 // const std::string MISC::itostr( const int n ) { std::ostringstream ss; ss << n; return ss.str(); } // // listで指定した数字を文字に変換 // const std::string MISC::intlisttostr( const std::list< int >& list_num ) { std::ostringstream comment; std::list < int >::const_iterator it = list_num.begin(); bool comma = false; int num_from = *it; int num_to = -1; int i = 0; for(;;){ ++i; ++it; const int num = *it; if( num_from + i != num || it == list_num.end() ){ if( comma ) comment << ","; comment << num_from; if( num_to != -1 ) comment << "-" << num_to; num_from = num; num_to = -1; i = 0; comma = true; if( it == list_num.end() ) break; } else num_to = num; } return comment.str(); } // // 16進数表記文字をバイナリに変換する( 例 "E38182" -> 0xE38182 ) // // 出力 : char_out // 戻り値: 変換に成功した chr_in のバイト数 // const size_t MISC::chrtobin( const char* chr_in, char* chr_out ) { if( ! chr_in ) return 0; const size_t chr_in_length = strlen( chr_in ); size_t a, b; for( a = 0, b = a; a < chr_in_length; ++a ) { unsigned char chr = chr_in[a]; chr_out[b] <<= 4; // 0(0x30)〜9(0x39) if( (unsigned char)( chr - 0x30 ) < 10 ) chr_out[b] |= chr - 0x30; // A(0x41)〜F(0x46) else if( (unsigned char)( chr - 0x41 ) < 6 ) chr_out[b] |= chr - 0x37; // a(0x61)〜f(0x66) else if( (unsigned char)( chr - 0x61 ) < 6 ) chr_out[b] |= chr - 0x57; // その他 else break; if( a % 2 != 0 ) ++b; } return a; } // // strが半角でmaxsize文字を超えたらカットして後ろに...を付ける // const std::string MISC::cut_str( const std::string& str, const unsigned int maxsize ) { std::string outstr = str; unsigned int pos, lng_str; int byte = 0; const size_t outstr_length = outstr.length(); for( pos = 0, lng_str = 0; pos < outstr_length; pos += byte ){ MISC::utf8toucs2( outstr.c_str()+pos, byte ); if( byte > 1 ) lng_str += 2; else ++lng_str; if( lng_str >= maxsize ) break; } // カットしたら"..."をつける if( pos != outstr_length ) outstr = outstr.substr( 0, pos ) + "..."; return outstr; } // // 正規表現のメタ文字が含まれているか // // escape == true ならエスケープを考慮 (例) escape == true なら \+ → \+ のまま、falseなら \+ → \\\+ // #define REGEX_METACHARS ".+*?^$|{}[]()\\" const bool MISC::has_regex_metachar( const std::string& str, const bool escape ) { const char metachars[] = REGEX_METACHARS; const size_t str_length = str.length(); for( size_t pos = 0; pos < str_length; ++pos ){ if( escape && str[ pos ] == '\\' ){ int i = 0; while( metachars[ i ] != '\0' ){ if( str[ pos + 1 ] == metachars[ i ] ) break; ++i; } if( metachars[ i ] == '\0' ) return true; ++pos; } else{ int i = 0; while( metachars[ i ] != '\0' ){ if( str[ pos ] == metachars[ i ] ) return true; ++i; } } } return false; } // // 正規表現のメタ文字をエスケープ // // escape == true ならエスケープを考慮 (例) escape == true なら \+ → \+ のまま、falseなら \+ → \\\+ // const std::string MISC::regex_escape( const std::string& str, const bool escape ) { if( ! has_regex_metachar( str, escape ) ) return str; #ifdef _DEBUG std::cout << "MISC::regex_escape" << std::endl; #endif std::string str_out; const char metachars[] = REGEX_METACHARS; const size_t str_length = str.length(); for( size_t pos = 0; pos < str_length; ++pos ){ if( escape && str[ pos ] == '\\' ){ int i = 0; while( metachars[ i ] != '\0' ){ if( str[ pos + 1 ] == metachars[ i ] ) break; ++i; } if( metachars[ i ] == '\0' ) str_out += '\\'; else{ str_out += str[ pos ]; ++pos; } } else{ int i = 0; while( metachars[ i ] != '\0' ){ if( str[ pos ] == metachars[ i ] ){ str_out += '\\'; break; } ++i; } } str_out += str[ pos ]; } #ifdef _DEBUG std::cout << str << " -> " << str_out << std::endl; #endif return str_out; } // // 正規表現のメタ文字をアンエスケープ // const std::string MISC::regex_unescape( const std::string& str ) { #ifdef _DEBUG std::cout << "MISC::regex_unescape" << std::endl; #endif std::string str_out; const char metachars[] = REGEX_METACHARS; const size_t str_length = str.length(); for( size_t pos = 0; pos < str_length; ++pos ){ if( str[ pos ] == '\\' ){ int i = 0; while( metachars[ i ] != '\0' ){ if( str[ pos + 1 ] == metachars[ i ] ){ ++pos; break; } ++i; } } str_out += str[ pos ]; } #ifdef _DEBUG std::cout << str << " -> " << str_out << std::endl; #endif return str_out; } // // HTMLエスケープ // // include_url : URL中でもエスケープする( デフォルト = true ) // const std::string MISC::html_escape( const std::string& str, const bool include_url ) { if( str.empty() ) return str; bool is_url = false; int scheme = SCHEME_NONE; std::string str_out; const size_t str_length = str.length(); for( size_t pos = 0; pos < str_length; ++pos ) { char tmpchar = str.c_str()[ pos ]; // URL中はエスケープしない場合 if( ! include_url ) { // URLとして扱うかどうか // エスケープには影響がないので loose_url としておく if( scheme != SCHEME_NONE ) is_url = is_url_char( str.c_str() + pos, true ); // URLスキームが含まれているか判別 int len = 0; if( ! is_url ) scheme = is_url_scheme( str.c_str() + pos, &len ); // URLスキームが含まれていた場合は文字数分進めてループに戻る if( len > 0 ) { str_out += str.substr( pos, len ); pos += len - 1; // あとで ++pos される分を引く continue; } } // include_url = false でURL中ならエスケープしない if( is_url ) str_out += tmpchar; else if( tmpchar == '&' ) { const int bufsize = 64; char out_char[ bufsize ]; int n_in, n_out; const int type = DBTREE::decode_char( str.c_str() + pos, n_in, out_char, n_out, false ); if( type == DBTREE::NODE_NONE ) str_out += "&"; else str_out += tmpchar; } else if( tmpchar == '\"' ) str_out += """; else if( tmpchar == '<' ) str_out += "<"; else if( tmpchar == '>' ) str_out += ">"; else str_out += tmpchar; } #ifdef _DEBUG if( str != str_out ){ std::cout << "MISC::html_escape\nstr = " << str << std::endl << "out = " << str_out << std::endl; } #endif return str_out; } // // HTMLアンエスケープ // const std::string MISC::html_unescape( const std::string& str ) { if( str.empty() ) return str; if( str.find( "&" ) == std::string::npos ) return str; std::string str_out; const size_t str_length = str.length(); for( size_t pos = 0; pos < str_length; ++pos ){ const int bufsize = 64; char out_char[ bufsize ]; int n_in, n_out; DBTREE::decode_char( str.c_str() + pos, n_in, out_char, n_out, false ); if( n_out ){ str_out += out_char; pos += n_in -1; } else str_out += str.c_str()[ pos ]; } #ifdef _DEBUG if( str != str_out ){ std::cout << "MISC::html_unescape\nstr = " << str << std::endl << "out = " << str_out << std::endl; } #endif return str_out; } // // URL中のスキームを判別する // // 戻り値 : スキームタイプ // length : "http://"等の文字数 // const int MISC::is_url_scheme_impl( const char* str_in, int* length ) { int scheme = SCHEME_NONE; int len = 0; // http https if( *str_in == 'h' && *( str_in + 1 ) == 't' && *( str_in + 2 ) == 't' && *( str_in + 3 ) == 'p' ) { scheme = SCHEME_HTTP; len = 4; if( *( str_in + len ) == 's' ) ++len; } // ftp else if( *str_in == 'f' && *( str_in + 1 ) == 't' && *( str_in + 2 ) == 'p' ) { scheme = SCHEME_FTP; len = 3; } // ttp ttps else if( *str_in == 't' && *( str_in + 1 ) == 't' && *( str_in + 2 ) == 'p' ) { scheme = SCHEME_TTP; len = 3; if( *( str_in + len ) == 's' ) ++len; } // tp tps else if( *str_in == 't' && *( str_in + 1 ) == 'p' ) { scheme = SCHEME_TP; len = 2; if( *( str_in + len ) == 's' ) ++len; } // sssp // デフォルトでモザイクを解除するのでimg.2ch以外のアドレスにはリンクを張らない else if( *str_in == 's' && *( str_in + 1 ) == 's' && *( str_in + 2 ) == 's' && *( str_in + 3 ) == 'p' && *( str_in + 7 ) == 'i' && *( str_in + 8 ) == 'm' && *( str_in + 9 ) == 'g' && *( str_in + 10 ) == '.' && *( str_in + 11 ) == '2' && *( str_in + 12 ) == 'c' && *( str_in + 13 ) == 'h' ) { scheme = SCHEME_SSSP; len = 4; } // 各スキーム後に続く共通の"://" if( *( str_in + len ) == ':' && *( str_in + len + 1 ) == '/' && *( str_in + len + 2 ) == '/' ) { len += 3; if( length ) *length = len; } else scheme = SCHEME_NONE; return scheme; } // // URLとして扱う文字かどうか判別する // // 基本 : 「!#$%&'()*+,-./0-9:;=?@A-Z_a-z~」 // 拡張 : 「[]^|」 // // "RFC 3986" : http://www.ietf.org/rfc/rfc3986.txt // "RFC 2396" : http://www.ietf.org/rfc/rfc2396.txt // static const char s_url_char[ 128 ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ! " # $ % & ' ( ) * + , - . / 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, // @ A B C D E F G H I J K L M N O 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // P Q R S T U V W X Y Z [ \ ] ^ _ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 2, 2, 1, // ` a b c d e f g h i j k l m n o 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // p q r s t u v w x y z { | } ~ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 0, }; const bool MISC::is_url_char( const char* str_in, const bool loose_url ) { unsigned char c = (unsigned char)(*str_in); // 128以上のテーブルはないので先に判定 if( c & 0x80 ) return false; // 基本 if( s_url_char[ c ] == 1 ) return true; // 拡張 // RFC 3986(2.2.)では"[]"が予約文字として定義されているが // RFC 2396(2.4.3.)では除外されていて、普通にURLとして扱う // と問題がありそうなので"loose_url"の扱いにしておく。 if( loose_url && s_url_char[ c ] == 2 ) return true; return false; } // // URLデコード // const std::string MISC::url_decode( const std::string& url ) { if( url.empty() ) return std::string(); const size_t url_length = url.length(); char decoded[ url_length + 1 ]; memset( decoded, 0, sizeof( decoded ) ); unsigned int a, b; for( a = 0, b = a; a < url_length; ++a, ++b ) { if( url[a] == '%' && ( a + 2 < url_length ) ) { char src[3] = { url[ a + 1 ], url[ a + 2 ], '\0' }; char tmp[3] = { '\0', '\0', '\0' }; if( chrtobin( src, tmp ) == 2 ) { // '%4A' など、2文字が変換できていること decoded[b] = *tmp; a += 2; } else { // 変換失敗は、単なる '%' 文字として扱う decoded[b] = url[a]; } } else if( url[a] == '+' ) { decoded[b] = ' '; } else { decoded[b] = url[a]; } } return std::string( decoded ); } // // url エンコード // const std::string MISC::url_encode( const char* str, const size_t n ) { if( str[ n ] != '\0' ){ ERRMSG( "url_encode : invalid input." ); return std::string(); } std::string str_encoded; for( size_t i = 0; i < n; i++ ){ unsigned char c = str[ i ]; const int tmplng = 16; char str_tmp[ tmplng ]; if( ! ( 'a' <= c && c <= 'z' ) && ! ( 'A' <= c && c <= 'Z' ) && ! ( '0' <= c && c <= '9' ) && ( c != '*' ) && ( c != '-' ) && ( c != '.' ) && ( c != '@' ) && ( c != '_' )){ snprintf( str_tmp, tmplng , "\%%%02x", c ); } else { str_tmp[ 0 ] = c; str_tmp[ 1 ] = '\0'; } str_encoded += str_tmp; } return str_encoded; } const std::string MISC::url_encode( const std::string& str ) { return url_encode( str.c_str(), str.length() ); } // // 文字コード変換して url エンコード // // str は UTF-8 であること // const std::string MISC::charset_url_encode( const std::string& str, const std::string& charset ) { if( charset.empty() || charset == "UTF-8" ) return MISC::url_encode( str.c_str(), str.length() ); const std::string str_enc = MISC::Iconv( str, "UTF-8", charset ); return MISC::url_encode( str_enc.c_str(), str_enc.length() ); } // // 文字コード変換して url エンコード // // ただし半角スペースのところを+に置き換えて区切る // const std::string MISC::charset_url_encode_split( const std::string& str, const std::string& charset ) { std::list< std::string > list_str = MISC::split_line( str ); std::list< std::string >::iterator it = list_str.begin(); std::string str_out; for( ; it != list_str.end(); ++it ){ if( it != list_str.begin() ) str_out += "+"; str_out += MISC::charset_url_encode( *it, charset ); } return str_out; } // // BASE64 // const std::string MISC::base64( const std::string& str ) { char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int lng = str.length(); std::string out; out.reserve( lng * 2 ); std::string data = str + "\0\0\0\0"; for( int i = 0; i < lng; i += 3 ){ unsigned char* cstr = (unsigned char*)( data.c_str() + i ); unsigned char key[ 4 ]; key[ 0 ] = (*cstr) >> 2; key[ 1 ] = ( ( (*cstr) << 4 ) + ( (*(cstr+1)) >> 4 ) ); key[ 2 ] = ( ( (*(cstr+1)) << 2 ) + ( (*(cstr+2)) >> 6 ) ); key[ 3 ] = *(cstr+2); for( int j = 0; j < 4; ++j ){ key[ j ] &= 0x3f; out += table[ key[ j ] ]; } } if( lng % 3 == 1 ){ out[ out.length()-2 ] = '='; out[ out.length()-1 ] = '='; } else if( lng % 3 == 2 ){ out[ out.length()-1 ] = '='; } #ifdef _DEBUG std::cout << "MISC::base64 " << str << " -> " << out << std::endl; #endif return out; } // // 文字コードを coding_from から coding_to に変換 // // 遅いので連続的な処理が必要な時は使わないこと // const std::string MISC::Iconv( const std::string& str, const std::string& coding_from, const std::string& coding_to ) { if( coding_from == coding_to ) return str; char* str_bk = ( char* ) malloc( str.length() + 64 ); strcpy( str_bk, str.c_str() ); JDLIB::Iconv* libiconv = new JDLIB::Iconv( coding_from, coding_to ); int byte_out; const std::string str_enc = libiconv->convert( str_bk, strlen( str_bk ), byte_out ); delete libiconv; free( str_bk ); return str_enc; } // // 「&#数字;」形式の数字参照文字列の中の「数字」部分の文字列長 // // in_char: 入力文字列、in_char[0] == "&" && in_char[1] == "#" であること // offset : 開始位置が返る // // 戻り値 : 「&#数字;」の中の数字の文字列の長さ、変換出来ないときは -1 // // 例 : ✏ なら 戻り値 = 4、 offset = 2 // const int MISC::spchar_number_ln( const char* in_char, int& offset ) { int lng = 0; offset = 2; // offset == 2 なら 10 進数、3 なら16進数 if( in_char[ offset ] == 'x' || in_char[ offset ] == 'X' ) ++offset; // UCS2の2バイトの範囲でデコードするので最大65535 // デコードするとき「;」で終端されていなくてもよい // デコード可能かチェック // 10 進数 if( offset == 2 ){ // 最大5桁 (𐀀) for( lng = 0; lng <= 5; lng++ ){ if( in_char[ offset + lng ] < '0' || in_char[ offset + lng ] > '9' ) break; } // 桁数チェック if( lng == 0 || lng == 6 ) return -1; } // 16 進数 else{ // 最大4桁 (￿) for( lng = 0; lng <= 4; lng++ ){ if( ! ( ( in_char[ offset + lng ] >= '0' && in_char[ offset + lng ] <= '9' ) || ( in_char[ offset + lng ] >= 'a' && in_char[ offset + lng ] <= 'f' ) || ( in_char[ offset + lng ] >= 'A' && in_char[ offset + lng ] <= 'F' ) ) ) break; } // 桁数チェック if( lng == 0 || lng == 5 ) return -1; } return lng; } // // 「&#数字;」形式の数字参照文字列を数字(int)に変換する // // 最初に MISC::spchar_number_ln() を呼び出して offset と lng を取得すること // // in_char: 入力文字列、in_char[0] == "&" && in_char[1] == "#" であること // offset : spchar_number_ln() の戻り値 // lng : spchar_number_ln() の戻り値 // // 戻り値 : 「&#数字;」の中の数字(int型) // const int MISC::decode_spchar_number( const char* in_char, const int offset, const int lng ) { char str_num[ 16 ]; memcpy( str_num, in_char + offset, lng ); str_num[ lng ] = '\0'; #ifdef _DEBUG std::cout << "MISC::decode_spchar_number offset = " << offset << " lng = " << lng << " str = " << str_num << std::endl; #endif int num = 0; if( offset == 2 ) num = atoi( str_num ); else num = strtol( str_num, NULL, 16 ); return num; } // // str に含まれる「&#数字;」形式の数字参照文字列を全てユニーコード文字に変換する // const std::string MISC::decode_spchar_number( const std::string& str ) { std::string str_out; const size_t str_length = str.length(); for( size_t i = 0; i < str_length ; ++i ){ if( str[ i ] == '&' && str[ i + 1 ] == '#' ){ int offset; const int lng = MISC::spchar_number_ln( str.c_str()+i, offset ); if( lng == -1 ){ str_out += str[ i ]; continue; } const int num = MISC::decode_spchar_number( str.c_str()+i, offset, lng ); char out_char[ 64 ]; const int n_out = MISC::ucs2toutf8( num, out_char ); if( ! n_out ){ str_out += str[ i ]; continue; } for( int j = 0; j < n_out; ++j ) str_out += out_char[ j ]; i += offset + lng; } else str_out += str[ i ]; } return str_out; } // // utf-8 -> ucs2 変換 // // 入力 : utfstr 入力文字 (UTF-8) // // 出力 : byte 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す // // 戻り値 : ucs2 // const int MISC::utf8toucs2( const char* utfstr, int& byte ) { int ucs2 = 0; byte = 0; if( utfstr[ 0 ] == '\0' ) return '\0'; else if( ( ( unsigned char ) utfstr[ 0 ] & 0xf0 ) == 0xe0 ){ byte = 3; ucs2 = utfstr[ 0 ] & 0x0f; ucs2 = ( ucs2 << 6 ) + ( utfstr[ 1 ] & 0x3f ); ucs2 = ( ucs2 << 6 ) + ( utfstr[ 2 ] & 0x3f ); } else if( ( ( unsigned char ) utfstr[ 0 ] & 0x80 ) == 0 ){ // ascii byte = 1; ucs2 = utfstr[ 0 ]; } else if( ( ( unsigned char ) utfstr[ 0 ] & 0xe0 ) == 0xc0 ){ byte = 2; ucs2 = utfstr[ 0 ] & 0x1f; ucs2 = ( ucs2 << 6 ) + ( utfstr[ 1 ] & 0x3f ); } else if( ( ( unsigned char ) utfstr[ 0 ] & 0xf8 ) == 0xf0 ){ byte = 4; ucs2 = utfstr[ 0 ] & 0x07; ucs2 = ( ucs2 << 6 ) + ( utfstr[ 1 ] & 0x3f ); ucs2 = ( ucs2 << 6 ) + ( utfstr[ 2 ] & 0x3f ); ucs2 = ( ucs2 << 6 ) + ( utfstr[ 3 ] & 0x3f ); } // 不正なUTF8 else { byte = 1; ucs2 = utfstr[ 0 ]; ERRMSG( "MISC::utf8toucs2 : invalid code = " + MISC::itostr( ucs2 ) ); } return ucs2; } // // ucs2 -> utf8 変換 // // 出力 : utfstr 変換後の文字 // // 戻り値 : バイト数 // const int MISC::ucs2toutf8( const int ucs2, char* utfstr ) { int byte = 0; if( ucs2 < 0x7f ){ // ascii byte = 1; utfstr[ 0 ] = ucs2; } else if( ucs2 < 0x07ff ){ byte = 2; utfstr[ 0 ] = ( 0xc0 ) + ( ucs2 >> 6 ); utfstr[ 1 ] = ( 0x80 ) + ( ucs2 & 0x3f ); } else if( ucs2 < 0xffff){ byte = 3; utfstr[ 0 ] = ( 0xe0 ) + ( ucs2 >> 12 ); utfstr[ 1 ] = ( 0x80 ) + ( ( ucs2 >>6 ) & 0x3f ); utfstr[ 2 ] = ( 0x80 ) + ( ucs2 & 0x3f ); } else{ byte = 4; utfstr[ 0 ] = ( 0xf0 ) + ( ucs2 >> 18 ); utfstr[ 1 ] = ( 0x80 ) + ( ( ucs2 >>12 ) & 0x3f ); utfstr[ 2 ] = ( 0x80 ) + ( ( ucs2 >>6 ) & 0x3f ); utfstr[ 3 ] = ( 0x80 ) + ( ucs2 & 0x3f ); } utfstr[ byte ] = 0; return byte; } // // ucs2 の種類 // const int MISC::get_ucs2mode( const int ucs2 ) { if( ucs2 >= 0x0000 && ucs2 <= 0x007f ) return UCS2MODE_BASIC_LATIN; if( ucs2 >= 0x3040 && ucs2 <= 0x309f ) return UCS2MODE_HIRA; if( ucs2 >= 0x30a0 && ucs2 <= 0x30ff ) return UCS2MODE_KATA; return UCS2MODE_OTHER; } // // WAVEDASHなどのWindows系UTF-8文字をUnix系文字と相互変換 // const std::string MISC::utf8_fix_wavedash( const std::string& str, const int mode ) { // WAVE DASH 問題 const size_t size = 4; const char Win[size][4] = { { -17, -67, -98, '\0' }, // FULLWIDTH TILDE (U+FF5E) { -30, -128, -107, '\0' }, // HORIZONTAL BAR (U+2015) { -30, -120, -91, '\0' }, // PARALLEL TO (U+2225) { -17, -68, -115, '\0' } // FULLWIDTH HYPHEN-MINUS (U+FF0D) }; const char Unix[size][4] = { { -29, -128, -100, '\0' }, // WAVE DASH (U+301C) { -30, -128, -108, '\0' }, // EM DASH(U+2014) { -30, -128, -106, '\0' }, // DOUBLE VERTICAL LINE (U+2016) { -30, -120, -110, '\0' } // MINUS SIGN (U+2212) }; std::string ret(str); if( mode == WINtoUNIX ){ for( size_t i = 0; i < ret.length(); i++ ) { for( size_t s = 0; s < size; s++ ) { if( ret[ i ] != Win[ s ][ 0 ] || ret[ i+1 ] != Win[ s ][ 1 ] || ret[ i+2 ] != Win[ s ][ 2 ] ) continue; for( size_t t = 0; t < 3; t++ ) ret[ i+t ] = Unix[ s ][ t ]; i += 2; break; } } }else{ for( size_t i = 0; i < ret.length(); i++ ) { for( size_t s = 0; s < size; s++ ) { if( ret[ i ] != Unix[ s ][ 0 ] || ret[ i+1 ] != Unix[ s ][ 1 ] || ret[ i+2 ] != Unix[ s ][ 2 ] ) continue; for( size_t t = 0; t < 3; t++ ) ret[ i+t ] = Win[ s ][ t ]; i += 2; break; } } } return ret; } // // str を大文字化 // const std::string MISC::toupper_str( const std::string& str ) { std::string str_out; const size_t str_length = str.length(); for( size_t i = 0; i < str_length ; ++i ) str_out += toupper( str[ i ] ); return str_out; } // // list 内のアイテムを全部大文字化 // const std::list< std::string > MISC::toupper_list( const std::list< std::string >& list_str ) { std::list< std::string > list_out; std::list< std::string >::const_iterator it = list_str.begin(); for( ; it != list_str.end() ; ++it ) list_out.push_back( MISC::toupper_str( *it ) ); return list_out; } // // str を小文字化 // const std::string MISC::tolower_str( const std::string& str ) { std::string str_out; const size_t str_length = str.length(); for( size_t i = 0; i < str_length; ++i ) str_out += tolower( str[ i ] ); return str_out; } // // path からホスト名だけ取り出す // // protocol = false のときはプロトコルを除く // const std::string MISC::get_hostname( const std::string& path, bool protocol ) { int lng = 0; if( path.find( "http://" ) == 0 ) lng = strlen( "http://" ); else if( path.find( "https://" ) == 0 ) lng = strlen( "https://" ); else if( path.find( "ftp://" ) == 0 ) lng = strlen( "ftp://" ); if( !lng ) return std::string(); int pos = 0; if( ! protocol ) pos = lng; size_t i = path.find( "/", lng ); if( i == std::string::npos ) path.substr( pos ); return path.substr( pos, i - pos ); } // // path からファイル名だけ取り出す // const std::string MISC::get_filename( const std::string& path ) { if( path.empty() ) return std::string(); size_t i = path.rfind( "/" ); if( i == std::string::npos ) return path; return path.substr( i+1 ); } // // path からファイル名を除いてディレクトリだけ取り出す // const std::string MISC::get_dir( const std::string& path ) { if( path.empty() ) return std::string(); size_t i = path.rfind( "/" ); if( i == std::string::npos ) return std::string(); return path.substr( 0, i+1 ); } // // 文字数を限定して環境変数の値を返す // const std::string MISC::getenv_limited( const char *name, const size_t size ) { if( ! name || ! getenv( name ) ) return std::string(); char env[ size + 1 ]; env[ size ] = '\0'; strncpy( env, getenv( name ), size ); #ifdef _WIN32 return recover_path( Glib::locale_to_utf8( std::string( env ) ) ); #else return std::string( env ); #endif } // // pathセパレータを / に置き換える // const std::string MISC::recover_path( const std::string& str ) { #ifdef _WIN32 // Windowsのpathセパレータ \ を、jdの / に置き換える std::string ret( str ); for (int i=ret.length()-1; i>=0; i--) if (ret[ i ] == '\\') ret[ i ] = '/'; return ret; #else return str; #endif } const std::list< std::string > MISC::recover_path( const std::list< std::string >& list_str ) { #ifdef _WIN32 std::list< std::string > list_ret; std::list< std::string >::const_iterator it = list_str.begin(); for( ; it != list_str.end() ; ++it ) list_ret.push_back( MISC::recover_path( *it ) ); return list_ret; #else return list_str; #endif } // // 文字列(utf-8)に全角英数字が含まれるか判定する // const bool MISC::has_widechar( const char* str ) { while( *str != '\0' ){ const unsigned char in = *str; if( ( in & 0xf0 ) == 0xe0 ){ if( in == 0xef ){ const unsigned char in2 = * ( str + 1 ); const unsigned char in3 = * ( str + 2 ); if( in2 == 0xbc ){ // 全角数字 if( 0x90 <= in3 && in3 <= 0x99 ) return true; // 全角大文字 else if( 0xa1 <= in3 && in3 <= 0xba ) return true; } // 全角小文字 else if( in2 == 0xbd && ( 0x81 <= in3 && in3 <= 0x9a ) ) return true; // 半角かな else if( ( in2 == 0xbd && ( 0xa1 <= in3 && in3 <= 0xbf ) ) || ( in2 == 0xbe && ( 0x80 <= in3 && in3 <= 0x9f ) ) ) return true; } str += 3; } else if( ( in & 0xe0 ) == 0xc0 ) str += 2; else if( ( in & 0xf8 ) == 0xf0 ) str += 4; else ++str; } return false; } // // 全角英数字(str1) -> 半角英数字(str2) // // table_pos : 置き換えた文字列の位置 // n : str2 と table_pos のバッファサイズ // void MISC::asc( const char* str1, char* str2, int* table_pos, const size_t n ) { const size_t mrg = 18; size_t pos = 0; size_t pos2 = 0; while( pos2 < ( n - mrg ) && *( str1 + pos ) != '\0' ){ const unsigned char in = *( str1 + pos ); if( in == 0xef ){ const unsigned char in2 = * ( str1 + pos + 1 ); const unsigned char in3 = * ( str1 + pos + 2 ); if( in2 == 0xbc ){ // 全角数字 if( 0x90 <= in3 && in3 <= 0x99 ){ str2[ pos2 ] = '0' + in3 - 0x90;; table_pos[ pos2 ] = pos; pos += 3; ++pos2; continue; } // 全角大文字 else if( 0xa1 <= in3 && in3 <= 0xba ){ str2[ pos2 ] = 'A' + in3 - 0xa1; table_pos[ pos2 ] = pos; pos += 3; ++pos2; continue; } } // 全角小文字 else if( in2 == 0xbd && ( 0x81 <= in3 && in3 <= 0x9a ) ){ str2[ pos2 ] = 'a' + in3 - 0x81; table_pos[ pos2 ] = pos; pos += 3; ++pos2; continue; } // 半角かな else if( ( in2 == 0xbd && ( 0xa1 <= in3 && in3 <= 0xbf ) ) || ( in2 == 0xbe && ( 0x80 <= in3 && in3 <= 0x9f ) ) ){ bool flag_hkana = false; bool dakuten = false; size_t i = 0; // 濁点、半濁点 const unsigned char in4 = * ( str1 + pos + 3 ); const unsigned char in5 = * ( str1 + pos + 4 ); if( in4 == 0xef && in5 == 0xbe ){ const unsigned char in6 = * ( str1 + pos + 5 ); // 濁点 if( in6 == 0x9e ){ dakuten = true; i = 61; } // 半濁点 else if( in6 == 0x9f ){ dakuten = true; i = 61 + 21; } } while( !flag_hkana && hkana_table1[ i ][ 0 ][ 0 ] != '\0' ){ if( in == hkana_table1[ i ][ 0 ][ 0 ] && in2 == hkana_table1[ i ][ 0 ][ 1 ] && in3 == hkana_table1[ i ][ 0 ][ 2 ] ){ str2[ pos2 ] = hkana_table1[ i ][ 1 ][ 0 ]; str2[ pos2 +1 ] = hkana_table1[ i ][ 1 ][ 1 ]; str2[ pos2 +2 ] = hkana_table1[ i ][ 1 ][ 2 ]; table_pos[ pos2 ] = pos; pos += 3; if( dakuten ) pos += 3; pos2 += 3; flag_hkana = true; } ++i; } if( flag_hkana ) continue; } } str2[ pos2 ] = str1[ pos ]; table_pos[ pos2 ] = pos; ++pos; ++pos2; } if( pos2 >= ( n - mrg ) ){ ERRMSG( "MISC::asc : buffer overflow." ); pos2 = ( n - mrg ) - 1; } table_pos[ pos2 ] = pos; str2[ pos2 ] = '\0'; } jd-2.8.7-140104/src/jdlib/miscutil.h0000644000076400010400000002606612074603162013460 0ustar // ライセンス: GPL2 // 文字列関係の関数 #ifndef _MISCUTIL_H #define _MISCUTIL_H #include #include #include #include #include namespace MISC { // URLスキームタイプ enum { SCHEME_NONE, SCHEME_HTTP, SCHEME_FTP, SCHEME_TTP, SCHEME_TP, SCHEME_SSSP }; // get_ucs2mode()の戻り値 enum { UCS2MODE_BASIC_LATIN = 0, UCS2MODE_HIRA, UCS2MODE_KATA, UCS2MODE_OTHER }; // utf8_fix_wavedash のモード enum { UNIXtoWIN = 0, WINtoUNIX }; // str を "\n" ごとに区切ってlistにして出力 const std::list< std::string > get_lines( const std::string& str ); // strを空白または "" 単位で区切って list で出力 const std::list< std::string > split_line( const std::string& str ); // strを delimで区切って list で出力 const std::list< std::string > StringTokenizer( const std::string& str, const char delim ); // emacs lisp のリスト型を要素ごとにlistにして出力 const std::list< std::string > get_elisp_lists( const std::string& str ); // list_inから空白行を除いてリストを返す const std::list< std::string > remove_nullline_from_list( const std::list< std::string >& list_in ); // list_inの各行から前後の空白を除いてリストを返す const std::list< std::string > remove_space_from_list( const std::list< std::string >& list_in ); // list_inからコメント行(#)を除いてリストを返す const std::list< std::string > remove_commentline_from_list( const std::list< std::string >& list_in ); // 空白と""で区切られた str_in の文字列をリストにして出力 // \"は " に置換される // (例) "aaa" "bbb" "\"ccc\"" → aaa と bbb と "ccc" const std::list< std::string > strtolist( const std::string& str_in ); // list_in の文字列リストを空白と""で区切ってストリングにして出力 // "は \" に置換される // (例) "aaa" "bbb" "\"ccc\"" const std::string listtostr( const std::list< std::string >& list_in ); // strの前後の空白削除 const std::string remove_space( const std::string& str ); // str前後の改行、タブ、スペースを削除 const std::string remove_spaces( const std::string& str ); // str1からstr2で示された文字列を除く const std::string remove_str( const std::string& str1, const std::string& str2 ); // start 〜 end の範囲をstrから取り除く ( /* コメント */ など ) const std::string remove_str( const std::string& str, const std::string& start, const std::string& end ); // 正規表現を使ってstr1からqueryで示された文字列を除く const std::string remove_str_regex( const std::string& str1, const std::string& query ); // str1, str2 に囲まれた文字列を切り出す const std::string cut_str( const std::string& str, const std::string& str1, const std::string& str2 ); // str1 を str2 に置き換え const std::string replace_str( const std::string& str, const std::string& str1, const std::string& str2 ); // list_inから str1 を str2 に置き換えてリストを返す const std::list< std::string > replace_str_list( const std::list< std::string >& list_in, const std::string& str1, const std::string& str2 ); // str_in に含まれる改行文字を replace に置き換え const std::string replace_newlines_to_str( const std::string& str_in, const std::string& replace ); // " を \" に置き換え const std::string replace_quot( const std::string& str ); // \" を " に置き換え const std::string recover_quot( const std::string& str ); // str 中に含まれている str2 の 数を返す const int count_str( const std::string& str, const std::string& str2 ); // str 中に含まれている chr の 数を返す const int count_chr( const std::string& str, const char chr ); // 文字列(utf-8も) -> 整数変換 // (例) "123" -> 123 // 入力: str // 出力: // dig: 桁数、0なら失敗 // n : str から何バイト読み取ったか // 戻り値: 数値 const int str_to_uint( const char* str, size_t& dig, size_t& n ); // 数字 -> 文字変換 const std::string itostr( const int n ); // listで指定した数字を文字に変換 const std::string intlisttostr( const std::list< int >& list_num ); // 16進数表記文字をバイナリに変換する( 例 "E38182" -> 0xE38182 ) // 出力 : char_out // 戻り値: 変換に成功した chr_in のバイト数 const size_t chrtobin( const char* chr_in, char* chr_out ); // strが半角でmaxsize文字を超えたらカットして後ろに...を付ける const std::string cut_str( const std::string& str, const unsigned int maxsize ); // 正規表現のメタ文字が含まれているか // escape == true ならエスケープを考慮 (例) escape == true なら \+ → \+ のまま、falseなら \+ → \\\+ const bool has_regex_metachar( const std::string& str, const bool escape ); // 正規表現のメタ文字をエスケープ // escape == true ならエスケープを考慮 (例) escape == true なら \+ → \+ のまま、falseなら \+ → \\\+ const std::string regex_escape( const std::string& str, const bool escape ); // 正規表現のメタ文字をアンエスケープ const std::string regex_unescape( const std::string& str ); // HTMLエスケープ // include_url : URL中でもエスケープする( デフォルト = true ) const std::string html_escape( const std::string& str, const bool include_url = true ); // HTMLアンエスケープ const std::string html_unescape( const std::string& str ); // URL中のスキームを判別する // 戻り値 : スキームタイプ // length : "http://"等の文字数 const int is_url_scheme( const char* str_in, int* length = NULL ); const int is_url_scheme_impl( const char* str_in, int* length ); // URLとして扱う文字かどうか判別する // 基本 : 「!#$%&'()*+,-./0-9:;=?@A-Z_a-z~」 // 拡張 : 「[]^|」 // // "RFC 3986" : http://www.ietf.org/rfc/rfc3986.txt // "RFC 2396" : http://www.ietf.org/rfc/rfc2396.txt const bool is_url_char( const char* str_in, const bool loose_url ); // URLデコード const std::string url_decode( const std::string& url ); // urlエンコード const std::string url_encode( const char* str, const size_t n ); const std::string url_encode( const std::string& str ); // 文字コードを変換して url エンコード // str は UTF-8 であること const std::string charset_url_encode( const std::string& str, const std::string& charset ); // 文字コード変換して url エンコード // ただし半角スペースのところを+に置き換えて区切る const std::string charset_url_encode_split( const std::string& str, const std::string& charset ); // BASE64 const std::string base64( const std::string& str ); // 文字コードを coding_from から coding_to に変換 // 遅いので連続的な処理が必要な時は使わないこと const std::string Iconv( const std::string& str, const std::string& coding_from, const std::string& coding_to ); // 「&#数字;」形式の数字参照文字列の中の「数字」部分の文字列長 // // in_char: 入力文字列、in_char[0] == "&" && in_char[1] == "#" であること // offset : 開始位置が返る // // 戻り値 : 「&#数字;」の中の数字の文字列の長さ、変換出来ないときは -1 // // 例 : ✏ なら 戻り値 = 4、 offset = 2 // const int spchar_number_ln( const char* in_char, int& offset ); // 「&#数字;」形式の数字参照文字列を数字(int)に変換する // // 最初に MISC::spchar_number_ln() を呼び出して offset と lng を取得すること // // in_char: 入力文字列、in_char[0] == "&" && in_char[1] == "#" であること // offset : spchar_number_ln() の戻り値 // lng : spchar_number_ln() の戻り値 // // 戻り値 : 「&#数字;」の中の数字(int型) // const int decode_spchar_number( const char* in_char, const int offset, const int lng ); // str に含まれる「&#数字;」形式の数字参照文字列を全てユニーコード文字に変換する const std::string decode_spchar_number( const std::string& str ); // utf-8 -> ucs2 変換 // 入力 : utfstr 入力文字 (UTF-8) // 出力 : byte 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す // 戻り値 : ucs2 const int utf8toucs2( const char* utfstr, int& byte ); // ucs2 の種類 const int get_ucs2mode( const int ucs2 ); // ucs2 -> utf8 変換 // 出力 : utfstr 変換後の文字 // 戻り値 : バイト数 const int ucs2toutf8( const int ucs2, char* utfstr ); // WAVEDASHなどのWindows系UTF-8文字をUnix系文字と相互変換 const std::string utf8_fix_wavedash( const std::string& str, const int mode ); // str を大文字化 const std::string toupper_str( const std::string& str ); // list 内のアイテムを全部大文字化 const std::list< std::string > toupper_list( const std::list< std::string >& list_str ); //str を小文字化 const std::string tolower_str( const std::string& str ); // path からホスト名だけ取り出す // protocol = false のときはプロトコルを除く const std::string get_hostname( const std::string& path, const bool protocol = true ); // path からファイル名だけ取り出す const std::string get_filename( const std::string& path ); // path からファイル名を除いてディレクトリだけ取り出す const std::string get_dir( const std::string& path ); // 文字数を限定して環境変数の値を返す const std::string getenv_limited( const char *name, const size_t size = 1 ); // pathセパレータを / に置き換える const std::string recover_path( const std::string& str ); const std::list< std::string > recover_path( const std::list< std::string >& list_str ); // 文字列(utf-8)に全角英数字が含まれるか判定する const bool has_widechar( const char* str ); // 全角英数字(str1) -> 半角英数字(str2) // table_pos : 置き換えた文字列の位置 // n : str2 と table_pos のバッファサイズ void asc( const char* str1, char* str2, int* table_pos, const size_t n ); // URL中のスキームを判別する inline const int is_url_scheme( const char* str_in, int* length ) { // 候補になり得ない場合は以降の処理はしない if( *str_in != 'h' && *str_in != 'f' && *str_in != 't' && *str_in != 's' ) return SCHEME_NONE; return is_url_scheme_impl( str_in, length ); } } #endif jd-2.8.7-140104/src/jdlib/miscx.cpp0000644000076400010400000000070211215464761013300 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "miscx.h" #ifndef _WIN32 #include #endif void MISC::WarpPointer( Glib::RefPtr< Gdk::Window > src, Glib::RefPtr< Gdk::Window > dest, int x, int y ){ #ifndef _WIN32 XWarpPointer( GDK_WINDOW_XDISPLAY( Glib::unwrap( src ) ), None, GDK_WINDOW_XWINDOW( Glib::unwrap( dest ) ) , 0, 0, 0, 0, x, y ); #endif } jd-2.8.7-140104/src/jdlib/miscx.h0000644000076400010400000000035310566340571012747 0ustar // ライセンス: GPL2 // X 関係の関数 #ifndef _MISCX_H #define _MISCX_H #include namespace MISC { void WarpPointer( Glib::RefPtr< Gdk::Window > src, Glib::RefPtr< Gdk::Window > dest, int x, int y ); } #endif jd-2.8.7-140104/src/jdlib/refptr_lock.h0000644000076400010400000000314410540252733014131 0ustar // ライセンス: GPL2 // // ロック付きリファレンスクラスのテンプレート // // SKELETON::Lockable を継承したクラスを RefPtr_Lock 経由で呼ぶことによってロックを掛ける // #ifndef _REFPTR_LOCK_H #define _REFPTR_LOCK_H namespace JDLIB { template < typename T > class RefPtr_Lock { T *m_p; public: void clear(){ if( m_p ){ m_p->unlock(); m_p = NULL; } } void set( T *p ){ clear(); m_p = p; if( m_p ) m_p->lock(); } T* operator -> (){ return m_p; } bool operator == ( const T *p ) const { return( m_p == p ); } bool operator != ( const T *p ) const { return( m_p != p ); } bool operator ! () const { return ( m_p == NULL ); } operator bool () const { return ( m_p != NULL ); } RefPtr_Lock< T >& operator = ( const RefPtr_Lock< T >& a ){ set( a.m_p ); return *this; } RefPtr_Lock< T >& operator = ( RefPtr_Lock< T >& a ){ set( a.m_p ); return *this; } RefPtr_Lock< T >& operator = ( const T *p ){ set( p ); return *this; } RefPtr_Lock< T >& operator = ( T *p ){ set( p ); return *this; } RefPtr_Lock() : m_p (0){} RefPtr_Lock( const RefPtr_Lock< T >& a ): m_p (0){ set( a.m_p ); } RefPtr_Lock( RefPtr_Lock< T >& a ) : m_p (0){ set( a.m_p ); } RefPtr_Lock( T *p ) : m_p (0){ set( p ); } RefPtr_Lock( const T *p ) : m_p (0){ set( p ); } virtual ~RefPtr_Lock(){ clear();} }; } #endif jd-2.8.7-140104/src/jdlib/ssl.cpp0000644000076400010400000001125511713217606012760 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "ssl.h" using namespace JDLIB; #ifdef USE_GNUTLS // gnutls 使用 void JDLIB::init_ssl() { #ifdef _DEBUG std::cout << "init_ssl(gnutls)\n"; #endif gnutls_global_init(); } void JDLIB::deinit_ssl() { #ifdef _DEBUG std::cout << "deinit_ssl(gnutls)\n"; #endif gnutls_global_deinit(); } JDSSL::JDSSL() : m_session( 0 ), m_cred( 0 ) { #ifdef _DEBUG std::cout << "JDSSL::JDSSL(gnutls)\n"; #endif } JDSSL::~JDSSL() { #ifdef _DEBUG std::cout << "JDSSL::~JDSSL(gnutls)\n"; #endif close(); } const bool JDSSL::connect( const int soc ) { #ifdef _DEBUG std::cout << "JDSSL::connect(gnutls)\n"; #endif if( soc < 0 ) return false; if( m_session ) return false; if( m_cred ) return false; int ret; ret = gnutls_init( &m_session, GNUTLS_CLIENT ); if( ret != 0 ){ m_errmsg = "gnutls_init failed"; return false; } #if GNUTLS_VERSION_NUMBER >= 0x020108 // gnutls >= 2.1.7 (unreleased) gnutls_priority_set_direct( m_session, "NORMAL:%COMPAT", NULL ); #else // GNUTLS_VERSION_NUMBER >= 0x020108 static const int priority_prot[] = { GNUTLS_SSL3, 0 }; // DEPRECATED (gnutls >= 2.1.4 gnutls =< 2.1.6) // UNDEPRECATED (gnutls >= 2.1.7) gnutls_set_default_priority( m_session ); // _GNUTLS_GCC_ATTR_DEPRECATE (gnutls >= 2.12.0) gnutls_protocol_set_priority( m_session, priority_prot ); #endif // GNUTLS_VERSION_NUMBER >= 0x020108 gnutls_transport_set_ptr( m_session, (gnutls_transport_ptr_t)(long) soc ); gnutls_certificate_allocate_credentials( &m_cred ); gnutls_credentials_set( m_session, GNUTLS_CRD_CERTIFICATE, m_cred ); while ( ( ret = gnutls_handshake( m_session ) ) != GNUTLS_E_SUCCESS ) { if ( gnutls_error_is_fatal( ret ) != 0 ) { m_errmsg = "gnutls_handshake failed"; return false; } } #ifdef _DEBUG std::cout << "connect ok\n"; #endif return true; } const bool JDSSL::close() { #ifdef _DEBUG std::cout << "JDSSL::close(gnutlsl)\n"; #endif if( m_session ){ gnutls_bye( m_session, GNUTLS_SHUT_RDWR ); gnutls_deinit( m_session ); m_session = 0; } if( m_cred ){ gnutls_certificate_free_credentials( m_cred ); m_cred = 0; } return true; } const int JDSSL::write( const char* buf, const size_t bufsize ) { int tmpsize = gnutls_record_send( m_session, buf, bufsize ); if( tmpsize < 0 ) m_errmsg = "gnutls_record_send failed"; return tmpsize; } const int JDSSL::read( char* buf, const size_t bufsize ) { int tmpsize = gnutls_record_recv( m_session, buf, bufsize ); if( tmpsize < 0 ) m_errmsg = "gnutls_record_recv failed"; return tmpsize; } #else //////////////////////////////////////////////////////////////////// // OpenSSL 使用 void JDLIB::init_ssl() { #ifdef _DEBUG std::cout << "init_ssl(openssl)\n"; #endif } void JDLIB::deinit_ssl() { #ifdef _DEBUG std::cout << "deinit_ssl(openssl)\n"; #endif } JDSSL::JDSSL() : m_ctx( NULL ), m_ssl( NULL ) { #ifdef _DEBUG std::cout << "JDSSL::JDSSL(openssl)\n"; #endif } JDSSL::~JDSSL() { #ifdef _DEBUG std::cout << "JDSSL::~JDSSL(openssl)\n"; #endif close(); } const bool JDSSL::connect( const int soc ) { #ifdef _DEBUG std::cout << "JDSSL::connect(openssl)\n"; #endif if( soc < 0 ) return false; if( m_ctx ) return false; if( m_ssl ) return false; SSL_library_init(); m_ctx = SSL_CTX_new( SSLv23_client_method() ); if( ! m_ctx ){ m_errmsg = "SSL_CTX_new failed"; return false; } m_ssl = SSL_new( m_ctx ); if( ! m_ssl ){ m_errmsg = "SSL_new failed"; return false; } if( SSL_set_fd( m_ssl, soc ) == 0 ){ m_errmsg = "SSL_set_fd failed"; return false; } if( SSL_connect( m_ssl ) != 1 ){ m_errmsg = "SSL_connect failed"; return false; } #ifdef _DEBUG std::cout << "connect ok\n"; #endif return true; } const bool JDSSL::close() { #ifdef _DEBUG std::cout << "JDSSL::close(openssl)\n"; #endif if( m_ssl ){ SSL_shutdown( m_ssl ); SSL_free( m_ssl ); m_ssl = NULL; } if( m_ctx ){ SSL_CTX_free( m_ctx ); m_ctx = NULL; } return true; } const int JDSSL::write( const char* buf, const size_t bufsize ) { int tmpsize = SSL_write( m_ssl, buf, bufsize ); if( tmpsize < 0 ) m_errmsg = "SSL_write failed"; return tmpsize; } const int JDSSL::read( char* buf, const size_t bufsize ) { int tmpsize = SSL_read( m_ssl, buf, bufsize ); if( tmpsize < 0 ) m_errmsg = "SSL_read failed"; return tmpsize; } #endif jd-2.8.7-140104/src/jdlib/ssl.h0000644000076400010400000000220412006765627012426 0ustar // ライセンス: GPL2 // // SSL ローダ // #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef USE_GNUTLS #include #else #include // gdkmm/device.h で定義される set_key マクロと衝突する #ifdef set_key #undef set_key #endif #endif #include namespace JDLIB { class JDSSL { std::string m_errmsg; #ifdef USE_GNUTLS gnutls_session_t m_session; #if GNUTLS_VERSION_NUMBER >= 0x020000 gnutls_certificate_credentials_t m_cred; #else // GNUTLS_VERSION_NUMBER >= 0x020000 // DEPRECATED (gnutls >= 2.x) gnutls_certificate_credentials m_cred; #endif // GNUTLS_VERSION_NUMBER >= 0x020000 #else // USE_GNUTLS SSL_CTX *m_ctx; SSL* m_ssl; #endif // USE_GNUTLS public: JDSSL(); virtual ~JDSSL(); const std::string& get_errmsg(){ return m_errmsg; } const bool connect( const int soc ); const bool close(); const int write( const char* buf, const size_t bufsize ); const int read( char* buf, const size_t bufsize ); }; void init_ssl(); void deinit_ssl(); } jd-2.8.7-140104/src/jdlib/tfidf.cpp0000644000076400010400000001570011307731405013247 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "tfidf.h" #include "dbtree/articlebase.h" #include "global.h" #include #include // // 単語ベクトル作成 // void MISC::tfidf_create_vec_words( VEC_WORDS& vec_words, const Glib::ustring& document ) { const int n = document.length() - 1; #ifdef _DEBUG std::cout << "tfidf_create_vec_words\n"; std::cout << "doc = " << document.raw() << std::endl; std::cout << "n = " << n << std::endl; #endif if( n <= 0 ) return; std::set< Glib::ustring > set_words; for( int i = 0; i < n; ++i ){ Glib::ustring word = document.substr( i, 2 ); if( set_words.find( word ) == set_words.end() ){ set_words.insert( word ); vec_words.push_back( word ); } } #ifdef _DEBUG // for( int i = 0; i < (int)vec_words.size(); ++i ) std::cout << vec_words[ i ].raw() << std::endl; #endif } // // IDF計算 (実際には頻度計算) // // vec_idf はあらかじめ resize しておくこと // void MISC::tfidf_create_vec_idf( VEC_IDF& vec_idf, const Glib::ustring& document, const VEC_WORDS& vec_words ) { const int n = vec_words.size(); #ifdef _DEBUG // std::cout << "MISC::tfidf_create_vec_idf n = " << n << std::endl; #endif if( ! n || n != (int)vec_idf.size() ) return; for( int i = 0; i < n; ++i ){ if( document.find( vec_words[ i ] ) != Glib::ustring::npos ) vec_idf[ i ] += 1; } } // // documnet に対する TFIDF ベクトル計算 // // vec_tfidf はあらかじめ resize しておくこと // void MISC::tfidf_calc_vec_tfifd( VEC_TFIDF& vec_tfidf, const Glib::ustring& document, const VEC_IDF& vec_idf, const VEC_WORDS& vec_words ) { const int n = vec_words.size(); const int n_doc = document.size() - 1; #ifdef _DEBUG std::cout << "tfidf_calc_vec_tfidf\n"; std::cout << "doc = " << document.raw() << std::endl; std::cout << "n = " << n << " n_doc = " << n_doc << std::endl; #endif if( ! n || n_doc <= 0 || n != (int)vec_tfidf.size() ) return; double total = 0; for( int i = 0; i < n; ++i ){ if( document.find( vec_words[ i ] ) == Glib::ustring::npos ){ vec_tfidf[ i ] = 0; continue; } int hit = 0; for( int j = 0; j < n_doc; ++j ) if( document.substr( j, 2 ) == vec_words[ i ] ) ++hit; vec_tfidf[ i ] = hit; total += hit; } for( int i = 0; i < n; ++i ){ #ifdef _DEBUG // std::cout << vec_words[ i ].raw() << " : hit = " << (int)vec_tfidf[ i ]; #endif if( total ){ vec_tfidf[ i ] /= total; vec_tfidf[ i ] *= vec_idf[ i ]; } else vec_tfidf[ i ] = 0; #ifdef _DEBUG // std::cout << " tfidf = " << vec_tfidf[ i ] << std::endl; #endif } } // // 相関計算 // const double MISC::tfidf_cos_similarity( const VEC_TFIDF& vec_tfidf1, const VEC_TFIDF& vec_tfidf2 ) { const int n = vec_tfidf1.size(); #ifdef _DEBUG std::cout << "MISC::tfidf_cos_similarity n = " << n << std::endl; #endif if( ! n || n != (int)vec_tfidf1.size() ) return 0; double product = 0; double lng1 = 0; double lng2 = 0; for( int i = 0; i < n; ++i ){ product += vec_tfidf1[ i ] * vec_tfidf2[ i ]; lng1 += vec_tfidf1[ i ] * vec_tfidf1[ i ]; lng2 += vec_tfidf2[ i ] * vec_tfidf2[ i ]; } if( lng1 == 0 ) return 0; if( lng2 == 0 ) return 0; const double ret = product / sqrt( lng1 * lng2 ); #ifdef _DEBUG std::cout << "similarity = " << ret << std::endl; #endif return ret; } // // スレ一覧からIDF 計算 // void MISC::tfidf_create_vec_idf_from_board( VEC_IDF& vec_idf, const Glib::ustring& subject_src, const std::vector< DBTREE::ArticleBase* >& list_subject, const VEC_WORDS& vec_words ) { #ifdef _DEBUG std::cout << "MISC::tfidf_create_vec_idf_from_board\n"; #endif if( subject_src.empty() || ! list_subject.size() || ! vec_words.size() ) return; vec_idf.resize( vec_words.size() ); MISC::tfidf_create_vec_idf( vec_idf, subject_src, vec_words ); int D = 1; std::vector< DBTREE::ArticleBase* >::const_iterator it = list_subject.begin(); for( ; it != list_subject.end(); ++it ){ // DAT落ちのスレは除く if( ( *it )->get_status() & STATUS_OLD ) continue; const Glib::ustring subject = ( *it )->get_subject(); if( subject != subject_src ){ MISC::tfidf_create_vec_idf( vec_idf, subject, vec_words ); ++D; } } for( int i = 0; i < (int)vec_words.size(); ++i ){ #ifdef _DEBUG std::cout << vec_words[ i ].raw() << " hit = " << (int)vec_idf[ i ] << " / " << D; #endif vec_idf[ i ] = log( D / vec_idf[ i ] ); #ifdef _DEBUG std::cout << " idf = " << vec_idf[ i ] << std::endl; #endif } } // str1 と str2 間のレーベンシュタイン距離 const double MISC::leven( std::vector< std::vector< int > >& dist, const Glib::ustring& str1, const Glib::ustring& str2 ) { const size_t maxlng = dist.size() -1; const size_t lng1 = MIN( maxlng, str1.length() ); const size_t lng2 = MIN( maxlng, str2.length() ); const gunichar sp_wide = Glib::ustring( " " )[0]; #ifdef _DEBUG std::cout << "MISC::leven< str1 = " << str1.raw() << " lng1 = " << lng1 << std::endl << "str2 = " << str2.raw() << " lng2 = " << lng2 << std::endl << "maxlng = " << maxlng << std::endl; #endif dist[ 0 ][ 0 ] = 0; for( size_t i = 1, cost = 0; i <= lng1; ++i ){ const gunichar c = str1[ i-1 ]; // 半角、全角空白の挿入コストは0 if( c != ' ' && c != sp_wide ) ++cost; dist[ i ][ 0 ] = cost; } for( size_t i = 1, cost = 0; i <= lng2; ++i ){ const gunichar c = str2[ i-1 ]; // 半角、空白の削除コストは0 if( c != ' ' && c != sp_wide ) ++cost; dist[ 0 ][ i ] = cost; } for( size_t i = 1; i <= lng1; ++i ){ for( size_t j = 1; j <= lng2; ++j ){ const gunichar c1 = str1[ i-1 ]; const gunichar c2 = str2[ j-1 ]; int cost_replace = dist[ i-1 ][ j-1 ]; if( c1 != c2 ) cost_replace += 1; int cost_insert = dist[ i-1 ][ j ]; // 半角、空白の挿入コストは0 if( c1 != ' ' && c1 != sp_wide ) cost_insert += 1; int cost_delete = dist[ i ][ j-1 ]; // 半角、空白の削除コストは0 if( c2 != ' ' && c2 != sp_wide ) cost_delete += 1; dist[ i ][ j ] = MIN( cost_replace, MIN( cost_insert, cost_delete ) ); } } #ifdef _DEBUG for( size_t i = 0; i <= lng1; ++i ){ for( size_t j = 0; j <= lng2; ++j ) std::cout << dist[ i ][ j ] << " "; std::cout << std::endl; } #endif // 0 - 1 の範囲に正規化 return ( double )dist[ lng1 ][ lng2 ] / MAX( dist[ lng1 ][ 0 ], dist[ 0 ][ lng2 ] ); } jd-2.8.7-140104/src/jdlib/tfidf.h0000644000076400010400000000311711307731405012713 0ustar // ライセンス: GPL2 // // TF-IDF // #ifndef _TFIDF_H #define _TFIDF_H #include #include namespace DBTREE { class ArticleBase; } namespace MISC { typedef std::vector< double > VEC_TFIDF; typedef std::vector< Glib::ustring > VEC_WORDS; typedef std::vector< double > VEC_IDF; // 単語ベクトル作成 void tfidf_create_vec_words( VEC_WORDS& vec_words, const Glib::ustring& document ); // IDF計算 (実際には頻度計算) // vec_idf はあらかじめ resize しておくこと void tfidf_create_vec_idf( VEC_IDF& vec_idf, const Glib::ustring& document, const VEC_WORDS& vec_words ); // documnet に対する TFIDF ベクトル計算 // vec_tfidf はあらかじめ resize しておくこと void tfidf_calc_vec_tfifd( VEC_TFIDF& vec_tfidf, const Glib::ustring& document, const VEC_IDF& vec_idf, const VEC_WORDS& vec_words ); // tfidf1 と tfidf2 の相関計算 const double tfidf_cos_similarity( const VEC_TFIDF& vec_tfidf1, const VEC_TFIDF& vec_tfidf2 ); // スレ一覧からIDF 計算 void tfidf_create_vec_idf_from_board( VEC_IDF& vec_idf, const Glib::ustring& subject_src, const std::vector< DBTREE::ArticleBase* >& list_subject, const VEC_WORDS& vec_words ); // str1 と str2 間のレーベンシュタイン距離 // スレ一覧を使用できない場合に使う const double leven( std::vector< std::vector< int > >& dist, const Glib::ustring& str1, const Glib::ustring& str2 ); } #endif jd-2.8.7-140104/src/jdlib/timeout.cpp0000644000076400010400000000450311715713066013646 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "timeout.h" #include "miscmsg.h" #ifdef _WIN32 #include #endif using namespace JDLIB; #ifdef _WIN32 // static Glib::StaticMutex Timeout::s_lock = GLIBMM_STATIC_MUTEX_INIT; std::map< UINT_PTR, Timeout* > Timeout::s_timeouts; #endif /* * Glib::signal_timeout()はタイムアウトのタイミングを得るために、インターバルに応じたsleepで * g_get_current_time()を呼んで時刻取得することで、タイミングを得ている * マイクロ秒オーダのインターバルでは、Windowsでの時刻取得にかかる負荷は無視できないので、 * Windowsタイマーに基づいてタイムアウトを発生させる */ // private Timeout::Timeout( const sigc::slot< bool > slot_timeout ) : m_slot_timeout( slot_timeout ) { #ifdef _WIN32 m_identifer = 0; m_context = Glib::MainContext::get_default(); #endif } Timeout::~Timeout() { #ifdef _WIN32 if( m_identifer != 0 ){ Glib::Mutex::Lock lock( s_lock ); KillTimer( NULL, m_identifer ); s_timeouts.erase( m_identifer ); m_identifer = 0; } #else m_connection.disconnect(); #endif } // static Timeout* Timeout::connect( const sigc::slot< bool > slot_timeout, unsigned int interval ) { Timeout* timeout = new Timeout( slot_timeout ); #ifdef _WIN32 Glib::Mutex::Lock lock( s_lock ); // use global windows timer UINT_PTR ident = SetTimer( NULL, 0, interval, slot_timeout_win32 ); if( ident != 0 ) { // register object into static domain s_timeouts.insert( std::map< UINT_PTR, Timeout* >::value_type( ident, timeout )); timeout->m_identifer = ident; } else { std::stringstream msg; msg << "Set timer : " << std::hex << GetLastError(); MISC::ERRMSG( msg.str() ); } #else timeout->m_connection = Glib::signal_timeout().connect( slot_timeout, interval ); #endif return timeout; } #ifdef _WIN32 void Timeout::slot_timeout_callback() { m_context->acquire(); m_slot_timeout(); m_context->release(); } // static VOID CALLBACK Timeout::slot_timeout_win32( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ) { Timeout* timeout = s_timeouts[ idEvent ]; if( timeout != NULL ){ timeout->slot_timeout_callback(); } } #endif jd-2.8.7-140104/src/jdlib/timeout.h0000644000076400010400000000161311345747600013312 0ustar // ライセンス: GPL2 #ifndef _TIMEOUT_H #define _TIMEOUT_H #include #ifdef _WIN32 #include #undef DELETE // conflict with Gtk::Stock::DELETE #endif namespace JDLIB { class Timeout { sigc::slot< bool > m_slot_timeout; #ifdef _WIN32 Glib::RefPtr m_context; UINT_PTR m_identifer; static Glib::StaticMutex s_lock; static std::map< UINT_PTR, Timeout* > s_timeouts; #else sigc::connection m_connection; #endif public: ~Timeout(); static Timeout* connect( const sigc::slot< bool > slot_timeout, unsigned int interval ); private: Timeout( const sigc::slot< bool > slot_timeout ); #ifdef _WIN32 void slot_timeout_callback(); static VOID CALLBACK slot_timeout_win32( HWND, UINT, UINT_PTR, DWORD ); #endif }; } #endif // _TIMEOUT_H jd-2.8.7-140104/src/jdversion.h0000644000076400010400000000656212261751177012555 0ustar // バージョン情報 #ifndef _JDVER_H #define _JDVER_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_BUILDINFO_H #include "buildinfo.h" #endif // svn 版の時は JDVERSION_SVN をdefineする //#define JDVERSION_SVN #define MAJORVERSION 2 #define MINORVERSION 8 #define MICROVERSION 7 #define JDDATE "140104" #define JDTAG "" //--------------------------------- #define JDVERSION ( MAJORVERSION * 100 + MINORVERSION * 10 + MICROVERSION ) #define JDVERSION_FULL ( JDVERSION * 1000000 + atoi( JDDATE ) ) //--------------------------------- #define JDCOMMENT "JD は gtkmm/GTK+2 を用いた2chブラウザです。" #define JDCOPYRIGHT "(c) 2006-2014 JD project" #define JDBBS CONFIG::get_url_jdhp()+"cgi-bin/bbs/support/" #define JD2CHLOG CONFIG::get_url_jdhp()+"old2ch/" #define JDHELP CONFIG::get_url_jdhp()+"manual/"+MISC::itostr( JDVERSION )+"/" #define JDHELPCMD CONFIG::get_url_jdhp()+"manual/"+MISC::itostr( JDVERSION )+"/usrcmd.html" // [ ライセンス表記 ] // // 以下の文章は和訳を元にバージョン及び住所を訂正した物です。 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt // http://www.opensource.jp/gpl/gpl.ja.html#SEC4 (和訳) #define JDLICENSE JDCOMMENT "\n" \ "\n" \ JDCOPYRIGHT "\n" \ "\n" \ "このプログラムはフリーソフトウェアです。あなたはこれを、フリーソフトウェ" \ "ア財団によって発行された GNU 一般公衆利用許諾契約書(バージョン2)の定める" \ "条件の下で再頒布または改変することができます。\n" \ "\n" \ "このプログラムは有用であることを願って頒布されますが、*全くの無保証* " \ "です。商業可能性の保証や特定の目的への適合性は、言外に示されたものも含" \ "め全く存在しません。詳しくはGNU 一般公衆利用許諾契約書をご覧ください。\n" \ "\n" \ "あなたはこのプログラムと共に、GNU 一般公衆利用許諾契約書の複製物を一部" \ "受け取ったはずです。もし受け取っていなければ、フリーソフトウェア財団ま" \ "で請求してください(宛先は the Free Software Foundation, Inc., 51 " \ "Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA)。\n" #endif //--------------------------------- // for windres.rc #ifndef DEBUG #define JDVER_DEBUG 0 #else #define JDVER_DEBUG VS_FF_DEBUG #endif #define JDVER_FILEVERSION MAJORVERSION,MINORVERSION,MICROVERSION,0 #define JDVER_PRODUCTVERSION JDVER_FILEVERSION // Two macros expansion is gcc preprocessor technic #define JDRC_VERSION_EXP(a,b,c,d,e) JDRC_VERSION_FMT(a,b,c,d,e) #ifdef JDVERSION_SVN #define JDRC_VERSION_FMT(a,b,c,d,e) #a "." #b "." #c "-svnversion" #else #define JDRC_VERSION_FMT(a,b,c,d,e) #a "." #b "." #c "-" d e #endif #define JDRC_VERSION_STR JDRC_VERSION_EXP( \ MAJORVERSION, MINORVERSION, MICROVERSION, JDTAG, JDDATE) #define JDRC_FILEVERSION JDRC_VERSION_STR #define JDRC_PRODUCTVERSION JDRC_FILEVERSION #define JDRC_PRODUCTNAME "JD for Linux" #define JDRC_INTERNALNAME "JD" #define JDRC_ORIGINALFILENAME "jd.exe" #define JDRC_COMPANYNAME "JD project" #define JDRC_FILEDESCRIPTION JDRC_PRODUCTNAME #define JDRC_COMMENTS JDRC_PRODUCTNAME #define JDRC_LEGALCOPYRIGHT JDCOPYRIGHT jd-2.8.7-140104/src/jd_windres.rc0000644000076400010400000000226611260143364013043 0ustar #include #include "jdversion.h" // // DEFAULT ICON // jd ICON "icons/jd_windres.ico" // // VERSION INFO // 1 VERSIONINFO FILEVERSION JDVER_FILEVERSION PRODUCTVERSION JDVER_PRODUCTVERSION FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS (JDVER_DEBUG) FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", JDRC_COMPANYNAME VALUE "FileDescription", JDRC_FILEDESCRIPTION VALUE "FileVersion", JDRC_FILEVERSION VALUE "InternalName", JDRC_INTERNALNAME VALUE "LegalCopyright", JDRC_LEGALCOPYRIGHT VALUE "OriginalFilename", JDRC_ORIGINALFILENAME VALUE "ProductName", JDRC_PRODUCTNAME VALUE "ProductVersion", JDRC_PRODUCTVERSION VALUE "Comments", JDRC_COMMENTS END END BLOCK "VarFileInfo" BEGIN /* Don't modify without localized versions. */ /* set to U.S. English(0x0409) , Unicode(1200) */ VALUE "Translation", 0x0409, 1200 END END jd-2.8.7-140104/src/linkfiltermanager.cpp0000644000076400010400000001071411716225460014570 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "linkfiltermanager.h" #include "usrcmdmanager.h" #include "cache.h" #include "type.h" #include "command.h" #include "jdlib/jdregex.h" #include "jdlib/miscutil.h" #include "xml/document.h" #include "xml/tools.h" #define ROOT_NODE_NAME_LINKFILTER "linkfilterlist" CORE::Linkfilter_Manager* instance_linkfilter_manager = NULL; CORE::Linkfilter_Manager* CORE::get_linkfilter_manager() { if( ! instance_linkfilter_manager ) instance_linkfilter_manager = new Linkfilter_Manager(); assert( instance_linkfilter_manager ); return instance_linkfilter_manager; } void CORE::delete_linkfilter_manager() { if( instance_linkfilter_manager ) delete instance_linkfilter_manager; instance_linkfilter_manager = NULL; } /////////////////////////////////////////////// using namespace CORE; Linkfilter_Manager::Linkfilter_Manager() { std::string xml; if( CACHE::load_rawdata( CACHE::path_linkfilter(), xml ) ) xml2list( xml ); } // // xml -> リスト // void Linkfilter_Manager::xml2list( const std::string& xml ) { m_list_cmd.clear(); if( xml.empty() ) return; XML::Document document( xml ); XML::Dom* root = document.get_root_element( std::string( ROOT_NODE_NAME_LINKFILTER ) ); if( ! root ) return; XML::DomList domlist = root->childNodes(); #ifdef _DEBUG std::cout << "Linkfilter_Manager::xml2list"; std::cout << " children =" << document.childNodes().size() << std::endl; #endif std::list< XML::Dom* >::iterator it = domlist.begin(); while( it != domlist.end() ){ if( ( *it )->nodeType() == XML::NODE_TYPE_ELEMENT ){ LinkFilterItem item; item.url = (*it)->getAttribute( "url" ); item.cmd = (*it)->getAttribute( "data" ); #ifdef _DEBUG std::cout << "url = " << item.url << " cmd =" << item.cmd << std::endl; #endif if( ! item.url.empty() && ! item.cmd.empty() ) m_list_cmd.push_back( item ); } ++it; } } // // XML 保存 // void Linkfilter_Manager::save_xml() { XML::Document document; XML::Dom* root = document.appendChild( XML::NODE_TYPE_ELEMENT, std::string( ROOT_NODE_NAME_LINKFILTER ) ); if( ! root ) return; std::vector< LinkFilterItem >::iterator it = m_list_cmd.begin(); while( it != m_list_cmd.end() ){ const std::string url = ( *it ).url; const std::string cmd = ( *it ).cmd; if( ! url.empty() && ! cmd.empty() ){ XML::Dom* node = root->appendChild( XML::NODE_TYPE_ELEMENT, XML::get_name( TYPE_LINKFILTER ) ); node->setAttribute( "url", url ); node->setAttribute( "data", cmd ); } ++it; } #ifdef _DEBUG std::cout << "Linkfilter_Manager::save_xml\n"; std::cout << document.get_xml() << std::endl; #endif CACHE::save_rawdata( CACHE::path_linkfilter(), document.get_xml() ); } // // 実行 // // 実行したら true を返す // const bool Linkfilter_Manager::exec( const std::string& url, const std::string& link, const std::string& selection ) { if( ! m_list_cmd.size() ) return false; #ifdef _DEBUG std::cout << "Linkfilter_Manager::exec\n" << "url = " << url << std::endl << "link = " << link << std::endl << "selection = " << selection << std::endl; #endif JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::vector< LinkFilterItem >::iterator it = m_list_cmd.begin(); for( ; it != m_list_cmd.end(); ++it ){ const std::string query = ( *it ).url; const std::string cmd = ( *it ).cmd; #ifdef _DEBUG std::cout << "query = " << query << std::endl << "cmd = " << cmd << std::endl; #endif if( ! regex.exec( query, link, offset, icase, newline, usemigemo, wchar ) ) continue; // \0 ... \9 までのcmd文字列を置換 std::string cmd_out = cmd; char rep_text[] = "\\0"; for( int i = 0; i < 9; i++ ){ if( regex.pos( i ) == -1 ){ continue; } rep_text[ 1 ] = '0' + i; cmd_out = MISC::replace_str( cmd_out, rep_text, regex.str( i ) ); } // queryと一致したら実行 CORE::get_usrcmd_manager()->exec( cmd_out, url, link, selection, 0 ); return true; } return false; } jd-2.8.7-140104/src/linkfiltermanager.h0000644000076400010400000000170511045622102014222 0ustar // ライセンス: GPL2 // // リンクフィルタの管理クラス // #ifndef _LINKFILTERMANAGER_H #define _LINKFILTERMANAGER_H #include #include namespace CORE { struct LinkFilterItem { std::string url; std::string cmd; }; class Linkfilter_Manager { std::vector< LinkFilterItem > m_list_cmd; public: Linkfilter_Manager(); virtual ~Linkfilter_Manager(){} std::vector< LinkFilterItem >& get_list(){ return m_list_cmd; } void save_xml(); // 実行 // 実行したら true を返す const bool exec( const std::string& url, const std::string& link, const std::string& selection ); private: void xml2list( const std::string& xml ); }; /////////////////////////////////////// // インターフェース Linkfilter_Manager* get_linkfilter_manager(); void delete_linkfilter_manager(); } #endif jd-2.8.7-140104/src/linkfilterpref.cpp0000644000076400010400000002344511360116564014116 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "linkfilterpref.h" #include "linkfiltermanager.h" #include "skeleton/msgdiag.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" #include "control/controlid.h" #include "command.h" #include "jdversion.h" using namespace CORE; LinkFilterDiag::LinkFilterDiag( Gtk::Window* parent, const std::string& url, const std::string& cmd ) : SKELETON::PrefDiag( parent, "" ), m_label_url( "アドレス", Gtk::ALIGN_LEFT ), m_label_cmd( "実行するコマンド", Gtk::ALIGN_LEFT ), m_button_manual( "オンラインマニュアルの置換文字一覧を表示" ) { resize( 640, 1 ); m_entry_url.set_text( url ); m_entry_cmd.set_text( cmd ); m_button_manual.signal_clicked().connect( sigc::mem_fun( *this, &LinkFilterDiag::slot_show_manual ) ); m_vbox.set_spacing( 8 ); m_vbox.pack_start( m_label_url, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_entry_url, Gtk::PACK_SHRINK ); m_hbox_cmd.pack_start( m_label_cmd, Gtk::PACK_SHRINK ); m_hbox_cmd.pack_end( m_button_manual, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox_cmd, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_entry_cmd, Gtk::PACK_SHRINK ); set_activate_entry( m_entry_url ); set_activate_entry( m_entry_cmd ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_vbox ); set_title( "フィルタ設定" ); show_all_children(); } void LinkFilterDiag::slot_show_manual() { CORE::core_set_command( "open_url_browser", JDHELPCMD ); } /////////////////////////////////////////////// LinkFilterPref::LinkFilterPref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url ), m_label( "追加ボタンを押すとフィルタ設定を追加出来ます。編集するにはダブルクリックします。" ), m_button_top( Gtk::Stock::GOTO_TOP ), m_button_up( Gtk::Stock::GO_UP ), m_button_down( Gtk::Stock::GO_DOWN ), m_button_bottom( Gtk::Stock::GOTO_BOTTOM ), m_button_delete( Gtk::Stock::DELETE ), m_button_add( Gtk::Stock::ADD ) { m_button_top.signal_clicked().connect( sigc::mem_fun( *this, &LinkFilterPref::slot_top ) ); m_button_up.signal_clicked().connect( sigc::mem_fun( *this, &LinkFilterPref::slot_up ) ); m_button_down.signal_clicked().connect( sigc::mem_fun( *this, &LinkFilterPref::slot_down ) ); m_button_bottom.signal_clicked().connect( sigc::mem_fun( *this, &LinkFilterPref::slot_bottom ) ); m_button_delete.signal_clicked().connect( sigc::mem_fun( *this, &LinkFilterPref::slot_delete ) ); m_button_add.signal_clicked().connect( sigc::mem_fun( *this, &LinkFilterPref::slot_add ) ); m_liststore = Gtk::ListStore::create( m_columns ); m_treeview.set_model( m_liststore ); m_treeview.set_size_request( 640, 400 ); m_treeview.signal_row_activated().connect( sigc::mem_fun( *this, &LinkFilterPref::slot_row_activated ) ); m_treeview.sig_key_release().connect( sigc::mem_fun(*this, &LinkFilterPref::slot_key_release ) ); Gtk::TreeViewColumn* column = Gtk::manage( new Gtk::TreeViewColumn( "アドレス", m_columns.m_col_url ) ); column->set_fixed_width( 240 ); column->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ); column->set_resizable( true ); m_treeview.append_column( *column ); column = Gtk::manage( new Gtk::TreeViewColumn( "コマンド", m_columns.m_col_cmd ) ); column->set_fixed_width( 240 ); column->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ); column->set_resizable( true ); m_treeview.append_column( *column ); m_scrollwin.add( m_treeview ); m_scrollwin.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS ); m_vbuttonbox.pack_start( m_button_top, Gtk::PACK_SHRINK ); m_vbuttonbox.pack_start( m_button_up, Gtk::PACK_SHRINK ); m_vbuttonbox.pack_start( m_button_down, Gtk::PACK_SHRINK ); m_vbuttonbox.pack_start( m_button_bottom, Gtk::PACK_SHRINK ); m_vbuttonbox.pack_start( m_button_delete, Gtk::PACK_SHRINK ); m_vbuttonbox.pack_start( m_button_add, Gtk::PACK_SHRINK ); m_vbuttonbox.set_layout( Gtk::BUTTONBOX_START ); m_vbuttonbox.set_spacing( 4 ); m_hbox.pack_start( m_scrollwin, Gtk::PACK_SHRINK ); m_hbox.pack_start( m_vbuttonbox, Gtk::PACK_SHRINK ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_label ); get_vbox()->pack_start( m_hbox ); show_all_children(); set_title( "リンクフィルタ設定" ); append_rows(); } void LinkFilterPref::append_rows() { std::vector< LinkFilterItem >& list_item = CORE::get_linkfilter_manager()->get_list(); const int size = list_item.size(); if( ! size ) return; for( int i = 0; i < size; ++i ) append_row( list_item[ i ].url, list_item[ i ].cmd ); select_row( get_top_row() ); } void LinkFilterPref::append_row( const std::string& url, const std::string& cmd ) { Gtk::TreeModel::Row row; row = *( m_liststore->append() ); if( row ){ row[ m_columns.m_col_url ] = url; row[ m_columns.m_col_cmd ] = cmd; select_row( row ); } } const Gtk::TreeModel::iterator LinkFilterPref::get_selected_row() { Gtk::TreeModel::iterator row; std::list< Gtk::TreeModel::Path > paths = m_treeview.get_selection()->get_selected_rows(); if( ! paths.size() ) return row; row = *( m_liststore->get_iter( *paths.begin() ) ); return row; } const Gtk::TreeModel::iterator LinkFilterPref::get_top_row() { Gtk::TreeModel::iterator row; Gtk::TreeModel::Children children = m_liststore->children(); if( children.empty() ) return row; row = children.begin(); return row; } const Gtk::TreeModel::iterator LinkFilterPref::get_bottom_row() { Gtk::TreeModel::iterator row; Gtk::TreeModel::Children children = m_liststore->children(); if( children.empty() ) return row; row = --children.end(); return row; } void LinkFilterPref::select_row( const Gtk::TreeModel::iterator& row ) { const Gtk::TreePath path( row ); m_treeview.get_selection()->select( path ); } // // OK ボタンを押した // void LinkFilterPref::slot_ok_clicked() { #ifdef _DEBUG std::cout << "LinkFilterPref::slot_ok_clicked\n"; #endif std::vector< LinkFilterItem >& list_item = CORE::get_linkfilter_manager()->get_list(); list_item.clear(); const Gtk::TreeModel::Children children = m_liststore->children(); Gtk::TreeModel::iterator it = children.begin(); while( it != children.end() ){ Gtk::TreeModel::Row row = ( *it ); if( row ){ LinkFilterItem item; item.url = row[ m_columns.m_col_url ]; item.cmd = row[ m_columns.m_col_cmd ]; list_item.push_back( item ); #ifdef _DEBUG std::cout << item.url << " " << item.cmd << std::endl; #endif } ++it; } CORE::get_linkfilter_manager()->save_xml(); } void LinkFilterPref::slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ) { #ifdef _DEBUG std::cout << "LinkFilterPref::slot_row_activated path = " << path.to_string() << std::endl; #endif Gtk::TreeModel::Row row = *( m_liststore->get_iter( path ) ); if( ! row ) return; LinkFilterDiag diag( this, row[ m_columns.m_col_url ], row[ m_columns.m_col_cmd ] ); if( diag.run() == Gtk::RESPONSE_OK ){ row[ m_columns.m_col_url ] = diag.get_url(); row[ m_columns.m_col_cmd ] = diag.get_cmd(); } } bool LinkFilterPref::slot_key_release( GdkEventKey* event ) { const int id = m_control.key_press( event ); #ifdef _DEBUG std::cout << "LinkFilterPref::slot_key_release id = " << id << std::endl; #endif if( id == CONTROL::Delete ) slot_delete(); return true; } // // 一番上へ移動 // void LinkFilterPref::slot_top() { Gtk::TreeModel::iterator row = get_selected_row(); Gtk::TreeModel::iterator row_top = get_top_row(); if( row && row != row_top ) m_liststore->move( row, row_top ); } // // 上へ移動 // void LinkFilterPref::slot_up() { Gtk::TreeModel::iterator row = get_selected_row(); Gtk::TreeModel::iterator row_top = get_top_row(); if( row && row != row_top ){ Gtk::TreePath path_dst( row ); if( path_dst.prev() ){ Gtk::TreeModel::iterator row_dst = m_liststore->get_iter( path_dst ); m_liststore->iter_swap( row, row_dst ); } } } // // 下へ移動 // void LinkFilterPref::slot_down() { Gtk::TreeModel::iterator row = get_selected_row(); Gtk::TreeModel::iterator row_bottom = get_bottom_row(); if( row && row != row_bottom ){ Gtk::TreePath path_dst( row ); path_dst.next(); Gtk::TreeModel::iterator row_dst = m_liststore->get_iter( path_dst ); if( row_dst ) m_liststore->iter_swap( row, row_dst ); } } // // 一番下へ移動 // void LinkFilterPref::slot_bottom() { Gtk::TreeModel::iterator row = get_selected_row(); Gtk::TreeModel::iterator row_bottom = get_bottom_row(); if( row && row != row_bottom ){ m_liststore->move( row, m_liststore->children().end() ); } } // // 削除ボタン // void LinkFilterPref::slot_delete() { Gtk::TreeModel::iterator row = get_selected_row(); if( ! row ) return; SKELETON::MsgDiag mdiag( NULL, "削除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; Gtk::TreePath path_next( row ); path_next.next(); Gtk::TreeModel::iterator row_next = m_liststore->get_iter( path_next ); m_liststore->erase( row ); if( row_next ) select_row( row_next ); else{ Gtk::TreeModel::iterator row_bottom = get_bottom_row(); if( row_bottom ) select_row( row_bottom ); } } // // 追加ボタン // void LinkFilterPref::slot_add() { LinkFilterDiag diag( this, "", "" ); if( diag.run() == Gtk::RESPONSE_OK ) append_row( diag.get_url(), diag.get_cmd() ); } jd-2.8.7-140104/src/linkfilterpref.h0000644000076400010400000000477611070177641013572 0ustar // ライセンス: GPL2 // リンククリック時のフィルタ設定ダイアログ #ifndef _LINKFILTERPREF_H #define _LINKFILTERPREF_H #include "skeleton/prefdiag.h" #include "skeleton/treeviewbase.h" #include "control/control.h" namespace CORE { class LinkFilterDiag : public SKELETON::PrefDiag { Gtk::VBox m_vbox; Gtk::Entry m_entry_url; Gtk::Entry m_entry_cmd; Gtk::Label m_label_url; Gtk::HBox m_hbox_cmd; Gtk::Label m_label_cmd; Gtk::Button m_button_manual; public: LinkFilterDiag( Gtk::Window* parent, const std::string& url, const std::string& cmd ); const Glib::ustring get_url() { return m_entry_url.get_text(); } const Glib::ustring get_cmd() { return m_entry_cmd.get_text(); } private: void slot_show_manual(); }; class TreeColumn : public Gtk::TreeModel::ColumnRecord { public: Gtk::TreeModelColumn< std::string > m_col_url; Gtk::TreeModelColumn< std::string > m_col_cmd; TreeColumn() { add( m_col_url ); add( m_col_cmd ); } }; class LinkFilterPref : public SKELETON::PrefDiag { SKELETON::JDTreeViewBase m_treeview; CONTROL::Control m_control; Glib::RefPtr< Gtk::ListStore > m_liststore; TreeColumn m_columns; Gtk::ScrolledWindow m_scrollwin; Gtk::Label m_label; Gtk::Button m_button_top; Gtk::Button m_button_up; Gtk::Button m_button_down; Gtk::Button m_button_bottom; Gtk::Button m_button_delete; Gtk::Button m_button_add; Gtk::VButtonBox m_vbuttonbox; Gtk::HBox m_hbox; public: LinkFilterPref( Gtk::Window* parent, const std::string& url ); private: void append_rows(); void append_row( const std::string& url, const std::string& cmd ); const Gtk::TreeModel::iterator get_selected_row(); const Gtk::TreeModel::iterator get_top_row(); const Gtk::TreeModel::iterator get_bottom_row(); void select_row( const Gtk::TreeModel::iterator& row ); // OK押した virtual void slot_ok_clicked(); void slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ); bool slot_key_release( GdkEventKey* event ); void slot_top(); void slot_up(); void slot_down(); void slot_bottom(); void slot_delete(); void slot_add(); }; } #endif jd-2.8.7-140104/src/livepref.cpp0000644000076400010400000000631011360116564012702 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "livepref.h" #include "config/globalconf.h" #include "config/defaultconf.h" #include "global.h" using namespace CORE; LivePref::LivePref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url ), m_label_inst( "実況を行うには始めに板のプロパティで更新間隔を設定して下さい。\n速度を0にするとスクロールしません。" ), m_mode1( m_radiogroup, "速度可変、速度がしきい値を越えると行単位でスクロール(_1)", true ), m_mode2( m_radiogroup, "速度一定、遅れがしきい値を越えると行単位でスクロール(_2)", true ), m_bt_reset( "設定を全てデフォルトに戻す(_F)", true ) { const int mrg = 8; // スクロールモード m_vbox_mode.set_spacing( mrg ); m_vbox_mode.set_border_width( mrg ); m_vbox_mode.pack_start( m_mode1 ); m_vbox_mode.pack_start( m_mode2 ); m_frame_mode.set_label( "オートスクロールモード" ); m_frame_mode.add( m_vbox_mode ); if( CONFIG::get_live_mode() == LIVE_SCRMODE_VARIABLE ) m_mode1.set_active( true ); else m_mode2.set_active( true ); // 速度 m_spin_speed.set_range( 0, 50 ); m_spin_speed.set_increments( 1, 1 ); m_spin_speed.set_value( CONFIG::get_live_speed() ); m_label_speed.set_text_with_mnemonic( "可変モードでの最低速度/一定モードでの速度(_S):" ); m_label_speed.set_mnemonic_widget( m_spin_speed ); m_hbox_speed.set_spacing( mrg ); m_hbox_speed.pack_start( m_label_speed, Gtk::PACK_SHRINK ); m_hbox_speed.pack_start( m_spin_speed, Gtk::PACK_SHRINK ); set_activate_entry( m_spin_speed ); // しきい値 m_spin_th.set_range( 1, 50 ); m_spin_th.set_increments( 1, 1 ); m_spin_th.set_value( CONFIG::get_live_threshold() ); m_label_th.set_text_with_mnemonic( "しきい値(_T):" ); m_label_th.set_mnemonic_widget( m_spin_th ); m_hbox_th.set_spacing( mrg ); m_hbox_th.pack_start( m_label_th, Gtk::PACK_SHRINK ); m_hbox_th.pack_start( m_spin_th, Gtk::PACK_SHRINK ); set_activate_entry( m_spin_th ); m_bt_reset.signal_clicked().connect( sigc::mem_fun( *this, &LivePref::slot_reset ) ); m_vbox.pack_start( m_frame_mode, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox_speed, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox_th, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_bt_reset, Gtk::PACK_SHRINK ); m_vbox.set_border_width( mrg ); get_vbox()->set_spacing( mrg ); get_vbox()->pack_start( m_label_inst, Gtk::PACK_SHRINK ); get_vbox()->pack_start( m_vbox, Gtk::PACK_SHRINK ); set_title( "実況設定" ); show_all_children(); } // OK押した void LivePref::slot_ok_clicked() { if( m_mode1.get_active() ) CONFIG::set_live_mode( LIVE_SCRMODE_VARIABLE ); else CONFIG::set_live_mode( LIVE_SCRMODE_STEADY ); CONFIG::set_live_speed( m_spin_speed.get_value_as_int() ); CONFIG::set_live_threshode( m_spin_th.get_value_as_int() ); } void LivePref::slot_reset() { m_mode1.set_active( true ); m_spin_speed.set_value( CONFIG::CONF_LIVE_SPEED ); m_spin_th.set_value( CONFIG::CONF_LIVE_THRESHOLD ); } jd-2.8.7-140104/src/livepref.h0000644000076400010400000000167011360116564012353 0ustar // ライセンス: GPL2 // 実況設定ダイアログ #ifndef _LIVEPREF_H #define _LIVEPREF_H #include "skeleton/prefdiag.h" #include "skeleton/spinbutton.h" namespace CORE { class LivePref : public SKELETON::PrefDiag { Gtk::VBox m_vbox; Gtk::Label m_label_inst; Gtk::Frame m_frame_mode; Gtk::VBox m_vbox_mode; Gtk::RadioButtonGroup m_radiogroup; Gtk::RadioButton m_mode1; Gtk::RadioButton m_mode2; Gtk::HBox m_hbox_speed; SKELETON::SpinButton m_spin_speed; Gtk::Label m_label_speed; Gtk::HBox m_hbox_th; SKELETON::SpinButton m_spin_th; Gtk::Label m_label_th; Gtk::Button m_bt_reset; public: LivePref( Gtk::Window* parent, const std::string& url ); virtual ~LivePref(){} private: // OK押した virtual void slot_ok_clicked(); void slot_reset(); }; } #endif jd-2.8.7-140104/src/login2ch.cpp0000644000076400010400000001154511513340547012601 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "login2ch.h" #include "global.h" #include "httpcode.h" #include "session.h" #include "command.h" #include "skeleton/msgdiag.h" #include "config/globalconf.h" #include "jdlib/loaderdata.h" #include "jdlib/miscmsg.h" #include enum { SIZE_OF_RAWDATA = 64 * 1024 }; CORE::Login2ch* instance_login2ch = NULL; CORE::Login2ch* CORE::get_login2ch() { if( ! instance_login2ch ) instance_login2ch = new CORE::Login2ch(); assert( instance_login2ch ); return instance_login2ch; } void CORE::delete_login2ch() { if( instance_login2ch ){ instance_login2ch->terminate_load(); delete instance_login2ch; } instance_login2ch = NULL; } using namespace CORE; Login2ch::Login2ch() : SKELETON::Login( URL_LOGIN2CH ) , m_rawdata( 0 ), m_lng_rawdata( 0 ) { #ifdef _DEBUG std::cout << "Login2ch::Login2ch\n"; #endif } Login2ch::~Login2ch() { #ifdef _DEBUG std::cout << "Login2ch::~Login2ch\n"; #endif if( m_rawdata ) free( m_rawdata ); } // // ログアウト // void Login2ch::logout() { #ifdef _DEBUG std::cout << "Login2ch::logout\n"; #endif if( is_loading() ) return; SKELETON::Login::set_login_now( false ); SKELETON::Login::set_sessionid( std::string() ); SESSION::set_login2ch( false ); } // // ログイン開始 // void Login2ch::start_login() { if( is_loading() ) return; #ifdef _DEBUG std::cout << "Login2ch::start_login url = " << CONFIG::get_url_login2ch() << std::endl; #endif set_str_code( "" ); if( ! SESSION::is_online() ){ // ディスパッチャ経由でreceive_finish()を呼ぶ finish(); return; } if( CONFIG::get_url_login2ch().empty() || get_username().empty() || get_passwd().empty() ){ finish(); return; } JDLIB::LOADERDATA data; data.init_for_data(); data.url = CONFIG::get_url_login2ch(); data.agent = "DOLIB/1.00"; data.ex_field = "X-2ch-UA: " + CONFIG::get_x_2ch_ua() + "\r\n"; data.str_post = "ID="; data.str_post += get_username(); data.str_post += "&PW="; data.str_post += get_passwd(); logout(); if( ! m_rawdata ) m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA ); memset( m_rawdata, 0, SIZE_OF_RAWDATA ); m_lng_rawdata = 0; start_load( data ); } // // データ受信 // void Login2ch::receive_data( const char* data, size_t size ) { #ifdef _DEBUG std::cout << "Login2ch::receive_data\n"; #endif memcpy( m_rawdata + m_lng_rawdata , data, size ); m_lng_rawdata += size; assert( m_lng_rawdata < SIZE_OF_RAWDATA ); } // // データ受信完了 // void Login2ch::receive_finish() { #ifdef _DEBUG std::cout << "Login2ch::receive_finish code = " << get_code() << " lng_rawdata = " << m_lng_rawdata << std::endl; // if( m_rawdata ) std::cout << m_rawdata << std::endl; #endif std::string sid; bool show_err = true; if( m_rawdata && get_code() == HTTP_OK ){ // 末尾のLFを除去 char *pos_lf = strchr( m_rawdata, '\n' ); if( pos_lf ){ *pos_lf= '\0'; #ifdef _DEBUG std::cout << "removed LF\n"; #endif } // SID 取得 sid = std::string( m_rawdata ); if( sid.find( "SESSION-ID=" ) == 0 ){ sid = sid.substr( strlen( "SESSION-ID=" ) ); #ifdef _DEBUG // std::cout << "sid = " << sid << std::endl; #endif if( sid.find( "ERROR" ) != 0 ){ SKELETON::Login::set_login_now( true ); SKELETON::Login::set_sessionid( sid ); show_err = false; SESSION::set_login2ch( true ); } else{ MISC::ERRMSG( "2chログイン失敗 : sid = " + sid ); set_str_code( get_str_code() + "\nIDとパスワードを確認して下さい" ); } } else set_str_code( get_str_code() + "\n認証サーバーのURLを確認して下さい" ); } // エラー表示 if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( NULL, "オフラインです" ); mdiag.run(); } else if( get_username().empty() || get_passwd().empty() ){ SKELETON::MsgDiag mdiag( NULL, "IDまたはパスワードが設定されていません\n\n設定→ネットワーク→パスワードで設定してください" ); mdiag.run(); } else if( CONFIG::get_url_login2ch().empty() ){ SKELETON::MsgDiag mdiag( NULL, "2chの認証サーバのURLが指定されていません。" ); mdiag.run(); } else if( show_err ){ std::string str_err = "ログインに失敗しました。\n"; str_err += get_str_code(); SKELETON::MsgDiag mdiag( NULL, str_err ); mdiag.run(); } // コアに受信完了を知らせる CORE::core_set_command( "login2ch_finished", "" ); } jd-2.8.7-140104/src/login2ch.h0000644000076400010400000000124111020303226012220 0ustar // ライセンス: GPL2 // // 2chへのログイン管理クラス // // セッション管理やログイン、パスワードの保存などを行う // #ifndef _LOGIN2CH_H #define _LOGIN2CH_H #include "skeleton/login.h" namespace CORE { class Login2ch : public SKELETON::Login { char* m_rawdata; int m_lng_rawdata; public: Login2ch(); virtual ~Login2ch(); virtual void start_login(); virtual void logout(); private: virtual void receive_data( const char* , size_t ); virtual void receive_finish(); }; Login2ch* get_login2ch(); void delete_login2ch(); } #endif jd-2.8.7-140104/src/loginbe.cpp0000644000076400010400000001154511513340547012513 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "loginbe.h" #include "global.h" #include "httpcode.h" #include "session.h" #include "command.h" #include "config/globalconf.h" #include "skeleton/msgdiag.h" #include "jdlib/loaderdata.h" #include "jdlib/miscutil.h" #include "jdlib/jdregex.h" enum { SIZE_OF_RAWDATA = 64 * 1024 }; CORE::LoginBe* instance_loginbe = NULL; CORE::LoginBe* CORE::get_loginbe() { if( ! instance_loginbe ) instance_loginbe = new CORE::LoginBe(); assert( instance_loginbe ); return instance_loginbe; } void CORE::delete_loginbe() { if( instance_loginbe ){ instance_loginbe->terminate_load(); delete instance_loginbe; } instance_loginbe = NULL; } using namespace CORE; LoginBe::LoginBe() : SKELETON::Login( URL_LOGINBE ), m_rawdata( NULL ), m_lng_rawdata( 0 ) { #ifdef _DEBUG std::cout << "LoginBe::LoginBe\n"; #endif } LoginBe::~LoginBe() { #ifdef _DEBUG std::cout << "LoginBe::~LoginBe\n"; #endif if( m_rawdata ) free( m_rawdata ); } // // ログアウト // void LoginBe::logout() { #ifdef _DEBUG std::cout << "LoginBe::logout\n"; #endif if( is_loading() ) return; SKELETON::Login::set_login_now( false ); SKELETON::Login::set_sessionid( std::string() ); SKELETON::Login::set_sessiondata( std::string() ); SESSION::set_loginbe( false ); } // // ログイン開始 // void LoginBe::start_login() { if( is_loading() ) return; #ifdef _DEBUG std::cout << "LoginBe::start_login url = " << CONFIG::get_url_loginbe() << std::endl; #endif set_str_code( "" ); if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( NULL, "オフラインです" ); mdiag.run(); return; } if( get_username().empty() || get_passwd().empty() ){ SKELETON::MsgDiag mdiag( NULL, "メールアドレスまたはパスワードが設定されていません\n\n設定→ネットワーク→パスワードで設定してください" ); mdiag.run(); return; } if( CONFIG::get_url_loginbe().empty() ){ SKELETON::MsgDiag mdiag( NULL, "BEの認証サーバのアドレスが指定されていません。" ); mdiag.run(); return; } JDLIB::LOADERDATA data; data.init_for_data(); data.url = CONFIG::get_url_loginbe(); data.contenttype = "application/x-www-form-urlencoded"; data.str_post = "m=" + MISC::url_encode( get_username() ); data.str_post += "&p=" + MISC::url_encode( get_passwd() ); data.str_post += "&submit=" + MISC::charset_url_encode( "登録", "EUC-JP" ); logout(); if( ! m_rawdata ) m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA ); memset( m_rawdata, 0, SIZE_OF_RAWDATA ); m_lng_rawdata = 0; start_load( data ); } // // データ受信 // void LoginBe::receive_data( const char* data, size_t size ) { if( ! m_rawdata ) return; #ifdef _DEBUG std::cout << "LoginBe::receive_data\n"; #endif if( m_lng_rawdata + size < SIZE_OF_RAWDATA ){ memcpy( m_rawdata + m_lng_rawdata , data, size ); m_lng_rawdata += size; } } // // データ受信完了 // void LoginBe::receive_finish() { if( ! m_rawdata ) return; m_rawdata[ m_lng_rawdata ] = '\0'; #ifdef _DEBUG std::cout << "LoginBe::receive_finish code = " << get_code() << std::endl; std::cout << "lng_rawdata = " << m_lng_rawdata << std::endl; std::cout << m_rawdata << std::endl; #endif std::string dmdm; std::string mdmd; if( get_code() == HTTP_OK ){ std::list< std::string >::const_iterator it = cookies().begin(); for( ; it != cookies().end(); ++it ){ #ifdef _DEBUG std::cout << ( *it ) << std::endl; #endif JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string query = "DMDM=([^;]*)"; if( regex.exec( query, (*it), offset, icase, newline, usemigemo, wchar ) ) dmdm = regex.str( 1 ); query = "MDMD=([^;]*)"; if( regex.exec( query, (*it), offset, icase, newline, usemigemo, wchar ) ) mdmd = regex.str( 1 ); } } #ifdef _DEBUG std::cout << "dmdm = " << dmdm << " mdmd = " << mdmd << std::endl; #endif if( ! dmdm.empty() && ! mdmd.empty() ){ set_login_now( true ); set_sessionid( dmdm ); set_sessiondata( mdmd ); SESSION::set_loginbe( true ); CORE::core_set_command( "loginbe_finished", "" ); } else{ std::string str_err = "ログインに失敗しました。\n\nBEの認証サーバのアドレスやメールアドレス、パスワード等を確認して下さい。\n\n"; str_err += get_str_code(); SKELETON::MsgDiag mdiag( NULL, str_err ); mdiag.run(); } } jd-2.8.7-140104/src/loginbe.h0000644000076400010400000000122211513340547012147 0ustar // ライセンス: GPL2 // // BEログイン管理クラス // // セッション管理やログイン、パスワードの保存などを行う // #ifndef _LOGINBE_H #define _LOGINBE_H #include "skeleton/login.h" namespace CORE { class LoginBe : public SKELETON::Login { char* m_rawdata; int m_lng_rawdata; public: LoginBe(); virtual ~LoginBe(); virtual void start_login(); virtual void logout(); private: virtual void receive_data( const char* , size_t ); virtual void receive_finish(); }; LoginBe* get_loginbe(); void delete_loginbe(); } #endif jd-2.8.7-140104/src/loginp2.cpp0000644000076400010400000002253411711144230012435 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "loginp2.h" #include "global.h" #include "httpcode.h" #include "session.h" #include "command.h" #include "skeleton/msgdiag.h" #include "config/globalconf.h" #include "jdlib/loaderdata.h" #include "jdlib/miscutil.h" #include "jdlib/jdregex.h" #include enum { SIZE_OF_RAWDATA = 64 * 1024 }; CORE::Loginp2* instance_loginp2 = NULL; CORE::Loginp2* CORE::get_loginp2() { if( ! instance_loginp2 ) instance_loginp2 = new CORE::Loginp2(); assert( instance_loginp2 ); return instance_loginp2; } void CORE::delete_loginp2() { if( instance_loginp2 ){ instance_loginp2->terminate_load(); delete instance_loginp2; } instance_loginp2 = NULL; } using namespace CORE; Loginp2::Loginp2() : SKELETON::Login( URL_LOGINP2 ) , m_rawdata( 0 ), m_lng_rawdata( 0 ) { #ifdef _DEBUG std::cout << "Loginp2::Loginp2\n"; #endif } Loginp2::~Loginp2() { #ifdef _DEBUG std::cout << "Loginp2::~Loginp2\n"; #endif if( m_rawdata ) free( m_rawdata ); } // // ログアウト // void Loginp2::logout() { #ifdef _DEBUG std::cout << "Loginp2::logout\n"; #endif if( is_loading() ) return; SKELETON::Login::set_login_now( false ); SKELETON::Login::set_sessionid( std::string() ); SKELETON::Login::set_sessiondata( std::string() ); SESSION::set_loginp2( false ); } // // ログイン開始 // void Loginp2::start_login() { if( is_loading() ) return; #ifdef _DEBUG std::cout << "Loginp2::start_login url = " << CONFIG::get_url_loginp2() << std::endl; #endif // cid の取得に成功したら receive_finish() の中でもう一度ローダを起動して csrfid を取得する m_loading_csrfid = false; set_str_code( "" ); if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( NULL, "オフラインです" ); mdiag.run(); return; } if( get_username().empty() || get_passwd().empty() ){ SKELETON::MsgDiag mdiag( NULL, "IDまたはパスワードが設定されていません\n\n設定→ネットワーク→パスワードで設定してください" ); mdiag.run(); return; } if( CONFIG::get_url_loginp2().empty() ){ SKELETON::MsgDiag mdiag( NULL, "p2の認証サーバのアドレスが指定されていません。" ); mdiag.run(); return; } JDLIB::LOADERDATA data; data.init_for_data(); data.url = CONFIG::get_url_loginp2() + "?guid=ON"; data.contenttype = "application/x-www-form-urlencoded"; data.str_post = "form_login_id="; data.str_post += MISC::url_encode( get_username() ); data.str_post += "&form_login_pass="; data.str_post += MISC::url_encode( get_passwd() ); data.str_post += "&ctl_regist_cookie=1"; // p2(rep2) data.str_post += "®ist_cookie=1"; // p2(rep2) data.str_post += "&ctl_register_cookie=1"; // p2.2ch.net(2012/01/24修正) data.str_post += "®ister_cookie=1"; // p2.2ch.net(2012/01/24修正) // data.str_post += "&submit_member=" + MISC::charset_url_encode( "ユーザログイン", "MS932" ); // 2009/12/20 仕様変更 data.str_post += "&submit_userlogin=" + MISC::charset_url_encode( "ユーザログイン", "MS932" ); logout(); if( ! m_rawdata ) m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA ); memset( m_rawdata, 0, SIZE_OF_RAWDATA ); m_lng_rawdata = 0; start_load( data ); } // // データ受信 // void Loginp2::receive_data( const char* data, size_t size ) { #ifdef _DEBUG std::cout << "Loginp2::receive_data\n"; #endif if( m_lng_rawdata + size < SIZE_OF_RAWDATA ){ memcpy( m_rawdata + m_lng_rawdata , data, size ); m_lng_rawdata += size; } } // // データ受信完了 // void Loginp2::receive_finish() { #ifdef _DEBUG std::cout << "Loginp2::receive_finish code = " << get_code() << std::endl; std::cout << "lng_rawdata = " << m_lng_rawdata << std::endl; if( !m_loading_csrfid && m_rawdata ) std::cout << m_rawdata << std::endl; #endif // csrfid 取得 if( m_loading_csrfid ){ std::string csrfid; if( m_rawdata && get_code() == HTTP_OK ){ m_rawdata[ m_lng_rawdata ] = '\0'; JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string query = "csrfid=([^\"]*)"; if( regex.exec( query, m_rawdata, offset, icase, newline, usemigemo, wchar ) ) csrfid = regex.str( 1 ); } #ifdef _DEBUG std::cout << "csrfid = " << csrfid << std::endl; #endif if( ! csrfid.empty() ){ set_login_now( true ); set_sessiondata( csrfid ); SESSION::set_loginp2( true ); CORE::core_set_command( "loginp2_finished", "" ); } else{ SKELETON::MsgDiag mdiag( NULL, "csrfid の取得に失敗しました。p2のサーバが落ちていないか確認して下さい。" ); mdiag.run(); } return; } /////////////////////////////////// // p2.2ch.net -> w2.p2.2ch.netなどのリダイレクト if( get_code() == HTTP_REDIRECT ){ std::string loc = location(); if( ! loc.empty() ){ // ログインサーバ書き換え JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string query = "^([^#&\?]*/)"; if( regex.exec( query, loc, offset, icase, newline, usemigemo, wchar ) ){ if( CONFIG::get_url_loginp2() != regex.str( 1 ) ){ std::string str_err = "p2のリダイレクト要求がされました。ログイン先を変更してよろしいですか?\n\n"; str_err += regex.str( 1 ); SKELETON::MsgDiag mdiag( NULL, str_err, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) { return; } CONFIG::set_url_loginp2( regex.str( 1 ) ); } }else{ return; // 不当なリダイレクト先 } // Cookieが付いてきたら、そのままリダイレクト先へ投げる std::string cookie; std::list< std::string >::const_iterator it = cookies().begin(); for( ; it != cookies().end(); ++it ){ JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string query = "^([^=]*?=[^;]*?)"; if( regex.exec( query, (*it), offset, icase, newline, usemigemo, wchar ) ){ if( cookie.empty() ){ cookie = regex.str( 1 ); }else{ cookie += "; " + regex.str( 1 ); } } } #ifdef _DEBUG std::cout << "cookie = " << cookie << std::endl; std::cout << "redirect = " << loc << std::endl; std::cout << std::endl; #endif // リダイレクト先をロード JDLIB::LOADERDATA data; data.init_for_data(); data.url = loc; data.referer = CONFIG::get_url_loginp2(); // リファラセット data.cookie_for_write = cookie; start_load( data ); } } /////////////////////////////////// // cid 取得 std::string cid; if( m_rawdata && get_code() == HTTP_OK ){ std::list< std::string >::const_iterator it = cookies().begin(); for( ; it != cookies().end(); ++it ){ #ifdef _DEBUG std::cout << ( *it ) << std::endl; #endif JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string query = "cid=([^;]*)?"; if( regex.exec( query, (*it), offset, icase, newline, usemigemo, wchar ) ){ if( regex.str( 1 ) != "deleted" ){ cid = regex.str( 1 ); break; } } } #ifdef _DEBUG std::cout << "cid = " << cid << std::endl; #endif if( ! cid.empty() ){ set_sessionid( cid ); // ( menu.php から ) csrfid 取得 JDLIB::LOADERDATA data; data.init_for_data(); data.url = CONFIG::get_url_loginp2() + "menu.php"; data.referer = CONFIG::get_url_loginp2(); // リファラセット data.cookie_for_write = "cid="+cid; m_loading_csrfid = true; start_load( data ); } else{ std::string str_err = "ログインに失敗しました。\n\np2の認証サーバのアドレスやID、パスワード等を確認して下さい。\n\n"; str_err += get_str_code(); SKELETON::MsgDiag mdiag( NULL, str_err ); mdiag.run(); } } } jd-2.8.7-140104/src/loginp2.h0000644000076400010400000000134111157077436012114 0ustar // ライセンス: GPL2 // // p2へのログイン管理クラス // // セッション管理やログイン、パスワードの保存などを行う // #ifndef _LOGINP2_H #define _LOGINP2_H #include "skeleton/login.h" namespace CORE { class Loginp2 : public SKELETON::Login { char* m_rawdata; int m_lng_rawdata; bool m_loading_csrfid; // ( menu.php から ) csrfid 取得中 public: Loginp2(); virtual ~Loginp2(); virtual void start_login(); virtual void logout(); private: virtual void receive_data( const char* , size_t ); virtual void receive_finish(); }; Loginp2* get_loginp2(); void delete_loginp2(); } #endif jd-2.8.7-140104/src/main.cpp0000644000076400010400000004525011601654071012016 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _DEBUG_MEM_PROFILE #include "jddebug.h" #include "config/globalconf.h" #include "winmain.h" #include "cache.h" #include "environment.h" #include "iomonitor.h" #include "jdlib/miscmsg.h" #include "jdlib/miscutil.h" #include "jdlib/ssl.h" #include "jdlib/jdregex.h" #include #include #include #include #include #include #include #include #ifdef USE_GNOMEUI #include #endif #ifdef USE_XSMP #include #include struct XSMPDATA { SmcConn smc_connect; IceConn ice_connect; guint id_process_message; }; #endif enum { MAX_SAFE_ARGC = 4, // 引数の数の制限値 MAX_SAFE_ARGV = 1024 // 各引数の文字列の制限値 }; JDWinMain* Win_Main = NULL; // バックアップ復元 void restore_bkup( const bool no_restore_bkup ) { struct timeval tv; struct timezone tz; gettimeofday( &tv, &tz ); const std::string path_main = CACHE::path_xml_listmain(); const std::string path_favor = CACHE::path_xml_favorite(); const std::string path_main_bkup = CACHE::path_xml_listmain_bkup(); const std::string path_favor_bkup = CACHE::path_xml_favorite_bkup(); const std::string path_main_old = path_main + "." + MISC::itostr( tv.tv_sec ); const std::string path_favor_old = path_favor + "." + MISC::itostr( tv.tv_sec ); const bool bkup_main = ( CACHE::file_exists( path_main_bkup ) == CACHE::EXIST_FILE ); const bool bkup_favor = ( CACHE::file_exists( path_favor_bkup ) == CACHE::EXIST_FILE ); if( bkup_main || bkup_favor ){ bool restore = false; if( ! no_restore_bkup ){ Gtk::MessageDialog* mdiag = new Gtk::MessageDialog( "前回の起動時に正しくJDが終了されませんでした。\n\n板リストとお気に入りをバックアップファイルから復元しますか?\nいいえを押すとバックアップファイルを削除します。", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag->run() == Gtk::RESPONSE_YES ) restore = true; delete mdiag; } if( restore ){ if( bkup_main ){ rename( path_main.c_str(), path_main_old.c_str() ); rename( path_main_bkup.c_str(), path_main.c_str() ); } if( bkup_favor ){ rename( path_favor.c_str(), path_favor_old.c_str() ); rename( path_favor_bkup.c_str(), path_favor.c_str() ); } std::string msg = "更新しました。\n\n古いリストはそれぞれ\n\n"; if( bkup_main ) msg += path_main_old + "\n"; if( bkup_favor ) msg += path_favor_old + "\n"; msg += "\nに移動しました。"; Gtk::MessageDialog* mdiag = new Gtk::MessageDialog( msg ); mdiag->run(); delete mdiag; } else{ if( bkup_main ) unlink( to_locale_cstr( path_main_bkup ) ); if( bkup_favor ) unlink( to_locale_cstr( path_favor_bkup ) ); } } } // SIGINTのハンドラ void sig_handler( int sig ) { #ifdef _WIN32 if( sig == SIGINT ){ #else if( sig == SIGHUP || sig == SIGINT || sig == SIGQUIT ){ #endif #ifdef _DEBUG std::cout << "sig_handler sig = " << sig << std::endl; #endif if( Win_Main ) Win_Main->save_session(); } exit(0); } // GNOMEUI によるセッション管理 #ifdef USE_GNOMEUI // gnomeセッションマネージャから "save_yourself" シグナルを受け取った static int save_yourself_gnome( GnomeClient *client, int phase, GnomeSaveStyle save_style, int shutdown, GnomeInteractStyle interact_style, int fast, gpointer client_data ) { if( Win_Main ) Win_Main->save_session(); return TRUE; } #endif // XSMPによるセッション管理 #ifdef USE_XSMP // セッションが終了したので情報を保存するコールバック関数 void xsmp_session_save_yourself( SmcConn smc_connect, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast ) { if( shutdown && !fast ){ #ifdef _DEBUG std::cout << "session_save_yourself\n"; #endif if( Win_Main ) Win_Main->save_session(); } SmcSaveYourselfDone( smc_connect, TRUE ) ; } // ダミー void xsmp_session_die( SmcConn conn, SmPointer data ){} void xsmp_session_save_complete( SmcConn conn, SmPointer data ){} void xsmp_session_shutdown_cancelled( SmcConn conn, SmPointer data ){} gboolean ice_process_message( GIOChannel *channel, GIOCondition condition, XSMPDATA *xsmpdata ) { if( ! xsmpdata->ice_connect ) return FALSE; IceProcessMessagesStatus status = IceProcessMessages( xsmpdata->ice_connect, NULL, NULL ); #ifdef _DEBUG std::cout << "ice_process_message status = " << status << std::endl; #endif if( status == IceProcessMessagesIOError ){ #ifdef _DEBUG std::cout << "ice_process_message IOError\n"; #endif IceCloseConnection( xsmpdata->ice_connect ); xsmpdata->ice_connect = NULL; return FALSE; } return TRUE; } void ice_watch_proc( IceConn ice_connect, IcePointer client_data, Bool opening, IcePointer *watch_data ) { XSMPDATA *xsmpdata = ( XSMPDATA* ) client_data; xsmpdata->ice_connect = ice_connect; if( xsmpdata->id_process_message ){ #ifdef _DEBUG std::cout << "ice_watch_proc remove\n"; #endif g_source_remove( xsmpdata->id_process_message ); xsmpdata->id_process_message = 0; } else if( opening && xsmpdata->ice_connect ){ int fd = IceConnectionNumber( xsmpdata->ice_connect ); if( fd >= 0 ){ #ifdef _DEBUG std::cout << "ice_watch_proc opening fd = " << fd << std::endl; #endif GIOChannel *channel = g_io_channel_unix_new( fd ); *watch_data = xsmpdata; xsmpdata->id_process_message = g_io_add_watch_full( channel, G_PRIORITY_DEFAULT, ( GIOCondition )( G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP ), ( GIOFunc ) ice_process_message, xsmpdata, NULL ); g_io_channel_unref( channel ); } } } // XSMP初期化関数 void xsmp_session_init( XSMPDATA* xsmpdata ) { if( xsmpdata->smc_connect ) return; if( g_getenv("SESSION_MANAGER") == NULL ) return; #ifdef _DEBUG std::cout << "SESSION_MANAGER = " << g_getenv("SESSION_MANAGER") << std::endl; #endif IceAddConnectionWatch( ice_watch_proc, xsmpdata ); SmcCallbacks smc_callbacks; memset( &smc_callbacks, 0, sizeof( SmcCallbacks ) ); smc_callbacks.save_yourself.callback = xsmp_session_save_yourself; smc_callbacks.die.callback = xsmp_session_die; smc_callbacks.save_complete.callback = xsmp_session_save_complete; smc_callbacks.shutdown_cancelled.callback = xsmp_session_shutdown_cancelled; gchar *id = NULL; gchar errstr[ 1024 ]; xsmpdata->smc_connect = SmcOpenConnection( NULL, NULL, SmProtoMajor, SmProtoMinor, SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask, &smc_callbacks, NULL, &id, 1024, errstr ); if( ! xsmpdata->smc_connect ){ MISC::ERRMSG( "SmcOpenConnection failed." ); return; } } // XSMP終了関数 void xsmp_session_end( XSMPDATA* xsmpdata ) { if( xsmpdata->smc_connect ) SmcCloseConnection( xsmpdata->smc_connect, 0, NULL ); xsmpdata->smc_connect = NULL; } #endif //////////////////////////////////////////////////////////// void usage( const int status ) { // -h, --help で表示するメッセージ std::stringstream help_message; help_message << "Usage: jd [OPTION] [URL,FILE]\n" "\n" "-h, --help\n" " Display this information\n" //"-t , --tab=\n" //" URL open of BBS etc by Tab\n" "-m, --multi\n" " Do not quit even if multiple sub-process\n" "-n, --norestore\n" " Do not restore backup files\n" "-s, --skip-setup\n" " Skip the setup dialog\n" "-l, --logfile\n" " Write message to msglog file\n" "-g, --geometry WxH-X+Y\n" " The initial size and location\n" "-V, --version\n" " Display version of this program\n"; std::cout << help_message.str() << std::endl; exit( status ); } int main( int argc, char **argv ) { /*--- 引数処理 --------------------------------------------------*/ // 引数の数を制限 if( argc > MAX_SAFE_ARGC ) { MISC::ERRMSG( "main(): Too many arguments." ); exit( EXIT_FAILURE ); } // 各引数の文字数を制限 int i; for( i = 0; i < argc; ++i ) { if( strlen( argv[ i ] ) > MAX_SAFE_ARGV ) { MISC::ERRMSG( "main(): Too many the strings in argument." ); exit( EXIT_FAILURE ); } } // "現在のタブ/新規タブ"など引数によって開き方を変えたい場合は、--tab= // など新しいオプションを追加する // --help, --tab=, --multi, --norestore, --logfile --version const struct option options[] = { { "help", 0, 0, 'h' }, //{ "tab", 1, 0, 't' }, { "multi", 0, 0, 'm' }, { "norestore", 0, 0, 'n' }, { "skip-setup", 0, 0, 's' }, { "logfile", 0, 0, 'l' }, { "geometry", required_argument, NULL, 'g' }, { "version", 0, 0, 'V' }, { 0, 0, 0, 0 } }; std::string url; bool multi_mode = false; bool no_restore_bkup = false; bool skip_setupdiag = false; bool logfile_mode = false; int init_w = -1; int init_h = -1; int init_x = -1; int init_y = -1; JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string query; // -h, -t , -m, -n, -s, -l, -g WxH+X+Y, -V int opt = 0; while( ( opt = getopt_long( argc, argv, "ht:mnslg:V", options, NULL ) ) != -1 ) { switch( opt ) { case 'h': usage( EXIT_SUCCESS ); break; //case 't': //url = optarg; //break; case 'm': #ifndef _WIN32 multi_mode = true; #endif break; case 'n': no_restore_bkup = true; break; case 's': skip_setupdiag = true; break; case 'l': // メッセージをログファイルに出力 logfile_mode = true; break; case 'g': if( ! optarg ) usage( EXIT_FAILURE ); query = "(([0-9]*)x([0-9]*))?\\-([0-9]*)\\+([0-9]*)"; if( regex.exec( query, optarg, offset, icase, newline, usemigemo, wchar ) ){ if( ! regex.str( 2 ).empty() ) init_w = atoi( regex.str( 2 ).c_str() ); if( ! regex.str( 3 ).empty() ) init_h = atoi( regex.str( 3 ).c_str() ); if( ! regex.str( 4 ).empty() ) init_x = atoi( regex.str( 4 ).c_str() ); if( ! regex.str( 5 ).empty() ) init_y = atoi( regex.str( 5 ).c_str() ); } else usage( EXIT_FAILURE ); break; case 'V': // バージョンと完全なconfigureオプションを表示 std::cout << "JD " << ENVIRONMENT::get_jdversion() << ", " << ENVIRONMENT::get_jdcopyright() << "\n" "configure: " << ENVIRONMENT::get_configure_args( ENVIRONMENT::CONFIGURE_FULL ) << std::endl; exit( 0 ); break; default: usage( EXIT_FAILURE ); } } if( url.empty() ) { // 引数がURLのみの場合 if( argc > optind ) { url = argv[ optind ]; } // -m 、-s でなく、URLを含まない引数だけの場合は終了 else if( optind > 1 && ! ( multi_mode || no_restore_bkup || skip_setupdiag || logfile_mode ) ){ usage( EXIT_FAILURE ); } } /*---------------------------------------------------------------*/ #ifndef _WIN32 // SIGINT、SIGQUITのハンドラ設定 struct sigaction sigact; sigset_t blockset; sigemptyset( &blockset ); sigaddset( &blockset, SIGHUP ); sigaddset( &blockset, SIGINT ); sigaddset( &blockset, SIGQUIT ); sigaddset( &blockset, SIGTERM ); memset( &sigact, 0, sizeof(struct sigaction) ); sigact.sa_handler = sig_handler; sigact.sa_mask = blockset; sigact.sa_flags = SA_RESETHAND; // シグナルハンドラ設定 if( sigaction( SIGHUP, &sigact, NULL ) != 0 || sigaction( SIGINT, &sigact, NULL ) != 0 || sigaction( SIGQUIT, &sigact, NULL ) != 0 ){ fprintf( stderr, "sigaction failed\n" ); exit( 1 ); } #endif #ifdef _DEBUG_MEM_PROFILE g_mem_set_vtable( glib_mem_profiler_table ); atexit( g_mem_profile ); #else GMemVTable vtable; vtable = *glib_mem_profiler_table; vtable.malloc = malloc; vtable.realloc = realloc; vtable.free = free; vtable.calloc = calloc; vtable.try_malloc = malloc; vtable.try_realloc = realloc; g_mem_set_vtable( &vtable ); #endif Gtk::Main m( &argc, &argv ); // XSMPによるセッション管理 #ifdef USE_XSMP #ifdef _DEBUG std::cout << "USE_XSMP\n"; #endif XSMPDATA xsmpdata; memset( &xsmpdata, 0, sizeof( XSMPDATA ) ); xsmp_session_init( &xsmpdata ); #endif // GNOMEUIによるセッション管理 #ifdef USE_GNOMEUI #ifdef _DEBUG std::cout << "USE_GNOMEUI\n"; #endif // gnomeセッションマネージャとつないでログアウト時に"save_yourself"シグナルをもらう gnome_init( "jd", "1.0", argc, argv ); GnomeClient *client_gnome = gnome_master_client(); if( client_gnome ) gtk_signal_connect( GTK_OBJECT( client_gnome ), "save_yourself", GTK_SIGNAL_FUNC( save_yourself_gnome ), NULL ); else MISC::ERRMSG( "failed to connect to gnome session manager" ); #endif JDLIB::init_ssl(); // 全体設定ロード bool init = !( CONFIG::load_conf() ); if( init ){ // 設定ファイルが読み込めないときに存在するか確認 int exists = CACHE::file_exists( CACHE::path_conf() ); if( exists == CACHE::EXIST_FILE || exists == CACHE::EXIST_DIR ){ std::string msg = "JDの設定ファイル(" + CACHE::path_conf() + ")は存在しますが読み込むことが出来ませんでした。\n\n起動しますか?"; Gtk::MessageDialog* mdiag = new Gtk::MessageDialog( msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); int ret = mdiag->run(); delete mdiag; if( ret != Gtk::RESPONSE_YES ) return 0; } // 初回起動時にルートを作る CACHE::mkdir_root(); } // メッセージをログファイルに出力 if( logfile_mode && CACHE::mkdir_logroot() ){ FILE *tmp; // warning 消し const char *logfile = to_locale_cstr( CACHE::path_msglog() ); tmp = freopen( logfile, "ab", stdout ); tmp = freopen( logfile, "ab", stderr ); fclose( tmp ); } /*--- IOMonitor -------------------------------------------------*/ CORE::IOMonitor iomonitor; // FIFOの状態をチェックする if( iomonitor.get_fifo_stat() == CORE::FIFO_OK ) { // 引数にURLがある if( ! url.empty() ) { // ローカルファイルかどうかチェック const std::string url_real = CACHE::get_realpath( url ); if( ! url_real.empty() ) url = url_real; // FIFOに書き込む iomonitor.send_command( url.c_str() ); // マルチモードでなく、メインプロセスでもない場合は終了 if( ! multi_mode && ! iomonitor.is_main_process() ) return 0; } // マルチモードでなく、メインプロセスでもない場合は問い合わせる else if( ! multi_mode && ! iomonitor.is_main_process() ) { Gtk::MessageDialog* mdiag = new Gtk::MessageDialog( "JDは既に起動しています。起動しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); int ret = mdiag->run(); delete mdiag; if( ret != Gtk::RESPONSE_YES ) return 0; } } // FIFOに問題がある(FATで作成出来ないなど) else { if( CONFIG::get_show_diag_fifo_error() ) { Gtk::MessageDialog* mdiag = new Gtk::MessageDialog( CACHE::path_lock() + "の作成またはオープンに問題があります。このまま起動しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); Gtk::CheckButton chk_button( "今後表示しない" ); mdiag->get_vbox()->pack_start( chk_button, Gtk::PACK_SHRINK ); chk_button.show(); const int ret = mdiag->run(); CONFIG::set_show_diag_fifo_error( ! chk_button.get_active() ); delete mdiag; if( ret != Gtk::RESPONSE_YES ) { CONFIG::save_conf(); return 1; } } } /*---------------------------------------------------------------*/ // バックアップファイル復元 restore_bkup( no_restore_bkup ); Win_Main = new JDWinMain( init, skip_setupdiag, init_w, init_h, init_x, init_y ); if( Win_Main ){ m.run( *Win_Main ); delete Win_Main; Win_Main = NULL; } #ifdef USE_XSMP xsmp_session_end( &xsmpdata ); #endif JDLIB::deinit_ssl(); return 0; } jd-2.8.7-140104/src/mainitempref.cpp0000644000076400010400000000420711577662613013564 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "mainitempref.h" #include "config/globalconf.h" #include "icons/iconmanager.h" #include "jdlib/miscutil.h" #include "global.h" #include "session.h" #include "command.h" using namespace CORE; MainItemPref::MainItemPref( Gtk::Window* parent, const std::string& url ) : SKELETON::SelectItemPref( parent, url ) { // デフォルトの項目を設定 append_default_pair( ITEM_NAME_BBSLISTVIEW, ICON::get_icon( ICON::BBSLISTVIEW ) ); append_default_pair( ITEM_NAME_FAVORITEVIEW, ICON::get_icon( ICON::FAVORITEVIEW ) ); append_default_pair( ITEM_NAME_HISTVIEW, ICON::get_icon( ICON::HISTVIEW ) ); append_default_pair( ITEM_NAME_HIST_BOARDVIEW, ICON::get_icon( ICON::HIST_BOARDVIEW ) ); append_default_pair( ITEM_NAME_HIST_CLOSEVIEW, ICON::get_icon( ICON::HIST_CLOSEVIEW ) ); append_default_pair( ITEM_NAME_HIST_CLOSEBOARDVIEW, ICON::get_icon( ICON::HIST_CLOSEBOARDVIEW ) ); append_default_pair( ITEM_NAME_HIST_CLOSEIMGVIEW, ICON::get_icon( ICON::HIST_CLOSEIMGVIEW ) ); append_default_pair( ITEM_NAME_BOARDVIEW, ICON::get_icon( ICON::BOARDVIEW ) ); append_default_pair( ITEM_NAME_ARTICLEVIEW, ICON::get_icon( ICON::ARTICLEVIEW ) ); if( CONFIG::get_use_image_view() ) { append_default_pair( ITEM_NAME_IMAGEVIEW, ICON::get_icon( ICON::IMAGEVIEW ) ); } append_default_pair( ITEM_NAME_SEPARATOR, ICON::get_icon( ICON::TRANSPARENT ) ); append_default_pair( ITEM_NAME_URL, ICON::get_icon( ICON::TRANSPARENT ) ); append_default_pair( ITEM_NAME_GO, ICON::get_icon( ICON::GO ) ); append_default_pair( ITEM_NAME_SEPARATOR, ICON::get_icon( ICON::TRANSPARENT ) ); // 文字列を元に列を追加 append_rows( SESSION::get_items_main_toolbar_str() ); set_title( "ツールバー項目設定(メイン)" ); } // OKを押した void MainItemPref::slot_ok_clicked() { SESSION::set_items_main_toolbar_str( get_items() ); CORE::core_set_command( "update_main_toolbar_button" ); } // // デフォルトボタン // void MainItemPref::slot_default() { append_rows( SESSION::get_items_main_toolbar_default_str() ); } jd-2.8.7-140104/src/mainitempref.h0000644000076400010400000000102411235056116013205 0ustar // ライセンス: GPL2 // メインツールバーの表示項目設定 #ifndef _MAINITEMPREF_H #define _MAINITEMPREF_H #include "skeleton/selectitempref.h" namespace CORE { class MainItemPref : public SKELETON::SelectItemPref { public: MainItemPref( Gtk::Window* parent, const std::string& url ); virtual ~MainItemPref(){} private: // OK押した virtual void slot_ok_clicked(); // デフォルトボタン virtual void slot_default(); }; } #endif jd-2.8.7-140104/src/maintoolbar.cpp0000644000076400010400000001017311577662613013412 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "maintoolbar.h" #include "config/globalconf.h" #include "icons/iconmanager.h" #include "control/controlutil.h" #include "control/controlid.h" #include "session.h" #include "global.h" using namespace CORE; MainToolBar::MainToolBar() : SKELETON::ToolBar( NULL ), m_button_go( ICON::GO ), m_button_bbslist( ICON::BBSLISTVIEW ), m_button_favorite( ICON::FAVORITEVIEW ), m_button_hist( ICON::HISTVIEW ), m_button_hist_board( ICON::HIST_BOARDVIEW ), m_button_hist_close( ICON::HIST_CLOSEVIEW ), m_button_hist_closeboard( ICON::HIST_CLOSEBOARDVIEW ), m_button_hist_closeimg( ICON::HIST_CLOSEIMGVIEW ), m_button_board( ICON::BOARDVIEW ), m_button_thread( ICON::ARTICLEVIEW ), m_button_image( ICON::IMAGEVIEW ) { m_entry_url.set_size_request( 0 ); m_tool_url.add( m_entry_url ); m_tool_url.set_expand( true ); set_tooltip( m_button_go, ITEM_NAME_GO ); set_tooltip( m_button_bbslist, std::string( ITEM_NAME_BBSLISTVIEW ) + "\n\nお気に入りに切替え " + CONTROL::get_str_motions( CONTROL::TabRight ) ); set_tooltip( m_button_favorite, std::string( ITEM_NAME_FAVORITEVIEW ) + "\n\n板一覧に切替え " + CONTROL::get_str_motions( CONTROL::TabLeft ) ); set_tooltip( m_button_hist, std::string( ITEM_NAME_HISTVIEW ) ); set_tooltip( m_button_hist_board, std::string( ITEM_NAME_HIST_BOARDVIEW ) ); set_tooltip( m_button_hist_close, std::string( ITEM_NAME_HIST_CLOSEVIEW ) ); set_tooltip( m_button_hist_closeboard, std::string( ITEM_NAME_HIST_CLOSEBOARDVIEW ) ); set_tooltip( m_button_hist_closeimg, std::string( ITEM_NAME_HIST_CLOSEIMGVIEW ) ); set_tooltip( m_button_board, std::string( ITEM_NAME_BOARDVIEW ) + "\n\n" + CONTROL::get_label_motions( CONTROL::ToggleArticle ) ); set_tooltip( m_button_thread, std::string( ITEM_NAME_ARTICLEVIEW ) + "\n\n" + CONTROL::get_label_motions( CONTROL::ToggleArticle ) ); set_tooltip( m_button_image, std::string( ITEM_NAME_IMAGEVIEW ) + "\n\nスレビューに切替 " + CONTROL::get_str_motions( CONTROL::ToggleArticle ) + " , " + CONTROL::get_str_motions( CONTROL::Left ) ); pack_buttons(); } // ボタンのパッキング // virtual void MainToolBar::pack_buttons() { int num = 0; for(;;){ int item = SESSION::get_item_main_toolbar( num ); if( item == ITEM_END ) break; switch( item ){ case ITEM_BBSLISTVIEW: get_buttonbar().append( m_button_bbslist ); break; case ITEM_FAVORITEVIEW: get_buttonbar().append( m_button_favorite ); break; case ITEM_HISTVIEW: get_buttonbar().append( m_button_hist ); break; case ITEM_HIST_BOARDVIEW: get_buttonbar().append( m_button_hist_board ); break; case ITEM_HIST_CLOSEVIEW: get_buttonbar().append( m_button_hist_close ); break; case ITEM_HIST_CLOSEBOARDVIEW: get_buttonbar().append( m_button_hist_closeboard ); break; case ITEM_HIST_CLOSEIMGVIEW: get_buttonbar().append( m_button_hist_closeimg ); break; case ITEM_BOARDVIEW: get_buttonbar().append( m_button_board ); break; case ITEM_ARTICLEVIEW: get_buttonbar().append( m_button_thread ); break; case ITEM_IMAGEVIEW: if( CONFIG::get_use_image_view() ) get_buttonbar().append( m_button_image ); break; case ITEM_URL: get_buttonbar().append( m_tool_url ); break; case ITEM_GO: get_buttonbar().append( m_button_go ); break; case ITEM_SEPARATOR: pack_separator(); break; } ++num; } set_relief(); show_all_children(); } jd-2.8.7-140104/src/maintoolbar.h0000644000076400010400000000230611577662613013056 0ustar // ライセンス: GPL2 // メインツールバークラス // // CORE::Core 以外では使わない // #ifndef _MAIN_TOOLBAR_H #define _MAIN_TOOLBAR_H #include #include "skeleton/toolbar.h" #include "skeleton/imgtoolbutton.h" #include "skeleton/imgtoggletoolbutton.h" namespace CORE { class MainToolBar : public SKELETON::ToolBar { friend class Core; Gtk::ToolItem m_tool_url; Gtk::Entry m_entry_url; SKELETON::ImgToolButton m_button_go; SKELETON::ImgToggleToolButton m_button_bbslist; SKELETON::ImgToggleToolButton m_button_favorite; SKELETON::ImgToggleToolButton m_button_hist; SKELETON::ImgToggleToolButton m_button_hist_board; SKELETON::ImgToggleToolButton m_button_hist_close; SKELETON::ImgToggleToolButton m_button_hist_closeboard; SKELETON::ImgToggleToolButton m_button_hist_closeimg; SKELETON::ImgToggleToolButton m_button_board; SKELETON::ImgToggleToolButton m_button_thread; SKELETON::ImgToggleToolButton m_button_image; public: MainToolBar(); virtual ~MainToolBar(){} protected: virtual void pack_buttons(); }; } #endif jd-2.8.7-140104/src/Makefile.am0000644000076400010400000000511512110176460012413 0ustar SUBDIRS = dbtree dbimg bbslist board article image message jdlib skeleton history config icons sound xml control bin_PROGRAMS = jd jd_LDADD = \ ./dbimg/libdbimg.a \ ./bbslist/libbbslist.a \ ./board/libboard.a \ ./article/libarticle.a \ ./dbtree/libdbtree.a \ ./image/libimage.a \ ./message/libmessage.a \ ./skeleton/libskeleton.a \ ./history/libhistory.a \ ./config/libconfig.a \ ./jdlib/libjdlib.a \ ./icons/libicon.a \ ./sound/libsound.a \ ./xml/libxml.a \ ./control/libcontrol.a \ @LIBS@ @GTKMM_LIBS@ @GTHREAD_LIBS@ @GNUTLS_LIBS@ @OPENSSL_LIBS@ @GNOMEUI_LIBS@ @LIBSM_LIBS@ @ALSA_LIBS@ @ONIG_LIBS@ @X11_LIBS@ jd_SOURCES = \ main.cpp \ winmain.cpp \ core.cpp \ menuslots.cpp \ maintoolbar.cpp \ cache.cpp \ command.cpp \ sharedbuffer.cpp \ dndmanager.cpp \ usrcmdmanager.cpp \ linkfiltermanager.cpp \ urlreplacemanager.cpp \ compmanager.cpp \ searchmanager.cpp \ searchloader.cpp \ aamanager.cpp \ dispatchmanager.cpp \ cssmanager.cpp \ updatemanager.cpp \ browsers.cpp \ setupwizard.cpp \ \ session.cpp \ login2ch.cpp \ loginbe.cpp \ loginp2.cpp \ \ viewfactory.cpp \ \ prefdiagfactory.cpp \ mainitempref.cpp \ boarditempref.cpp \ articleitempref.cpp \ articleitemmenupref.cpp \ searchitempref.cpp \ boarditemmenupref.cpp \ msgitempref.cpp \ sidebaritempref.cpp \ fontcolorpref.cpp \ usrcmdpref.cpp \ linkfilterpref.cpp \ livepref.cpp \ openurldiag.cpp \ \ iomonitor.cpp \ environment.cpp if MAKE_WINDRES jd_SOURCES += jd_windres.rc endif noinst_HEADERS = \ winmain.h \ httpcode.h \ core.h \ maintoolbar.h \ cache.h \ jddebug.h \ global.h \ jdversion.h \ command.h \ sharedbuffer.h \ dndmanager.h \ usrcmdmanager.h \ linkfiltermanager.h \ urlreplacemanager.h \ compmanager.h \ searchmanager.h \ searchloader.h \ aamanager.h \ dispatchmanager.h \ cssmanager.h \ updatemanager.h \ colorid.h \ fontid.h \ command_args.h \ browsers.h \ setupwizard.h \ sign.h \ \ session.h \ login2ch.h \ loginbe.h \ loginp2.h \ \ viewfactory.h \ \ prefdiagfactory.h \ proxypref.h \ browserpref.h \ globalabonepref.h \ globalabonethreadpref.h \ passwdpref.h \ privacypref.h \ mainitempref.h \ boarditempref.h \ articleitempref.h \ articleitemmenupref.h \ searchitempref.h \ boarditemmenupref.h \ msgitempref.h \ sidebaritempref.h \ fontcolorpref.h \ usrcmdpref.h \ linkfilterpref.h \ livepref.h \ openurldiag.h \ \ iomonitor.h \ environment.h AM_CXXFLAGS = @GTKMM_CFLAGS@ @GTHREAD_CFLAGS@ @GNUTLS_CFLAGS@ @OPENSSL_CFLAGS@ @GNOMEUI_CFLAGS@ @LIBSM_CFLAGS@ jd_windres.o: jdversion.h SUFFIXES = .rc .o .rc.o: $(WINDRES) -o $@ $<; jd-2.8.7-140104/src/menuslots.cpp0000644000076400010400000006627311617532134013135 0ustar // ライセンス: GPL2 // メインウィンドウのメニューのslot関数 //#define _DEBUG #include "jddebug.h" #include "core.h" #include "command.h" #include "cache.h" #include "session.h" #include "login2ch.h" #include "loginbe.h" #include "loginp2.h" #include "winmain.h" #include "fontid.h" #include "colorid.h" #include "global.h" #include "sharedbuffer.h" #include "linkfiltermanager.h" #include "prefdiagfactory.h" #include "environment.h" #include "config/globalconf.h" #include "config/defaultconf.h" #include "control/controlutil.h" #include "skeleton/msgdiag.h" #include "skeleton/aboutdiag.h" #include "dbtree/interface.h" #include "dbimg/imginterface.h" #include "jdlib/miscutil.h" #include "message/logmanager.h" #include "bbslist/bbslistadmin.h" #include "board/boardadmin.h" #include "article/articleadmin.h" #include "image/imageadmin.h" #include "message/messageadmin.h" using namespace CORE; // // URLを開く // void Core::slot_openurl() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_OPENURL, "" ); pref->run(); delete pref; } // // オンライン、オフライン切替え // void Core::slot_toggle_online() { SESSION::set_online( !SESSION::is_online() ); set_maintitle(); // オートリロードキャンセル if( ! SESSION::is_online() ){ BOARD::get_admin()->set_command( "cancel_reload" ); ARTICLE::get_admin()->set_command( "cancel_reload" ); } } // // 2chにログイン // void Core::slot_toggle_login2ch() { if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::slot_toggle_login2ch\n"; #endif // ログイン中ならログアウト if( CORE::get_login2ch()->login_now() ){ CORE::get_login2ch()->logout(); set_maintitle(); } // ログオフ中ならログイン開始 else CORE::get_login2ch()->start_login(); } // // BEにログイン // void Core::slot_toggle_loginbe() { if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::slot_toggle_loginbe\n"; #endif // ログイン中ならログアウト if( CORE::get_loginbe()->login_now() ) CORE::get_loginbe()->logout(); // ログオフ中ならログイン開始 else CORE::get_loginbe()->start_login(); set_maintitle(); } // // p2にログイン // void Core::slot_toggle_loginp2() { if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::slot_toggle_loginp2\n"; #endif // ログイン中ならログアウト if( CORE::get_loginp2()->login_now() ){ CORE::get_loginp2()->logout(); set_maintitle(); } // ログオフ中ならログイン開始 else CORE::get_loginp2()->start_login(); } // // 板リスト再読込 // void Core::slot_reload_list() { if( ! SESSION::is_online() ){ SKELETON::MsgDiag mdiag( NULL, "オフラインです" ); mdiag.run(); return; } DBTREE::download_bbsmenu(); CORE::core_set_command( "set_status","", "板一覧再読み込み中...." ); } // // 終了 // void Core::slot_quit() { m_win_main.hide(); } // // スレ一覧のsinceの表示モード void Core::slot_toggle_since( const int mode ) { if( ! m_enable_menuslot ) return; if( SESSION::get_col_since_time() == mode ) return; #ifdef _DEBUG std::cout << "Core::slot_toggle_since mode = " << mode << std::endl; #endif SESSION::set_col_since_time( mode ); DBTREE::reset_all_since_date(); BOARD::get_admin()->set_command( "relayout_all" ); } // // スレ一覧の最終書込の表示モード void Core::slot_toggle_write( const int mode ) { if( ! m_enable_menuslot ) return; if( SESSION::get_col_write_time() == mode ) return; #ifdef _DEBUG std::cout << "Core::slot_toggle_write mode = " << mode << std::endl; #endif SESSION::set_col_write_time( mode ); DBTREE::reset_all_write_date(); BOARD::get_admin()->set_command( "relayout_all" ); } // // メインツールバー表示切り替え // void Core::slot_toggle_toolbarmain() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; pack_widget( true ); SESSION::set_show_main_toolbar( ! SESSION::get_show_main_toolbar() ); pack_widget( false ); restore_focus( true, false ); } // // メインツールバーの表示位置 // void Core::slot_toggle_toolbarpos( const int pos ) { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; #ifdef _DEBUG std::cout << "Core::slot_toggle_toolbarpos pos = " << pos << " / " << SESSION::get_toolbar_pos() << std::endl; #endif if( ! SESSION::get_show_main_toolbar() ) SESSION::set_toolbar_pos( pos ); else{ pack_widget( true ); SESSION::set_toolbar_pos( pos ); pack_widget( false ); restore_focus( true, false ); } } // // 板一覧のツールバー表示切り替え // void Core::slot_toggle_toolbarbbslist() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; SESSION::set_show_bbslist_toolbar( ! SESSION::get_show_bbslist_toolbar() ); BBSLIST::get_admin()->set_command_immediately( "toggle_toolbar" ); } // // スレ一覧のツールバー表示切り替え // void Core::slot_toggle_toolbarboard() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; SESSION::set_show_board_toolbar( ! SESSION::get_show_board_toolbar() ); BOARD::get_admin()->set_command_immediately( "toggle_toolbar" ); } // // スレビューのツールバー表示切り替え // void Core::slot_toggle_toolbararticle() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; SESSION::set_show_article_toolbar( ! SESSION::get_show_article_toolbar() ); ARTICLE::get_admin()->set_command_immediately( "toggle_toolbar" ); } // // スレ一覧のタブ表示切り替え // void Core::slot_toggle_tabboard() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; SESSION::set_show_board_tab( ! SESSION::get_show_board_tab() ); BOARD::get_admin()->set_command_immediately( "toggle_tab" ); } // // スレビューのタブ表示切り替え // void Core::slot_toggle_tabarticle() { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; SESSION::set_show_article_tab( ! SESSION::get_show_article_tab() ); ARTICLE::get_admin()->set_command_immediately( "toggle_tab" ); } // // 2paneモード // void Core::slot_toggle_2pane() { if( SESSION::get_mode_pane() == SESSION::MODE_2PANE ) return; pack_widget( true ); SESSION::set_mode_pane( SESSION::MODE_2PANE ); pack_widget( false ); restore_focus( true, false ); } // // 3paneモード // void Core::slot_toggle_3pane() { if( SESSION::get_mode_pane() == SESSION::MODE_3PANE ) return; pack_widget( true ); SESSION::set_mode_pane( SESSION::MODE_3PANE ); pack_widget( false ); restore_focus( true, false ); } // // 縦3paneモード // void Core::slot_toggle_v3pane() { if( SESSION::get_mode_pane() == SESSION::MODE_V3PANE ) return; pack_widget( true ); SESSION::set_mode_pane( SESSION::MODE_V3PANE ); pack_widget( false ); restore_focus( true, false ); } // // フルスクリーン // void Core::slot_toggle_fullscreen() { if( ! m_enable_menuslot ) return; if( SESSION::is_full_win_main() ) m_win_main.unfullscreen(); else m_win_main.fullscreen(); } // // messageビューをウィンドウ表示 // void Core::slot_toggle_winmsg() { pack_widget( true ); SESSION::set_embedded_mes( false ); pack_widget( false ); restore_focus( true, false ); } // // messageビューを埋め込み表示 // void Core::slot_toggle_embmsg() { pack_widget( true ); SESSION::set_embedded_mes( true ); pack_widget( false ); restore_focus( true, false ); } // // messgeビューのwrap切り替え // void Core::slot_toggle_msg_wrap() { CORE::core_set_command( "toggle_message_wrap", "" ); } // // imageビュー表示設定 // void Core::slot_toggle_imgview( const int mode ) { if( SESSION::is_booting() ) return; if( ! m_enable_menuslot ) return; int current_mode = IMGVIEW_NO; if( CONFIG::get_use_image_view() ){ if( SESSION::get_embedded_img() ) current_mode = IMGVIEW_EMB; else current_mode = IMGVIEW_WINDOW; } // ビュー使用切り替え if( current_mode == IMGVIEW_NO || current_mode == mode ){ CONFIG::set_use_image_view( ! CONFIG::get_use_image_view() ); if( ! CONFIG::get_use_image_view() ) IMAGE::get_admin()->set_command( "close_all_views" ); } // ウィンドウ、埋め込みモード切り替え pack_widget( true ); if( mode == IMGVIEW_EMB ) SESSION::set_embedded_img( true ); else SESSION::set_embedded_img( false ); pack_widget( false ); SESSION::set_focused_admin( SESSION::FOCUS_NOT ); SESSION::set_focused_admin_sidebar( SESSION::FOCUS_NOT ); restore_focus( true, false ); } // // 画像ポップアップon/off // void Core::slot_toggle_use_imgpopup() { CONFIG::set_use_image_popup( ! CONFIG::get_use_image_popup() ); } // // インライン画像on/off // void Core::slot_toggle_use_inlineimg() { CONFIG::set_use_inline_image( ! CONFIG::get_use_inline_image() ); ARTICLE::get_admin()->set_command( "relayout_all" ); } // // ssspアイコン on/off // void Core::slot_toggle_show_ssspicon() { CONFIG::set_show_sssp_icon( ! CONFIG::get_show_ssspicon() ); ARTICLE::get_admin()->set_command( "relayout_all" ); } // // リスト項目(スレ一覧)の設定 // void Core::slot_setup_boarditem_column() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_BOARDITEM_COLUM, "" ); pref->run(); delete pref; } // // ツールバーのアイコン(メインツールバー)の表示項目 // void Core::slot_setup_mainitem() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_MAINITEM, "" ); pref->run(); delete pref; } // // ツールバーのアイコン(サイドバー)の表示項目 // void Core::slot_setup_sidebaritem() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_SIDEBARITEM, "" ); pref->run(); delete pref; } // // ツールバーのアイコン(スレ一覧)の表示項目 // void Core::slot_setup_boarditem() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_BOARDITEM, "" ); pref->run(); delete pref; } // // ツールバーのアイコン(スレビュー)の表示項目 // void Core::slot_setup_articleitem() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_ARTICLEITEM, "" ); pref->run(); delete pref; } // // ツールバーのアイコン(ログ/スレタイ検索)の表示項目 // void Core::slot_setup_searchitem() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_SEARCHITEM, "" ); pref->run(); delete pref; } // // ツールバーのアイコン(書き込みビュー)の表示項目 // void Core::slot_setup_msgitem() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_MSGITEM, "" ); pref->run(); delete pref; } // // コンテキストメニュー(スレ一覧)の表示項目 // void Core::slot_setup_boarditem_menu() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_BOARDITEM_MENU, "" ); pref->run(); delete pref; } // // コンテキストメニュー(スレビュー)の表示項目 // void Core::slot_setup_articleitem_menu() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_ARTICLEITEM_MENU, "" ); pref->run(); delete pref; } // // 板一覧のプロパティ // void Core::slot_bbslist_pref() { BBSLIST::get_admin()->set_command( "show_preferences", URL_BBSLISTVIEW ); } // // スレ一覧のプロパティ // void Core::slot_board_pref() { BOARD::get_admin()->set_command( "show_current_preferences" ); } // // スレのプロパティ // void Core::slot_article_pref() { ARTICLE::get_admin()->set_command( "show_current_preferences" ); } // // 画像のプロパティ // void Core::slot_image_pref() { IMAGE::get_admin()->set_command( "show_current_preferences" ); } // // 起動時にviewを復元 // void Core::slot_toggle_restore_views() { bool status = CONFIG::get_restore_board() & CONFIG::get_restore_article() & CONFIG::get_restore_image(); CONFIG::set_restore_board( ! status ); CONFIG::set_restore_article( ! status ); CONFIG::set_restore_image( ! status ); } // // 非アクティブ時に書き込みビューを折りたたむ // void Core::slot_toggle_fold_message() { CONFIG::set_fold_message( ! CONFIG::get_fold_message() ); SKELETON::MsgDiag mdiag( NULL, "次に書き込みビューを開いた時から有効になります" ); mdiag.run(); } // // 書き込みログを保存 // void Core::slot_toggle_save_post_log() { CONFIG::set_save_post_log( ! CONFIG::get_save_post_log() ); } // // 書き込み履歴を保存 // void Core::slot_toggle_save_post_history() { CONFIG::set_save_post_history( ! CONFIG::get_save_post_history() ); } // // 画像モザイクon/off // void Core::slot_toggle_use_mosaic() { CONFIG::set_use_mosaic( ! CONFIG::get_use_mosaic() ); SKELETON::MsgDiag mdiag( NULL, "次に開いた画像から有効になります" ); mdiag.run(); } // // まちBBSのofflawモードの切り替え // void Core::slot_toggle_use_machi_offlaw() { CONFIG::set_use_machi_offlaw( ! CONFIG::get_use_machi_offlaw() ); if( CONFIG::get_use_machi_offlaw() ){ SKELETON::MsgDiag mdiag( NULL, "offlaw.cgiを使用すると以下の問題が生じるので注意して下さい。\n\n(1) リモートホストが表示されません\n\n(2) バージョン2.3.0以前のJDではofflaw.cgiで取得したログは読めません" ); mdiag.run(); } } // // タブで開くボタンを入れ替える // void Core::slot_toggle_tabbutton() { bool toggled = CONTROL::is_toggled_tab_button() && CONTROL::is_toggled_tab_key(); CONTROL::toggle_tab_button( !toggled ); CONTROL::toggle_tab_key( !toggled ); } // // クリックで多重ポップアップモードに移行 // void Core::slot_toggle_popupwarpmode() { CONTROL::toggle_popup_warpmode(); } // // マウス移動で多重ポップアップモードに移行 // void Core::slot_shortmargin_popup() { int margin = 2; if( CONFIG::get_margin_popup() != CONFIG::CONF_MARGIN_POPUP ) margin = CONFIG::CONF_MARGIN_POPUP; CONFIG::set_margin_popup( margin ); } // // editview を emacs風のキーバインドにする void Core::slot_toggle_emacsmode() { if( ! m_enable_menuslot ) return; CONTROL::toggle_emacs_mode(); } // // マウスジェスチャ詳細設定 // void Core::slot_setup_mouse() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_MOUSE, "" ); pref->run(); delete pref; } // // キーボード詳細設定 // void Core::slot_setup_key() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_KEY, "" ); pref->run(); delete pref; } // // マウスボタン詳細設定 // void Core::slot_setup_button() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_BUTTON, "" ); pref->run(); delete pref; } // // メインフォント変更 // void Core::slot_changefont_main() { Gtk::FontSelectionDialog diag; diag.set_font_name( CONFIG::get_fontname( FONT_MAIN ) ); diag.set_title( "スレビューフォント" ); diag.set_transient_for( *CORE::get_mainwindow() ); if( diag.run() == Gtk::RESPONSE_OK ){ CONFIG::set_fontname( FONT_MAIN, diag.get_font_name() ); ARTICLE::get_admin()->set_command( "init_font" ); ARTICLE::get_admin()->set_command( "relayout_all" ); CONFIG::set_fontname( FONT_MESSAGE, diag.get_font_name() ); MESSAGE::get_admin()->set_command( "relayout_all" ); } } // // ポップアップフォント変更 // void Core::slot_changefont_popup() { Gtk::FontSelectionDialog diag; diag.set_font_name( CONFIG::get_fontname( FONT_POPUP ) ); diag.set_title( "ポップアップフォント" ); diag.set_transient_for( *CORE::get_mainwindow() ); if( diag.run() == Gtk::RESPONSE_OK ){ CONFIG::set_fontname( FONT_POPUP, diag.get_font_name() ); ARTICLE::get_admin()->set_command( "init_font" ); } } // // 板/スレ一覧のフォント変更 // void Core::slot_changefont_tree() { Gtk::FontSelectionDialog diag; diag.set_font_name( CONFIG::get_fontname( FONT_BBS ) ); diag.set_title( "板/スレ一覧フォント" ); diag.set_transient_for( *CORE::get_mainwindow() ); if( diag.run() == Gtk::RESPONSE_OK ){ CONFIG::set_fontname( FONT_BBS, diag.get_font_name() ); BBSLIST::get_admin()->set_command( "relayout_all" ); CONFIG::set_fontname( FONT_BOARD, diag.get_font_name() ); BOARD::get_admin()->set_command( "relayout_all" ); } } // // スレ文字色変更 // void Core::slot_changecolor_char() { if( open_color_diag( "スレビュー文字色", COLOR_CHAR ) ){ ARTICLE::get_admin()->set_command( "relayout_all" ); CONFIG::set_color( COLOR_CHAR_MESSAGE, CONFIG::get_color( COLOR_CHAR ) ); MESSAGE::get_admin()->set_command( "relayout_all" ); } } // // スレ、ポップアップ背景色変更 // void Core::slot_changecolor_back() { if( open_color_diag( "スレビュー背景色", COLOR_BACK ) ){ CONFIG::set_color( COLOR_BACK_POPUP, CONFIG::get_color( COLOR_BACK) ); CONFIG::set_color( COLOR_BACK_MESSAGE, CONFIG::get_color( COLOR_BACK) ); MESSAGE::get_admin()->set_command( "relayout_all" ); ARTICLE::get_admin()->set_command( "relayout_all" ); } } // // 板/スレ一覧文字色変更 // void Core::slot_changecolor_char_tree() { if( open_color_diag( "板/スレ一覧文字色", COLOR_CHAR_BBS ) ){ CONFIG::set_color( COLOR_CHAR_BBS_COMMENT, CONFIG::get_color( COLOR_CHAR_BBS ) ); CONFIG::set_color( COLOR_CHAR_BOARD, CONFIG::get_color( COLOR_CHAR_BBS ) ); BBSLIST::get_admin()->set_command( "relayout_all" ); BOARD::get_admin()->set_command( "relayout_all" ); } } // // 板/スレ一覧背景色変更 // void Core::slot_changecolor_back_tree() { if( open_color_diag( "板/スレ一覧背景色", COLOR_BACK_BBS ) ){ CONFIG::set_color( COLOR_BACK_BBS_EVEN, CONFIG::get_color( COLOR_BACK_BBS ) ); CONFIG::set_color( COLOR_BACK_BOARD, CONFIG::get_color( COLOR_BACK_BBS ) ); CONFIG::set_color( COLOR_BACK_BOARD_EVEN, CONFIG::get_color( COLOR_BACK_BBS ) ); BBSLIST::get_admin()->set_command( "relayout_all" ); BOARD::get_admin()->set_command( "relayout_all" ); } } // // フォントと色の詳細設定 // void Core::slot_setup_fontcolor() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_FONTCOLOR, "" ); pref->run(); delete pref; } // // プロキシ設定 // void Core::slot_setup_proxy() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_PROXY, "" ); pref->run(); delete pref; } // // ブラウザ設定 // void Core::slot_setup_browser() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_BROWSER, URL_BROWSER ); pref->run(); delete pref; } // // パスワード設定 // void Core::slot_setup_passwd() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_PASSWD, "" ); pref->run(); delete pref; } // // IPv6使用 // void Core::slot_toggle_ipv6() { CONFIG::set_use_ipv6( ! CONFIG::get_use_ipv6() ); } // // あぼーん設定 // void Core::slot_setup_abone() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_GLOBALABONE, "" ); pref->run(); delete pref; } // // スレあぼーん設定 // void Core::slot_setup_abone_thread() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_GLOBALABONETHREAD, "" ); pref->run(); delete pref; } // // 透明/連鎖あぼーん切り替え // void Core::slot_toggle_abone_transp_chain() { const bool status = CONFIG::get_abone_chain() & CONFIG::get_abone_transparent(); CONFIG::set_abone_transparent( ! status ); CONFIG::set_abone_chain( ! status ); // あぼーん情報更新 DBTREE::update_abone_all_article(); CORE::core_set_command( "relayout_all_article" ); } // // NG正規表現によるあぼーん時に大小と全半角文字の違いを無視する // void Core::slot_toggle_abone_icase_wchar() { const bool status = CONFIG::get_abone_icase() & CONFIG::get_abone_wchar(); CONFIG::set_abone_icase( ! status ); CONFIG::set_abone_wchar( ! status ); // あぼーん情報更新 DBTREE::update_abone_thread(); DBTREE::update_abone_all_article(); CORE::core_set_command( "relayout_all_article" ); } // 実況設定 void Core::slot_setup_live() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_LIVE, "" ); pref->run(); delete pref; } // // ユーザコマンドの編集 // void Core::slot_usrcmd_pref() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_USRCMD, URL_USRCMD ); pref->run(); delete pref; } // // リンクフィルタの編集 // void Core::slot_filter_pref() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_LINKFILTER, URL_LINKFILTER ); pref->run(); delete pref; } // // about:config // void Core::slot_aboutconfig() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_ABOUTCONFIG, URL_ABOUTCONFIG ); pref->run(); delete pref; } // プライバシー情報のクリア void Core::slot_clear_privacy() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_PRIVACY, URL_PRIVACY ); pref->run(); delete pref; } // // 書き込みログのクリア // void Core::slot_clear_post_log() { SKELETON::MsgDiag mdiag( NULL, "書き込みログを削除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; MESSAGE::get_log_manager()->clear_post_log(); // ログ表示を閉じる ARTICLE::get_admin()->set_command( "close_view", "postlog" + std::string( POSTLOG_SIGN ), "closeall" ); } // // 全スレの書き込み履歴(鉛筆マーク)のクリア // void Core::slot_clear_post_history() { SKELETON::MsgDiag mdiag( NULL, "全スレの書き込み履歴を削除します。\n\nある板、または特定のスレの履歴を削除するには板またはスレのプロパティから行って下さい。\n\nまた全スレの書き込み履歴の削除には時間がかかります。\n\n全スレの書き込み履歴の削除を実行しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; DBTREE::clear_all_post_history(); // ビューの表示更新 CORE::core_set_command( "redraw_article" ); std::list< std::string > list_urls = BOARD::get_admin()->get_URLs(); std::list< std::string >::iterator it = list_urls.begin(); for( ; it != list_urls.end(); ++it ) CORE::core_set_command( "update_board", *it ); } // // 画像キャッシュクリア // void Core::slot_delete_all_images() { DBIMG::delete_all_files(); IMAGE::get_admin()->set_command( "close_uncached_views" ); } // // 実況 // void Core::slot_live_start_stop() { std::string url = ARTICLE::get_admin()->get_current_url(); ARTICLE::get_admin()->set_command( "live_start_stop", url ); } // // 現在開いている板のキャッシュ内のログ検索 // void Core::slot_search_cache_board() { const std::string url = BOARD::get_admin()->get_current_url(); if( ! url.empty() ) CORE::core_set_command( "open_article_searchlog", url, "", "noexec" ); } // // キャッシュ内のログ検索 // void Core::slot_search_cache() { CORE::core_set_command( "open_article_searchlog", URL_SEARCH_ALLBOARD, "", "noexec" ); } // // 現在開いている板のキャッシュ内のログ一覧表示 // void Core::slot_show_cache_board() { const std::string url = DBTREE::url_subject( BOARD::get_admin()->get_current_url() ); if( ! url.empty() ) CORE::core_set_command( "open_board_showlog", url ); } // // キャッシュ内の全ログ一覧表示 // void Core::slot_show_cache() { CORE::core_set_command( "open_board_showalllog" ); } // // スレタイ検索 // void Core::slot_search_title() { CORE::core_set_command( "open_article_searchtitle", "", "", "noexec" ); } // // サイドバーの全更新チェック // void Core::slot_check_update_root() { CORE::core_set_command( "check_update_root", "" ); } // // サイドバーを全更新チェックしてタブで開く // void Core::slot_check_update_open_root() { CORE::core_set_command( "check_update_open_root", "" ); } // // 更新チェックをキャンセル // void Core::slot_cancel_check_update() { CORE::core_set_command( "cancel_check_update", "" ); } // // お気に入りの編集 // void Core::slot_edit_favorite() { CORE::core_set_command( "edit_favorite","" ); } // // 書き込みログ // void Core::slot_show_postlog() { CORE::core_set_command( "open_article_postlog" ); } // // 開いている板にdatをインポート // void Core::slot_import_dat() { std::string url_board = BOARD::get_admin()->get_current_url(); #ifdef _DEBUG std::cout << "Core::slot_import_dat url = " << url_board << std::endl; #endif if( ! url_board.empty() ) CORE::core_set_command( "import_dat", url_board, "show_diag" ); } // // サイドバーをスレ一覧に表示 // void Core::slot_show_sidebarboard() { if( SESSION::get_sidebar_current_url() != URL_BBSLISTVIEW && SESSION::get_sidebar_current_url() != URL_HISTBOARDVIEW ){ const std::string tab = "true"; const std::string mode = ""; CORE::core_set_command( "open_sidebar_board", SESSION::get_sidebar_current_url(), tab, mode, "0" ); } } // // サイドバーの仮想板を作成 // void Core::slot_create_vboard() { if( SESSION::get_sidebar_current_url() != URL_BBSLISTVIEW && SESSION::get_sidebar_current_url() != URL_HISTBOARDVIEW ){ CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; info.type = TYPE_VBOARD; info.parent = CORE::get_mainwindow(); info.url = SESSION::get_sidebar_current_url() + SIDEBAR_SIGN + "0"; info.name = SESSION::get_sidebar_dirname( SESSION::get_sidebar_current_url(), 0 ); info.path = Gtk::TreePath( "0" ).to_string(); list_info.push_back( info ); CORE::SBUF_set_list( list_info ); CORE::core_set_command( "append_favorite", URL_FAVORITEVIEW ); } } // // サポートBBS // void Core::slot_show_bbs() { CORE::core_set_command( "open_board" , DBTREE::url_subject( ENVIRONMENT::get_jdbbs() ), "true" ); } // // 過去ログ // void Core::slot_show_old2ch() { CORE::core_set_command( "open_board" , DBTREE::url_subject( ENVIRONMENT::get_jd2chlog() ), "true" ); } // // マニュアル // void Core::slot_show_manual() { open_by_browser( ENVIRONMENT::get_jdhelp() ); } // // about // void Core::slot_show_about() { SKELETON::AboutDiag about( "JDについて" ); about.run(); } jd-2.8.7-140104/src/message/0000755000076400010400000000000012261751607012012 5ustar jd-2.8.7-140104/src/message/confirmdiag.cpp0000644000076400010400000000214111531461011014760 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "messageadmin.h" #include "confirmdiag.h" #include "dbtree/interface.h" #include "skeleton/view.h" using namespace MESSAGE; ConfirmDiag::ConfirmDiag( const std::string& url, const std::string& message ) : SKELETON::DetailDiag( MESSAGE::get_admin()->get_win(), url, true, message, "投稿確認", "", "ローカルルール" ), m_chkbutton( "今後表示しない(常にOK)(_D)", true ) { const int mrg = 16; Gtk::HBox* hbox = Gtk::manage( new Gtk::HBox ); hbox->pack_start( m_chkbutton, Gtk::PACK_EXPAND_WIDGET, mrg ); get_vbox()->pack_start( *hbox, Gtk::PACK_SHRINK ); set_title( "投稿確認" ); show_all_children(); grab_ok(); } void ConfirmDiag::slot_switch_page( GtkNotebookPage*, guint page ) { if( get_notebook().get_nth_page( page ) == get_detail() ){ get_detail()->set_command( "clear_screen" ); get_detail()->set_command( "append_html", DBTREE::localrule( get_url() ) ); } } jd-2.8.7-140104/src/message/confirmdiag.h0000644000076400010400000000102111531461011014421 0ustar // ライセンス: GPL2 // // 記事投稿確認ダイアログ // #ifndef _CONFIRMDIAG_H #define _CONFIRMDIAG_H #include "skeleton/detaildiag.h" namespace MESSAGE { class ConfirmDiag : public SKELETON::DetailDiag { Gtk::CheckButton m_chkbutton; public: ConfirmDiag( const std::string& url, const std::string& message ); Gtk::CheckButton& get_chkbutton(){ return m_chkbutton; } private: virtual void slot_switch_page( GtkNotebookPage*, guint page ); }; } #endif jd-2.8.7-140104/src/message/logitem.h0000644000076400010400000000374111460603610013616 0ustar // ライセンス: GPL2 // // 自分の書き込みを判定するために書き込み内容を一時的に保存しておくクラス // #ifndef _LOGITEM_H #define _LOGITEM_H #include "messageadmin.h" #include "jdlib/miscutil.h" #include #include #include #include #include enum { LOGITEM_SIZE_HEAD = 64 }; namespace MESSAGE { class LogItem { public: std::string url; const bool newthread; std::string msg; time_t time_write; std::list< std::string > msg_lines; char head[ LOGITEM_SIZE_HEAD ]; bool remove; LogItem( const std::string& _url, const bool _newthread, const std::string& _msg ) : url( _url ), newthread( _newthread ), msg( _msg ), remove( false ) { struct timeval tv; struct timezone tz; gettimeofday( &tv, &tz ); time_write = tv.tv_sec; if( newthread && url.find( ID_OF_NEWTHREAD ) != std::string::npos ) url = url.substr( 0, url.find( ID_OF_NEWTHREAD ) ); // WAVE DASH 問題 msg = MISC::utf8_fix_wavedash( msg, MISC::UNIXtoWIN ); // 水平タブを空白に置き換える msg = MISC::replace_str( msg, "\t", " " ); // 数字参照を変換 msg = MISC::decode_spchar_number( msg ); // MISC::replace_str( ..., "\n", " \n" ) しているのは MISC::get_lines 実行時に // 改行のみの行を削除しないようにするため msg_lines = MISC::get_lines( MISC::replace_str( MISC::remove_spaces( msg ), "\n", " \n" ) ); // 簡易チェック用に先頭の文字列をコピー(空白は除く) memset( head, 0, LOGITEM_SIZE_HEAD ); for( size_t i = 0, i2 = 0; i < LOGITEM_SIZE_HEAD && i2 < msg.length(); ++i2 ){ if( msg.c_str()[ i2 ] != ' ' ) head[ i++ ] = msg.c_str()[ i2 ]; } } }; } #endif jd-2.8.7-140104/src/message/logmanager.cpp0000644000076400010400000002606512116546561014643 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "logmanager.h" #include "logitem.h" #include "messageadmin.h" #include "config/globalconf.h" #include "dbtree/interface.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "cache.h" #include "session.h" #include #include #include // chmod #include enum { WRITE_TIMEOUT = 180 // 書き込んでからこの秒数を過ぎても書き込んだレスを判定できなかったらロストとする }; MESSAGE::Log_Manager* instance_log_manager = NULL; MESSAGE::Log_Manager* MESSAGE::get_log_manager() { if( ! instance_log_manager ) instance_log_manager = new MESSAGE::Log_Manager(); assert( instance_log_manager ); return instance_log_manager; } void MESSAGE::delete_log_manager() { if( instance_log_manager ) delete instance_log_manager; instance_log_manager = NULL; } /////////////////////////////////////////////// using namespace MESSAGE; Log_Manager::Log_Manager() { #ifdef _DEBUG std::cout << "MESSAGE::Log_Manager\n"; #endif } Log_Manager::~Log_Manager() { #ifdef _DEBUG std::cout << "MESSAGE::~Log_Manager\n"; #endif std::list< LogItem* >::iterator it = m_logitems.begin(); for( ; it != m_logitems.end(); ++it ){ #ifdef _DEBUG std::cout << "url = " << (*it)->url << std::endl; std::cout << "newthread = " << (*it)->newthread << std::endl; std::cout << "msg = " << (*it)->msg << std::endl; #endif delete *it; } } const bool Log_Manager::has_items( const std::string& url, const bool newthread ) { if( ! m_logitems.size() ) return false; #ifdef _DEBUG std::cout << "Log_Manager::has_items url = " << url << " newthread " << newthread << std::endl; #endif std::list< LogItem* >::iterator it = m_logitems.begin(); for( ; it != m_logitems.end(); ++it ){ #ifdef _DEBUG std::cout << "checking : " << (*it)->url << std::endl; #endif if( newthread != (*it)->newthread ) continue; if( (*it)->url == url ){ #ifdef _DEBUG std::cout << "found\n"; #endif return true; } if( (*it)->newthread && url.find( (*it)->url ) == 0 ){ #ifdef _DEBUG std::cout << "found\n"; #endif return true; } } #ifdef _DEBUG std::cout << "not found" << std::endl; #endif return false; } void Log_Manager::remove_items( const std::string& url ) { struct timeval tv; struct timezone tz; gettimeofday( &tv, &tz ); if( ! m_logitems.size() ) return; #ifdef _DEBUG std::cout << "Log_Manager::remove_items url = " << url << std::endl << "size = " << m_logitems.size() << std::endl; #endif std::list< LogItem* >::iterator it = m_logitems.begin(); for( ; it != m_logitems.end(); ++it ){ if( (*it)->url == url || ( (*it)->newthread && url.find( (*it)->url ) == 0 ) ){ const time_t elapsed = tv.tv_sec - (*it)->time_write; #ifdef _DEBUG std::cout << "elapsed = " << elapsed << std::endl; #endif // removeフラグが立っているか、時間切れの場合は削除 if( (*it)->remove || elapsed > WRITE_TIMEOUT ){ #ifdef _DEBUG std::cout << "removed url = " << (*it)->url << std::endl; #endif delete (*it); m_logitems.erase( it ); it = m_logitems.begin(); } } } #ifdef _DEBUG std::cout << "-> size = " << m_logitems.size() << std::endl; #endif } // // messageが自分の書き込んだものかチェックする // // newthread == true の時は新スレの>>1のチェック // // headsize > 0 の時は先頭の headsize 文字だけを比較 // const bool Log_Manager::check_write( const std::string& url, const bool newthread, const char* msg_in, const size_t headsize ) { if( ! m_logitems.size() ) return false; #ifdef _DEBUG std::cout << "Log_Manager::check_write url = " << url << " newthread = " << newthread << " headsize = " << headsize << std::endl; #endif #ifndef _WIN32 const char* msg = msg_in; #else // WAVE DASH 問題 ( UNIX用の文字コードになっていることがある ) const std::string msg_buf = MISC::utf8_fix_wavedash( msg_in, MISC::UNIXtoWIN ); const char* msg = msg_buf.c_str(); #endif std::list< LogItem* >::iterator it = m_logitems.begin(); for( ; it != m_logitems.end(); ++it ){ if( (*it)->newthread != newthread ) continue; if( ! (*it)->newthread && (*it)->url != url ) continue; if( (*it)->newthread && url.find( (*it)->url ) != 0 ) continue; // 先頭のheadsize文字だけ簡易チェックする // ヒットしても(*it)->remove を true にしない if( headsize ){ bool flag = true; size_t i = 0, i2 = 0; while( (*it)->head[ i ] != '\0' && i2 < headsize ){ // 空白は除く while( (*it)->head[ i ] == ' ' ) ++i; while( msg[ i2 ] == ' ' ) ++i2; #ifdef _DEBUG std::cout << (int)( (*it)->head[ i ] ) << " - " << (int)( msg[ i2 ] ) << std::endl; #endif // もしバッファの最後が空白で終わっていたら成功と見なす if( i && i2 && ( (*it)->head[ i ] == '\0' || msg[ i2 ] == '\0' ) ) break; if( (*it)->head[ i ] != msg[ i2 ] ){ flag = false; #ifdef _DEBUG std::cout << "!! failed (head) !!\n"; #endif break; } ++i; ++i2; } if( ! flag ) continue; #ifdef _DEBUG std::cout << "!! hit (head) !!\n"; #endif return true; } // 全文でチェック // MISC::replace_str( ..., "\n", " \n" ) しているのは MISC::get_lines 実行時に // 改行のみの行を削除しないようにするため std::list< std::string > msg_lines = MISC::get_lines( MISC::replace_str( MISC::remove_spaces( msg ), "\n", " \n" ) ); #ifdef _DEBUG std::cout << "lines = " << msg_lines.size() << " : " << (*it)->msg_lines.size() << std::endl; std::cout << "newthread = " << newthread << " : " << (*it)->newthread << std::endl; #endif if( msg_lines.size() != (*it)->msg_lines.size() ) continue; std::list< std::string >::iterator it_msg = msg_lines.begin(); std::list< std::string >::iterator it_item = (*it)->msg_lines.begin(); for( ; it_msg != msg_lines.end() ; ++it_msg, ++it_item ){ #ifdef _DEBUG std::cout << (*it_msg) << " | " << (*it_item) << std::endl; #endif if( MISC::remove_spaces( (*it_msg) ) != MISC::remove_spaces( (*it_item ) ) ) break; } if( it_msg != msg_lines.end() ) continue; #ifdef _DEBUG std::cout << "!! hit !!\n"; #endif (*it)->remove = true; return true; } return false; } // // 自分の書き込みの判定用データの保存 // void Log_Manager::push_logitem( const std::string& url, const bool newthread, const std::string& msg ) { if( ! CONFIG::get_save_post_history() ) return; LogItem *item = new LogItem( url, newthread, msg ); m_logitems.push_back( item ); #ifdef _DEBUG std::cout << "Log_Manager::push_logitem\n"; std::cout << "url = " << item->url << std::endl; std::cout << "newthread = " << item->newthread << std::endl; std::cout << "msg = " << item->msg << std::endl; #endif } // // ログの保存 // void Log_Manager::save( const std::string& url, const std::string& subject, const std::string& msg, const std::string& name, const std::string& mail ) { #ifdef _DEBUG std::cout << "Log_Manager::save\n"; std::cout << "url = " << url << std::endl; std::cout << "subject = " << subject << std::endl; std::cout << "msg = " << msg << std::endl; #endif if( ! CONFIG::get_save_post_log() ) return; // 実況中の時は保存しない if( SESSION::is_live( url ) ) return; if( ! CACHE::mkdir_logroot() ) return; struct timeval tv; struct timezone tz; gettimeofday( &tv, &tz ); // 保存メッセージ作成 const std::string date = MISC::timettostr( tv.tv_sec, MISC::TIME_WEEK ); const bool include_url = false; // URLを除外して msg をエスケープ std::string html = "

    " + DBTREE::url_readcgi( url, 0, 0 ) + "
    " + "[ " + MISC::html_escape( DBTREE::board_name( url ) ) + " ] " + MISC::html_escape( subject ) + "
    " + "名前:" + MISC::html_escape( name ) + " [" + MISC::html_escape( mail ) + "]:" + date + "
    " + MISC::html_escape( msg, include_url ) + "

    "; html = MISC::replace_str( html, "\n", "
    " ); html += "\n"; // 保存先決定 // もし保存先ファイルの容量が大きい場合は mv する const std::string path = CACHE::path_postlog(); const size_t filesize = CACHE::get_filesize( path ); #ifdef _DEBUG std::cout << path << std::endl; std::cout << "size = " << filesize << std::endl; #endif if( filesize > CONFIG::get_maxsize_post_log() ){ const int maxno = get_max_num_of_log() + 1; const std::string newpath = path + "-" + MISC::itostr( maxno ); CACHE::jdmv( path, newpath ); chmod( newpath.c_str(), S_IWUSR | S_IRUSR ); #ifdef _DEBUG std::cout << "mv to " << newpath << std::endl; #endif } // 保存 #ifdef _DEBUG std::cout << html << std::endl; #endif const bool append = true; CACHE::save_rawdata( path, html, append ); chmod( path.c_str(), S_IWUSR | S_IRUSR ); } // // 書き込みログ取得 // const std::string Log_Manager::get_post_log( const int num ) { std::string path = CACHE::path_postlog(); if( num ) path += "-" + MISC::itostr( num ); std::string html; CACHE::load_rawdata( path, html ); return html; } // // ログファイル( log/postlog-* ) の最大数 // const int Log_Manager::get_max_num_of_log() { #ifdef _DEBUG std::cout << "Log_Manager::get_max_num_of_log\n"; #endif std::list< std::string > filelist = CACHE::get_filelist( CACHE::path_logroot() ); if( ! filelist.size() ) return 0; const std::string path = CACHE::path_postlog() + "-"; int maxno = 0; std::list< std::string >::iterator it = filelist.begin(); for( ; it != filelist.end(); ++it ){ const std::string target = CACHE::path_logroot() + (*it); #ifdef _DEBUG std::cout << target << std::endl; #endif if( target.find( path ) == 0 ){ const int tmpno = atoi( target.substr( path.length() ).c_str() ); if( tmpno > maxno ) maxno = tmpno; #ifdef _DEBUG std::cout << "no = " << tmpno << " max = " << maxno << std::endl; #endif } } return maxno; } // // ログ削除 // void Log_Manager::clear_post_log() { const int maxno = get_max_num_of_log(); for( int num = 0; num <= maxno; ++num ){ std::string path = CACHE::path_postlog(); if( num ) path += "-" + MISC::itostr( num ); unlink( to_locale_cstr( path ) ); } } jd-2.8.7-140104/src/message/logmanager.h0000644000076400010400000000315012116546561014276 0ustar // ライセンス: GPL2 // // 書き込みログの管理クラス // #ifndef _LOGMANAGER_H #define _LOGMANAGER_H #include #include namespace MESSAGE { class LogItem; class Log_Manager { std::list< LogItem* > m_logitems; public: Log_Manager(); virtual ~Log_Manager(); const int size() const { return m_logitems.size(); } const bool has_items( const std::string& url, const bool newthread ); void remove_items( const std::string& url ); // messageが自分の書き込んだものかチェックする // newthread == true の時は新スレの>>1のチェック // headsize > 0 の時は先頭の headsize 文字だけを比較 const bool check_write( const std::string& url, const bool newthread, const char* msg_in, const size_t headsize ); // 自分の書き込みの判定用データの保存 void push_logitem( const std::string& url, const bool newthread, const std::string& msg ); // ログの保存 void save( const std::string& url, const std::string& subject, const std::string& msg, const std::string& name, const std::string& mail ); // 書き込みログ取得 const std::string get_post_log( const int num ); // ログファイル( log/postlog-* ) の最大数 const int get_max_num_of_log(); // ログ削除 void clear_post_log(); }; /////////////////////////////////////// // インターフェース Log_Manager* get_log_manager(); void delete_log_manager(); } #endif jd-2.8.7-140104/src/message/Makefile.am0000644000076400010400000000063212072045132014034 0ustar noinst_LIBRARIES = libmessage.a libmessage_a_SOURCES = \ messageadmin.cpp \ messagewin.cpp \ messageviewbase.cpp \ messageview.cpp \ post.cpp \ toolbar.cpp \ logmanager.cpp \ confirmdiag.cpp noinst_HEADERS = \ messageadmin.h \ messagewin.h \ messageviewbase.h \ messageview.h \ post.h \ toolbar.h \ logmanager.h \ confirmdiag.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/message/messageadmin.cpp0000644000076400010400000002361011517313451015147 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "messageadmin.h" #include "messagewin.h" #include "toolbar.h" #include "skeleton/view.h" #include "skeleton/msgdiag.h" #include "skeleton/dragnote.h" #include "skeleton/editview.h" #include "dbtree/interface.h" #include "config/globalconf.h" #include "viewfactory.h" #include "command.h" #include "global.h" #include "session.h" MESSAGE::MessageAdmin* instance_messageadmin = NULL; MESSAGE::MessageAdmin* MESSAGE::get_admin() { if( ! instance_messageadmin ) instance_messageadmin = new MESSAGE::MessageAdmin( URL_MESSAGEADMIN ); return instance_messageadmin; } void MESSAGE::delete_admin() { if( instance_messageadmin ) delete instance_messageadmin; instance_messageadmin = NULL; } using namespace MESSAGE; MessageAdmin::MessageAdmin( const std::string& url ) : SKELETON::Admin( url ), m_toolbar( NULL ), m_toolbar_preview( NULL ), m_text_message( NULL ) { get_notebook()->set_show_tabs( false ); } MessageAdmin::~MessageAdmin() { #ifdef _DEBUG std::cout << "MessageAdmin::~MessageAdmin\n"; #endif if( m_toolbar ) delete m_toolbar; if( m_toolbar_preview ) delete m_toolbar_preview; if( m_text_message ) delete m_text_message; } void MessageAdmin::show_entry_new_subject( bool show ) { if( m_toolbar ) m_toolbar->show_entry_new_subject( show ); } std::string MessageAdmin::get_new_subject() { if( m_toolbar ) return m_toolbar->get_new_subject(); return std::string(); } SKELETON::EditView* MessageAdmin::get_text_message() { if( ! m_text_message ) m_text_message = new SKELETON::EditView(); return m_text_message; } // // ローカルコマンド実行 // // virtual void MessageAdmin::command_local( const COMMAND_ARGS& command ) { #ifdef _DEBUG std::cout << "MessageAdmin::command_local command = " << command.command << std::endl; #endif SKELETON::View *view = get_current_view(); // 書き込みボタンにフォーカスを移す if( command.command == "focus_button_write" ){ if( get_notebook()->get_current_toolbar() == TOOLBAR_MESSAGE ) m_toolbar->focus_button_write(); else m_toolbar_preview->focus_button_write(); } // プレビュー切り替え else if( command.command == "toggle_preview" ){ if( view ) view->set_command( command.command ); } // undo else if( command.command == "undo_text" ){ if( view ) view->set_command( command.command ); } // 下書き挿入 else if( command.command == "insert_draft" ){ if( view ) view->set_command( command.command ); } // 通常のツールバーに表示切り替え else if( command.command == "switch_toolbar_message" ){ if( view ){ get_notebook()->set_current_toolbar( TOOLBAR_MESSAGE, view ); m_toolbar->set_active_previewbutton( false ); } } // プレビューツールバーに表示切り替え else if( command.command == "switch_toolbar_preview" ){ if( view ){ get_notebook()->set_current_toolbar( TOOLBAR_PREVIEW, view ); m_toolbar_preview->set_active_previewbutton( true ); } } // 指定したスレに対応する書き込みビューを開いていて // かつ書き込みビューが空なら閉じる else if( command.command == "close_message" ){ SKELETON::View *view = get_current_view(); if( view && view->set_command( "empty" ) && view->get_url().find( command.url ) != std::string::npos ){ close_current_view(); } } // ビューの wrap 切り替え else if( "toggle_wrap" ){ if( view ) view->set_command( command.command ); } } // // 閉じる // // virtual void MessageAdmin::close_view( const std::string& url ) { #ifdef _DEBUG std::cout << "MessageAdmin::close_view url = " << url << std::endl; #endif SKELETON::View *view = get_current_view(); if( ! view ) return; if( view->is_loading() ){ SKELETON::MsgDiag mdiag( get_win(), "書き込み中です" ); mdiag.run(); return; } if( ! view->set_command( "empty" ) ){ if( ! delete_message( view ) ) return; } if( m_toolbar ) m_toolbar->clear_new_subject(); if( view->is_locked() ) view->set_command( "clear_message" ); else{ Admin::close_view( url ); if( empty() ) close_window(); } } // // ウィンドウ開く // // virtual void MessageAdmin::open_window() { SKELETON::JDWindow* win = get_jdwin(); if( ! SESSION::get_embedded_mes() && ! win && ! empty() ){ #ifdef _DEBUG std::cout << "MessageAdmin::open_window\n"; #endif win = new MESSAGE::MessageWin(); set_jdwin( win ); win->pack_remove_end( false, *get_widget() ); win->show_all(); } else if( win && win->is_hide() ){ win->show(); win->focus_in(); } } // // ウィンドウ閉じる // // virtual void MessageAdmin::close_window() { if( get_jdwin() ){ #ifdef _DEBUG std::cout << "MessageAdmin::close_window\n"; #endif get_jdwin()->pack_remove_end( true, *get_widget() ); delete_jdwin(); } } // virtual void MessageAdmin::switch_admin() { if( ! has_focus() ) CORE::core_set_command( "switch_message" ); } // virtual void MessageAdmin::tab_left( const bool updated ) { SKELETON::View *view = get_current_view(); if( view ) view->set_command( "tab_left" ); } // virtual void MessageAdmin::tab_right( const bool updated ) { SKELETON::View *view = get_current_view(); if( view ) view->set_command( "tab_right" ); } // // 開く // // command.arg2 == "new" なら新スレ // // virtual void MessageAdmin::open_view( const COMMAND_ARGS& command ) { const std::string url = command.url; const std::string msg = command.arg1; const bool new_thread = ( command.arg2 == "new" ); #ifdef _DEBUG std::cout << "MessageAdmin::open_view " << url << std::endl; #endif SKELETON::View *current_view = get_current_view(); if( current_view ){ if( current_view->is_loading() ){ SKELETON::MsgDiag mdiag( get_win(), "書き込み中です" ); mdiag.run(); return; } // 既存のビューにメッセージを追加してフォーカスを移す if( url == current_view->get_url() ) { if( ! msg.empty() ) current_view->set_command( "add_message", msg ); switch_admin(); return; } // URLが異なればビューを破棄 if( ! current_view->set_command( "empty" ) ){ if( ! delete_message( current_view ) ) return; } // 古いビューを破棄 int page = get_notebook()->get_current_page(); get_notebook()->remove_page( page, true ); delete current_view; if( m_toolbar ) m_toolbar->clear_new_subject(); } std::string url_msg; int type; CORE::VIEWFACTORY_ARGS args; if( ! new_thread ){ type = CORE::VIEW_MESSAGE; args.arg1 = msg; url_msg = url; } // 新スレ // スレッドの id は ID_OF_NEWTHREAD.(各板別の拡張子) とする。 else{ type = CORE::VIEW_NEWTHREAD; args.arg1 = msg; url_msg = DBTREE::url_datbase( url ) + ID_OF_NEWTHREAD + DBTREE::board_ext( url ); } // ツールバー表示 show_toolbar(); SKELETON::View *view = CORE::ViewFactory( type, url_msg, args ); get_notebook()->append_page( url_msg, *view ); // ウィンドウ表示 open_window(); get_notebook()->show_all(); switch_admin(); view->show(); view->show_view(); get_notebook()->set_current_toolbar( view->get_id_toolbar(), view ); set_current_page( get_notebook()->page_num( *view ) ); focus_current_view(); } // // ステータス表示 // // virtual void MessageAdmin::set_status( const std::string& url, const std::string& stat, const bool force ) { // 埋め込みビューで、実況中の場合はステータス表示しない if( SESSION::get_embedded_mes() && SESSION::is_live( url ) ) return; SKELETON::Admin::set_status( url, stat, force ); } // // ツールバー表示 // // virtual void MessageAdmin::show_toolbar() { if( ! m_toolbar ){ // 通常のツールバー m_toolbar = new MessageToolBar(); get_notebook()->append_toolbar( *m_toolbar ); m_toolbar->open_buttonbar(); // プレビュー用のツールバー m_toolbar_preview = new MessageToolBarPreview(); get_notebook()->append_toolbar( *m_toolbar_preview ); m_toolbar_preview->open_buttonbar(); } get_notebook()->show_toolbar(); } // // メッセージを破棄するか尋ねる // // 破棄する場合はtrueが戻る // const bool MessageAdmin::delete_message( SKELETON::View * view ) { if( ! CONFIG::get_show_savemsgdiag() ) return true; SKELETON::MsgCheckDiag mdiag( get_win(), "編集中のメッセージを閉じる前に内容を保存しますか?\n\n保存ボタンを押すとメッセージを保存できます。", "今後表示しない(常に保存せずに閉じる) (_D)", Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE ); mdiag.add_button( "保存せずに閉じる(_Q)", Gtk::RESPONSE_NO ); mdiag.add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ); Gtk::Button button( Gtk::Stock::SAVE ); mdiag.add_default_button( &button, Gtk::RESPONSE_YES ); int ret = mdiag.run(); mdiag.hide(); bool result = false; switch( ret ) { case Gtk::RESPONSE_NO: result = true; if( mdiag.get_chkbutton().get_active() ) CONFIG::set_show_savemsgdiag( false ); break; case Gtk::RESPONSE_YES: if( ! view->set_command( "save_message" ) ) return delete_message( view ); result = true; break; } return result; } jd-2.8.7-140104/src/message/messageadmin.h0000644000076400010400000000427511500173015014612 0ustar // ライセンス: GPL2 // // 書き込みビューの管理クラス // #ifndef _MESSAGEADMIN_H #define _MESSAGEADMIN_H #include "skeleton/admin.h" namespace SKELETON { class EditView; } namespace MESSAGE { #define ID_OF_NEWTHREAD "0000000000" enum { TOOLBAR_MESSAGE = 0, TOOLBAR_PREVIEW = 1 }; class MessageToolBar; class MessageToolBarPreview; class MessageAdmin : public SKELETON::Admin { MessageToolBar* m_toolbar; MessageToolBarPreview* m_toolbar_preview; // 書き込み用のメッセージ欄 // インスタンスを破棄しないで、前回書き込みビューを閉じた時の // 日本語のON/OFF状態を次回開いたときに継続させる SKELETON::EditView* m_text_message; public: MessageAdmin( const std::string& url ); virtual ~MessageAdmin(); virtual void save_session(){} void show_entry_new_subject( bool show ); std::string get_new_subject(); SKELETON::EditView* get_text_message(); protected: virtual void set_status( const std::string& url, const std::string& stat, const bool force ); // ツールバー virtual void show_toolbar(); virtual void command_local( const COMMAND_ARGS& command ); private: const bool delete_message( SKELETON::View * view ); // 復元をしない virtual void restore( const bool only_locked ){} virtual COMMAND_ARGS url_to_openarg( const std::string& url, const bool tab, const bool lock ){ COMMAND_ARGS ret; return ret; } virtual void open_view( const COMMAND_ARGS& command ); virtual void switch_admin(); virtual void tab_left( const bool updated ); virtual void tab_right( const bool updated ); virtual void close_view( const std::string& url ); virtual void open_window(); virtual void close_window(); // タブの D&D 処理をしない virtual void slot_drag_data_get( Gtk::SelectionData& selection_data, const int page ){} }; MESSAGE::MessageAdmin* get_admin(); void delete_admin(); } #endif jd-2.8.7-140104/src/message/messageview.cpp0000644000076400010400000001352111455622660015037 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "messageadmin.h" #include "messageview.h" #include "post.h" #include "skeleton/msgdiag.h" #include "skeleton/label_entry.h" #include "skeleton/editview.h" #include "jdlib/miscutil.h" #include "dbtree/interface.h" #include "command.h" #include "session.h" #include using namespace MESSAGE; MessageViewMain::MessageViewMain( const std::string& url, const std::string& msg ) : MessageViewBase( url ) { setup_view(); set_message( msg ); // ツールバーのスレタイトルを編集不可にする MESSAGE::get_admin()->show_entry_new_subject( false ); // メインウィンドウのタイトルに表示する文字 set_title( "[ 書き込み ] " + DBTREE::article_subject( get_url() ) ); // ツールバーにスレ名を表示 set_label( DBTREE::article_subject( get_url() ) ); } MessageViewMain::~MessageViewMain() { save_name(); } // // ポストするメッセージ作成 // const std::string MessageViewMain::create_message() { if( ! get_text_message() ) return std::string(); const Glib::ustring msg = get_text_message()->get_text(); const std::string name = get_entry_name().get_text(); const std::string mail = get_entry_mail().get_text(); if( msg.empty() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "本文が空白です" ); mdiag.run(); return std::string(); } /* else { // 終端スペース/改行チェック const size_t end_pos = msg.find_last_not_of( "  \n" ); const size_t msg_length = msg.length(); // 最後がスペース/改行である if( end_pos != msg_length - 1 ) { SKELETON::MsgDiag mdiag( get_parent_win(), "メッセージがスペースまたは改行で終わっています。\n\n" "このまま書き込みますか? (または、改行等を削除)", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE ); mdiag.set_title( "確認" ); mdiag.add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ); mdiag.add_button( Gtk::Stock::REMOVE, Gtk::RESPONSE_DELETE_EVENT ); mdiag.add_button( Gtk::Stock::YES, Gtk::RESPONSE_YES ); switch( mdiag.run() ) { // スペース/改行を取り除いた物に置き換える(書き込まない) case Gtk::RESPONSE_DELETE_EVENT: get_text_message().set_text( msg.substr( 0, end_pos + 1 ) ); return std::string(); // キャンセル case Gtk::RESPONSE_CANCEL: return std::string(); } } } */ // 誤爆を警告 if( SESSION::get_article_current_url().find( get_url() ) == std::string::npos ){ SKELETON::MsgDiag mdiag( get_parent_win(), "スレビューで開いているスレと異なるスレに書き込もうとしています\n\n誤爆する可能性がありますが書き込みますか?", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE ); mdiag.set_title( "!!!誤爆注意!!!" ); mdiag.add_button( Gtk::Stock::NO, Gtk::RESPONSE_NO ); mdiag.add_button( Gtk::Stock::YES, Gtk::RESPONSE_YES ); mdiag.add_button( "スレを開く", Gtk::RESPONSE_YES + 100 ); int ret = mdiag.run(); if( ret != Gtk::RESPONSE_YES ){ if( ret == Gtk::RESPONSE_YES + 100 ) CORE::core_set_command( "open_article", get_url(), "true", "" ); return std::string(); } } return DBTREE::create_write_message( get_url(), name, mail, msg ); } // // 書き込み // // 書き込みが終わったら MessageViewBase::post_fin()が呼ばれる // void MessageViewMain::write_impl( const std::string& msg ) { post_msg( msg, false ); } void MessageViewMain::reload() { CORE::core_set_command( "open_article", get_url(), "true", "" ); } /////////////////////////// MessageViewNew::MessageViewNew( const std::string& url, const std::string& msg ) : MessageViewBase( url ) { setup_view(); set_message( msg ); // ツールバーのスレタイトルを編集可能にする MESSAGE::get_admin()->show_entry_new_subject( true ); // メインウィンドウのタイトルに表示する文字 set_title( "[ 新スレ作成 ] " + DBTREE::article_subject( get_url() ) ); } // // ポストするメッセージ作成 // const std::string MessageViewNew::create_message() { if( ! get_text_message() ) return std::string(); std::string subject = MESSAGE::get_admin()->get_new_subject(); std::string msg = get_text_message()->get_text(); std::string name = get_entry_name().get_text(); std::string mail = get_entry_mail().get_text(); if( subject.empty() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "スレタイトルが空白です" ); mdiag.run(); return std::string(); } if( msg.empty() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "本文が空白です" ); mdiag.run(); return std::string(); } SKELETON::MsgDiag mdiag( get_parent_win(), "新スレを作成しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() == Gtk::RESPONSE_YES ) return DBTREE::create_newarticle_message( get_url(), subject, name, mail, msg ); return std::string(); } // // 書き込み // // 書き込みが終わったら MessageViewBase::post_fin()が呼ばれる // void MessageViewNew::write_impl( const std::string& msg ) { post_msg( msg, true ); } void MessageViewNew::reload() { CORE::core_set_command( "open_board", DBTREE::url_subject( get_url() ), "true" ); } jd-2.8.7-140104/src/message/messageview.h0000644000076400010400000000161511455622660014505 0ustar // ライセンス: GPL2 #ifndef _MESSAGEVIEW_H #define _MESSAGEVIEW_H #include "messageviewbase.h" namespace MESSAGE { // 通常の書き込みビュー class MessageViewMain : public MessageViewBase { public: MessageViewMain( const std::string& url, const std::string& msg ); virtual ~MessageViewMain(); virtual void reload(); private: virtual void write_impl( const std::string& msg ); virtual const std::string create_message(); }; // 新スレ立て用ビュー class MessageViewNew : public MessageViewBase { public: MessageViewNew( const std::string& url, const std::string& msg ); virtual ~MessageViewNew(){} virtual void reload(); private: virtual void write_impl( const std::string& msg ); virtual const std::string create_message(); }; } #endif jd-2.8.7-140104/src/message/messageviewbase.cpp0000644000076400010400000007205212006761301015663 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _DEBUG_KEY #include "jddebug.h" #include "gtkmmversion.h" #include "messageadmin.h" #include "messageviewbase.h" #include "post.h" #include "logmanager.h" #include "skeleton/msgdiag.h" #include "skeleton/label_entry.h" #include "skeleton/editview.h" #include "skeleton/detaildiag.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "jdlib/misctrip.h" #include "jdlib/jdiconv.h" #include "jdlib/jdregex.h" #include "dbtree/interface.h" #include "config/globalconf.h" #include "control/controlutil.h" #include "control/controlid.h" #include "httpcode.h" #include "viewfactory.h" #include "fontid.h" #include "cache.h" #include "session.h" #include "colorid.h" #include "global.h" #include "compmanager.h" #include #include #include using namespace MESSAGE; enum { MAX_STR_ICONV = 128*1024, PASS_TIMEOUT = 500, PASS_MAXTIME = 120, }; // ページ番号 enum { PAGE_MESSAGE = 0, PAGE_PREVIEW }; MessageViewBase::MessageViewBase( const std::string& url ) : SKELETON::View( url ), m_post( 0 ), m_preview( 0 ), m_entry_name( CORE::COMP_NAME ), m_entry_mail( CORE::COMP_MAIL ), m_text_message( NULL ), m_enable_focus( true ), m_lng_str_enc( 0 ), m_counter( 0 ), m_text_changed( false ), m_over_lines( false ), m_over_lng( false ) { #ifdef _DEBUG std::cout << "MessageViewBase::MessageViewBase " << get_url() << std::endl; #endif // コントロールモード設定 get_control().add_mode( CONTROL::MODE_MESSAGE ); m_max_line = DBTREE::line_number( get_url() ) * 2; m_max_str = DBTREE::message_count( get_url() ); m_iconv = new JDLIB::Iconv( "UTF-8", DBTREE::board_charset( get_url() ) );; m_lng_iconv = m_max_str * 3; if( ! m_lng_iconv ) m_lng_iconv = MAX_STR_ICONV; if( SESSION::get_close_mes() ) unlock(); else lock(); } MessageViewBase::~MessageViewBase() { #ifdef _DEBUG std::cout << "MessageViewBase::~MessageViewBase " << get_url() << std::endl << "lock = " << is_locked() << std::endl; #endif // 名前、メール履歴保存 std::string name = m_entry_name.get_text(); std::string mail = m_entry_mail.get_text(); CORE::get_completion_manager()->set_query( CORE::COMP_NAME, name ); CORE::get_completion_manager()->set_query( CORE::COMP_MAIL, mail ); if( m_preview ) delete m_preview; m_preview = NULL; if( m_post ){ m_post->terminate_load(); delete m_post; } m_post = NULL; if( m_iconv ) delete m_iconv; m_iconv = NULL; SESSION::set_close_mes( ! is_locked() ); } SKELETON::Admin* MessageViewBase::get_admin() { return MESSAGE::get_admin(); } // // 親ウィンドウを取得 // Gtk::Window* MessageViewBase::get_parent_win() { return MESSAGE::get_admin()->get_win(); } // // コピー用URL( readcgi型 ) // // メインウィンドウのURLバーなどに表示する) // const std::string MessageViewBase::url_for_copy() { return DBTREE::url_readcgi( get_url(), 0, 0 ); } void MessageViewBase::clock_in() { if( m_preview ) m_preview->clock_in(); ++m_counter; if( m_counter % ( PASS_TIMEOUT / TIMER_TIMEOUT ) == 0 ){ m_counter = 0; // 書き込みから時間があまり経っていなければステータス表示を更新 if( time( NULL ) - DBTREE::article_write_time( get_url() ) < 60 * 60 ) show_status(); // 書き込み規制経過時刻表示 time_t left = DBTREE::board_write_leftsec( get_url() ); if( left ){ bool set_color = false; if( m_str_pass.empty() ) set_color = true; m_str_pass = "規制中 " + MISC::itostr( left ) + " 秒 "; std::string force; if( SESSION::focused_admin() == SESSION::FOCUS_MESSAGE ) force = "force"; MESSAGE::get_admin()->set_command( "set_title", get_url(), m_str_pass + get_title(), force ); MESSAGE::get_admin()->set_command( "set_status", get_url(), m_str_pass + get_status(), force ); if( set_color ){ MESSAGE::get_admin()->set_command( "redraw_toolbar" ); MESSAGE::get_admin()->set_command( "set_status_color", get_url(), get_color(), force ); } } else if( ! m_str_pass.empty() ){ m_str_pass = std::string(); std::string force; if( SESSION::focused_admin() == SESSION::FOCUS_MESSAGE ) force = "force"; MESSAGE::get_admin()->set_command( "set_title", get_url(), get_title(), force ); MESSAGE::get_admin()->set_command( "set_status", get_url(), get_status(), force ); MESSAGE::get_admin()->set_command( "redraw_toolbar" ); MESSAGE::get_admin()->set_command( "set_status_color", get_url(), get_color(), force ); } } } // // セットアップ // void MessageViewBase::setup_view() { pack_widget(); } // // フォント初期化 // void MessageViewBase::init_font( const std::string& fontname ) { Pango::FontDescription pfd( fontname ); pfd.set_weight( Pango::WEIGHT_NORMAL ); m_entry_name.modify_font( pfd ); m_entry_mail.modify_font( pfd ); if( m_text_message ) m_text_message->modify_font( pfd ); } // // 色初期化 // void MessageViewBase::init_color() { if( m_text_message ){ m_text_message->modify_text( Gtk::STATE_NORMAL, Gdk::Color( CONFIG::get_color( COLOR_CHAR_MESSAGE ) ) ); m_text_message->modify_text( Gtk::STATE_SELECTED, Gdk::Color( CONFIG::get_color( COLOR_CHAR_MESSAGE_SELECTION ) ) ); m_text_message->modify_base( Gtk::STATE_NORMAL, Gdk::Color( CONFIG::get_color( COLOR_BACK_MESSAGE ) ) ); m_text_message->modify_base( Gtk::STATE_SELECTED, Gdk::Color( CONFIG::get_color( COLOR_BACK_MESSAGE_SELECTION ) ) ); } } void MessageViewBase::set_message( const std::string& msg ) { if( m_text_message ) m_text_message->set_text( msg ); } const Glib::ustring MessageViewBase::get_message() { if( m_text_message ) return m_text_message->get_text(); return Glib::ustring(); } // // ロード中 // // virtual const bool MessageViewBase::is_loading() { if( ! m_post ) return false; return m_post->is_loading(); } // // コマンド // const bool MessageViewBase::set_command( const std::string& command, const std::string& arg1, const std::string& arg2 ) { if( command == "empty" ) return get_message().empty(); else if( command == "toggle_preview" ) toggle_preview(); else if( command == "undo_text" && m_text_message ) m_text_message->undo(); else if( command == "insert_draft" ) insert_draft(); else if( command == "tab_left" ) tab_left(); else if( command == "tab_right" ) tab_right(); else if( command == "hide_popup" && m_preview ) m_preview->set_command( "hide_popup" ); // メッセージをクリア else if( command == "clear_message" ){ if( m_text_message ){ m_text_message->set_text( std::string() ); m_text_message->clear_undo(); } if( m_notebook.get_current_page() != PAGE_MESSAGE ){ m_enable_focus = false; m_notebook.set_current_page( PAGE_MESSAGE ); m_enable_focus = true; } } // メッセージを追加 else if( command == "add_message" ) { if( ! arg1.empty() && m_text_message ) m_text_message->insert_str( arg1, true ); } // メッセージ保存 else if( command == "save_message" ) { if( ! get_message().empty() ){ std::string filename = "draft-" + MISC::get_filename( get_url() ); if( filename.find( ".dat" ) != std::string::npos ) filename = MISC::replace_str( filename, ".dat", ".txt" ); else filename += ".txt"; std::string save_to = CACHE::open_save_diag( MESSAGE::get_admin()->get_win(), SESSION::get_dir_draft(), filename, CACHE::FILE_TYPE_TEXT ); if( ! save_to.empty() ){ SESSION::set_dir_draft( MISC::get_dir( save_to ) ); if( CACHE::save_rawdata( save_to, get_message() ) != get_message().raw().length() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "保存に失敗しました。\nハードディスクの容量やパーミッションなどを確認してください。" ); mdiag.run(); } else return true; } } } // ビューの wrap 切り替え else if( command == "toggle_wrap" ) set_wrap(); return false; } // // 名前やメールを保存 // void MessageViewBase::save_name() { bool check_fixname = m_check_fixname.get_active(); bool check_fixmail = m_check_fixmail.get_active(); if( check_fixname != DBTREE::write_fixname( get_url() ) ) DBTREE::set_write_fixname( get_url(), check_fixname ); if( check_fixname ){ std::string name = m_entry_name.get_text(); if( name != DBTREE::write_name( get_url() ) ) DBTREE::set_write_name( get_url(), name ); } if( check_fixmail != DBTREE::write_fixmail( get_url() ) ) DBTREE::set_write_fixmail( get_url(), check_fixmail ); if( check_fixmail ){ std::string mail = m_entry_mail.get_text(); if( mail != DBTREE::write_mail( get_url() ) ) DBTREE::set_write_mail( get_url(), mail ); } } // // 名前欄に名前をセット // void MessageViewBase::set_name() { // スレ別の名前 if( DBTREE::write_fixname( get_url() ) ){ m_check_fixname.set_active(); m_entry_name.set_text( DBTREE::write_name( get_url() ) ); } // スレ別の名前が設定されていなかったら板別の名前 else if( ! DBTREE::board_get_write_name( get_url() ).empty() ){ std::string tmpname = DBTREE::board_get_write_name( get_url() ); // 空白セット if( tmpname == JD_NAME_BLANK ) m_entry_name.set_text( std::string() ); else m_entry_name.set_text( tmpname ); } // デフォルトをセット else m_entry_name.set_text( CONFIG::get_write_name() ); } // // メール欄にアドレスをセット // void MessageViewBase::set_mail() { // スレ別のメール if( DBTREE::write_fixmail( get_url() ) ){ m_check_fixmail.set_active(); m_entry_mail.set_text( DBTREE::write_mail( get_url() ) ); } // スレ別の名前が設定されていなかったら板別のメール else if( ! DBTREE::board_get_write_mail( get_url() ).empty() ){ std::string tmpmail = DBTREE::board_get_write_mail( get_url() ); // 空白セット if( tmpmail == JD_MAIL_BLANK ) m_entry_mail.set_text( std::string() ); else m_entry_mail.set_text( tmpmail ); } // デフォルトをセット else m_entry_mail.set_text( CONFIG::get_write_mail() ); } // // ツールバーなどのパック // void MessageViewBase::pack_widget() { // 書き込みビュー m_label_name.set_alignment( Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER ); m_label_mail.set_alignment( Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER ); m_label_name.set_text( " 名前 " ); m_label_mail.set_text( " メール " ); m_check_fixname.set_label( "固定" ); m_check_fixmail.set_label( "固定" ); m_tooltip.set_tip( m_check_fixname, "チェックすると名前欄を保存して固定にする" ); m_tooltip.set_tip( m_check_fixmail, "チェックするとメール欄を保存して固定にする" ); set_name(); set_mail(); m_tool_name.add( m_label_name ); m_tool_mail.add( m_label_mail ); m_tool_fixname.add( m_check_fixname ); m_tool_fixmail.add( m_check_fixmail ); m_tool_entry_name.add( m_entry_name ); m_tool_entry_mail.add( m_entry_mail ); m_tool_entry_name.set_expand( true ); m_tool_entry_mail.set_expand( true ); #if GTKMM_CHECK_VERSION(2,12,0) m_toolbar_name_mail.set_icon_size( Gtk::ICON_SIZE_MENU ); #endif m_toolbar_name_mail.set_toolbar_style( Gtk::TOOLBAR_ICONS ); m_toolbar_name_mail.append( m_tool_name ); m_toolbar_name_mail.append( m_tool_fixname ); m_toolbar_name_mail.append( m_tool_entry_name ); m_toolbar_name_mail.append( m_tool_mail ); m_toolbar_name_mail.append( m_tool_fixmail ); m_toolbar_name_mail.append( m_tool_entry_mail ); m_msgview.pack_start( m_toolbar_name_mail, Gtk::PACK_SHRINK ); if( ! m_text_message ){ // 日本語のON/OFF状態を保存 // Admin から EditView のインスタンスをもらう if( CONFIG::get_keep_im_status() ){ m_text_message = MESSAGE::get_admin()->get_text_message(); m_text_message->set_text( std::string() ); m_text_message->clear_undo(); } else m_text_message = Gtk::manage( new SKELETON::EditView() ); } set_wrap(); if( m_text_message->get_parent() ) m_text_message->reparent( m_msgview ); else m_msgview.pack_start( *m_text_message ); m_text_message->set_accepts_tab( false ); m_text_message->sig_key_press().connect( sigc::mem_fun(*this, &MessageViewBase::slot_key_press ) ); m_text_message->sig_button_press().connect( sigc::mem_fun(*this, &MessageViewBase::slot_button_press ) ); m_text_message->get_buffer()->signal_changed().connect( sigc::mem_fun(*this, &MessageViewBase::slot_text_changed ) ); // プレビュー m_preview = CORE::ViewFactory( CORE::VIEW_ARTICLEPREVIEW, get_url() ); m_notebook.set_show_tabs( false ); m_notebook.set_show_border( false ); m_notebook.append_page( m_msgview, "メッセージ" ); m_notebook.append_page( *m_preview, "プレビュー" ); m_notebook.signal_switch_page().connect( sigc::mem_fun( *this, &MessageViewBase::slot_switch_page ) ); m_notebook.set_current_page( PAGE_MESSAGE ); pack_start( m_notebook ); set_size_request( 1, 1 ); // フォントセット init_font( CONFIG::get_fontname( FONT_MESSAGE ) ); // 色セット init_color(); show_status(); } // // テキストの折り返し // void MessageViewBase::set_wrap() { if( ! m_text_message ) return; if( CONFIG::get_message_wrap() ) m_text_message->set_wrap_mode( Gtk::WRAP_CHAR ); else m_text_message->set_wrap_mode( Gtk::WRAP_NONE ); } // // 再描画 // void MessageViewBase::redraw_view() { if( m_preview ) m_preview->redraw_view(); } void MessageViewBase::focus_view() { #ifdef _DEBUG // std::cout << "MessageViewBase::focus_view page = " << m_notebook.get_current_page() << std::endl; #endif if( m_notebook.get_current_page() == PAGE_MESSAGE && m_text_message ) m_text_message->focus_view(); else if( m_preview && m_notebook.get_current_page() == PAGE_PREVIEW ) m_preview->focus_view(); } // // viewの操作 // const bool MessageViewBase::operate_view( const int control ) { if( control == CONTROL::None ) return false; switch( control ){ // 書き込まずに閉じる case CONTROL::CancelWrite: close_view(); break; // 書き込み実行 case CONTROL::ExecWrite: MESSAGE::get_admin()->set_command( "toolbar_write", get_url() ); break; case CONTROL::TabLeft: case CONTROL::TabLeftUpdated: MESSAGE::get_admin()->set_command( "tab_left" ); break; case CONTROL::TabRight: case CONTROL::TabRightUpdated: MESSAGE::get_admin()->set_command( "tab_right" ); break; case CONTROL::ToggleSage: if( m_entry_mail.get_text() == "sage" ) m_entry_mail.set_text( "" ); else set_mail(); break; // 書き込みボタンにフォーカスを移す case CONTROL::FocusWrite: MESSAGE::get_admin()->set_command( "focus_button_write" ); break; default: return false; } return true; } // // 書き込み実行 // void MessageViewBase::write() { #ifdef _DEBUG std::cout << "MessageViewBase::write\n"; #endif time_t left = DBTREE::board_write_leftsec( get_url() ); if( left && ! SESSION::loginbe() // BEログイン中はダイアログを表示しない ){ SKELETON::MsgDiag mdiag( get_parent_win(), "書き込み規制中です ( 残り " + MISC::itostr( left ) + " 秒 )\n\nもう暫くお待ち下さい。規制秒数が短くなった場合は板のプロパティからリセットできます。" ); mdiag.run(); return; } if( m_post && m_post->is_loading() ){ m_post->show_writingdiag( true ); return; } // fusianasan チェック if( DBTREE::default_noname( get_url() ) == "fusianasan" ) DBTREE::board_set_check_noname( get_url(), true ); // 名無し書き込みチェック if( DBTREE::board_check_noname( get_url() ) ){ std::string name = get_entry_name().get_text(); if( name.empty() ){ SKELETON::MsgDiag mdiag( get_parent_win(), "名前欄が空白です。fusianasan 書き込みになる可能性があります。" ); mdiag.run(); return; } } // 行数チェック if( m_max_line ){ if( m_text_message && m_text_message->get_buffer()->get_line_count() > m_max_line ){ SKELETON::MsgDiag mdiag( get_parent_win(), "行数が多すぎます。" ); mdiag.run(); return; } } // バイト数チェック if( m_max_str ){ if( m_lng_str_enc > m_max_str ){ SKELETON::MsgDiag mdiag( get_parent_win(), "文字数が多すぎます。" ); mdiag.run(); return; } } const std::string msg = create_message(); if( msg.empty() ) return; // 数値文字参照(&#????;)書き込み可能か if( DBTREE::get_unicode( get_url() ) == "change" ){ JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; if( regex.exec( "%26%23[0-9]*%3b", msg, offset, icase, newline, usemigemo, wchar ) ){ SKELETON::MsgDiag mdiag( get_parent_win(), "ユニコード文字が含まれていますが、この板ではユニコード文字は文字化けします(BBS_UNICODE=change)。\n\n書き込みますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; } } write_impl( msg ); } // // 下書きファイル挿入 // void MessageViewBase::insert_draft() { const std::list< std::string > list_files = CACHE::open_load_diag( MESSAGE::get_admin()->get_win(), SESSION::get_dir_draft(), CACHE::FILE_TYPE_TEXT, false ); if( list_files.size() ) { const std::string open_path = *list_files.begin(); std::string draft; SESSION::set_dir_draft( MISC::get_dir( open_path ) ); CACHE::load_rawdata( open_path, draft ); if( ! draft.empty() ) set_command( "add_message", draft ); } } // // プレビュー切り替え // void MessageViewBase::toggle_preview() { #ifdef _DEBUG std::cout << "MessageViewBase::toggle_preview page = " << m_notebook.get_current_page() << std::endl; #endif if( m_notebook.get_current_page() == PAGE_MESSAGE ) tab_right(); else tab_left(); } // // テキストビューでキーを押した // const bool MessageViewBase::slot_key_press( GdkEventKey* event ) { #ifdef _DEBUG_KEY guint key = event->keyval; bool ctrl = ( event->state ) & GDK_CONTROL_MASK; bool shift = ( event->state ) & GDK_SHIFT_MASK; bool alt = ( event->state ) & GDK_MOD1_MASK; std::cout << "MessageViewBase::slot_key_press" << " key = " << key << " ctrl = " << ctrl << " shift = " << shift << " alt = " << alt << std::endl; #endif return operate_view( SKELETON::View::get_control().key_press( event ) ); } // // テキストビューでマウスボタン押した // bool MessageViewBase::slot_button_press( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "MessageViewBase::slot_button_press\n"; #endif MESSAGE::get_admin()->set_command( "switch_admin" ); return true; } // // フォントの更新 // void MessageViewBase::relayout() { init_font( CONFIG::get_fontname( FONT_MESSAGE ) ); init_color(); } // // 閉じる // void MessageViewBase::close_view() { #ifdef _DEBUG std::cout << "MessageViewBase::close_view\n"; #endif MESSAGE::get_admin()->set_command( "close_currentview" ); } // // タブ左移動 // void MessageViewBase::tab_left() { #ifdef _DEBUG std::cout << "MessageViewBase::tab_left\n"; #endif int page = m_notebook.get_current_page(); if( page == PAGE_MESSAGE ) m_notebook.set_current_page( PAGE_PREVIEW ); else m_notebook.set_current_page( PAGE_MESSAGE ); focus_view(); } // // タブ右移動 // void MessageViewBase::tab_right() { #ifdef _DEBUG std::cout << "MessageViewBase::tab_right\n"; #endif int page = m_notebook.get_current_page(); if( page == PAGE_PREVIEW ) m_notebook.set_current_page( PAGE_MESSAGE ); else m_notebook.set_current_page( PAGE_PREVIEW ); m_preview->focus_view(); } // // 書き込み // void MessageViewBase::post_msg( const std::string& msg, bool new_article ) { push_logitem(); if( m_post ){ m_post->terminate_load(); delete m_post; } m_post = new Post( this, get_url(), msg, new_article ); m_post->sig_fin().connect( sigc::mem_fun( *this, &MessageViewBase::post_fin ) ); m_post->post_msg(); // 名前、メール履歴保存 std::string name = m_entry_name.get_text(); std::string mail = m_entry_mail.get_text(); CORE::get_completion_manager()->set_query( CORE::COMP_NAME, name ); CORE::get_completion_manager()->set_query( CORE::COMP_MAIL, mail ); } // // 書き込みが終わったら呼ばれる // void MessageViewBase::post_fin() { int code = m_post->get_code(); std::string location = m_post->location(); #ifdef _DEBUG std::cout << "MessageViewBase::post_fin" << std::endl << "code = " << code << std::endl << "location = " << location << std::endl; #endif // 成功 if( code == HTTP_OK || ( ( code == HTTP_MOVED_PERM || code == HTTP_REDIRECT ) && ! location.empty() ) // (まちBBSなどで)リダイレクトした場合 ){ save_postlog(); if( m_text_message ){ m_text_message->set_text( std::string() ); m_text_message->clear_undo(); } close_view(); if( ! SESSION::is_live( get_url() ) ) reload(); } // タイムアウト else if( code == HTTP_TIMEOUT ){ SKELETON::MsgDiag mdiag( get_parent_win(), "タイムアウトしました\n\n書き込み自体は成功している可能性があります。\nメッセージのバックアップをとってからスレを再読み込みして下さい。" ); mdiag.run(); } // 失敗 else if( code != HTTP_CANCEL ){ SKELETON::DetailDiag ddiag( get_parent_win(), get_url(), false, "書き込みに失敗しました\n\n" + m_post->get_errmsg(), "概要", m_post->get_return_html(), "詳細" ); ddiag.set_title( "書き込みエラー" ); ddiag.run(); } } // // タブのページが切り替わったら呼ばれるslot // void MessageViewBase::slot_switch_page( GtkNotebookPage*, guint page ) { #ifdef _DEBUG std::cout << "MessageViewBase::slot_switch_page : " << get_url() << " page = " << page << std::endl; #endif // プレビュー表示 if( m_preview && page == PAGE_PREVIEW ){ // ツールバー切り替え MESSAGE::get_admin()->set_command( "switch_toolbar_preview" ); std::string new_subject = MESSAGE::get_admin()->get_new_subject(); if( ! new_subject.empty() ) set_label( new_subject ); // URLを除外してエスケープ const bool include_url = false; std::string msg; if( m_text_message ) msg = MISC::html_escape( m_text_message->get_text(), include_url ); msg = MISC::replace_str( msg, "\n", "
    " ); std::stringstream ss; // 名前 + トリップ if( ! m_entry_name.get_text().empty() ){ const std::string name_field = m_entry_name.get_text(); const size_t trip_pos = name_field.find( "#", 0 ); const std::string name = MISC::html_escape( name_field.substr( 0, trip_pos ) ); std::string trip; if( trip_pos != std::string::npos ) { trip = MISC::get_trip( name_field.substr( trip_pos + 1 ), DBTREE::board_charset( get_url() ) ); } ss << name; if( ! trip.empty() ) ss << " ◆" << trip; } else ss << DBTREE::default_noname( get_url() ); std::string mail = MISC::html_escape( m_entry_mail.get_text() ); ss << "<>" << mail << "<>"; struct timeval tv; struct timezone tz; gettimeofday( &tv, &tz ); ss << MISC::timettostr( tv.tv_sec, MISC::TIME_WEEK ); ss << " ID:???" << "<>" << msg << "<>\n"; #ifdef _DEBUG std::cout << ss.str() << std::endl; #endif m_preview->set_command( "clear_screen" ); m_preview->set_command( "append_dat", ss.str() ); } // メッセージビュー else if( page == PAGE_MESSAGE ){ // ツールバー切り替え MESSAGE::get_admin()->set_command( "switch_toolbar_message" ); } if( m_enable_focus ){ MESSAGE::get_admin()->set_command( "switch_admin" ); MESSAGE::get_admin()->set_command( "focus_current_view" ); } } // // 書き込み欄のテキストが更新された // void MessageViewBase::slot_text_changed() { m_text_changed = true; show_status(); m_text_changed = false; } // // ステータス表示 // void MessageViewBase::show_status() { if( ! m_text_message ) return; const bool broken = is_broken(); std::stringstream ss; int line_count = 0; if( m_text_message ){ line_count = m_text_message->get_buffer()->get_line_count(); ss << " [ 行数 " << line_count; } if( m_max_line ){ ss << "/ " << m_max_line; if( m_max_line < line_count ) m_over_lines = true; else m_over_lines = false; } const std::string message = m_text_message->get_text(); ss << " / 文字数 "; if( ( int ) message.size() > m_lng_iconv ) { ss << "過多"; } else if( m_text_changed ) { int byte_out; const char* msgc = message.c_str(); std::string str_enc = m_iconv->convert( (char*)msgc, strlen( msgc ), byte_out ); m_lng_str_enc = str_enc.length(); // 特殊文字の文字数を計算 m_lng_str_enc += MISC::count_chr( str_enc, '\n' ) * 5; // "
    " = 6バイト m_lng_str_enc += MISC::count_chr( str_enc, '"' ) * 5; // " = 6バイト m_lng_str_enc += MISC::count_chr( str_enc, '<' ) * 3; // < = 4バイト m_lng_str_enc += MISC::count_chr( str_enc, '>' ) * 3; // > = 4バイト ss << m_lng_str_enc; } else ss << m_lng_str_enc; if( m_max_str ){ ss << "/ " << m_max_str; if( m_max_str < m_lng_str_enc ) m_over_lng = true; else m_over_lng = false; } if( DBTREE::get_unicode( get_url() ) == "pass" ) ss << " / unicode ○"; else if( DBTREE::get_unicode( get_url() ) == "change" ) ss << " / unicode ×"; const time_t wtime = DBTREE::article_write_time( get_url() ); if( wtime ) ss << " / 最終書込 " << ( MISC::timettostr( wtime, MISC::TIME_WEEK ) + " ( " + MISC::timettostr( wtime, MISC::TIME_PASSED ) + " )" ); ss << " ]"; set_status( ss.str() ); MESSAGE::get_admin()->set_command( "set_status", get_url(), m_str_pass + get_status() ); if( broken != is_broken() ){ MESSAGE::get_admin()->set_command( "redraw_toolbar" ); MESSAGE::get_admin()->set_command( "set_status_color", get_url(), get_color() ); } } // // 自分の書き込みの判定用データの保存 // // 実況中など post_fin() がコールされる前に自分のレスが表示されてしまう時があるので // m_post->post_msg() する前に情報を保存しておく // void MessageViewBase::push_logitem() { if( ! m_text_message ) return; const bool newthread = ! ( MESSAGE::get_admin()->get_new_subject().empty() ); const std::string msg = m_text_message->get_text(); MESSAGE::get_log_manager()->push_logitem( get_url(), newthread, msg ); } // // 書き込みログ保存 // void MessageViewBase::save_postlog() { if( ! m_text_message ) return; std::string subject = MESSAGE::get_admin()->get_new_subject(); if( subject.empty() ) subject = DBTREE::article_subject( get_url() ); const std::string msg = m_text_message->get_text(); const std::string name = get_entry_name().get_text(); const std::string mail = get_entry_mail().get_text(); MESSAGE::get_log_manager()->save( get_url(), subject, msg, name, mail ); } jd-2.8.7-140104/src/message/messageviewbase.h0000644000076400010400000001071111527756110015333 0ustar // ライセンス: GPL2 #ifndef _MESSAGEVIEWBASE_H #define _MESSAGEVIEWBASE_H #include "skeleton/view.h" #include "skeleton/imgbutton.h" #include "skeleton/compentry.h" #include "skeleton/jdtoolbar.h" namespace JDLIB { class Iconv; } namespace SKELETON { class Admin; class LabelEntry; class EditView; } namespace MESSAGE { class Post; class MessageViewBase : public SKELETON::View { Post* m_post; Gtk::Tooltips m_tooltip; Gtk::Notebook m_notebook; SKELETON::View* m_preview; Gtk::VBox m_msgview; SKELETON::JDToolbar m_toolbar_name_mail; Gtk::ToolItem m_tool_name; Gtk::ToolItem m_tool_mail; Gtk::ToolItem m_tool_fixname; Gtk::ToolItem m_tool_fixmail; Gtk::ToolItem m_tool_entry_name; Gtk::ToolItem m_tool_entry_mail; Gtk::Label m_label_name; Gtk::Label m_label_mail; Gtk::CheckButton m_check_fixname; Gtk::CheckButton m_check_fixmail; SKELETON::CompletionEntry m_entry_name; SKELETON::CompletionEntry m_entry_mail; SKELETON::EditView* m_text_message; bool m_enable_focus; // 文字数計算用 JDLIB::Iconv* m_iconv; int m_max_line; int m_max_str; int m_lng_str_enc; int m_lng_iconv; // 経過時間表示用 int m_counter; std::string m_str_pass; bool m_text_changed; bool m_over_lines; bool m_over_lng; public: MessageViewBase( const std::string& url ); virtual ~MessageViewBase(); // // SKELETON::View の関数のオーバロード // virtual void save_session(){} // 親ウィンドウを取得 virtual Gtk::Window* get_parent_win(); // コピー用のURL virtual const std::string url_for_copy(); // コマンド virtual const bool set_command( const std::string& command, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() ); // ロード中 virtual const bool is_loading(); // 規制中や行数や文字列がオーバーして書き込めない virtual const bool is_broken(){ return ( ! m_str_pass.empty() || m_over_lines || m_over_lng ); } // キーを押した virtual const bool slot_key_press( GdkEventKey* event ); virtual void clock_in(); virtual void write(); virtual void reload(){} virtual void relayout(); virtual void close_view(); virtual void redraw_view(); virtual void focus_view(); virtual const bool operate_view( const int control ); private: // フォント初期化 void init_font( const std::string& fontname ); // 色初期化 void init_color(); // 名前欄に名前をセット void set_name(); // メール欄にアドレスをセット void set_mail(); // 自分の書き込みの判定用データの保存 void push_logitem(); // 書き込みログ保存 void save_postlog(); // 実際の書き込み処理を行う関数(子クラス別に実装) virtual void write_impl( const std::string& msg ) = 0; // プレビュー切り替え void toggle_preview(); void tab_left(); void tab_right(); // 下書きファイル挿入 void insert_draft(); bool slot_button_press( GdkEventButton* event ); void slot_switch_page( GtkNotebookPage*, guint page ); void slot_text_changed(); virtual const std::string create_message() = 0; void show_status(); protected: // Viewが所属するAdminクラス virtual SKELETON::Admin* get_admin(); void set_message( const std::string& msg ); const Glib::ustring get_message(); SKELETON::CompletionEntry& get_entry_name(){ return m_entry_name; } SKELETON::CompletionEntry& get_entry_mail(){ return m_entry_mail; } SKELETON::EditView* get_text_message() { return m_text_message; } void post_msg( const std::string& msg, bool new_article ); void post_fin(); void save_name(); void setup_view(); void pack_widget(); // テキストの折り返し void set_wrap(); }; } #endif jd-2.8.7-140104/src/message/messagewin.cpp0000644000076400010400000000566711501147420014662 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "messageadmin.h" #include "messagewin.h" #include "jdlib/miscgtk.h" #include "config/globalconf.h" #include "session.h" #include "command.h" using namespace MESSAGE; // メッセージウィンドウにはステータスバー内のマウスジェスチャ表示欄が // 不要なので SKELETON::JDWindow() の第2引数を flase にする MessageWin::MessageWin() : SKELETON::JDWindow( CONFIG::get_fold_message(), false ) { #ifdef _DEBUG std::cout << "MessageWin::MessageWin x y w h = " << get_x_win() << " " << get_y_win() << " " << get_width_win() << " " << get_height_win() << std::endl; #endif get_vbox().pack_remove_end( false, get_statbar(), Gtk::PACK_SHRINK ); init_win(); if( ! CONFIG::get_fold_message() ) set_transient_for( *CORE::get_mainwindow() ); show_all_children(); } MessageWin::~MessageWin() { #ifdef _DEBUG std::cout << "MessageWin::~MessageWin window size : x = " << get_x_win() << " y = " << get_y_win() << " w = " << get_width_win() << " h = " << get_height_win() << " max = " << is_maximized_win() << std::endl; #endif set_shown_win( false ); CORE::core_set_command( "restore_focus" ); } bool MessageWin::on_delete_event( GdkEventAny* event ) { #ifdef _DEBUG std::cout << "MessageWin::on_delete_event\n"; #endif MESSAGE::get_admin()->set_command( "close_currentview" ); return true; } const int MessageWin::get_x_win() { return SESSION::get_x_win_mes(); } const int MessageWin::get_y_win() { return SESSION::get_y_win_mes(); } void MessageWin::set_x_win( const int x ) { SESSION::set_x_win_mes( x ); } void MessageWin::set_y_win( const int y ) { SESSION::set_y_win_mes( y ); } const int MessageWin::get_width_win() { return SESSION::get_width_win_mes(); } const int MessageWin::get_height_win() { return SESSION::get_height_win_mes(); } void MessageWin::set_width_win( const int width ) { SESSION::set_width_win_mes( width ); } void MessageWin::set_height_win( const int height ) { SESSION::set_height_win_mes( height ); } const bool MessageWin::is_focus_win() { return SESSION::is_focus_win_mes(); } void MessageWin::set_focus_win( const bool set ) { SESSION::set_focus_win_mes( set ); } const bool MessageWin::is_maximized_win() { return SESSION::is_maximized_win_mes(); } void MessageWin::set_maximized_win( const bool set ) { SESSION::set_maximized_win_mes( set ); } const bool MessageWin::is_iconified_win() { return SESSION::is_iconified_win_mes(); } void MessageWin::set_iconified_win( const bool set ) { SESSION::set_iconified_win_mes( set ); } const bool MessageWin::is_shown_win() { return SESSION::is_shown_win_mes(); } void MessageWin::set_shown_win( const bool set ) { SESSION::set_shown_win_mes( set ); } void MessageWin::switch_admin() { CORE::core_set_command( "switch_message" ); } jd-2.8.7-140104/src/message/messagewin.h0000644000076400010400000000241511501147420014313 0ustar // ライセンス: GPL2 #ifndef _MESSAGEWIN_H #define _MESSAGEWIN_H #include #include "skeleton/window.h" namespace MESSAGE { class MessageWin : public SKELETON::JDWindow { public: MessageWin(); virtual ~MessageWin(); protected: virtual void switch_admin(); virtual const int get_x_win(); virtual const int get_y_win(); virtual void set_x_win( const int x ); virtual void set_y_win( const int y ); virtual const int get_width_win(); virtual const int get_height_win(); virtual void set_width_win( const int width ); virtual void set_height_win( const int height ); virtual const bool is_focus_win(); virtual void set_focus_win( const bool set ); virtual const bool is_maximized_win(); virtual void set_maximized_win( const bool set ); virtual const bool is_iconified_win(); virtual void set_iconified_win( const bool set ); virtual const bool is_full_win(){ return false; } virtual void set_full_win( const bool set ){} virtual const bool is_shown_win(); virtual void set_shown_win( const bool set ); virtual bool on_delete_event( GdkEventAny* event ); }; } #endif jd-2.8.7-140104/src/message/post.cpp0000644000076400010400000003362112127260473013505 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "messageadmin.h" #include "post.h" #include "confirmdiag.h" #include "skeleton/msgdiag.h" #include "jdlib/loaderdata.h" #include "jdlib/jdiconv.h" #include "jdlib/miscmsg.h" #include "jdlib/miscutil.h" #include "jdlib/jdregex.h" #include "dbtree/interface.h" #include "config/globalconf.h" #include "httpcode.h" #include using namespace MESSAGE; enum { SIZE_OF_RAWDATA = 2 * 1024 * 1024 }; Post::Post( Gtk::Widget* parent, const std::string& url, const std::string& msg, bool new_article ) : SKELETON::Loadable(), m_parent( parent ), m_url( url ), m_msg( msg ), m_rawdata( 0 ), m_lng_rawdata( 0 ), m_count( 0 ), m_subbbs( 0 ), m_new_article( new_article ), m_writingdiag( 0 ) { #ifdef _DEBUG std::cout << "Post::Post " << m_url << std::endl; #endif clear(); } Post::~Post() { #ifdef _DEBUG std::cout << "Post::~Post " << m_url << std::endl; #endif clear(); if( m_writingdiag ) delete m_writingdiag; m_writingdiag = NULL; } void Post::clear() { #ifdef _DEBUG std::cout << "Post::clear\n"; #endif if( m_rawdata ) free( m_rawdata ); m_rawdata = NULL; if( m_writingdiag ) m_writingdiag->hide(); } void Post::emit_sigfin() { #ifdef _DEBUG std::cout << "Post::emit_sigfin\n"; #endif m_sig_fin.emit(); clear(); if( m_writingdiag ) delete m_writingdiag; m_writingdiag = NULL; } // // 書き込み中ダイアログ表示 // void Post::show_writingdiag( const bool show_buttons ) { Gtk::Window* toplevel = dynamic_cast< Gtk::Window* >( m_parent->get_toplevel() ); if( ! toplevel ) return; Gtk::ButtonsType buttons = Gtk::BUTTONS_NONE; if( show_buttons ) buttons = Gtk::BUTTONS_OK; if( ! m_writingdiag ){ m_writingdiag = new SKELETON::MsgDiag( *toplevel, "書き込み中・・・", false, Gtk::MESSAGE_INFO, buttons, false ); m_writingdiag->signal_response().connect( sigc::mem_fun( *this, &Post::slot_response ) ); } m_writingdiag->show(); // gtkのバージョンによってはラベルが選択状態になっている場合があるので // 選択状態を解除する Gtk::Label *label = dynamic_cast< Gtk::Label* >( m_writingdiag->get_focus() ); if( label ) label->set_selectable( false ); } // // 書き込み中ダイアログのボタンを押した // void Post::slot_response( int id ) { #ifdef _DEBUG std::cout << "Post::slot_response id = " << id << std::endl; #endif if( m_writingdiag ) m_writingdiag->hide(); } // // ポスト実行 // void Post::post_msg() { if( is_loading() ) return; clear(); m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA ); m_lng_rawdata = 0; // 書き込み中ダイアログ表示 if( ! CONFIG::get_hide_writing_dialog() ) show_writingdiag( false ); JDLIB::LOADERDATA data; // 通常書き込み if( ! m_new_article ){ if( ! m_subbbs ) data.url = DBTREE::url_bbscgi( m_url ); // 1回目の投稿先 else data.url = DBTREE::url_subbbscgi( m_url ); // 2回目の投稿先 } // 新スレ作成 else{ if( ! m_subbbs ) data.url = DBTREE::url_bbscgi_new( m_url ); // 1回目の投稿先 else data.url = DBTREE::url_subbbscgi_new( m_url ); // 2回目の投稿先 } // Content-Type (2009/02/18に報告された"したらば"に書き込めない問題で追加) // http://www.asahi-net.or.jp/~sd5a-ucd/rec-html401j/interact/forms.html#h-17.13.4.1 // http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 data.contenttype = "application/x-www-form-urlencoded"; data.agent = DBTREE::get_agent_w( m_url ); data.referer = DBTREE::get_write_referer( m_url ); data.str_post = m_msg; data.host_proxy = DBTREE::get_proxy_host_w( m_url ); data.port_proxy = DBTREE::get_proxy_port_w( m_url ); data.basicauth_proxy = DBTREE::get_proxy_basicauth_w( m_url ); data.size_buf = CONFIG::get_loader_bufsize(); data.timeout = CONFIG::get_loader_timeout_post(); data.cookie_for_write = DBTREE::board_cookie_for_write( m_url ); data.basicauth = DBTREE::board_basicauth( m_url ); #ifdef _DEBUG std::cout << "Post::post_msg : " << std::endl << "url = " << data.url << std::endl << "contenttype = " << data.contenttype << std::endl << "agent = " << data.agent << std::endl << "referer = " << data.referer << std::endl << "cookie = " << data.cookie_for_write << std::endl << "proxy = " << data.host_proxy << ":" << data.port_proxy << std::endl << m_msg << std::endl; #endif if( data.url.empty() ) return; start_load( data ); } // // ローダからデータを受け取る // void Post::receive_data( const char* data, size_t size ) { if( get_code() != HTTP_OK ) return; memcpy( m_rawdata + m_lng_rawdata , data, size ); m_lng_rawdata += size; m_rawdata[ m_lng_rawdata ] = '\0'; } // // ローダがsendを終了したので戻り値解析 // void Post::receive_finish() { #ifdef _DEBUG std::cout << "Post::receive_finish\n"; #endif std::string charset = DBTREE::board_charset( m_url ); JDLIB::Iconv* libiconv = new JDLIB::Iconv( charset, "UTF-8" ); int byte_out; m_return_html = libiconv->convert( m_rawdata, m_lng_rawdata, byte_out ); delete libiconv; #ifdef _DEBUG std::cout << "code = " << get_code() << std::endl; std::cout << str << std::endl; #endif clear(); /////////////////// // ポスト失敗 if( get_code() != HTTP_OK && ! ( ( get_code() == HTTP_MOVED_PERM || get_code() == HTTP_REDIRECT ) && ! location().empty() ) // リダイレクトは成功(かもしれない) ){ m_errmsg = get_str_code(); emit_sigfin(); return; } // 以下、code == 200、 又は 302 かつ locationがセットされている(リダイレクト) の場合 JDLIB::Regex regex; const size_t offset = 0; bool icase = false; bool newline = true; const bool usemigemo = false; const bool wchar = false; std::string title; std::string tag_2ch; std::string msg; std::string conf; bool ret; // タイトル icase = true; newline = false; // . に改行をマッチさせる regex.exec( ".*([^<]*).*", m_return_html, offset, icase, newline, usemigemo, wchar ); title = MISC::remove_space( regex.str( 1 ) ); // 2chタグ icase = false; newline = false; // . に改行をマッチさせる regex.exec( ".*2ch_X:([^\\-]*)\\-\\->.*", m_return_html, offset, icase, newline, usemigemo, wchar ); tag_2ch = MISC::remove_space( regex.str( 1 ) ); // エラー内容を取得 // 一番内側のを探して取得 icase = true; newline = false; // . に改行をマッチさせる m_errmsg = std::string(); if( regex.exec( "([^>]|[^b]>)*(([^>]|[^b]>)*).*", m_return_html, offset, icase, newline, usemigemo, wchar ) ){ m_errmsg = regex.str( 2 ); } // 2ch タグで error が返った場合 else if( tag_2ch.find( "error" ) != std::string::npos ){ icase = true; newline = false; // . に改行をマッチさせる if( regex.exec( "error +-->(.*)", m_return_html, offset, icase, newline, usemigemo, wchar ) ) m_errmsg = regex.str( 1 ); } // p2 型 else if( title.find( "error" ) != std::string::npos ){ icase = true; newline = false; // . に改行をマッチさせる if( regex.exec( "

    (.*)

    ", m_return_html, offset, icase, newline, usemigemo, wchar ) ) m_errmsg = regex.str( 1 ); } if( ! m_errmsg.empty() ){ m_errmsg = MISC::replace_str( m_errmsg, "\n", "" ); //
    (.*)(.*)", m_errmsg, offset, icase, newline, usemigemo, wchar ) ){ m_errmsg = regex.str( 1 ) + " " + regex.str( 2 ) + " " + regex.str( 3 ) + regex.str( 4 ); } // 改行その他 m_errmsg= MISC::replace_str( m_errmsg, "
    ", "\n" ); m_errmsg= MISC::replace_str( m_errmsg, "
    ", "\n-------------------\n" ); // samba秒取得 icase = false; newline = false; // . に改行をマッチさせる // Smaba24規制の場合 // ERROR - 593 60 sec たたないと書けません。(1回目、8 sec しかたってない) // 忍法帖規制の場合 ( samba秒だけ取得する。 ) // ERROR:修行が足りません(Lv=2)。しばらくたってから投稿してください。(48 sec) // この板のsambaは samba=30 sec if( regex.exec( "ERROR( +- +593 +|:.+samba=)([0-9]+) +sec", m_errmsg, offset, icase, newline, usemigemo, wchar ) ){ time_t sec = atoi( regex.str( 2 ).c_str() ); #ifdef _DEBUG std::cout << "samba = " << sec << std::endl; #endif DBTREE::board_set_samba_sec( m_url, sec ); DBTREE::board_update_writetime( m_url ); } } // 書き込み確認 icase = false; newline = true; regex.exec( ".*([^<]*).*", m_return_html, offset, icase, newline, usemigemo, wchar ); conf = MISC::remove_space( regex.str( 1 ) ); // メッセージ本文 // 2ch 型 icase = false; newline = false; // . に改行をマッチさせる ret = regex.exec( ".*.*(.*).*.*(.*).* list_cookies = SKELETON::Loadable::cookies(); #ifdef _DEBUG std::cout << "TITLE: [" << title << "]\n"; std::cout << "2ch_X: [" << tag_2ch << "]\n"; std::cout << "CONF: [" << conf << "]\n"; std::cout << "MSG: [" << msg << "]\n"; std::cout << "ERR: [" << m_errmsg << "]\n"; std::list< std::string >::const_iterator it = list_cookies.begin(); for( ; it != list_cookies.end(); ++it ) std::cout << "cookie : [" << (*it) << "]\n"; std::cout << "location: [" << location() << "]\n"; #endif // 成功 if( title.find( "書きこみました" ) != std::string::npos || tag_2ch.find( "true" ) != std::string::npos || ( ( get_code() == HTTP_MOVED_PERM || get_code() == HTTP_REDIRECT ) && ! location().empty() ) // リダイレクトされた場合 ){ #ifdef _DEBUG std::cout << "write ok" << std::endl; #endif // クッキーのセット DBTREE::board_set_list_cookies_for_write( m_url, list_cookies ); DBTREE::article_update_writetime( m_url ); emit_sigfin(); return; } // クッキー確認 else if( m_count < 1 && // 永久ループ防止 ( title.find( "書き込み確認" ) != std::string::npos || tag_2ch.find( "cookie" ) != std::string::npos || ( ! DBTREE::board_list_cookies_for_write( m_url ).size() && list_cookies.size() ) ) ){ clear(); // 書き込み確認表示 if( ! CONFIG::get_always_write_ok() ){ std::string diagmsg = MISC::replace_str( msg, "
    ", "\n" ); if( diagmsg.empty() ){ if( m_errmsg.empty() ) diagmsg = "クッキーを有功にして書き込みますか?"; else diagmsg = m_errmsg; } ConfirmDiag mdiag( m_url, diagmsg ); const int ret = mdiag.run(); mdiag.hide(); if( ret != Gtk::RESPONSE_OK ){ set_code( HTTP_CANCEL ); emit_sigfin(); return; } if( mdiag.get_chkbutton().get_active() ) CONFIG::set_always_write_ok( true ); } // 書き込み用キーワード( hana=mogera や suka=pontan など )をセット DBTREE::board_analyze_keyword_for_write( m_url, m_return_html ); // 現在のメッセージにキーワードが付加されていない時は付け加える const std::string keyword = DBTREE::board_keyword_for_write( m_url ); if( ! keyword.empty() && m_msg.find( keyword ) == std::string::npos ) m_msg += "&" + keyword; // クッキーのセット DBTREE::board_set_list_cookies_for_write( m_url, list_cookies ); ++m_count; // 永久ループ防止 post_msg(); return; } // スレ立て時の書き込み確認 else if( m_count < 1 // 永久ループ防止 && ! m_subbbs && conf.find( "書き込み確認" ) != std::string::npos ){ // 書き込み用キーワード( hana=mogera や suka=pontan など )をセット DBTREE::board_analyze_keyword_for_write( m_url, m_return_html ); // 現在のメッセージにキーワードが付加されていない時は付け加える const std::string keyword = DBTREE::board_keyword_for_write( m_url ); if( ! keyword.empty() && m_msg.find( keyword ) == std::string::npos ) m_msg += "&" + keyword; // クッキーのセット DBTREE::board_set_list_cookies_for_write( m_url, list_cookies ); // subbbs.cgi にポスト先を変更してもう一回ポスト m_subbbs = true; ++m_count; // 永久ループ防止 post_msg(); return; } // その他のエラー #ifdef _DEBUG std::cout << "Error" << std::endl; std::cout << m_errmsg << std::endl; #endif // クッキー関係のエラーの時はクッキーをセット if( tag_2ch.find( "cookie" ) != std::string::npos ) DBTREE::board_set_list_cookies_for_write( m_url, list_cookies ); MISC::ERRMSG( m_return_html ); set_code( HTTP_ERR ); emit_sigfin(); } jd-2.8.7-140104/src/message/post.h0000644000076400010400000000307311531461011013135 0ustar // ライセンス: GPL2 // // 記事投稿クラス // #ifndef _POST_H #define _POST_H #include "skeleton/loadable.h" #include #include namespace SKELETON { class MsgDiag; } namespace MESSAGE { class Post : public SKELETON::Loadable { // ポスト終了シグナル typedef sigc::signal< void > SIG_FIN; SIG_FIN m_sig_fin; // 親widget Gtk::Widget* m_parent; std::string m_url; std::string m_msg; std::string m_return_html; std::string m_errmsg; char* m_rawdata; size_t m_lng_rawdata; int m_count; // 書き込み確認時の永久ループ防止用 bool m_subbbs; // true なら subbbs.cgiにpostする bool m_new_article; // 新スレ作成 // 書き込んでいますのダイアログ SKELETON::MsgDiag* m_writingdiag; public: Post( Gtk::Widget* parent, const std::string& url, const std::string& msg, bool new_article ); ~Post(); SIG_FIN sig_fin() const { return m_sig_fin; } const std::string& get_return_html() const { return m_return_html;} const std::string& get_errmsg() const { return m_errmsg; } void post_msg(); // 書き込み中ダイアログ表示 void show_writingdiag( const bool show_buttons ); private: void clear(); void emit_sigfin(); void slot_response( int id ); virtual void receive_data( const char* data, size_t size ); virtual void receive_finish(); }; } #endif jd-2.8.7-140104/src/message/toolbar.cpp0000644000076400010400000001756511637053473014200 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "toolbar.h" #include "messageadmin.h" #include "skeleton/imgtoolbutton.h" #include "skeleton/imgtoggletoolbutton.h" #include "icons/iconmanager.h" #include "control/controlutil.h" #include "control/controlid.h" #include "session.h" #include "global.h" using namespace MESSAGE; MessageToolBarBase::MessageToolBarBase() : SKELETON::ToolBar( MESSAGE::get_admin() ), m_enable_slot( true ), m_button_preview( NULL ) {} SKELETON::ImgToggleToolButton* MessageToolBarBase::get_button_preview() { #ifdef _DEBUG std::cout << "MessageToolBarBase::get_button_preview\n"; #endif if( ! m_button_preview ){ m_button_preview = Gtk::manage( new SKELETON::ImgToggleToolButton( ICON::PREVIEW ) ); m_button_preview->signal_clicked().connect( sigc::mem_fun( *this, &MessageToolBarBase::slot_toggle_preview ) ); } return m_button_preview; } // プレビュー切り替え void MessageToolBarBase::slot_toggle_preview() { if( ! m_enable_slot ) return; #ifdef _DEBUG std::cout << "MessageToolBarBase::slot_toggle_preview\n"; #endif MESSAGE::get_admin()->set_command( "toggle_preview" ); } // previewボタンのトグル void MessageToolBarBase::set_active_previewbutton( const bool active ) { m_enable_slot = false; m_button_preview->set_active( active ); m_enable_slot = true; } ////////////////////////////////// // 通常のツールバー MessageToolBar::MessageToolBar() : MessageToolBarBase(), m_button_insert_draft( NULL ), m_button_undo( NULL ), m_show_entry_new_subject( false ), m_tool_new_subject( NULL ), m_entry_new_subject( NULL ) { pack_buttons(); } // 新規スレ名entry表示切り替え void MessageToolBar::show_entry_new_subject( bool show ) { if( m_show_entry_new_subject == show ) return; m_show_entry_new_subject = show; update_button(); } std::string MessageToolBar::get_new_subject() { if( m_show_entry_new_subject && m_entry_new_subject ) return m_entry_new_subject->get_text(); return std::string(); } void MessageToolBar::clear_new_subject() { if( m_entry_new_subject ) m_entry_new_subject->set_text( "" ); } // ボタンのパッキング // virtual void MessageToolBar::pack_buttons() { #ifdef _DEBUG std::cout << "MessageToolBar::pack_buttons\n"; #endif int num = 0; for(;;){ int item = SESSION::get_item_msg_toolbar( num ); if( item == ITEM_END ) break; switch( item ){ case ITEM_PREVIEW: get_buttonbar().append( *get_button_preview() ); set_tooltip( *get_button_preview(), CONTROL::get_label_motions( CONTROL::Preview ) + "\n\nタブ移動のショートカットでも表示の切り替えが可能\n\n" + CONTROL::get_label_motions( CONTROL::TabRight ) + "\n\n"+ CONTROL::get_label_motions( CONTROL::TabLeft ) ); break; case ITEM_WRITEMSG: get_buttonbar().append( *get_button_write() ); set_tooltip( *get_button_write(), CONTROL::get_label_motions( CONTROL::ExecWrite ) + "\n\nTabキーで書き込みボタンにフォーカスを移すことも可能" ); break; case ITEM_OPENBOARD: get_buttonbar().append( *get_button_board() ); break; case ITEM_NAME: pack_transparent_separator(); // スレ名ラベルを表示 if( ! m_show_entry_new_subject ) get_buttonbar().append( *get_label() ); // 新規スレ名入力entry表示 else{ if( ! m_tool_new_subject ){ m_tool_new_subject = Gtk::manage( new Gtk::ToolItem ); m_entry_new_subject = Gtk::manage( new Gtk::Entry ); m_entry_new_subject->set_size_request( 0 ); m_tool_new_subject->add( *m_entry_new_subject ); m_tool_new_subject->set_expand( true ); } get_buttonbar().append( *m_tool_new_subject ); } pack_transparent_separator(); break; case ITEM_UNDO: if( ! m_button_undo ){ m_button_undo = Gtk::manage( new SKELETON::ImgToolButton( ICON::UNDO ) ); m_button_undo->signal_clicked().connect( sigc::mem_fun( *this, &MessageToolBar::slot_undo_clicked ) ); } get_buttonbar().append( *m_button_undo ); set_tooltip( *m_button_undo, CONTROL::get_label_motions( CONTROL::UndoEdit ) ); break; case ITEM_INSERTTEXT: if( ! m_button_insert_draft ){ m_button_insert_draft = Gtk::manage( new SKELETON::ImgToolButton( ICON::INSERTTEXT ) ); m_button_insert_draft->signal_clicked().connect( sigc::mem_fun( *this, &MessageToolBar::slot_insert_draft_clicked ) ); } get_buttonbar().append( *m_button_insert_draft ); set_tooltip( *m_button_insert_draft, CONTROL::get_label_motions( CONTROL::InsertText ) ); break; case ITEM_LOCK_MESSAGE: get_buttonbar().append( *get_button_lock() ); set_tooltip( *get_button_lock(), CONTROL::get_label_motions( CONTROL::LockMessage ) ); Gtk::ToolButton* toolbt; toolbt = dynamic_cast< Gtk::ToolButton* >( get_button_lock() ); if( toolbt ) toolbt->set_label( CONTROL::get_label( CONTROL::LockMessage ) ); break; case ITEM_QUIT: get_buttonbar().append( *get_button_close() ); set_tooltip( *get_button_close(), CONTROL::get_label_motions( CONTROL::CancelWrite ) ); break; case ITEM_SEPARATOR: pack_separator(); break; } ++num; } set_relief(); show_all_children(); } // undo ボタン void MessageToolBar::slot_undo_clicked() { MESSAGE::get_admin()->set_command( "undo_text" ); } // 下書き挿入ボタン void MessageToolBar::slot_insert_draft_clicked() { MESSAGE::get_admin()->set_command( "insert_draft" ); } /////////////////////// // プレビュー用のツールバー MessageToolBarPreview::MessageToolBarPreview() : MessageToolBarBase() { pack_buttons(); } // ボタンのパッキング // virtual void MessageToolBarPreview::pack_buttons() { #ifdef _DEBUG std::cout << "MessageToolBarPreview::pack_buttons\n"; #endif int num = 0; for(;;){ int item = SESSION::get_item_msg_toolbar( num ); if( item == ITEM_END ) break; switch( item ){ case ITEM_PREVIEW: get_buttonbar().append( *get_button_preview() ); set_tooltip( *get_button_preview(), "プレビューを閉じる" ); break; case ITEM_OPENBOARD: get_buttonbar().append( *get_button_board() ); break; case ITEM_NAME: pack_transparent_separator(); get_buttonbar().append( *get_label() ); pack_transparent_separator(); break; case ITEM_WRITEMSG: get_buttonbar().append( *get_button_write() ); set_tooltip( *get_button_write(), CONTROL::get_label_motions( CONTROL::ExecWrite ) + "\n\nTabキーで書き込みボタンにフォーカスを移すことも可能" ); break; case ITEM_QUIT: get_buttonbar().append( *get_button_close() ); set_tooltip( *get_button_close(), CONTROL::get_label_motions( CONTROL::CancelWrite ) ); break; } ++num; } set_relief(); show_all_children(); } jd-2.8.7-140104/src/message/toolbar.h0000644000076400010400000000350011065433241013613 0ustar // ライセンス: GPL2 // ツールバーのクラス #ifndef _MESSAGE_TOOLBAR_H #define _MESSAGE_TOOLBAR_H #include #include "skeleton/toolbar.h" #include "skeleton/label_entry.h" namespace SKELETON { class ImgToggleToolButton; class ImgToolButton; } namespace MESSAGE { class MessageToolBarBase : public SKELETON::ToolBar { bool m_enable_slot; SKELETON::ImgToggleToolButton* m_button_preview; public: MessageToolBarBase(); virtual ~MessageToolBarBase(){} // previewボタンのトグル void set_active_previewbutton( const bool active ); protected: SKELETON::ImgToggleToolButton* get_button_preview(); private: void slot_toggle_preview(); }; /////////////////////////////////// // 通常 class MessageToolBar : public MessageToolBarBase { SKELETON::ImgToolButton* m_button_insert_draft; SKELETON::ImgToolButton* m_button_undo; // false ならスレ名ラベル、trueなら新規レス名entry表示 bool m_show_entry_new_subject; Gtk::ToolItem* m_tool_new_subject; Gtk::Entry* m_entry_new_subject; public: MessageToolBar(); virtual ~MessageToolBar(){} void show_entry_new_subject( bool show ); std::string get_new_subject(); void clear_new_subject(); protected: virtual void pack_buttons(); private: void slot_undo_clicked(); void slot_insert_draft_clicked(); }; /////////////////////////////////// // プレビュー用 class MessageToolBarPreview : public MessageToolBarBase { public: MessageToolBarPreview(); virtual ~MessageToolBarPreview(){} protected: virtual void pack_buttons(); }; } #endif jd-2.8.7-140104/src/msgitempref.cpp0000644000076400010400000000310211506370702013402 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "msgitempref.h" #include "icons/iconmanager.h" #include "jdlib/miscutil.h" #include "global.h" #include "session.h" #include "command.h" using namespace CORE; MsgItemPref::MsgItemPref( Gtk::Window* parent, const std::string& url ) : SKELETON::SelectItemPref( parent, url ) { // デフォルトの項目を設定 append_default_pair( ITEM_NAME_PREVIEW, ICON::get_icon( ICON::PREVIEW ) ); append_default_pair( ITEM_NAME_WRITEMSG, ICON::get_icon( ICON::WRITE ) ); append_default_pair( ITEM_NAME_OPENBOARD, ICON::get_icon( ICON::TRANSPARENT ) ); append_default_pair( ITEM_NAME_NAME, ICON::get_icon( ICON::TRANSPARENT ) ); append_default_pair( ITEM_NAME_UNDO, ICON::get_icon( ICON::UNDO ) ); append_default_pair( ITEM_NAME_INSERTTEXT, ICON::get_icon( ICON::INSERTTEXT ) ); append_default_pair( ITEM_NAME_LOCK_MESSAGE, ICON::get_icon( ICON::LOCK) ); append_default_pair( ITEM_NAME_QUIT, ICON::get_icon( ICON::QUIT ) ); append_default_pair( ITEM_NAME_SEPARATOR, ICON::get_icon( ICON::TRANSPARENT ) ); // 文字列を元に行を追加 append_rows( SESSION::get_items_msg_toolbar_str() ); set_title( "ツールバー項目設定(書き込みビュー)" ); } // OKを押した void MsgItemPref::slot_ok_clicked() { SESSION::set_items_msg_toolbar_str( get_items() ); CORE::core_set_command( "update_message_toolbar_button" ); } // // デフォルトボタン // void MsgItemPref::slot_default() { append_rows( SESSION::get_items_msg_toolbar_default_str() ); } jd-2.8.7-140104/src/msgitempref.h0000644000076400010400000000103611235056116013052 0ustar // ライセンス: GPL2 // 書き込みビューのツールバーの表示項目設定 #ifndef _MSGITEMPREF_H #define _MSGITEMPREF_H #include "skeleton/selectitempref.h" namespace CORE { class MsgItemPref : public SKELETON::SelectItemPref { public: MsgItemPref( Gtk::Window* parent, const std::string& url ); virtual ~MsgItemPref(){} private: // OK押した virtual void slot_ok_clicked(); // デフォルトボタン virtual void slot_default(); }; } #endif jd-2.8.7-140104/src/openurldiag.cpp0000644000076400010400000000126411326341041013372 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "openurldiag.h" #include "command.h" using namespace CORE; OpenURLDialog::OpenURLDialog( const std::string& url ) : SKELETON::PrefDiag( NULL, url, true, false, true ), m_label_url( true, "URL :" ) { m_label_url.set_text( url ); set_activate_entry( m_label_url ); get_vbox()->pack_start( m_label_url, Gtk::PACK_SHRINK ); set_title( "URLを開く" ); resize( 600, 1 ); set_default_response( Gtk::RESPONSE_OK ); show_all_children(); m_label_url.grab_focus(); } void OpenURLDialog::slot_ok_clicked() { CORE::core_set_command( "open_url", m_label_url.get_text() ); } jd-2.8.7-140104/src/openurldiag.h0000644000076400010400000000070211326341041013033 0ustar // ライセンス: GPL2 // // URL を開く // #ifndef _OPENURL_H #define _OPENURL_H #include "skeleton/prefdiag.h" #include "skeleton/label_entry.h" namespace CORE { class OpenURLDialog : public SKELETON::PrefDiag { SKELETON::LabelEntry m_label_url; public: OpenURLDialog( const std::string& url ); virtual ~OpenURLDialog(){} protected: virtual void slot_ok_clicked(); }; }; #endif jd-2.8.7-140104/src/passwdpref.h0000644000076400010400000001261211513340547012713 0ustar // ライセンス: GPL2 // パスワード設定ダイアログ #ifndef _PASSWDPREF_H #define _PASSWDPREF_H #include "skeleton/prefdiag.h" #include "skeleton/label_entry.h" #include "login2ch.h" #include "loginbe.h" #include "loginp2.h" #include "jdlib/miscutil.h" enum { BOXSPACING = 8 }; namespace CORE { // 2chログイン用 class PasswdFrame2ch : public Gtk::VBox { SKELETON::LabelEntry m_label_sid_2ch; public: SKELETON::LabelEntry entry_id; SKELETON::LabelEntry entry_passwd; PasswdFrame2ch() : m_label_sid_2ch( false, "SID: ", CORE::get_login2ch()->get_sessionid() ), entry_id( true, "ユーザID(_I): " ), entry_passwd( true, "パスワード(_P): " ) { const int mrg = 8; set_border_width( BOXSPACING ); entry_id.set_border_width( BOXSPACING ); pack_start( entry_id ); entry_passwd.set_border_width( BOXSPACING ); entry_passwd.set_visibility( false ); pack_start( entry_passwd, Gtk::PACK_SHRINK ); m_label_sid_2ch.set_border_width( BOXSPACING ); pack_start( m_label_sid_2ch ); set_border_width( mrg ); } }; // BEログイン用 class PasswdFrameBe : public Gtk::VBox { SKELETON::LabelEntry m_label_dmdm; SKELETON::LabelEntry m_label_mdmd; public: SKELETON::LabelEntry entry_id; SKELETON::LabelEntry entry_passwd; PasswdFrameBe() : m_label_dmdm( false, "DMDM: ", CORE::get_loginbe()->get_sessionid() ), m_label_mdmd( false, "MDMD: ", CORE::get_loginbe()->get_sessiondata() ), entry_id( true, "メールアドレス(_I): " ), entry_passwd( true, "パスワード(_P): " ) { set_border_width( BOXSPACING ); entry_id.set_border_width( BOXSPACING ); pack_start( entry_id ); entry_passwd.set_border_width( BOXSPACING ); entry_passwd.set_visibility( false ); pack_start( entry_passwd, Gtk::PACK_SHRINK ); pack_start( m_label_dmdm ); pack_start( m_label_mdmd ); set_border_width( BOXSPACING ); } }; // p2ログイン用 class PasswdFramep2 : public Gtk::VBox { Gtk::Label m_label; public: SKELETON::LabelEntry entry_id; SKELETON::LabelEntry entry_passwd; PasswdFramep2() : m_label( "2ch、BEへのログインはp2から行って下さい" ), entry_id( true, "ユーザID(_I): " ), entry_passwd( true, "パスワード(_P): " ) { set_border_width( BOXSPACING ); entry_id.set_border_width( BOXSPACING ); pack_start( entry_id ); entry_passwd.set_border_width( BOXSPACING ); entry_passwd.set_visibility( false ); pack_start( entry_passwd, Gtk::PACK_SHRINK ); pack_start( m_label ); set_border_width( BOXSPACING ); } }; class PasswdPref : public SKELETON::PrefDiag { Gtk::Notebook m_notebook; PasswdFrame2ch m_frame_2ch; PasswdFrameBe m_frame_be; PasswdFramep2 m_frame_p2; // OK押した virtual void slot_ok_clicked(){ // 2ch CORE::get_login2ch()->set_username( MISC::remove_space( m_frame_2ch.entry_id.get_text() ) ); CORE::get_login2ch()->set_passwd( MISC::remove_space( m_frame_2ch.entry_passwd.get_text() ) ); // BE CORE::get_loginbe()->set_username( MISC::remove_space( m_frame_be.entry_id.get_text() ) ); CORE::get_loginbe()->set_passwd( MISC::remove_space( m_frame_be.entry_passwd.get_text() ) ); // p2 CORE::get_loginp2()->set_username( MISC::remove_space( m_frame_p2.entry_id.get_text() ) ); CORE::get_loginp2()->set_passwd( MISC::remove_space( m_frame_p2.entry_passwd.get_text() ) ); } public: PasswdPref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url ) , m_frame_2ch(), m_frame_be() { // 2chログイン用 m_frame_2ch.entry_id.set_text( CORE::get_login2ch()->get_username() ); m_frame_2ch.entry_passwd.set_text( CORE::get_login2ch()->get_passwd() ); set_activate_entry( m_frame_2ch.entry_id ); set_activate_entry( m_frame_2ch.entry_passwd ); // beログイン用 m_frame_be.entry_id.set_text( CORE::get_loginbe()->get_username() ); m_frame_be.entry_passwd.set_text( CORE::get_loginbe()->get_passwd() ); set_activate_entry( m_frame_be.entry_id ); set_activate_entry( m_frame_be.entry_passwd ); // p2ログイン用 m_frame_p2.entry_id.set_text( CORE::get_loginp2()->get_username() ); m_frame_p2.entry_passwd.set_text( CORE::get_loginp2()->get_passwd() ); set_activate_entry( m_frame_p2.entry_id ); set_activate_entry( m_frame_p2.entry_passwd ); m_notebook.append_page( m_frame_2ch, "2ch" ); m_notebook.append_page( m_frame_be, "BE" ); m_notebook.append_page( m_frame_p2, "p2" ); get_vbox()->pack_start( m_notebook ); set_title( "パスワード設定" ); show_all_children(); } virtual ~PasswdPref(){} }; } #endif jd-2.8.7-140104/src/prefdiagfactory.cpp0000644000076400010400000000720211571723321014237 0ustar // ライセンス: GPL2 #include "prefdiagfactory.h" #include "passwdpref.h" #include "privacypref.h" #include "browserpref.h" #include "linkfilterpref.h" #include "usrcmdpref.h" #include "proxypref.h" #include "globalabonepref.h" #include "globalabonethreadpref.h" #include "fontcolorpref.h" #include "livepref.h" #include "openurldiag.h" #include "mainitempref.h" #include "sidebaritempref.h" #include "boarditempref.h" #include "boarditemmenupref.h" #include "articleitempref.h" #include "articleitemmenupref.h" #include "searchitempref.h" #include "msgitempref.h" #include "dbimg/delimgdiag.h" #include "board/preference.h" #include "article/preference.h" #include "image/preference.h" #include "control/keypref.h" #include "control/mousepref.h" #include "control/buttonpref.h" #include "config/aboutconfig.h" SKELETON::PrefDiag* CORE::PrefDiagFactory( Gtk::Window* parent, const int type, const std::string& url, const std::string command ) { switch( type ) { case PREFDIAG_PASSWD: return new CORE::PasswdPref( parent, url ); case PREFDIAG_PRIVACY: return new CORE::PrivacyPref( parent, url ); case PREFDIAG_BROWSER: return new CORE::BrowserPref( parent, url ); case PREFDIAG_LINKFILTER: return new CORE::LinkFilterPref( parent, url ); case PREFDIAG_USRCMD: return new CORE::UsrCmdPref( parent, url ); case PREFDIAG_PROXY: return new CORE::ProxyPref( parent, url ); case PREFDIAG_GLOBALABONE: return new CORE::GlobalAbonePref( parent, url ); case PREFDIAG_GLOBALABONETHREAD: return new CORE::GlobalAboneThreadPref( parent, url ); case PREFDIAG_FONTCOLOR: return new CORE::FontColorPref( parent, url ); case PREFDIAG_LIVE: return new CORE::LivePref( parent, url ); case PREFDIAG_MAINITEM: return new CORE::MainItemPref( parent, url ); case PREFDIAG_SIDEBARITEM: return new CORE::SidebarItemPref( parent, url ); case PREFDIAG_BOARDITEM_COLUM: return new CORE::BoardItemColumnPref( parent, url ); case PREFDIAG_BOARDITEM: return new CORE::BoardItemPref( parent, url ); case PREFDIAG_BOARDITEM_MENU: return new CORE::BoardItemMenuPref( parent, url ); case PREFDIAG_ARTICLEITEM: return new CORE::ArticleItemPref( parent, url ); case PREFDIAG_ARTICLEITEM_MENU: return new CORE::ArticleItemMenuPref( parent, url ); case PREFDIAG_SEARCHITEM: return new CORE::SearchItemPref( parent, url ); case PREFDIAG_MSGITEM: return new CORE::MsgItemPref( parent, url ); case PREFDIAG_DELIMG: return new DBIMG::DelImgDiag( parent, url ); case PREFDIAG_BOARD: return new BOARD::Preferences( parent, url, command ); case PREFDIAG_ARTICLE: return new ARTICLE::Preferences( parent, url, command ); case PREFDIAG_IMAGE: return new IMAGE::Preferences( parent, url ); case PREFDIAG_KEY: return new CONTROL::KeyPref( parent, url ); case PREFDIAG_MOUSE: return new CONTROL::MousePref( parent, url ); case PREFDIAG_BUTTON: return new CONTROL::ButtonPref( parent, url ); case PREFDIAG_ABOUTCONFIG: return new CONFIG::AboutConfig( parent ); case PREFDIAG_OPENURL: return new CORE::OpenURLDialog( url ); default: return NULL; } } jd-2.8.7-140104/src/prefdiagfactory.h0000644000076400010400000000226111571723321013704 0ustar // ライセンス: GPL2 // // SKELETON::PrefDiagのファクトリー // #ifndef _PREFDIAGFACTORY_H #define _PREFDIAGFACTORY_H #include "skeleton/prefdiag.h" #include #include namespace CORE { enum { PREFDIAG_PASSWD, PREFDIAG_PRIVACY, PREFDIAG_BROWSER, PREFDIAG_LINKFILTER, PREFDIAG_USRCMD, PREFDIAG_PROXY, PREFDIAG_GLOBALABONETHREAD, PREFDIAG_GLOBALABONE, PREFDIAG_FONTCOLOR, PREFDIAG_LIVE, PREFDIAG_MAINITEM, PREFDIAG_SIDEBARITEM, PREFDIAG_BOARDITEM, PREFDIAG_BOARDITEM_MENU, PREFDIAG_BOARDITEM_COLUM, PREFDIAG_ARTICLEITEM, PREFDIAG_ARTICLEITEM_MENU, PREFDIAG_SEARCHITEM, PREFDIAG_MSGITEM, PREFDIAG_DELIMG, PREFDIAG_BOARD, PREFDIAG_ARTICLE, PREFDIAG_IMAGE, PREFDIAG_KEY, PREFDIAG_MOUSE, PREFDIAG_BUTTON, PREFDIAG_ABOUTCONFIG, PREFDIAG_OPENURL, PREFDIAG_NONE }; SKELETON::PrefDiag* PrefDiagFactory( Gtk::Window* parent, const int type, const std::string& url, const std::string command = std::string() ); } #endif jd-2.8.7-140104/src/privacypref.h0000644000076400010400000000553211232510605013062 0ustar // ライセンス: GPL2 // プライバシー設定ダイアログ #ifndef _PRIVACYPREF_H #define _PRIVACYPREF_H #include "skeleton/prefdiag.h" #include "skeleton/msgdiag.h" #include "command.h" namespace CORE { class PrivacyPref : public SKELETON::PrefDiag { Gtk::VBox m_vbox; Gtk::CheckButton m_bt_board; Gtk::CheckButton m_bt_thread; Gtk::CheckButton m_bt_close; Gtk::CheckButton m_bt_search; Gtk::CheckButton m_bt_name; Gtk::CheckButton m_bt_mail; Gtk::HBox m_hbox_selectall; Gtk::Button m_bt_selectall; void slot_selectall() { m_bt_board.set_active( true ); m_bt_thread.set_active( true ); m_bt_close.set_active( true ); m_bt_search.set_active( true ); m_bt_name.set_active( true ); m_bt_mail.set_active( true ); } // OK押した virtual void slot_ok_clicked() { if( m_bt_board.get_active() ) CORE::core_set_command( "clear_board" ); if( m_bt_thread.get_active() ) CORE::core_set_command( "clear_thread" ); if( m_bt_close.get_active() ) CORE::core_set_command( "clear_closed_thread" ); if( m_bt_search.get_active() ) CORE::core_set_command( "clear_search" ); if( m_bt_name.get_active() ) CORE::core_set_command( "clear_name" ); if( m_bt_mail.get_active() ) CORE::core_set_command( "clear_mail" ); } public: PrivacyPref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url ), m_bt_board( "板履歴(_B)", true ), m_bt_thread( "スレ履歴(_T)", true ), m_bt_close( "最近閉じたスレの履歴(_R)", true ), m_bt_search( "検索履歴(_F)", true ), m_bt_name( "書き込みビューの名前履歴(_N)", true ), m_bt_mail( "書き込みビューのメール履歴(_E)", true ), m_bt_selectall( "全て選択(_A)", true ) { m_vbox.set_spacing( 8 ); m_vbox.set_border_width( 8 ); m_vbox.pack_start( m_bt_thread ); m_vbox.pack_start( m_bt_board ); m_vbox.pack_start( m_bt_close ); m_vbox.pack_start( m_bt_search ); m_vbox.pack_start( m_bt_name ); m_vbox.pack_start( m_bt_mail ); m_bt_selectall.signal_clicked().connect( sigc::mem_fun( *this, &PrivacyPref::slot_selectall ) ); m_hbox_selectall.pack_start( m_bt_selectall, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox_selectall, Gtk::PACK_SHRINK ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_vbox, Gtk::PACK_SHRINK ); set_title( "プライバシー情報の消去" ); show_all_children(); } virtual ~PrivacyPref(){} }; } #endif jd-2.8.7-140104/src/proxypref.h0000644000076400010400000001302011360116564012565 0ustar // ライセンス: GPL2 // プロキシ設定ダイアログ #ifndef _PROXYPREF_H #define _PROXYPREF_H #include "skeleton/prefdiag.h" #include "skeleton/label_entry.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" namespace CORE { class ProxyFrame : public Gtk::Frame { Gtk::VBox m_vbox; Gtk::HBox m_hbox; public: Gtk::CheckButton ckbt; SKELETON::LabelEntry entry_host; SKELETON::LabelEntry entry_port; ProxyFrame( const std::string& title, const Glib::ustring& ckbt_label, const Glib::ustring& host_label, const Glib::ustring& port_label ) : ckbt( ckbt_label, true ), entry_host( true, host_label), entry_port( true, port_label ) { m_hbox.set_spacing( 8 ); m_hbox.pack_start( ckbt, Gtk::PACK_SHRINK ); m_hbox.pack_start( entry_host ); m_hbox.pack_start( entry_port, Gtk::PACK_SHRINK ); m_hbox.set_border_width( 8 ); m_vbox.set_spacing( 8 ); m_vbox.pack_start( m_hbox, Gtk::PACK_SHRINK ); set_label( title ); set_border_width( 8 ); add( m_vbox ); } }; class ProxyPref : public SKELETON::PrefDiag { Gtk::Label m_label; // 2ch読み込み用 ProxyFrame m_frame_2ch; // 2ch書き込み用 ProxyFrame m_frame_2ch_w; // 一般用 ProxyFrame m_frame_data; // OK押した virtual void slot_ok_clicked(){ // 2ch if( m_frame_2ch.ckbt.get_active() ) CONFIG::set_use_proxy_for2ch( true ); else CONFIG::set_use_proxy_for2ch( false ); CONFIG::set_proxy_for2ch( MISC::remove_space( m_frame_2ch.entry_host.get_text() ) ); CONFIG::set_proxy_port_for2ch( atoi( m_frame_2ch.entry_port.get_text().c_str() ) ); // 2ch書き込み用 if( m_frame_2ch_w.ckbt.get_active() ) CONFIG::set_use_proxy_for2ch_w( true ); else CONFIG::set_use_proxy_for2ch_w( false ); CONFIG::set_proxy_for2ch_w( MISC::remove_space( m_frame_2ch_w.entry_host.get_text() ) ); CONFIG::set_proxy_port_for2ch_w( atoi( m_frame_2ch_w.entry_port.get_text().c_str() ) ); // 一般 if( m_frame_data.ckbt.get_active() ) CONFIG::set_use_proxy_for_data( true ); else CONFIG::set_use_proxy_for_data( false ); CONFIG::set_proxy_for_data( MISC::remove_space( m_frame_data.entry_host.get_text() ) ); CONFIG::set_proxy_port_for_data( atoi( m_frame_data.entry_port.get_text().c_str() ) ); } public: ProxyPref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url ), m_label( "認証を行う場合はホスト名を「ユーザID:パスワード@ホスト名」としてください。" ), m_frame_2ch( "2ch読み込み用", "使用する(_U)", "ホスト名(_H): ", "ポート番号(_P): " ), m_frame_2ch_w( "2ch書き込み用", "使用する(_S)", "ホスト名(_N): ", "ポート番号(_R): " ), m_frame_data( "その他のサーバ用(板一覧、外部板、画像など)", "使用する(_E)", "ホスト名(_A): ", "ポート番号(_T): " ) { std::string host; // 2ch用 if( CONFIG::get_use_proxy_for2ch() ) m_frame_2ch.ckbt.set_active( true ); else m_frame_2ch.ckbt.set_active( false ); if( CONFIG::get_proxy_basicauth_for2ch().empty() ) host = CONFIG::get_proxy_for2ch(); else host = CONFIG::get_proxy_basicauth_for2ch() + "@" + CONFIG::get_proxy_for2ch(); m_frame_2ch.entry_host.set_text( host ); m_frame_2ch.entry_port.set_text( MISC::itostr( CONFIG::get_proxy_port_for2ch() ) ); set_activate_entry( m_frame_2ch.entry_host ); set_activate_entry( m_frame_2ch.entry_port ); // 2ch書き込み用 if( CONFIG::get_use_proxy_for2ch_w() ) m_frame_2ch_w.ckbt.set_active( true ); else m_frame_2ch_w.ckbt.set_active( false ); if( CONFIG::get_proxy_basicauth_for2ch_w().empty() ) host = CONFIG::get_proxy_for2ch_w(); else host = CONFIG::get_proxy_basicauth_for2ch_w() + "@" + CONFIG::get_proxy_for2ch_w(); m_frame_2ch_w.entry_host.set_text( host ); m_frame_2ch_w.entry_port.set_text( MISC::itostr( CONFIG::get_proxy_port_for2ch_w() ) ); set_activate_entry( m_frame_2ch_w.entry_host ); set_activate_entry( m_frame_2ch_w.entry_port ); // 一般用 if( CONFIG::get_use_proxy_for_data() ) m_frame_data.ckbt.set_active( true ); else m_frame_data.ckbt.set_active( false ); if( CONFIG::get_proxy_basicauth_for_data().empty() ) host = CONFIG::get_proxy_for_data(); else host = CONFIG::get_proxy_basicauth_for_data() + "@" + CONFIG::get_proxy_for_data(); m_frame_data.entry_host.set_text( host ); m_frame_data.entry_port.set_text( MISC::itostr( CONFIG::get_proxy_port_for_data() ) ); set_activate_entry( m_frame_data.entry_host ); set_activate_entry( m_frame_data.entry_port ); get_vbox()->set_spacing( 4 ); get_vbox()->pack_start( m_label ); get_vbox()->pack_start( m_frame_2ch ); get_vbox()->pack_start( m_frame_2ch_w ); get_vbox()->pack_start( m_frame_data ); set_title( "プロキシ設定" ); show_all_children(); } virtual ~ProxyPref(){} }; } #endif jd-2.8.7-140104/src/searchitempref.cpp0000644000076400010400000000253211571723321014070 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "searchitempref.h" #include "icons/iconmanager.h" #include "global.h" #include "session.h" #include "command.h" using namespace CORE; SearchItemPref::SearchItemPref( Gtk::Window* parent, const std::string& url ) : SKELETON::SelectItemPref( parent, url ) { // デフォルトの項目を設定 append_default_pair( ITEM_NAME_NAME, ICON::get_icon( ICON::TRANSPARENT ) ); append_default_pair( ITEM_NAME_SEARCH, ICON::get_icon( ICON::SEARCH ) ); append_default_pair( ITEM_NAME_RELOAD, ICON::get_icon( ICON::RELOAD ) ); append_default_pair( ITEM_NAME_STOPLOADING, ICON::get_icon( ICON::STOPLOADING ) ); append_default_pair( ITEM_NAME_QUIT, ICON::get_icon( ICON::QUIT ) ); append_default_pair( ITEM_NAME_SEPARATOR, ICON::get_icon( ICON::TRANSPARENT ) ); // 文字列を元に行を追加 append_rows( SESSION::get_items_search_toolbar_str() ); set_title( "ツールバー項目設定(ログ/スレタイ検索)" ); } // // OKを押した // void SearchItemPref::slot_ok_clicked() { SESSION::set_items_search_toolbar_str( get_items() ); CORE::core_set_command( "update_article_toolbar_button" ); } // // デフォルトボタン // void SearchItemPref::slot_default() { append_rows( SESSION::get_items_search_toolbar_default_str() ); } jd-2.8.7-140104/src/searchitempref.h0000644000076400010400000000106111571723321013531 0ustar // ライセンス: GPL2 // ログ/スレタイ検索のツールバーの表示項目設定 #ifndef _SEARCHITEMPREF_H #define _SEARCHITEMPREF_H #include "skeleton/selectitempref.h" namespace CORE { class SearchItemPref : public SKELETON::SelectItemPref { public: SearchItemPref( Gtk::Window* parent, const std::string& url ); virtual ~SearchItemPref(){} private: // OKボタン virtual void slot_ok_clicked(); // デフォルトボタン virtual void slot_default(); }; } #endif jd-2.8.7-140104/src/searchloader.cpp0000644000076400010400000000312411157077436013532 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "searchloader.h" #include "usrcmdmanager.h" #include "jdlib/loaderdata.h" #include "jdlib/miscutil.h" #include "config/globalconf.h" using namespace CORE; SearchLoader::SearchLoader() : SKELETON::TextLoader() { std::string url = CONFIG::get_url_search_title(); m_charset = "UTF-8"; if( url.find( "$TEXTX" ) != std::string::npos ) m_charset = "EUC-JP"; else if( url.find( "$TEXTE" ) != std::string::npos ) m_charset = "MS932"; #ifdef _DEBUG std::cout << "SearchLoader::SearchLoader charset = " << m_charset << std::endl;; #endif } SearchLoader::~SearchLoader() { #ifdef _DEBUG std::cout << "SearchLoader::~SearchLoader\n"; #endif } const std::string SearchLoader::get_url() { std::string url = get_usrcmd_manager()->replace_cmd( CONFIG::get_url_search_title(), "", "", m_query, 0 ); #ifdef _DEBUG std::cout << "SearchLoader::get_url url = " << url << std::endl; #endif return url; } void SearchLoader::search( const std::string& query ) { #ifdef _DEBUG std::cout << "SearchLoader::search query = " << query << std::endl; #endif m_query = query; reset(); download_text(); } // ロード用データ作成 void SearchLoader::create_loaderdata( JDLIB::LOADERDATA& data ) { #ifdef _DEBUG std::cout << "SearchLoader::create_loaderdata\n"; #endif data.init_for_data(); data.url = get_url(); } // ロード後に呼び出される void SearchLoader::parse_data() { #ifdef _DEBUG std::cout << "SearchLoader::parse_data\n"; #endif m_sig_search_fin.emit(); } jd-2.8.7-140104/src/searchloader.h0000644000076400010400000000201611273044650013165 0ustar // ライセンス: GPL2 // // スレタイ検索ローダ // #ifndef _SEARCHLOADER_H #define _SEARCHLOADER_H #include "skeleton/textloader.h" #include namespace CORE { class SearchLoader : public SKELETON::TextLoader { // 検索が終了するとemitされる typedef sigc::signal< void > SIG_SEARCH_FIN; SIG_SEARCH_FIN m_sig_search_fin; std::string m_charset; std::string m_query; public: SearchLoader(); ~SearchLoader(); SIG_SEARCH_FIN sig_search_fin(){ return m_sig_search_fin; } void search( const std::string& query ); protected: virtual const std::string get_url(); virtual const std::string get_path(){ return std::string(); } virtual const std::string get_charset(){ return m_charset; } // ロード用データ作成 virtual void create_loaderdata( JDLIB::LOADERDATA& data ); // ロード後に呼び出される virtual void parse_data(); }; } #endif jd-2.8.7-140104/src/searchmanager.cpp0000644000076400010400000001772311405713530013674 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "searchmanager.h" #include "searchloader.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" #include "jdlib/jdregex.h" #include "dbtree/interface.h" #include "dbtree/articlebase.h" #include "config/globalconf.h" CORE::Search_Manager* instance_search_manager = NULL; CORE::Search_Manager* CORE::get_search_manager() { if( ! instance_search_manager ) instance_search_manager = new Search_Manager(); assert( instance_search_manager ); return instance_search_manager; } void CORE::delete_search_manager() { if( instance_search_manager ) delete instance_search_manager; instance_search_manager = NULL; } /////////////////////////////////////////////// using namespace CORE; Search_Manager::Search_Manager() : m_searching( false ), m_searchloader( NULL ) {} Search_Manager::~Search_Manager() { // デストラクタの中からdispatchを呼ぶと落ちるので dispatch不可にする set_dispatchable( false ); stop( std::string() ); wait(); if( m_searchloader ) delete m_searchloader; } // // ログ検索 // // 結果は m_list_article と m_list_data に入る。 // // id : 呼び出し元の ID。 検索終了時に SIG_SEARCH_FIN シグナルで送る // searchmode : 検索モード // url: ログ検索先の板のアドレス // query : 検索文字列、空文字ならキャッシュにあるスレを全て選択 // mode_or : false なら AND、true なら OR で検索する // bm : trueの時、しおりが付いている(スレ一覧でしおりを付けた or レスに一つでもしおりが付いている)スレのみを対象に検索する // calc_data : 検索終了時に m_list_data を求める // const bool Search_Manager::search( const std::string& id, const int searchmode, const std::string& url, const std::string& query, const bool mode_or, const bool bm, const bool calc_data ) { #ifdef _DEBUG std::cout << "Search_Manager::search url = " << url << " query = " << query << std::endl; #endif if( m_searching ) return false; if( m_thread.is_running() ) return false; m_searchmode = searchmode; m_id = id; m_url = url; m_query = query; m_mode_or = mode_or; m_bm = bm; m_calc_data = calc_data; m_list_article.clear(); m_list_data.clear(); // 全ログ検索のとき、スレッドを起動する前にメインスレッドで板情報ファイルを // 読み込んでおかないと大量の warning が出る if( m_searchmode == SEARCHMODE_ALLLOG ) DBTREE::read_boardinfo_all(); if( ! m_thread.create( ( STARTFUNC ) launcher, ( void * ) this, JDLIB::NODETACH ) ){ MISC::ERRMSG( "Search_Manager::search : could not start thread" ); return FALSE; } m_searching = true; return true; } // // スレッドのランチャ (static) // void* Search_Manager::launcher( void* dat ) { Search_Manager* sm = ( Search_Manager * ) dat; sm->thread_search(); return 0; } // // ログ検索実行スレッド // void Search_Manager::thread_search() { #ifdef _DEBUG std::cout << "Search_Manager::thread_search\n"; #endif m_stop = false; if( m_searchmode == SEARCHMODE_LOG ) DBTREE::search_cache( m_url, m_list_article, m_query, m_mode_or, m_bm, m_stop ); else if( m_searchmode == SEARCHMODE_ALLLOG ) DBTREE::search_cache_all( m_list_article, m_query, m_mode_or, m_bm, m_stop ); if( m_calc_data ){ std::vector< DBTREE::ArticleBase* >::iterator it = m_list_article.begin(); for( ; it != m_list_article.end(); ++it ){ DBTREE::ArticleBase* article = ( *it ); SEARCHDATA data; data.url_readcgi = DBTREE::url_readcgi( article->get_url(), 0, 0 ); data.subject = article->get_subject(); data.num = article->get_number_load(); data.bookmarked = article->is_bookmarked_thread(); data.num_bookmarked = article->get_num_bookmark(); data.boardname = DBTREE::board_name( data.url_readcgi ); #ifdef _DEBUG std::cout << "url = " << data.url_readcgi << std::endl << "board = " << data.boardname << std::endl << "subject = " << data.subject << std::endl << "num = " << data.num << std::endl << std::endl; #endif m_list_data.push_back( data ); } } dispatch(); } // // ディスパッチャのコールバック関数 // void Search_Manager::callback_dispatch() { wait(); search_fin(); } // // 検索終了 // void Search_Manager::search_fin() { #ifdef _DEBUG std::cout << "Search_Manager::search_fin\n"; #endif m_sig_search_fin.emit( m_id ); m_searching = false; } // // 検索中止 // void Search_Manager::stop( const std::string& id ) { if( ! m_searching ) return; if( ! id.empty() && id != m_id ) return; #ifdef _DEBUG std::cout << "Search_Manager::stop\n"; #endif m_stop = true; // スレタイ検索停止 if( m_searchmode == SEARCHMODE_TITLE && m_searchloader ) m_searchloader->stop_load(); } void Search_Manager::wait() { m_thread.join(); } ///////////////////////////////////////////////////////////////////////// // // スレタイ検索 // const bool Search_Manager::search_title( const std::string& id, const std::string& query ) { if( m_searching ) return false; if( m_searchloader && m_searchloader->is_loading() ) return false; #ifdef _DEBUG std::cout << "Search_Manager::search_title query = " << query << std::endl; #endif m_searchmode = SEARCHMODE_TITLE; m_id = id; m_query = query; m_list_data.clear(); // スレタイの検索が終わったら search_fin_title が呼び出される if( ! m_searchloader ){ m_searchloader = new SearchLoader(); m_searchloader->sig_search_fin().connect( sigc::mem_fun( *this, &Search_Manager::search_fin_title ) ); } m_searching = true; m_searchloader->search( m_query ); return true; } // // スレタイ検索ロード終了 // void Search_Manager::search_fin_title() { #ifdef _DEBUG std::cout << "Search_Manager::search_fin_title\n"; #endif if( ! m_searchloader ) return; // 行ごとに分割し、regexを使ってurl取得 if( ! m_searchloader->get_data().empty() ){ JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; regex.compile( CONFIG::get_regex_search_title(), icase, newline, usemigemo, wchar ); std::list< std::string > lines = MISC::get_lines( m_searchloader->get_data() ); std::list< std::string >::iterator it; for( it = lines.begin(); it != lines.end(); ++it ){ std::string line = MISC::remove_space( *it ); // & が & に置き換わっているので直す if( line.find( "&" ) != std::string::npos ) line = MISC::replace_str( line, "&", "&" ); if( ! line.empty() && regex.exec( line, offset ) ){ SEARCHDATA data; data.url_readcgi = DBTREE::url_readcgi( regex.str( 1 ), 0, 0 ); data.subject = MISC::html_unescape( regex.str( 2 ) ); data.num = atoi( regex.str( 3 ).c_str() ); data.bookmarked = false; data.num_bookmarked = 0; if( ! data.url_readcgi.empty() ){ data.boardname = DBTREE::board_name( data.url_readcgi ); #ifdef _DEBUG std::cout << "url = " << data.url_readcgi << std::endl << "board = " << data.boardname << std::endl << "subject = " << data.subject << std::endl << "num = " << data.num << std::endl << std::endl; #endif m_list_data.push_back( data ); } } } } m_searchloader->reset(); search_fin(); } jd-2.8.7-140104/src/searchmanager.h0000644000076400010400000000663411401470653013342 0ustar // ライセンス: GPL2 // // ログ、スレタイ検索クラス // #ifndef _SEARCHMANAGER_H #define _SEARCHMANAGER_H #include "skeleton/dispatchable.h" #include #include "jdlib/jdthread.h" #include #include namespace DBTREE { class ArticleBase; } namespace CORE { class SearchLoader; // 検索モード enum { SEARCHMODE_LOG = 0, // ログ検索 SEARCHMODE_ALLLOG, // 全ログ検索 SEARCHMODE_TITLE // スレタイ検索 }; struct SEARCHDATA { std::string url_readcgi; std::string boardname; std::string subject; int num; // 読み込み数 bool bookmarked; // スレ全体にしおりがついているか int num_bookmarked; // レスにつけられたしおりの数 }; class Search_Manager : public SKELETON::Dispatchable { typedef sigc::signal< void, const std::string& > SIG_SEARCH_FIN; SIG_SEARCH_FIN m_sig_search_fin; JDLIB::Thread m_thread; int m_searchmode; std::string m_id; std::string m_url; std::string m_query; bool m_mode_or; bool m_bm; bool m_calc_data; std::vector< DBTREE::ArticleBase* > m_list_article; std::list< SEARCHDATA > m_list_data; // 検索実行中 bool m_searching; bool m_stop; // スレタイ検索ローダ SearchLoader* m_searchloader; public: Search_Manager(); virtual ~Search_Manager(); SIG_SEARCH_FIN sig_search_fin(){ return m_sig_search_fin; } const std::vector< DBTREE::ArticleBase* >& get_list_article() const{ return m_list_article; } const std::list< SEARCHDATA >& get_list_data() const { return m_list_data; } const bool is_searching() const { return m_searching; } const bool is_searching( const std::string& id ) const { if( id == m_id ) return m_searching; else return false; } void stop( const std::string& id ); // ログ検索 // // 結果は m_list_article と m_list_data に入る。 // // id : 呼び出し元の ID。 検索終了時に SIG_SEARCH_FIN シグナルで送る // searchmode : 検索モード // url: ログ検索先の板のアドレス // query : 検索文字列、空文字ならキャッシュにあるスレを全て選択 // mode_or : false なら AND、true なら OR で検索する // bm : trueの時、しおりが付いている(スレ一覧でしおりを付けた or レスに一つでもしおりが付いている)スレのみを対象に検索する // calc_data : 検索終了時に m_list_data を求める const bool search( const std::string& id, const int searchmode, const std::string& url, const std::string& query, const bool mode_or, const bool bm, const bool calc_data ); // スレタイ検索 const bool search_title( const std::string& id, const std::string& query ); private: static void* launcher( void* ); void wait(); void thread_search(); virtual void callback_dispatch(); void search_fin(); void search_fin_title(); }; /////////////////////////////////////// // インターフェース Search_Manager* get_search_manager(); void delete_search_manager(); } #endif jd-2.8.7-140104/src/session.cpp0000644000076400010400000015200611724350130012546 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "session.h" #include "cache.h" #include "global.h" #include "jdlib/confloader.h" #include "jdlib/miscutil.h" #include "jdlib/misctime.h" #include "bbslist/bbslistadmin.h" #include "article/articleadmin.h" #include "article/articleviewbase.h" #include bool booting = true; bool quitting = false; bool tab_operating_article = false; bool tab_operating_image = false; int mode_pane; bool mode_online; bool mode_login2ch; bool mode_loginbe; bool mode_loginp2; int win_hpane_main_pos; int win_vpane_main_pos; int win_hpane_main_r_pos; int win_vpane_main_mes_pos; int win_notebook_main_page; int win_bbslist_page; int win_board_page; int win_article_page; int win_image_page; std::list< std::string > board_urls; std::list< bool > board_locked; std::list< std::string > board_switchhistory; std::list< std::string > article_urls; std::list< bool > article_locked; std::list< std::string > article_switchhistory; std::list< std::string > image_urls; std::list< bool > image_locked; std::string items_sidebar_toolbar_str; std::vector< int > items_sidebar_toolbar; std::string items_main_toolbar_str; std::vector< int > items_main_toolbar; std::string items_article_toolbar_str; std::vector< int > items_article_toolbar; std::string items_search_toolbar_str; std::vector< int > items_search_toolbar; std::string items_board_toolbar_str; std::vector< int > items_board_toolbar; std::string items_board_col_str; std::vector< int > items_board_col; std::string items_msg_toolbar_str; std::vector< int > items_msg_toolbar; std::string items_board_menu_str; std::vector< int > items_board_menu; std::string items_article_menu_str; std::vector< int > items_article_menu; int board_col_mark; int board_col_id; int board_col_board; int board_col_subject; int board_col_number; int board_col_load; int board_col_new; int board_col_since; int board_col_write; int board_col_access; int board_col_speed; int board_col_diff; int board_col_since_time; int board_col_write_time; bool win_show_sidebar; bool win_show_menubar; bool show_main_toolbar; int win_toolbar_pos; bool show_bbslist_toolbar; bool show_board_toolbar; bool show_article_toolbar; bool show_board_tab; bool show_article_tab; bool show_main_statbar; int win_focused_admin; int win_focused_admin_sidebar; int x_win_main; int y_win_main; int x_win_img; int y_win_img; int x_win_mes; int y_win_mes; int width_win_main; int height_win_main; int width_win_img; int height_win_img; int width_win_mes; int height_win_mes; bool focus_win_main = false; bool focus_win_img = false; bool focus_win_mes = false; bool maximized_win_main = false; bool maximized_win_img = false; bool maximized_win_mes = false; bool iconified_win_main = false; bool iconified_win_img = false; bool iconified_win_mes = false; bool shown_win_main = false; bool shown_win_img = false; bool shown_win_mes = false; bool full_win_main = false; bool dialog_shown = false; bool embedded_img; bool embedded_mes; bool close_mes; std::string dir_dat; std::string img_dir_img_save; std::string dir_draft; bool popupmenu_shown; std::vector< std::string > delete_list; std::vector< std::string > live_urls; int img_fit_mode; std::string dir_select_favorite; ///////////////////////////////////// // ツールバー等の項目名 -> ID 変換 const int SESSION::parse_item( const std::string& item_name ) { int item = ITEM_END; if( item_name == ITEM_NAME_BBSLISTVIEW ) item = ITEM_BBSLISTVIEW; else if( item_name == ITEM_NAME_FAVORITEVIEW ) item = ITEM_FAVORITEVIEW; else if( item_name == ITEM_NAME_BOARDVIEW ) item = ITEM_BOARDVIEW; else if( item_name == ITEM_NAME_HISTVIEW ) item = ITEM_HISTVIEW; else if( item_name == ITEM_NAME_HIST_BOARDVIEW ) item = ITEM_HIST_BOARDVIEW; else if( item_name == ITEM_NAME_HIST_CLOSEVIEW ) item = ITEM_HIST_CLOSEVIEW; else if( item_name == ITEM_NAME_HIST_CLOSEBOARDVIEW ) item = ITEM_HIST_CLOSEBOARDVIEW; else if( item_name == ITEM_NAME_HIST_CLOSEIMGVIEW ) item = ITEM_HIST_CLOSEIMGVIEW; else if( item_name == ITEM_NAME_ARTICLEVIEW ) item = ITEM_ARTICLEVIEW; else if( item_name == ITEM_NAME_IMAGEVIEW ) item = ITEM_IMAGEVIEW; else if( item_name == ITEM_NAME_URL ) item = ITEM_URL; else if( item_name == ITEM_NAME_GO ) item = ITEM_GO; else if( item_name == ITEM_NAME_SEPARATOR ) item = ITEM_SEPARATOR; else if( item_name == ITEM_NAME_MARK ) item = ITEM_MARK; else if( item_name == ITEM_NAME_ID ) item = ITEM_ID; else if( item_name == ITEM_NAME_BOARD ) item = ITEM_BOARD; else if( item_name == ITEM_NAME_NAME ) item = ITEM_NAME; else if( item_name == ITEM_NAME_RES ) item = ITEM_RES; else if( item_name == ITEM_NAME_LOAD ) item = ITEM_LOAD; else if( item_name == ITEM_NAME_NEW ) item = ITEM_NEW; else if( item_name == ITEM_NAME_SINCE ) item = ITEM_SINCE; else if( item_name == ITEM_NAME_LASTWRITE ) item = ITEM_LASTWRITE; else if( item_name == ITEM_NAME_ACCESS ) item = ITEM_ACCESS; else if( item_name == ITEM_NAME_SPEED ) item = ITEM_SPEED; else if( item_name == ITEM_NAME_DIFF ) item = ITEM_DIFF; else if( item_name == ITEM_NAME_WRITEMSG ) item = ITEM_WRITEMSG; else if( item_name == ITEM_NAME_OPENBOARD ) item = ITEM_OPENBOARD; else if( item_name == ITEM_NAME_OPENARTICLETAB ) item = ITEM_OPENARTICLETAB; else if( item_name == ITEM_NAME_REGETARTICLE ) item = ITEM_REGETARTICLE; else if( item_name == ITEM_NAME_BOOKMARK ) item = ITEM_BOOKMARK; else if( item_name == ITEM_NAME_SEARCH ) item = ITEM_SEARCH; else if( item_name == ITEM_NAME_DRAWOUT ) item = ITEM_DRAWOUT; else if( item_name == ITEM_NAME_RELOAD ) item = ITEM_RELOAD; else if( item_name == ITEM_NAME_STOPLOADING ) item = ITEM_STOPLOADING; else if( item_name == ITEM_NAME_APPENDFAVORITE ) item = ITEM_APPENDFAVORITE; else if( item_name == ITEM_NAME_FAVORITE_ARTICLE ) item = ITEM_FAVORITE_ARTICLE; else if( item_name == ITEM_NAME_CHECK_UPDATE_ROOT ) item = ITEM_CHECK_UPDATE_ROOT; else if( item_name == ITEM_NAME_CHECK_UPDATE_OPEN_ROOT ) item = ITEM_CHECK_UPDATE_OPEN_ROOT; else if( item_name == ITEM_NAME_COPY ) item = ITEM_COPY; else if( item_name == ITEM_NAME_COPY_URL ) item = ITEM_COPY_URL; else if( item_name == ITEM_NAME_COPY_TITLE_URL ) item = ITEM_COPY_TITLE_URL; else if( item_name == ITEM_NAME_COPY_TITLE_URL_THREAD ) item = ITEM_COPY_TITLE_URL_THREAD; else if( item_name == ITEM_NAME_COPY_THREAD_INFO ) item = ITEM_COPY_THREAD_INFO; else if( item_name == ITEM_NAME_DELETE ) item = ITEM_DELETE; else if( item_name == ITEM_NAME_QUIT ) item = ITEM_QUIT; else if( item_name == ITEM_NAME_BACK ) item = ITEM_BACK; else if( item_name == ITEM_NAME_FORWARD ) item = ITEM_FORWARD; else if( item_name == ITEM_NAME_LOCK ) item = ITEM_LOCK; else if( item_name == ITEM_NAME_LIVE ) item = ITEM_LIVE; else if( item_name == ITEM_NAME_NEWARTICLE ) item = ITEM_NEWARTICLE; else if( item_name == ITEM_NAME_SEARCHBOX ) item = ITEM_SEARCHBOX; else if( item_name == ITEM_NAME_SEARCH_NEXT ) item = ITEM_SEARCH_NEXT; else if( item_name == ITEM_NAME_SEARCH_PREV ) item = ITEM_SEARCH_PREV; else if( item_name == ITEM_NAME_NEXTARTICLE ) item = ITEM_NEXTARTICLE; else if( item_name == ITEM_NAME_CLEAR_HIGHLIGHT ) item = ITEM_CLEAR_HIGHLIGHT; else if( item_name == ITEM_NAME_INSERTTEXT ) item = ITEM_INSERTTEXT; else if( item_name == ITEM_NAME_LOCK_MESSAGE ) item = ITEM_LOCK_MESSAGE; else if( item_name == ITEM_NAME_PREVIEW ) item = ITEM_PREVIEW; else if( item_name == ITEM_NAME_UNDO ) item = ITEM_UNDO; else if( item_name == ITEM_NAME_REDO ) item = ITEM_REDO; else if( item_name == ITEM_NAME_NGWORD ) item = ITEM_NGWORD; else if( item_name == ITEM_NAME_ABONE_SELECTION ) item = ITEM_ABONE_SELECTION; else if( item_name == ITEM_NAME_ABONE_ARTICLE ) item = ITEM_ABONE_ARTICLE; else if( item_name == ITEM_NAME_QUOTE_SELECTION ) item = ITEM_QUOTE_SELECTION; else if( item_name == ITEM_NAME_OPEN_BROWSER ) item = ITEM_OPEN_BROWSER; else if( item_name == ITEM_NAME_OPEN_CACHE_BROWSER ) item = ITEM_OPEN_CACHE_BROWSER; else if( item_name == ITEM_NAME_USER_COMMAND ) item = ITEM_USER_COMMAND; else if( item_name == ITEM_NAME_ETC ) item = ITEM_ETC; else if( item_name == ITEM_NAME_SAVE_DAT ) item = ITEM_SAVE_DAT; else if( item_name == ITEM_NAME_SELECTIMG ) item = ITEM_SELECTIMG; else if( item_name == ITEM_NAME_SELECTDELIMG ) item = ITEM_SELECTDELIMG; else if( item_name == ITEM_NAME_SELECTABONEIMG ) item = ITEM_SELECTABONEIMG; else if( item_name == ITEM_NAME_PREF_BOARD ) item = ITEM_PREF_BOARD; else if( item_name == ITEM_NAME_PREF_THREAD ) item = ITEM_PREF_THREAD; return item; } std::vector< int > parse_items( const std::string& items_str ) { std::vector< int > items; const std::list< std::string > list_order = MISC::split_line( items_str ); std::list< std::string >::const_iterator it = list_order.begin(); for( ; it != list_order.end(); ++it ){ const int item = SESSION::parse_item( *it ); if( item != ITEM_END ) items.push_back( item ); } items.push_back( ITEM_END ); return items; } void read_list_urls( JDLIB::ConfLoader& cf, const std::string& id_urls, std::list< std::string >& list_urls ) { list_urls.clear(); std::string str_tmp; std::list< std::string > list_tmp; std::list< std::string >::iterator it_tmp; str_tmp = cf.get_option_str( id_urls, "" ); if( ! str_tmp.empty() ){ list_tmp = MISC::split_line( str_tmp ); it_tmp = list_tmp.begin(); for( ; it_tmp != list_tmp.end(); ++it_tmp ) if( !(*it_tmp).empty() ) list_urls.push_back( (*it_tmp)); } } void read_list_locked( JDLIB::ConfLoader& cf, const std::string& id_locked, std::list< bool >& list_locked ) { list_locked.clear(); std::string str_tmp; std::list< std::string > list_tmp; std::list< std::string >::iterator it_tmp; str_tmp = cf.get_option_str( id_locked, "" ); if( ! str_tmp.empty() ){ list_tmp = MISC::split_line( str_tmp ); it_tmp = list_tmp.begin(); for( ; it_tmp != list_tmp.end(); ++it_tmp ){ if( ( *it_tmp ) == "1" ) list_locked.push_back( true ); else list_locked.push_back( false ); } } } // セッション情報読み込み void SESSION::init_session() { #ifdef _DEBUG std::cout << "SESSION::init_session\n"; #endif JDLIB::ConfLoader cf( CACHE::path_session(), std::string() ); // オンライン mode_online = cf.get_option_bool( "mode_online", true ); // 2chログイン mode_login2ch = cf.get_option_bool( "mode_login2ch", false ); // beログイン mode_loginbe = cf.get_option_bool( "mode_loginbe", false ); // p2ログイン mode_loginp2 = cf.get_option_bool( "mode_loginp2", false ); // paneのモード mode_pane = cf.get_option_int( "mode_pane", MODE_2PANE, 0, MODE_PANE_NUM -1 ); x_win_main = cf.get_option_int( "x", 0, 0, 8192 ); y_win_main = cf.get_option_int( "y", 0, 0, 8192 ); width_win_main = cf.get_option_int( "width", 800, 80, 8192 ); height_win_main = cf.get_option_int( "height", 600, 60, 8192 ); maximized_win_main = cf.get_option_bool( "maximized", false ); full_win_main = cf.get_option_bool( "full_win_main", false ); win_show_sidebar = cf.get_option_bool( "show_sidebar", true ); win_show_menubar = cf.get_option_bool( "show_menubar", true ); show_main_toolbar = cf.get_option_bool( "show_main_toolbar", true ); win_toolbar_pos = cf.get_option_int( "toolbar_pos", TOOLBAR_POS_NORMAL, 0, TOOLBAR_POS_NUM -1 ); show_bbslist_toolbar = cf.get_option_bool( "show_bbslist_toolbar", true ); show_board_toolbar = cf.get_option_bool( "show_board_toolbar", true ); show_article_toolbar = cf.get_option_bool( "show_article_toolbar", true ); show_board_tab = cf.get_option_bool( "show_board_tab", true ); show_article_tab = cf.get_option_bool( "show_article_tab", true ); show_main_statbar = cf.get_option_bool( "show_main_statbar", true ); win_focused_admin = cf.get_option_int( "focused_admin", FOCUS_NOT, 0, FOCUS_NUM -1 ); win_focused_admin_sidebar = cf.get_option_int( "focused_admin_sidebar", FOCUS_NOT, 0, FOCUS_NUM -1 ); win_hpane_main_pos = cf.get_option_int( "hpane_main_pos", 190, 0, 8192 ); win_vpane_main_pos = cf.get_option_int( "vpane_main_pos", 200, 0, 8192 ); win_hpane_main_r_pos = cf.get_option_int( "hpane_main_r_pos", 300, 0, 8192 ); win_vpane_main_mes_pos = cf.get_option_int( "vpane_main_mes_pos", 400, 0, 8192 ); // メインnotebookのページ番号 win_notebook_main_page = cf.get_option_int( "notebook_main_page", PAGE_ARTICLE, 0, PAGE_NUM -1 ); // 各ビューの開いてるページ番号 win_bbslist_page = cf.get_option_int( "bbslist_page", 0, 0, 1024 ); win_board_page = cf.get_option_int( "board_page", 0, 0, 1024 ); win_article_page = cf.get_option_int( "article_page", 0, 0, 1024 ); win_image_page = cf.get_option_int( "image_page", 0, 0, 1024 ); // スレ一覧のURLとロック状態と切り替え履歴 read_list_urls( cf, "board_urls", board_urls ); read_list_locked( cf, "board_locked", board_locked ); read_list_urls( cf, "board_switchhistory", board_switchhistory ); // スレタブのURLとロック状態と切り替え履歴 read_list_urls( cf, "article_urls", article_urls ); read_list_locked( cf, "article_locked", article_locked ); read_list_urls( cf, "article_switchhistory", article_switchhistory ); // 画像タブのURLとロック状態 read_list_urls( cf, "image_urls", image_urls ); read_list_locked( cf, "image_locked", image_locked ); // サイドバーのツールバー項目 items_sidebar_toolbar_str = cf.get_option_str( "items_sidebar", get_items_sidebar_toolbar_default_str() ); items_sidebar_toolbar = parse_items( items_sidebar_toolbar_str ); // メインツールバーの項目 items_main_toolbar_str = cf.get_option_str( "items_main_toolbar", get_items_main_toolbar_default_str() ); items_main_toolbar = parse_items( items_main_toolbar_str ); // スレビューのツールバーの項目 items_article_toolbar_str = cf.get_option_str( "items_article_toolbar", get_items_article_toolbar_default_str() ); items_article_toolbar = parse_items( items_article_toolbar_str ); // 検索ビューのツールバーの項目 items_search_toolbar_str = cf.get_option_str( "items_search_toolbar", get_items_search_toolbar_default_str() ); items_search_toolbar = parse_items( items_search_toolbar_str ); // スレ一覧のツールバー項目 items_board_toolbar_str = cf.get_option_str( "items_board_toolbar", get_items_board_toolbar_default_str() ); items_board_toolbar = parse_items( items_board_toolbar_str ); // 書き込みビューのツールバー項目 items_msg_toolbar_str = cf.get_option_str( "items_msg_toolbar", get_items_msg_toolbar_default_str() ); items_msg_toolbar = parse_items( items_msg_toolbar_str ); // スレ一覧の列項目 items_board_col_str = cf.get_option_str( "items_board", get_items_board_col_default_str() ); items_board_col = parse_items( items_board_col_str ); // スレ一覧のコンテキストメニュー項目 items_board_menu_str = cf.get_option_str( "items_board_menu", get_items_board_menu_default_str() ); items_board_menu = parse_items( items_board_menu_str ); // スレビューのコンテキストメニュー項目 items_article_menu_str = cf.get_option_str( "items_article_menu", get_items_article_menu_default_str() ); items_article_menu = parse_items( items_article_menu_str ); // board ビューの列幅 board_col_mark = cf.get_option_int( "col_mark", 30, 4, 8192 ); board_col_id = cf.get_option_int( "col_id", 45, 4, 8192 ); board_col_board = cf.get_option_int( "col_board", 70, 4, 8192 ); board_col_subject = cf.get_option_int( "col_subject", 190, 4, 8192 ); board_col_number = cf.get_option_int( "col_number", 45, 4, 8192 ); board_col_load = cf.get_option_int( "col_load", 45, 4, 8192 ); board_col_new = cf.get_option_int( "col_new", 45, 4, 8192 ); board_col_since = cf.get_option_int( "col_since", 70, 4, 8192 ); board_col_write = cf.get_option_int( "col_write", 70, 4, 8192 ); board_col_access = cf.get_option_int( "col_access", 70, 4, 8192 ); board_col_speed = cf.get_option_int( "col_speed", 45, 4, 8192 ); board_col_diff = cf.get_option_int( "col_diff", 45, 4, 8192 ); // スレ一覧の since の表示モード board_col_since_time = cf.get_option_int( "col_since_time", MISC::TIME_NORMAL, 0, MISC::TIME_NUM-1 ); // スレ一覧の 最終書込 の表示モード board_col_write_time = cf.get_option_int( "col_write_time", MISC::TIME_NORMAL, 0, MISC::TIME_NUM-1 ); embedded_img = cf.get_option_bool( "embedded_img", true ); x_win_img = cf.get_option_int( "x_win_img", 0, 0, 8192 ); y_win_img = cf.get_option_int( "y_win_img", 0, 0, 8192 ); width_win_img = cf.get_option_int( "width_win_img", 600, 60, 8192 ); height_win_img = cf.get_option_int( "height_win_img", 400, 40, 8192 ); embedded_mes = cf.get_option_bool( "embedded_mes", false ); // 書き込み後にmessageを閉じる close_mes = cf.get_option_bool( "close_mes", true ); x_win_mes = cf.get_option_int( "x_win_mes", 0, 0, 8192 ); y_win_mes = cf.get_option_int( "y_win_mes", 0, 0, 8192 ); width_win_mes = cf.get_option_int( "width_win_mes", 600, 60, 8192 ); height_win_mes = cf.get_option_int( "height_win_mes", 400, 40, 8192 ); dir_dat = cf.get_option_str( "dir_dat", "" ); img_dir_img_save = cf.get_option_str( "img_dir_img_save", "" ); dir_draft = cf.get_option_str( "dir_draft", "" ); popupmenu_shown = false; // 画像のfitモード img_fit_mode = cf.get_option_int( "img_fit_mode", IMG_FIT_NORMAL, 0, IMG_FIT_NUM -1 ); dir_select_favorite = cf.get_option_str( "dir_select_favorite", "" ); #ifdef _DEBUG std::cout << "x=" << x_win_main << std::endl << "y=" << y_win_main << std::endl << "w=" << width_win_main << std::endl << "h=" << height_win_main << std::endl << "max=" << maximized_win_main << std::endl << "toolbar_pos=" << win_toolbar_pos << std::endl << "sidebar=" << win_show_sidebar << std::endl << "menubar=" << win_show_menubar << std::endl << "focused_admin=" << win_focused_admin << std::endl << "focused_admin_sidebar=" << win_focused_admin_sidebar << std::endl << "hpane=" << win_hpane_main_pos << std::endl << "vpane=" << win_vpane_main_pos << std::endl << "hpane_r=" << win_hpane_main_r_pos << std::endl << "vpane_mes=" << win_vpane_main_mes_pos << std::endl << "notebook_main_page=" << win_notebook_main_page << std::endl << "bbslist_page=" << win_bbslist_page << std::endl << "board_page=" << win_board_page << std::endl << "article_page=" << win_article_page << std::endl << "image_page=" << win_image_page << std::endl; std::cout << "board_urls\n"; std::list< std::string >::iterator it_tmp = board_urls.begin(); for( ; it_tmp != board_urls.end(); ++it_tmp ) if( !(*it_tmp).empty() ) std::cout << (*it_tmp); std::cout << "article_urls\n"; it_tmp = article_urls.begin(); for( ; it_tmp != article_urls.end(); ++it_tmp ) if( !(*it_tmp).empty() ) std::cout << (*it_tmp); std::cout << "image_urls\n"; it_tmp = image_urls.begin(); for( ; it_tmp != image_urls.end(); ++it_tmp ) if( !(*it_tmp).empty() ) std::cout << (*it_tmp); std::cout << "columns\n" << board_col_mark << std::endl << board_col_id << std::endl << board_col_board << std::endl << board_col_subject << std::endl << board_col_number << std::endl << board_col_load << std::endl << board_col_new << std::endl << board_col_since << std::endl << board_col_write << std::endl << board_col_speed << std::endl << board_col_diff << std::endl << "embedded_mes = " << embedded_mes << std::endl << "close_mes = " << close_mes << std::endl << "wx=" << x_win_mes << std::endl << "wy=" << y_win_mes << std::endl << "ww=" << width_win_mes << std::endl << "wh=" << height_win_mes << std::endl; #endif } // セッション情報保存 void SESSION::save_session() { // 開いているタブのURL std::string str_board_urls; std::string str_article_urls; std::string str_image_urls; std::list< std::string >::iterator it_url = board_urls.begin(); for( ; it_url != board_urls.end(); ++it_url ){ if( ! ( *it_url ).empty() ) str_board_urls += " \"" + ( *it_url ) + "\""; } it_url = article_urls.begin(); for( ; it_url != article_urls.end(); ++it_url ){ if( ! ( *it_url ).empty() ) str_article_urls += " \"" + ( *it_url ) + "\""; } it_url = image_urls.begin(); for( ; it_url != image_urls.end(); ++it_url ){ if( ! ( *it_url ).empty() ) str_image_urls += " \"" + ( *it_url ) + "\""; } // 開いているタブのロック状態 std::string str_board_locked; std::string str_article_locked; std::string str_image_locked; std::list< bool >::iterator it_locked = board_locked.begin(); for( ; it_locked != board_locked.end(); ++it_locked ){ if( *it_locked ) str_board_locked += " 1"; else str_board_locked += " 0"; } it_locked = article_locked.begin(); for( ; it_locked != article_locked.end(); ++it_locked ){ if( *it_locked ) str_article_locked += " 1"; else str_article_locked += " 0"; } it_locked = image_locked.begin(); for( ; it_locked != image_locked.end(); ++it_locked ){ if( *it_locked ) str_image_locked += " 1"; else str_image_locked += " 0"; } // タブの切り替え履歴 std::string str_board_switchhistory; std::string str_article_switchhistory; it_url = board_switchhistory.begin(); for( ; it_url != board_switchhistory.end(); ++it_url ){ if( ! ( *it_url ).empty() ) str_board_switchhistory += " \"" + ( *it_url ) + "\""; } it_url = article_switchhistory.begin(); for( ; it_url != article_switchhistory.end(); ++it_url ){ if( ! ( *it_url ).empty() ) str_article_switchhistory += " \"" + ( *it_url ) + "\""; } // 保存内容作成 std::ostringstream oss; oss << "mode_pane = " << mode_pane << std::endl << "mode_online = " << mode_online << std::endl << "mode_login2ch = " << mode_login2ch << std::endl << "mode_loginbe = " << mode_loginbe << std::endl << "mode_loginp2 = " << mode_loginp2 << std::endl << "x = " << x_win_main << std::endl << "y = " << y_win_main << std::endl << "width = " << width_win_main << std::endl << "height = " << height_win_main << std::endl << "maximized = " << maximized_win_main << std::endl << "full_win_main = " << full_win_main << std::endl << "show_main_toolbar = " << show_main_toolbar << std::endl << "toolbar_pos = " << win_toolbar_pos << std::endl << "show_bbslist_toolbar = " << show_bbslist_toolbar << std::endl << "show_board_toolbar = " << show_board_toolbar << std::endl << "show_article_toolbar = " << show_article_toolbar << std::endl << "show_board_tab = " << show_board_tab << std::endl << "show_article_tab = " << show_article_tab << std::endl << "show_sidebar = " << win_show_sidebar << std::endl << "show_menubar = " << win_show_menubar << std::endl << "show_main_statbar = " << show_main_statbar << std::endl << "focused_admin = " << win_focused_admin << std::endl << "focused_admin_sidebar = " << win_focused_admin_sidebar << std::endl << "hpane_main_pos = " << win_hpane_main_pos << std::endl << "vpane_main_pos = " << win_vpane_main_pos << std::endl << "hpane_main_r_pos = " << win_hpane_main_r_pos << std::endl << "vpane_main_mes_pos = " << win_vpane_main_mes_pos << std::endl << "notebook_main_page = " << win_notebook_main_page << std::endl << "bbslist_page = " << win_bbslist_page << std::endl << "board_page = " << win_board_page << std::endl << "board_urls = " << str_board_urls << std::endl << "board_locked = " << str_board_locked << std::endl << "board_switchhistory = " << str_board_switchhistory << std::endl << "article_page = " << win_article_page << std::endl << "article_urls = " << str_article_urls << std::endl << "article_locked = " << str_article_locked << std::endl << "article_switchhistory = " << str_article_switchhistory << std::endl << "image_page = " << win_image_page << std::endl << "image_urls = " << str_image_urls << std::endl << "image_locked = " << str_image_locked << std::endl << "items_sidebar = " << items_sidebar_toolbar_str << std::endl << "items_main_toolbar = " << items_main_toolbar_str << std::endl << "items_article_toolbar = " << items_article_toolbar_str << std::endl << "items_search_toolbar = " << items_search_toolbar_str << std::endl << "items_board_toolbar = " << items_board_toolbar_str << std::endl << "items_msg_toolbar = " << items_msg_toolbar_str << std::endl << "items_board = " << items_board_col_str << std::endl << "items_board_menu = " << items_board_menu_str << std::endl << "items_article_menu = " << items_article_menu_str << std::endl << "col_mark = " << board_col_mark << std::endl << "col_id = " << board_col_id << std::endl << "col_board = " << board_col_board << std::endl << "col_subject = " << board_col_subject << std::endl << "col_number = " << board_col_number << std::endl << "col_load = " << board_col_load << std::endl << "col_new = " << board_col_new << std::endl << "col_since = " << board_col_since << std::endl << "col_write = " << board_col_write << std::endl << "col_access = " << board_col_access << std::endl << "col_speed = " << board_col_speed << std::endl << "col_diff = " << board_col_diff << std::endl << "col_since_time = " << board_col_since_time << std::endl << "col_write_time = " << board_col_write_time << std::endl << "embedded_img = " << embedded_img << std::endl << "x_win_img = " << x_win_img << std::endl << "y_win_img = " << y_win_img << std::endl << "width_win_img = " << width_win_img << std::endl << "height_win_img = " << height_win_img << std::endl << "embedded_mes = " << embedded_mes << std::endl << "close_mes = " << close_mes << std::endl << "x_win_mes = " << x_win_mes << std::endl << "y_win_mes = " << y_win_mes << std::endl << "width_win_mes = " << width_win_mes << std::endl << "height_win_mes = " << height_win_mes << std::endl << "dir_dat = " << dir_dat << std::endl << "img_dir_img_save = " << img_dir_img_save << std::endl << "dir_draft = " << dir_draft << std::endl << "img_fit_mode = " << img_fit_mode << std::endl << "dir_select_favorite = " << dir_select_favorite << std::endl; CACHE::save_rawdata( CACHE::path_session(), oss.str() ); #ifdef _DEBUG std::cout << "SESSION::save_session\n" << oss.str() << std::endl; #endif } // ブート中 const bool SESSION::is_booting(){ return booting; } void SESSION::set_booting( const bool boot ){ booting = boot; } // 終了中 const bool SESSION::is_quitting(){ return quitting; } void SESSION::set_quitting( const bool quit ){ quitting = quit; } // 入れ替えなどのタブ操作中 // ビューの再描画などを禁止する const bool SESSION::is_tab_operating( const std::string& url_admin ) { if( url_admin == URL_ARTICLEADMIN ) return tab_operating_article; if( url_admin == URL_IMAGEADMIN ) return tab_operating_image; return false; } void SESSION::set_tab_operating( const std::string& url_admin, const bool operating ) { if( url_admin == URL_ARTICLEADMIN ) tab_operating_article = operating; if( url_admin == URL_IMAGEADMIN ) tab_operating_image = operating; } const int SESSION::get_mode_pane() { return mode_pane; } void SESSION::set_mode_pane( const int mode ){ mode_pane = mode; } const bool SESSION::is_online(){ return mode_online; } void SESSION::set_online( const bool mode ){ mode_online = mode; } const bool SESSION::login2ch(){ return mode_login2ch; } void SESSION::set_login2ch( const bool login ){ mode_login2ch = login; } const bool SESSION::loginbe(){ return mode_loginbe; } void SESSION::set_loginbe( const bool login ){ mode_loginbe = login; } const bool SESSION::loginp2(){ return mode_loginp2; } void SESSION::set_loginp2( const bool login ){ mode_loginp2 = login; } const bool SESSION::show_sidebar(){ return win_show_sidebar; } const bool SESSION::show_menubar(){ return win_show_menubar; } void SESSION::set_show_menubar( const bool show ){ win_show_menubar = show; } const bool SESSION::get_show_main_toolbar(){ return show_main_toolbar; } void SESSION::set_show_main_toolbar( const bool show ){ show_main_toolbar = show; } const int SESSION::get_toolbar_pos(){ return win_toolbar_pos; } void SESSION::set_toolbar_pos( const int pos ){ win_toolbar_pos = pos; } const bool SESSION::get_show_bbslist_toolbar(){ return show_bbslist_toolbar; } void SESSION::set_show_bbslist_toolbar( const bool show ){ show_bbslist_toolbar = show; } const bool SESSION::get_show_board_toolbar(){ return show_board_toolbar; } void SESSION::set_show_board_toolbar( const bool show ){ show_board_toolbar = show; } const bool SESSION::get_show_article_toolbar(){ return show_article_toolbar; } void SESSION::set_show_article_toolbar( const bool show ){ show_article_toolbar = show; } const bool SESSION::get_show_board_tab(){ return show_board_tab; } void SESSION::set_show_board_tab( const bool show ){ show_board_tab = show; } const bool SESSION::get_show_article_tab(){ return show_article_tab; } void SESSION::set_show_article_tab( const bool show ){ show_article_tab = show; } const bool SESSION::get_show_main_statbar(){ return show_main_statbar; } void SESSION::set_show_main_statbar( const bool show ){ show_main_statbar = show; } const int SESSION::focused_admin(){ return win_focused_admin; } void SESSION::set_focused_admin( const int admin ){ win_focused_admin = admin; } const int SESSION::focused_admin_sidebar(){ return win_focused_admin_sidebar; } void SESSION::set_focused_admin_sidebar( const int admin ){ win_focused_admin_sidebar = admin; } // 各windowの座標 const int SESSION::get_x_win_main(){ return x_win_main; } const int SESSION::get_y_win_main(){ return y_win_main; } void SESSION::set_x_win_main( const int x ){ x_win_main = x; } void SESSION::set_y_win_main( const int y ){ y_win_main = y; } const int SESSION::get_x_win_img(){ return x_win_img; } const int SESSION::get_y_win_img(){ return y_win_img; } void SESSION::set_x_win_img( const int x ){ x_win_img = x; } void SESSION::set_y_win_img( const int y ){ y_win_img = y; } const int SESSION::get_x_win_mes(){ return x_win_mes; } const int SESSION::get_y_win_mes(){ return y_win_mes; } void SESSION::set_x_win_mes( const int x ){ x_win_mes = x; } void SESSION::set_y_win_mes( const int y ){ y_win_mes = y; } // 各windowのサイズ const int SESSION::get_width_win_main(){ return width_win_main; } const int SESSION::get_height_win_main(){ return height_win_main; } void SESSION::set_width_win_main( const int width ){ width_win_main = width; } void SESSION::set_height_win_main( const int height ){ height_win_main = height; } const int SESSION::get_width_win_img(){ return width_win_img; } const int SESSION::get_height_win_img(){ return height_win_img; } void SESSION::set_width_win_img( const int width ){ width_win_img = width; } void SESSION::set_height_win_img( const int height ){ height_win_img = height; } const int SESSION::get_width_win_mes(){ return width_win_mes; } const int SESSION::get_height_win_mes(){ return height_win_mes; } void SESSION::set_width_win_mes( const int width ){ width_win_mes = width; } void SESSION::set_height_win_mes( const int height ){ height_win_mes = height; } // 各window がフォーカスされているか const bool SESSION::is_focus_win_main(){ return focus_win_main; } void SESSION::set_focus_win_main( const bool set ){ focus_win_main = set; } const bool SESSION::is_focus_win_img(){ return focus_win_img; } void SESSION::set_focus_win_img( const bool set ){ focus_win_img = set; } const bool SESSION::is_focus_win_mes(){ return focus_win_mes; } void SESSION::set_focus_win_mes( const bool set ){ focus_win_mes = set; } // 各window が最大化されているか const bool SESSION::is_maximized_win_main(){ return maximized_win_main; } void SESSION::set_maximized_win_main( const bool set ){ maximized_win_main = set; } const bool SESSION::is_maximized_win_img(){ return maximized_win_img; } void SESSION::set_maximized_win_img( const bool set ){ maximized_win_img = set; } bool SESSION::is_maximized_win_mes(){ return maximized_win_mes; } void SESSION::set_maximized_win_mes( const bool set ){ maximized_win_mes = set; } // 各window が最小化されているか const bool SESSION::is_iconified_win_main(){ return iconified_win_main; } void SESSION::set_iconified_win_main( const bool set ){ iconified_win_main = set; } const bool SESSION::is_iconified_win_img(){ return iconified_win_img; } void SESSION::set_iconified_win_img( const bool set ){ iconified_win_img = set; } const bool SESSION::is_iconified_win_mes(){ return iconified_win_mes; } void SESSION::set_iconified_win_mes( const bool set ){ iconified_win_mes = set; } // 各window が画面に表示されているか const bool SESSION::is_shown_win_main(){ return shown_win_main; } void SESSION::set_shown_win_main( const bool set ){ shown_win_main = set; } const bool SESSION::is_shown_win_img(){ return shown_win_img; } void SESSION::set_shown_win_img( const bool set ){ shown_win_img = set; } const bool SESSION::is_shown_win_mes(){ return shown_win_mes; } void SESSION::set_shown_win_mes( const bool set ){ shown_win_mes = set; } // windowがフルスクリーンか const bool SESSION::is_full_win_main(){ return full_win_main; } void SESSION::set_full_win_main( const bool set ){ full_win_main = set; } // ダイアログ表示中 const bool SESSION::is_dialog_shown(){ return dialog_shown; } void SESSION::set_dialog_shown( const bool set ){ dialog_shown = set; } void SESSION::set_show_sidebar( const bool showurl ){ win_show_sidebar = showurl; } // メインウィンドウのペインの敷居の位置 const int SESSION::hpane_main_pos(){ return win_hpane_main_pos; } const int SESSION::vpane_main_pos(){ return win_vpane_main_pos; } const int SESSION::hpane_main_r_pos(){ return win_hpane_main_r_pos; } const int SESSION::vpane_main_mes_pos(){ return win_vpane_main_mes_pos; } void SESSION::set_hpane_main_pos( const int pos ){ win_hpane_main_pos = pos; } void SESSION::set_vpane_main_pos( const int pos ){ win_vpane_main_pos = pos; } void SESSION::set_hpane_main_r_pos( const int pos ){ win_hpane_main_r_pos = pos; } void SESSION::set_vpane_main_mes_pos( const int pos ){ win_vpane_main_mes_pos = pos; } // メインnotebookのページ番号 const int SESSION::notebook_main_page(){ return win_notebook_main_page; } void SESSION::set_notebook_main_page( const int page ){ win_notebook_main_page = page; } // bbslistの開いてるページ番号 const int SESSION::bbslist_page(){ return win_bbslist_page; } void SESSION::set_bbslist_page( const int page ){ win_bbslist_page = page; } // 前回閉じたときに開いていたboardのページ番号とURL const int SESSION::board_page(){ return win_board_page; } void SESSION::set_board_page( const int page ){ win_board_page = page; } const std::list< std::string >& SESSION::get_board_URLs(){ return board_urls; } void SESSION::set_board_URLs( const std::list< std::string >& urls ){ board_urls = urls; } // スレ一覧のロック状態 const std::list< bool >& SESSION::get_board_locked(){ return board_locked; } void SESSION::set_board_locked( const std::list< bool >& locked ){ board_locked = locked; } // スレ一覧の切り替え履歴 const std::list< std::string >& SESSION::get_board_switchhistory(){ return board_switchhistory; } void SESSION::set_board_switchhistory( const std::list< std::string >& hist ){ board_switchhistory = hist; } // 前回閉じたときに開いていたスレタブのページ番号とURL const int SESSION::article_page(){ return win_article_page; } void SESSION::set_article_page( const int page ){ win_article_page = page; } const std::list< std::string >& SESSION::get_article_URLs(){ return article_urls; } void SESSION::set_article_URLs( const std::list< std::string >& urls ){ article_urls = urls; } // スレタブのロック状態 const std::list< bool >& SESSION::get_article_locked(){ return article_locked; } void SESSION::set_article_locked( const std::list< bool >& locked ){ article_locked = locked; } // スレタブの切り替え履歴 const std::list< std::string >& SESSION::get_article_switchhistory(){ return article_switchhistory; } void SESSION::set_article_switchhistory( const std::list< std::string >& hist ){ article_switchhistory = hist; } // 前回閉じたときに開いていたimageのページ番号とURL const int SESSION::image_page(){ return win_image_page; } void SESSION::set_image_page( const int page ){ win_image_page = page; } const std::list< std::string >& SESSION::image_URLs(){ return image_urls; } void SESSION::set_image_URLs( const std::list< std::string >& urls ){ image_urls = urls; } // 画像タブのロック状態 const std::list< bool >& SESSION::get_image_locked(){ return image_locked; } void SESSION::set_image_locked( const std::list< bool >& locked ){ image_locked = locked; } // サイドバーのツールバーの項目 const std::string& SESSION::get_items_sidebar_toolbar_str(){ return items_sidebar_toolbar_str; } const std::string SESSION::get_items_sidebar_toolbar_default_str() { return ITEM_NAME_SEARCHBOX + std::string ( " " ) + ITEM_NAME_SEARCH_NEXT + std::string ( " " ) + ITEM_NAME_SEARCH_PREV; } void SESSION::set_items_sidebar_toolbar_str( const std::string& items_str ) { items_sidebar_toolbar_str = items_str; items_sidebar_toolbar = parse_items( items_sidebar_toolbar_str ); } const int SESSION::get_item_sidebar_toolbar( const int num ){ return items_sidebar_toolbar[ num ]; } // メインツールバーの項目 const std::string& SESSION::get_items_main_toolbar_str(){ return items_main_toolbar_str; } const std::string SESSION::get_items_main_toolbar_default_str() { return ITEM_NAME_BBSLISTVIEW + std::string ( " " ) + ITEM_NAME_FAVORITEVIEW + std::string ( " " ) + ITEM_NAME_BOARDVIEW + std::string ( " " ) + ITEM_NAME_ARTICLEVIEW + std::string ( " " ) + ITEM_NAME_IMAGEVIEW + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_URL + std::string ( " " ) + ITEM_NAME_GO; } void SESSION::set_items_main_toolbar_str( const std::string& items_str ) { items_main_toolbar_str = items_str; items_main_toolbar = parse_items( items_main_toolbar_str ); } const int SESSION::get_item_main_toolbar( const int num ){ return items_main_toolbar[ num ]; } // スレビューのツールバーの項目 const std::string& SESSION::get_items_article_toolbar_str(){ return items_article_toolbar_str; } const std::string SESSION::get_items_article_toolbar_default_str() { return ITEM_NAME_WRITEMSG + std::string ( " " ) + ITEM_NAME_OPENBOARD + std::string ( " " ) + ITEM_NAME_NAME + std::string ( " " ) + ITEM_NAME_SEARCH + std::string ( " " ) + ITEM_NAME_RELOAD + std::string ( " " ) + ITEM_NAME_STOPLOADING + std::string ( " " ) + ITEM_NAME_APPENDFAVORITE + std::string ( " " ) + ITEM_NAME_DELETE + std::string ( " " ) + ITEM_NAME_QUIT; } void SESSION::set_items_article_toolbar_str( const std::string& items_str ) { items_article_toolbar_str = items_str; items_article_toolbar = parse_items( items_article_toolbar_str ); } const int SESSION::get_item_article_toolbar( const int num ){ return items_article_toolbar[ num ]; } // 検索ビューのツールバーの項目 const std::string& SESSION::get_items_search_toolbar_str(){ return items_search_toolbar_str; } const std::string SESSION::get_items_search_toolbar_default_str() { return ITEM_NAME_NAME + std::string ( " " ) + ITEM_NAME_SEARCH + std::string ( " " ) + ITEM_NAME_RELOAD + std::string ( " " ) + ITEM_NAME_STOPLOADING + std::string ( " " ) + ITEM_NAME_QUIT; } void SESSION::set_items_search_toolbar_str( const std::string& items_str ) { items_search_toolbar_str = items_str; items_search_toolbar = parse_items( items_search_toolbar_str ); } const int SESSION::get_item_search_toolbar( const int num ){ return items_search_toolbar[ num ]; } // スレ一覧のツールバー項目 const std::string& SESSION::get_items_board_toolbar_str(){ return items_board_toolbar_str; } const std::string SESSION::get_items_board_toolbar_default_str() { return ITEM_NAME_NEWARTICLE + std::string ( " " ) + ITEM_NAME_SEARCHBOX + std::string ( " " ) + ITEM_NAME_SEARCH_NEXT + std::string ( " " ) + ITEM_NAME_SEARCH_PREV + std::string ( " " ) + ITEM_NAME_RELOAD + std::string ( " " ) + ITEM_NAME_STOPLOADING + std::string ( " " ) + ITEM_NAME_APPENDFAVORITE + std::string ( " " ) + ITEM_NAME_DELETE + std::string ( " " ) + ITEM_NAME_QUIT; } void SESSION::set_items_board_toolbar_str( const std::string& items_str ) { items_board_toolbar_str = items_str; items_board_toolbar = parse_items( items_board_toolbar_str ); } const int SESSION::get_item_board_toolbar( const int num ){ return items_board_toolbar[ num ]; } // 書き込みビューのツールバー項目 const std::string& SESSION::get_items_msg_toolbar_str(){ return items_msg_toolbar_str; } const std::string SESSION::get_items_msg_toolbar_default_str() { return ITEM_NAME_PREVIEW + std::string ( " " ) + ITEM_NAME_WRITEMSG+ std::string ( " " ) + ITEM_NAME_NAME + std::string ( " " ) + ITEM_NAME_UNDO + std::string ( " " ) + ITEM_NAME_INSERTTEXT + std::string ( " " ) + ITEM_NAME_LOCK_MESSAGE + std::string ( " " ) + ITEM_NAME_QUIT; } void SESSION::set_items_msg_toolbar_str( const std::string& items_str ) { items_msg_toolbar_str = items_str; items_msg_toolbar = parse_items( items_msg_toolbar_str ); } const int SESSION::get_item_msg_toolbar( const int num ){ return items_msg_toolbar[ num ]; } // スレ一覧の列項目 const std::string& SESSION::get_items_board_col_str(){ return items_board_col_str; } const std::string SESSION::get_items_board_col_default_str() { return ITEM_NAME_MARK + std::string ( " " ) + ITEM_NAME_ID + std::string ( " " ) + ITEM_NAME_NAME + std::string ( " " ) + ITEM_NAME_RES + std::string ( " " ) + ITEM_NAME_LOAD + std::string ( " " ) + ITEM_NAME_NEW + std::string ( " " ) + ITEM_NAME_SINCE + std::string ( " " ) + ITEM_NAME_LASTWRITE + std::string ( " " ) + ITEM_NAME_SPEED; } void SESSION::set_items_board_col_str( const std::string& items_str ) { items_board_col_str = items_str; items_board_col = parse_items( items_board_col_str ); } const int SESSION::get_item_board_col( const int num ){ return items_board_col[ num ]; } // スレ一覧のコンテキストメニュー項目 const std::string& SESSION::get_items_board_menu_str(){ return items_board_menu_str; } const std::string SESSION::get_items_board_menu_default_str() { return ITEM_NAME_BOOKMARK + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_OPENARTICLETAB + std::string ( " " ) + ITEM_NAME_OPEN_BROWSER + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_COPY_URL + std::string ( " " ) + ITEM_NAME_COPY_TITLE_URL_THREAD + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_ABONE_ARTICLE + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_DELETE + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_ETC + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_PREF_THREAD + std::string ( " " ) + ITEM_NAME_PREF_BOARD; } void SESSION::set_items_board_menu_str( const std::string& items_str ) { items_board_menu_str = items_str; items_board_menu = parse_items( items_board_menu_str ); } const int SESSION::get_item_board_menu( const int num ){ return items_board_menu[ num ]; } // スレビューのコンテキストメニュー項目 const std::string& SESSION::get_items_article_menu_str(){ return items_article_menu_str; } const std::string SESSION::get_items_article_menu_default_str() { return ITEM_NAME_DRAWOUT + std::string ( " " ) + ITEM_NAME_GO + std::string ( " " ) + ITEM_NAME_SEARCH + std::string ( " " ) + ITEM_NAME_NGWORD + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_QUOTE_SELECTION + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_OPEN_BROWSER + std::string ( " " ) + ITEM_NAME_USER_COMMAND + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_COPY_URL + std::string ( " " ) + ITEM_NAME_COPY + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_ETC + std::string ( " " ) + ITEM_NAME_SEPARATOR + std::string ( " " ) + ITEM_NAME_PREF_THREAD; } void SESSION::set_items_article_menu_str( const std::string& items_str ) { items_article_menu_str = items_str; items_article_menu = parse_items( items_article_menu_str ); } const int SESSION::get_item_article_menu( const int num ){ return items_article_menu[ num ]; } // board ビューの列幅 const int SESSION::col_mark(){ return board_col_mark; } const int SESSION::col_id(){ return board_col_id; } const int SESSION::col_board(){ return board_col_board; } const int SESSION::col_subject(){ return board_col_subject; } const int SESSION::col_number(){ return board_col_number; } const int SESSION::col_load(){ return board_col_load; } const int SESSION::col_new(){ return board_col_new; } const int SESSION::col_since(){ return board_col_since; } const int SESSION::col_write(){ return board_col_write; } const int SESSION::col_access(){ return board_col_access; } const int SESSION::col_speed(){ return board_col_speed; } const int SESSION::col_diff(){ return board_col_diff; } // スレ一覧の since の表示モード const int SESSION::get_col_since_time() { return board_col_since_time; } void SESSION::set_col_since_time( const int mode ){ board_col_since_time = mode; } // スレ一覧の 最終書込 の表示モード const int SESSION::get_col_write_time() { return board_col_write_time; } void SESSION::set_col_write_time( const int mode ){ board_col_write_time = mode; } // 現在開いているサイドバーのページ const int SESSION::get_sidebar_current_page() { return BBSLIST::get_admin()->get_current_page(); } // 現在開いているサイドバーのurl const std::string SESSION::get_sidebar_current_url() { return BBSLIST::get_admin()->get_current_url(); } void SESSION::set_col_mark( const int width ){ board_col_mark = width; } void SESSION::set_col_id( const int width ){ board_col_id = width; } void SESSION::set_col_board( const int width ){ board_col_board = width; } void SESSION::set_col_subject( const int width ){ board_col_subject = width; } void SESSION::set_col_number( const int width ){ board_col_number = width; } void SESSION::set_col_load( const int width ){ board_col_load = width; } void SESSION::set_col_new( const int width ){ board_col_new = width; } void SESSION::set_col_since( const int width ){ board_col_since = width; } void SESSION::set_col_write( const int width ){ board_col_write = width; } void SESSION::set_col_access( const int width ){ board_col_access = width; } void SESSION::set_col_speed( const int width ){ board_col_speed = width; } void SESSION::set_col_diff( const int width ){ board_col_diff = width; } // 現在開いているarticle の ARTICLE::DrawAreaBase ARTICLE::DrawAreaBase* SESSION::get_base_drawarea() { ARTICLE::ArticleViewBase* base_view = NULL; base_view = dynamic_cast< ARTICLE::ArticleViewBase* >( ARTICLE::get_admin()->get_current_view() ); if( base_view == NULL ) return NULL; ARTICLE::DrawAreaBase* base_drawarea = NULL; base_drawarea = base_view->drawarea(); return base_drawarea; } // 現在開いているarticle のurl const std::string SESSION::get_article_current_url() { return ARTICLE::get_admin()->get_current_url(); } // 埋め込みimage使用 const bool SESSION::get_embedded_img(){ return embedded_img; } void SESSION::set_embedded_img( const bool set ){ embedded_img = set; } // 埋め込みmessageを使用 const bool SESSION::get_embedded_mes(){ return embedded_mes; } void SESSION::set_embedded_mes( const bool set ){ embedded_mes = set; } // 書き込み後にmessageを閉じる const bool SESSION::get_close_mes(){ return close_mes; } void SESSION::set_close_mes( const bool set ){ close_mes = set; } // 最後にdatを読み書きしたディレクトリ const std::string& SESSION::get_dir_dat(){ return dir_dat; } void SESSION::set_dir_dat( const std::string& dir ){ dir_dat = dir; } // 最後に画像を保存したディレクトリ const std::string& SESSION::dir_img_save(){ return img_dir_img_save; } void SESSION::set_dir_img_save( const std::string& dir ){ img_dir_img_save = dir; } // 下書きファイルのディレクトリ const std::string& SESSION::get_dir_draft(){ return dir_draft; } void SESSION::set_dir_draft( const std::string& dir ){ dir_draft = dir; } // ポップアップメニュー表示中 const bool SESSION::is_popupmenu_shown(){ return popupmenu_shown; } void SESSION::set_popupmenu_shown( const bool shown ){ popupmenu_shown = shown; } // JD終了時に削除するスレのリスト // 実況などしたスレは削除する。 Core::~Core()を参照 const std::vector< std::string >& SESSION::get_delete_list() { return delete_list; } void SESSION::append_delete_list( const std::string& url ) { std::vector< std::string >::iterator it = delete_list.begin(); for( ; it != delete_list.end(); ++it ){ if( ( *it ) == url ) return; } delete_list.push_back( url ); #ifdef _DEBUG std::cout << "SESSION::append_delete_list urls == " << delete_list.size() << " url = " << url << std::endl; #endif } void SESSION::remove_delete_list( const std::string& url ) { if( delete_list.empty() ) return; std::vector< std::string >::iterator it = delete_list.begin(); for( ; it != delete_list.end(); ++it ) if( ( *it ) == url ){ delete_list.erase( it ); break; } #ifdef _DEBUG std::cout << "SESSION::remove_delete_list urls == " << delete_list.size() << " url = " << url << std::endl; #endif } // 実況実行中のスレか const bool SESSION::is_live( const std::string& url ) { #ifdef _DEBUG std::cout << "SESSION::is_live live_urls == " << live_urls.size() << " url = " << url << std::endl; #endif if( live_urls.empty() ) return false; std::vector< std::string >::iterator it = live_urls.begin(); for( ; it != live_urls.end(); ++it ){ #ifdef _DEBUG std::cout << (*it) << std::endl; #endif if( ( *it ) == url ) return true; } return false; } void SESSION::append_live( const std::string& url ) { if( ! is_live( url ) ) live_urls.push_back( url ); #ifdef _DEBUG std::cout << "SESSION::append_live live_urls == " << live_urls.size() << " url = " << url << std::endl; #endif } void SESSION::remove_live( const std::string& url ) { if( live_urls.empty() ) return; std::vector< std::string >::iterator it = live_urls.begin(); for( ; it != live_urls.end(); ++it ) if( ( *it ) == url ){ live_urls.erase( it ); break; } #ifdef _DEBUG std::cout << "SESSION::remove_live live_urls == " << live_urls.size() << " url = " << url << std::endl; #endif } // 画像のfitモード const int SESSION::get_img_fit_mode() { return img_fit_mode; } void SESSION::toggle_img_fit_mode() { if( img_fit_mode == IMG_FIT_NORMAL ) img_fit_mode = IMG_FIT_WIDTH; else img_fit_mode = IMG_FIT_NORMAL; } // お気に入り挿入ダイアログで最後に保存したディレクトリ名 const std::string& SESSION::get_dir_select_favorite() { return dir_select_favorite; } void SESSION::set_dir_select_favorite( const std::string& dir ) { dir_select_favorite = dir; } // 各履歴を取得 void SESSION::get_history( const std::string& url, CORE::DATA_INFO_LIST& info_list ) { return BBSLIST::get_admin()->get_history( url, info_list ); } // サイドバーの指定したidのディレクトリに含まれるスレのアドレスを取得 void SESSION::get_sidebar_threads( const std::string& url, const int dirid, std::vector< std::string >& list_url ) { BBSLIST::get_admin()->get_threads( url, dirid, list_url ); } // サイドバーの指定したidのディレクトリの名前を取得 const std::string SESSION::get_sidebar_dirname( const std::string& url, const int dirid ) { return BBSLIST::get_admin()->get_dirname( url, dirid ); } jd-2.8.7-140104/src/session.h0000644000076400010400000003637611724350130012226 0ustar // ライセンス: GPL2 // // 座標などのウィンドウ情報とかのセッション情報 // #ifndef _SESSION_H #define _SESSION_H #include "type.h" #include "data_info.h" #include #include #include namespace ARTICLE { class DrawAreaBase; }; namespace SESSION { // focused_admin の値。どこにフォーカスしているか // Core::slot_focus_in_event, Core::slot_focus_out_event などを参照 enum { FOCUS_SIDEBAR = 0, FOCUS_BOARD, FOCUS_ARTICLE, FOCUS_IMAGE, FOCUS_MESSAGE, FOCUS_NOT, // どこもフォーカスされていない FOCUS_NUM }; // ペーンモード enum { MODE_2PANE = 0, MODE_3PANE, MODE_V3PANE, MODE_PANE_NUM }; // メインウィンドウの右ペーンに表示中のnotebook enum { PAGE_ARTICLE = 0, PAGE_IMAGE, PAGE_BOARD, PAGE_NUM }; // メインツールバーの位置 enum { TOOLBAR_POS_NORMAL = 0, // メニューバーの下に表示 TOOLBAR_POS_RIGHT, // サイドバーの右に表示 TOOLBAR_POS_NUM }; // 画像のfitモード enum { IMG_FIT_NORMAL = 0, // 縦と横で小さい方をウィンドウに合わせる IMG_FIT_WIDTH, // 常に横をウィンドウに合わせる IMG_FIT_NUM }; void init_session(); void save_session(); // ブート中 const bool is_booting(); void set_booting( const bool boot ); // 終了中 const bool is_quitting(); void set_quitting( const bool quit ); // 入れ替えなどのタブ操作中 // ビューの再描画などを禁止する const bool is_tab_operating( const std::string& url_admin ); void set_tab_operating( const std::string& url_admin, const bool operating ); const int get_mode_pane(); void set_mode_pane( const int mode ); const bool is_online(); void set_online( const bool mode ); // 2chログイン中 const bool login2ch(); void set_login2ch( const bool login ); // BEログイン中 const bool loginbe(); void set_loginbe( const bool login ); // P2ログイン中 const bool loginp2(); void set_loginp2( const bool login ); // サイドバー表示中 const bool show_sidebar(); void set_show_sidebar( const bool showbar ); // メニューバー const bool show_menubar(); void set_show_menubar( const bool show ); // メインツールバー表示 const bool get_show_main_toolbar(); void set_show_main_toolbar( const bool show ); // メインツールバー位置 const int get_toolbar_pos(); void set_toolbar_pos( const int pos ); // 板一覧のツールバー表示 const bool get_show_bbslist_toolbar(); void set_show_bbslist_toolbar( const bool show ); // スレ一覧のツールバー表示 const bool get_show_board_toolbar(); void set_show_board_toolbar( const bool show ); // スレビューのツールバー表示 const bool get_show_article_toolbar(); void set_show_article_toolbar( const bool show ); // スレ一覧のタブ表示 const bool get_show_board_tab(); void set_show_board_tab( const bool show ); // スレビューのタブ const bool get_show_article_tab(); void set_show_article_tab( const bool show ); // メインステータスバー表示 const bool get_show_main_statbar(); void set_show_main_statbar( const bool show ); // フォーカスされているadmin const int focused_admin(); void set_focused_admin( const int admin ); // 各windowの座標 const int get_x_win_main(); // メインウィンドウ const int get_y_win_main(); void set_x_win_main( const int x ); void set_y_win_main( const int y ); const int get_x_win_img(); // 画像ウィンドウ const int get_y_win_img(); void set_x_win_img( const int x ); void set_y_win_img( const int y ); const int get_x_win_mes(); // 書き込みウィンドウ const int get_y_win_mes(); void set_x_win_mes( const int x ); void set_y_win_mes( const int y ); // 各windowのサイズ const int get_width_win_main(); // メインウィンドウ const int get_height_win_main(); void set_width_win_main( const int width ); void set_height_win_main( const int height ); const int get_width_win_img(); // 画像ウィンドウ const int get_height_win_img(); void set_width_win_img( const int width ); void set_height_win_img( const int height ); const int get_width_win_mes(); // 書き込みウィンドウ const int get_height_win_mes(); void set_width_win_mes( const int width ); void set_height_win_mes( const int height ); // 各window がフォーカスされているか const bool is_focus_win_main(); // メインウィンドウ void set_focus_win_main( const bool set ); const bool is_focus_win_img(); // 画像ウィンドウ void set_focus_win_img( const bool set ); const bool is_focus_win_mes(); // 書き込みウィンドウ void set_focus_win_mes( const bool set ); // 各window が最大化されているか const bool is_maximized_win_main(); // メインウィンドウ void set_maximized_win_main( const bool maximized ); const bool is_maximized_win_img(); // 画像ウィンドウ void set_maximized_win_img( const bool set ); bool is_maximized_win_mes(); // 書き込みウィンドウ void set_maximized_win_mes( const bool maximized ); // 各window が最小化されているか const bool is_iconified_win_main(); // メインウィンドウ void set_iconified_win_main( const bool set ); const bool is_iconified_win_img(); // 画像ウィンドウ void set_iconified_win_img( const bool set ); const bool is_iconified_win_mes(); // 書き込みウィンドウ void set_iconified_win_mes( const bool set ); // 各window が画面に表示されているか const bool is_shown_win_main(); // メインウィンドウ void set_shown_win_main( const bool set ); const bool is_shown_win_img(); // 画像ウィンドウ void set_shown_win_img( const bool set ); const bool is_shown_win_mes(); // 書き込みウィンドウ void set_shown_win_mes( const bool set ); // windowがフルスクリーンか const bool is_full_win_main(); // メインウィンドウ void set_full_win_main( const bool set ); // ダイアログ表示中 const bool is_dialog_shown(); void set_dialog_shown( const bool set ); // サイドバーを閉じる前にフォーカスされていたadmin const int focused_admin_sidebar(); void set_focused_admin_sidebar( const int admin ); /// メインウィンドウのペインの敷居の位置 const int hpane_main_pos(); const int vpane_main_pos(); const int hpane_main_r_pos(); const int vpane_main_mes_pos(); void set_hpane_main_pos( const int pos ); void set_vpane_main_pos( const int pos ); void set_hpane_main_r_pos( const int pos ); void set_vpane_main_mes_pos( const int pos ); // 前回閉じたときに開いていたメインnotebookのページ番号 const int notebook_main_page(); void set_notebook_main_page( const int page ); // 前回閉じたときに開いていたbbslistの開いてるページ番号 const int bbslist_page(); void set_bbslist_page( const int page ); // 前回閉じたときに開いていたスレ一覧のページ番号とURL const int board_page(); void set_board_page( const int page ); const std::list< std::string >& get_board_URLs(); void set_board_URLs( const std::list< std::string >& urls ); // スレ一覧のロック状態 const std::list< bool >& get_board_locked(); void set_board_locked( const std::list< bool >& locked ); // スレ一覧の切り替え履歴 const std::list< std::string >& get_board_switchhistory(); void set_board_switchhistory( const std::list< std::string >& hist ); // 前回閉じたときに開いていたスレタブのページ番号とURL const int article_page(); void set_article_page( const int page ); const std::list< std::string >& get_article_URLs(); void set_article_URLs( const std::list< std::string >& urls ); // スレタブのロック状態 const std::list< bool >& get_article_locked(); void set_article_locked( const std::list< bool >& locked ); // スレタブの切り替え履歴 const std::list< std::string >& get_article_switchhistory(); void set_article_switchhistory( const std::list< std::string >& hist ); // 前回閉じたときに開いていたimageのページ番号とURL const int image_page(); void set_image_page( const int page ); const std::list< std::string >& image_URLs(); void set_image_URLs( const std::list< std::string >& urls ); // 画像タブのロック状態 const std::list< bool >& get_image_locked(); void set_image_locked( const std::list< bool >& locked ); // 現在開いているサイドバーのページ const int get_sidebar_current_page(); // 現在開いているサイドバーのurl const std::string get_sidebar_current_url(); // ツールバー等の項目名 -> ID 変換 const int parse_item( const std::string& item_name ); // サイドバーのツールバー項目 const std::string& get_items_sidebar_toolbar_str(); const std::string get_items_sidebar_toolbar_default_str(); void set_items_sidebar_toolbar_str( const std::string& items ); const int get_item_sidebar_toolbar( const int num ); // メインツールバーの項目 const std::string& get_items_main_toolbar_str(); const std::string get_items_main_toolbar_default_str(); void set_items_main_toolbar_str( const std::string& items_str ); const int get_item_main_toolbar( const int num ); // スレビューのツールバーの項目 const std::string& get_items_article_toolbar_str(); const std::string get_items_article_toolbar_default_str(); void set_items_article_toolbar_str( const std::string& items_str ); const int get_item_article_toolbar( const int num ); // 検索ビューのツールバーの項目 const std::string& get_items_search_toolbar_str(); const std::string get_items_search_toolbar_default_str(); void set_items_search_toolbar_str( const std::string& items_str ); const int get_item_search_toolbar( const int num ); // スレ一覧のツールバー項目 const std::string& get_items_board_toolbar_str(); const std::string get_items_board_toolbar_default_str(); void set_items_board_toolbar_str( const std::string& items ); const int get_item_board_toolbar( const int num ); // 書き込みビューのツールバー項目 const std::string& get_items_msg_toolbar_str(); const std::string get_items_msg_toolbar_default_str(); void set_items_msg_toolbar_str( const std::string& items ); const int get_item_msg_toolbar( const int num ); // スレ一覧の列項目 const std::string& get_items_board_col_str(); const std::string get_items_board_col_default_str(); void set_items_board_col_str( const std::string& items ); const int get_item_board_col( const int num ); // スレ一覧のコンテキストメニュー項目 const std::string& get_items_board_menu_str(); const std::string get_items_board_menu_default_str(); void set_items_board_menu_str( const std::string& items_str ); const int get_item_board_menu( const int num ); // スレビューのコンテキストメニュー項目 const std::string& get_items_article_menu_str(); const std::string get_items_article_menu_default_str(); void set_items_article_menu_str( const std::string& items_str ); const int get_item_article_menu( const int num ); // スレ一覧の列幅 const int col_mark(); const int col_id(); const int col_board(); const int col_subject(); const int col_number(); const int col_load(); const int col_new(); const int col_since(); const int col_write(); const int col_access(); const int col_speed(); const int col_diff(); void set_col_mark( const int width ); void set_col_id( const int width ); void set_col_board( const int width ); void set_col_subject( const int width ); void set_col_number( const int width ); void set_col_load( const int width ); void set_col_new( const int width ); void set_col_since( const int width ); void set_col_write( const int width ); void set_col_access( const int width ); void set_col_speed( const int width ); void set_col_diff( const int width ); // スレ一覧の since の表示モード const int get_col_since_time(); void set_col_since_time( const int mode ); // スレ一覧の 最終書込 の表示モード const int get_col_write_time(); void set_col_write_time( const int mode ); // 現在開いているarticle の ARTICLE::DrawAreaBase ARTICLE::DrawAreaBase* get_base_drawarea(); // 現在開いているarticle のurl const std::string get_article_current_url(); // 埋め込みimage使用 const bool get_embedded_img(); void set_embedded_img( const bool set ); // 埋め込みmessageを使用 const bool get_embedded_mes(); void set_embedded_mes( const bool set ); // 書き込み後にmessageを閉じる const bool get_close_mes(); void set_close_mes( const bool set ); // 最後にdatを読み書きしたディレクトリ const std::string& get_dir_dat(); void set_dir_dat( const std::string& dir ); // 最後に画像を保存したディレクトリ const std::string& dir_img_save(); void set_dir_img_save( const std::string& dir ); // 下書きファイルのディレクトリ const std::string& get_dir_draft(); void set_dir_draft( const std::string& dir ); // ポップアップメニュー表示中 const bool is_popupmenu_shown(); void set_popupmenu_shown( const bool shown ); // JD終了時に削除するスレのリスト const std::vector< std::string >& get_delete_list(); void append_delete_list( const std::string& url ); void remove_delete_list( const std::string& url ); // 実況実行中のスレ const bool is_live( const std::string& url ); void append_live( const std::string& url ); void remove_live( const std::string& url ); // 画像のfitモード const int get_img_fit_mode(); void toggle_img_fit_mode(); // お気に入り挿入ダイアログで最後に保存したディレクトリ名 const std::string& get_dir_select_favorite(); void set_dir_select_favorite( const std::string& dir ); // 各履歴を取得 void get_history( const std::string& url, CORE::DATA_INFO_LIST& info_list ); // サイドバーの指定したidのディレクトリに含まれるスレのアドレスを取得 void get_sidebar_threads( const std::string& url, const int dirid, std::vector< std::string >& list_url ); // サイドバーの指定したidのディレクトリの名前を取得 const std::string get_sidebar_dirname( const std::string& url, const int dirid ); } #endif jd-2.8.7-140104/src/setupwizard.cpp0000644000076400010400000002625111060403412013441 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "setupwizard.h" #include "prefdiagfactory.h" #include "fontid.h" #include "session.h" #include "config/globalconf.h" #include "icons/iconmanager.h" using namespace CORE; enum { SPACING_SIZE = 8 }; PageStart::PageStart() : Gtk::VBox(), m_label( "1/5.JD セットアップ開始", Gtk::ALIGN_LEFT ), m_label2( "JDセットアップウィザードへようこそ\n\nこのウィザードでネットワークとフォント等の設定をおこないます\n\n設定を始めるには[次へ]を押してください", Gtk::ALIGN_LEFT ) { m_icon.set( ICON::get_icon_manager()->get_icon( ICON::JD48 ) ); m_hbox_label.set_spacing( SPACING_SIZE ); m_hbox_label.pack_start( m_icon, Gtk::PACK_SHRINK ); m_hbox_label.pack_start( m_label ); set_spacing( SPACING_SIZE ); pack_start( m_hbox_label, Gtk::PACK_SHRINK ); pack_start( m_label2, Gtk::PACK_SHRINK ); } ///////////////////////////////////////////// PageNet::PageNet() : Gtk::VBox(), m_label( "2/5.ネットワークの設定をします", Gtk::ALIGN_LEFT ), m_proxy( "プロキシ設定(_P)", true ), m_browser( "ブラウザ設定(_W)", true ), m_frame( "ブラウザ起動コマンド" ), // フレーム m_label_browser( CONFIG::get_command_openurl(), Gtk::ALIGN_LEFT ) { m_icon.set( ICON::get_icon_manager()->get_icon( ICON::JD48 ) ); m_hbox_label.set_spacing( SPACING_SIZE ); m_hbox_label.pack_start( m_icon, Gtk::PACK_SHRINK ); m_hbox_label.pack_start( m_label ); m_vbox.set_spacing( SPACING_SIZE ); m_vbox.pack_start( m_proxy, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_browser, Gtk::PACK_SHRINK ); // m_hbox_commnad に m_label_browser を格納 m_hbox_command.set_spacing( SPACING_SIZE ); m_hbox_command.pack_start( m_label_browser, Gtk::PACK_SHRINK ); m_hbox_command.set_border_width( SPACING_SIZE ); // フレーム内にHBoxを格納 m_frame.add( m_hbox_command ); m_proxy.signal_clicked().connect( sigc::mem_fun( *this, &PageNet::slot_setup_proxy ) ); m_browser.signal_clicked().connect( sigc::mem_fun( *this, &PageNet::slot_setup_browser ) ); set_spacing( SPACING_SIZE ); pack_start( m_hbox_label, Gtk::PACK_SHRINK ); pack_start( m_vbox, Gtk::PACK_SHRINK ); // フレームの追加 pack_start( m_frame, Gtk::PACK_SHRINK ); } // // プロキシ設定 // void PageNet::slot_setup_proxy() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_PROXY, "" ); pref->run(); delete pref; } // // ブラウザ設定 // void PageNet::slot_setup_browser() { SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_BROWSER, "" ); pref->run(); delete pref; m_label_browser.set_text( CONFIG::get_command_openurl() ); } ///////////////////////////////////////////// PageFont::PageFont() : Gtk::VBox(), m_label( "3/5.フォントの設定をします", Gtk::ALIGN_LEFT ), m_table( 2, 3 ), m_label_res( "スレ(_T)", Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP, true ), m_label_popup( "ポップアップ(_P)", Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP, true ), m_label_tree( "板/スレ一覧(_O)", Gtk::ALIGN_LEFT, Gtk::ALIGN_TOP, true ), m_font_res( "スレフォント" ), m_font_popup( "ポップアップフォント" ), m_font_tree( "板/スレ一覧フォント" ) { m_label_res.set_mnemonic_widget( m_font_res ); m_label_popup.set_mnemonic_widget( m_font_popup ); m_label_tree.set_mnemonic_widget( m_font_tree ); m_icon.set( ICON::get_icon_manager()->get_icon( ICON::JD48 ) ); m_hbox_label.set_spacing( SPACING_SIZE ); m_hbox_label.pack_start( m_icon, Gtk::PACK_SHRINK ); m_hbox_label.pack_start( m_label ); m_font_res.set_font_name( CONFIG::get_fontname( FONT_MAIN ) ); m_font_popup.set_font_name( CONFIG::get_fontname( FONT_POPUP ) ); m_font_tree.set_font_name( CONFIG::get_fontname( FONT_BBS ) ); m_font_res.signal_font_set().connect( sigc::mem_fun( *this, &PageFont::slot_font_res ) ); m_font_popup.signal_font_set().connect( sigc::mem_fun( *this, &PageFont::slot_font_popup ) ); m_font_tree.signal_font_set().connect( sigc::mem_fun( *this, &PageFont::slot_font_tree ) ); m_table.set_spacings( 4 ); m_table.attach( m_label_res, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK ); m_table.attach( m_label_popup, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK ); m_table.attach( m_label_tree, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK ); m_table.attach( m_font_res, 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK ); m_table.attach( m_font_popup, 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK ); m_table.attach( m_font_tree, 1, 2, 2, 3, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK ); set_spacing( SPACING_SIZE ); pack_start( m_hbox_label, Gtk::PACK_SHRINK ); pack_start( m_table, Gtk::PACK_EXPAND_WIDGET ); } void PageFont::slot_font_res() { CONFIG::set_fontname( FONT_MAIN, m_font_res.get_font_name() ); CONFIG::set_fontname( FONT_MESSAGE, m_font_res.get_font_name() ); } void PageFont::slot_font_popup() { CONFIG::set_fontname( FONT_POPUP, m_font_popup.get_font_name() ); } void PageFont::slot_font_tree() { CONFIG::set_fontname( FONT_BBS, m_font_tree.get_font_name() ); CONFIG::set_fontname( FONT_BOARD, m_font_tree.get_font_name() ); } ///////////////////////////////////////////// PagePane::PagePane() : Gtk::VBox(), m_label( "4/5.ペイン表示設定をします", Gtk::ALIGN_LEFT ), m_2pane( m_radiogroup, "2ペイン表示(_2)", true ), m_3pane( m_radiogroup, "3ペイン表示(_3)", true ), m_v3pane( m_radiogroup, "縦3ペイン表示(_V)", true ), m_label_inst( "" , Gtk::ALIGN_LEFT ) { m_icon.set( ICON::get_icon_manager()->get_icon( ICON::JD48 ) ); m_hbox_label.set_spacing( SPACING_SIZE ); m_hbox_label.pack_start( m_icon, Gtk::PACK_SHRINK ); m_hbox_label.pack_start( m_label ); switch( SESSION::get_mode_pane() ){ case SESSION::MODE_2PANE: m_2pane.set_active( true ); slot_2pane(); break; case SESSION::MODE_3PANE: m_3pane.set_active( true ); slot_3pane(); break; case SESSION::MODE_V3PANE: m_v3pane.set_active( true ); slot_v3pane(); break; } m_2pane.signal_toggled().connect( sigc::mem_fun( *this, &PagePane::slot_2pane ) ); m_3pane.signal_toggled().connect( sigc::mem_fun( *this, &PagePane::slot_3pane ) ); m_v3pane.signal_toggled().connect( sigc::mem_fun( *this, &PagePane::slot_v3pane ) ); set_spacing( SPACING_SIZE ); pack_start( m_hbox_label, Gtk::PACK_SHRINK ); pack_start( m_2pane, Gtk::PACK_EXPAND_WIDGET ); pack_start( m_3pane, Gtk::PACK_EXPAND_WIDGET ); pack_start( m_v3pane, Gtk::PACK_EXPAND_WIDGET ); pack_start( m_label_inst, Gtk::PACK_EXPAND_WIDGET ); } void PagePane::slot_2pane() { SESSION::set_mode_pane( SESSION::MODE_2PANE ); m_label_inst.set_text( "ウィンドウの左に板一覧、右にスレ一覧とスレビューを切り替え表示" ); } void PagePane::slot_3pane() { SESSION::set_mode_pane( SESSION::MODE_3PANE ); m_label_inst.set_text( "ウィンドウの左に板一覧、右上にスレ一覧、右下にスレビューを表示" ); } void PagePane::slot_v3pane() { SESSION::set_mode_pane( SESSION::MODE_V3PANE ); m_label_inst.set_text( "ウィンドウの左に板一覧、中央にスレ一覧、右にスレビューを表示" ); } ///////////////////////////////////////////// PageEnd::PageEnd() : Gtk::VBox(), m_label( "5/5.JD セットアップ完了", Gtk::ALIGN_LEFT ), m_label2( "その他の設定は起動後に設定及び表示メニューからおこなって下さい\n\n完了を押すとJDを起動して板一覧のリストをロードします\n板一覧が表示されるまでしばらくお待ち下さい" , Gtk::ALIGN_LEFT ) { m_icon.set( ICON::get_icon_manager()->get_icon( ICON::JD48 ) ); m_hbox_label.set_spacing( SPACING_SIZE ); m_hbox_label.pack_start( m_icon, Gtk::PACK_SHRINK ); m_hbox_label.pack_start( m_label ); set_spacing( SPACING_SIZE ); pack_start( m_hbox_label, Gtk::PACK_SHRINK ); pack_start( m_label2, Gtk::PACK_SHRINK ); } ///////////////////////////////////////////// SetupWizard::SetupWizard() : Gtk::Dialog(), m_back( "<< 戻る(_B)", true ), m_next( "次へ(_N) >>", true ) { set_title( "JD セットアップウィザード" ); set_keep_above( true ); set_resizable( false ); const int width = 600; const int height = 300; const int sw = get_screen()->get_width(); const int sh = get_screen()->get_height(); resize( width, height ); if( sw > width && sh > height ) move( ( sw - width )/2, ( sh - height )/2 ); // ボタン get_action_area()->set_spacing( SPACING_SIZE / 2 ); get_action_area()->pack_start( m_back, Gtk::PACK_SHRINK ); get_action_area()->pack_start( m_next, Gtk::PACK_SHRINK ); m_fin = add_button( "完了(_C)", Gtk::RESPONSE_OK ); m_back.set_sensitive( false ); m_next.set_sensitive( true ); m_fin->set_sensitive( false ); m_back.signal_clicked().connect( sigc::mem_fun( *this, &SetupWizard::slot_back ) ); m_next.signal_clicked().connect( sigc::mem_fun( *this, &SetupWizard::slot_next ) ); // ページ m_notebook.append_page( m_page_start ); m_notebook.append_page( m_page_network ); m_notebook.append_page( m_page_font ); m_notebook.append_page( m_page_pane ); m_notebook.append_page( m_page_end ); m_notebook.set_border_width( SPACING_SIZE ); m_notebook.set_show_border( false ); m_notebook.set_show_tabs( false ); m_sigc_switch_page = m_notebook.signal_switch_page().connect( sigc::mem_fun( *this, &SetupWizard::slot_switch_page ) ); get_vbox()->pack_start( m_notebook, Gtk::PACK_EXPAND_PADDING, SPACING_SIZE ); show_all_children(); } SetupWizard::~SetupWizard() { if( m_sigc_switch_page.connected() ) m_sigc_switch_page.disconnect(); } void SetupWizard::slot_switch_page( GtkNotebookPage* notebookpage, guint page ) { switch( page ){ case 0: m_back.set_sensitive( false ); m_next.set_sensitive( true ); m_fin->set_sensitive( false ); break; case 1: case 2: case 3: m_back.set_sensitive( true ); m_next.set_sensitive( true ); m_fin->set_sensitive( false ); break; case 4: m_back.set_sensitive( true ); m_next.set_sensitive( false ); m_fin->set_sensitive( true ); m_fin->grab_focus(); break; } } void SetupWizard::slot_back() { int page = m_notebook.get_current_page(); m_notebook.set_current_page( page - 1 ); } void SetupWizard::slot_next() { int page = m_notebook.get_current_page(); m_notebook.set_current_page( page + 1 ); } jd-2.8.7-140104/src/setupwizard.h0000644000076400010400000000560311060403412013104 0ustar // ライセンス: GPL2 // // セットアップウィザード // #ifndef _SETUPWIZARD_H #define _SETUPWIZARD_H #include namespace CORE { class PageStart : public Gtk::VBox { Gtk::HBox m_hbox_label; Gtk::Image m_icon; Gtk::Label m_label; Gtk::Label m_label2; public: PageStart(); }; //////////////////////////////////////////// class PageNet : public Gtk::VBox { Gtk::HBox m_hbox_label; Gtk::Image m_icon; Gtk::Label m_label; Gtk::VBox m_vbox; Gtk::Button m_proxy; Gtk::Button m_browser; // フレームの追加 Gtk::Frame m_frame; // フレーム内に挿入する HBox Gtk::HBox m_hbox_command; Gtk::Label m_label_browser; public: PageNet(); private: void slot_setup_proxy(); void slot_setup_browser(); }; ///////////////////////////////////////////// class PageFont : public Gtk::VBox { Gtk::HBox m_hbox_label; Gtk::Image m_icon; Gtk::Label m_label; Gtk::Table m_table; Gtk::Label m_label_res; Gtk::Label m_label_popup; Gtk::Label m_label_tree; Gtk::FontButton m_font_res; Gtk::FontButton m_font_popup; Gtk::FontButton m_font_tree; public: PageFont(); private: void slot_font_res(); void slot_font_popup(); void slot_font_tree(); }; ///////////////////////////////////////////// class PagePane : public Gtk::VBox { Gtk::HBox m_hbox_label; Gtk::Image m_icon; Gtk::Label m_label; Gtk::RadioButtonGroup m_radiogroup; Gtk::RadioButton m_2pane; Gtk::RadioButton m_3pane; Gtk::RadioButton m_v3pane; Gtk::Label m_label_inst; public: PagePane(); private: void slot_2pane(); void slot_3pane(); void slot_v3pane(); }; ///////////////////////////////////////////// class PageEnd : public Gtk::VBox { Gtk::HBox m_hbox_label; Gtk::Image m_icon; Gtk::Label m_label; Gtk::Label m_label2; public: PageEnd(); }; ///////////////////////////////////////////// class SetupWizard : public Gtk::Dialog { sigc::connection m_sigc_switch_page; Gtk::Notebook m_notebook; PageStart m_page_start; PageNet m_page_network; PageFont m_page_font; PagePane m_page_pane; PageEnd m_page_end; Gtk::Button* m_fin; Gtk::Button m_back; Gtk::Button m_next; public: SetupWizard(); virtual ~SetupWizard(); private: void slot_switch_page( GtkNotebookPage* notebookpage, guint page ); void slot_back(); void slot_next(); void slot_fin(); }; } #endif jd-2.8.7-140104/src/sharedbuffer.cpp0000644000076400010400000000065411116750152013527 0ustar // ライセンス: GPL2 #include "sharedbuffer.h" using namespace CORE; CORE::DATA_INFO_LIST shared_infolist; const int CORE::SBUF_size() { return shared_infolist.size(); } void CORE:: SBUF_clear_info() { shared_infolist.clear(); } void CORE::SBUF_set_list( const CORE::DATA_INFO_LIST& list_info ) { shared_infolist = list_info; } CORE::DATA_INFO_LIST& CORE::SBUF_list_info() { return shared_infolist; } jd-2.8.7-140104/src/sharedbuffer.h0000644000076400010400000000062111350440352013164 0ustar // ライセンス: GPL2 // // 共有バッファ // // クラス間で情報をやり取りするときに使う // #ifndef _SHAREDBUFFER_H #define _SHAREDBUFFER_H #include "type.h" #include "data_info.h" namespace CORE { const int SBUF_size(); void SBUF_clear_info(); void SBUF_set_list( const CORE::DATA_INFO_LIST& list_info ); CORE::DATA_INFO_LIST& SBUF_list_info(); } #endif jd-2.8.7-140104/src/sidebaritempref.cpp0000644000076400010400000000301611506370702014231 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "sidebaritempref.h" #include "icons/iconmanager.h" #include "jdlib/miscutil.h" #include "global.h" #include "session.h" #include "command.h" using namespace CORE; SidebarItemPref::SidebarItemPref( Gtk::Window* parent, const std::string& url ) : SKELETON::SelectItemPref( parent, url ) { // デフォルトの項目を設定 append_default_pair( ITEM_NAME_SEARCHBOX, ICON::get_icon( ICON::TRANSPARENT ) ); append_default_pair( ITEM_NAME_SEARCH_NEXT, ICON::get_icon( ICON::SEARCH_NEXT ) ); append_default_pair( ITEM_NAME_SEARCH_PREV, ICON::get_icon( ICON::SEARCH_PREV ) ); append_default_pair( ITEM_NAME_CHECK_UPDATE_ROOT, ICON::get_icon( ICON::CHECK_UPDATE_ROOT ) ); append_default_pair( ITEM_NAME_CHECK_UPDATE_OPEN_ROOT, ICON::get_icon( ICON::CHECK_UPDATE_OPEN_ROOT ) ); append_default_pair( ITEM_NAME_STOPLOADING, ICON::get_icon( ICON::STOPLOADING ) ); append_default_pair( ITEM_NAME_SEPARATOR, ICON::get_icon( ICON::TRANSPARENT ) ); // 文字列を元に列を追加 append_rows( SESSION::get_items_sidebar_toolbar_str() ); set_title( "ツールバー項目設定(サイドバー)" ); } // OKを押した void SidebarItemPref::slot_ok_clicked() { SESSION::set_items_sidebar_toolbar_str( get_items() ); CORE::core_set_command( "update_bbslist_toolbar_button" ); } // // デフォルトボタン // void SidebarItemPref::slot_default() { append_rows( SESSION::get_items_sidebar_toolbar_default_str() ); } jd-2.8.7-140104/src/sidebaritempref.h0000644000076400010400000000105511235056116013676 0ustar // ライセンス: GPL2 // サイドバーのツールバーの表示項目設定 #ifndef _SIDEBARITEMPREF_H #define _SIDEBARITEMPREF_H #include "skeleton/selectitempref.h" namespace CORE { class SidebarItemPref : public SKELETON::SelectItemPref { public: SidebarItemPref( Gtk::Window* parent, const std::string& url ); virtual ~SidebarItemPref(){} private: // OK押した virtual void slot_ok_clicked(); // デフォルトボタン virtual void slot_default(); }; } #endif jd-2.8.7-140104/src/sign.h0000644000076400010400000000117011350440352011464 0ustar // ビューのアドレスで使用するサイン #ifndef _SIGN_H #define _SIGN_H #define ARTICLE_SIGN "_ARTICLE_" #define NEXT_SIGN "_NEXT_" #define LOG_SIGN "_LOG_" #define SIDEBAR_SIGN "_SIDEBAR_" #define BOARD_SIGN "_BOARD_" #define RES_SIGN "_RES_" #define NAME_SIGN "_NAME_" #define ID_SIGN "_ID_" #define BOOKMK_SIGN "_BM_" #define POST_SIGN "_POST_" #define URL_SIGN "_URL_" #define REFER_SIGN "_REF_" #define KEYWORD_SIGN "_KW_" #define POSTLOG_SIGN "_POST_" #define ORMODE_SIGN "_OR_" #define CENTER_SIGN "_CENTER_" #define TIME_SIGN "_TIME_" #define TITLE_SIGN "_TITLE_" #endif jd-2.8.7-140104/src/skeleton/0000755000076400010400000000000012261751611012205 5ustar jd-2.8.7-140104/src/skeleton/aamenu.cpp0000644000076400010400000001560211322610554014160 0ustar // AA 選択ポップアップメニュークラス //#define _DEBUG #include "jddebug.h" #include "aamenu.h" #include "jdlib/miscutil.h" #include "config/globalconf.h" #include "fontid.h" #include "colorid.h" #include "aamanager.h" #include "cache.h" using namespace SKELETON; AAMenu::AAMenu( Gtk::Window& parent ) : Gtk::Menu() , m_parent( parent ), m_popup( SKELETON::POPUPWIN_NOFRAME ) { #ifdef _DEBUG std::cout << "AAMenu::AAMenu\n"; #endif Pango::FontDescription pfd( CONFIG::get_fontname( FONT_MESSAGE ) ); pfd.set_weight( Pango::WEIGHT_NORMAL ); m_textview.modify_font( pfd ); m_textview.modify_text( Gtk::STATE_NORMAL, Gdk::Color( CONFIG::get_color( COLOR_CHAR_SELECTION ) ) ); m_textview.modify_base( Gtk::STATE_NORMAL, Gdk::Color( CONFIG::get_color( COLOR_BACK_SELECTION ) ) ); m_popup.sig_configured().connect( sigc::mem_fun( *this, &AAMenu::slot_configured_popup ) ); m_popup.add( m_textview ); m_popup.show_all_children(); create_popupmenu(); } AAMenu::~AAMenu() { #ifdef _DEBUG std::cout << "AAMenu::~AAMenu\n"; #endif } const int AAMenu::get_size() { return items().size(); } void AAMenu::set_text( const std::string& text ) { m_popup.show(); m_popup.resize( 1, 1 ); m_textview.get_buffer()->set_text( text ); } // メニュー項目作成 void AAMenu::create_menuitem( Glib::RefPtr< Gtk::ActionGroup > actiongroup, Gtk::Menu* menu, const int id ) { const int maxchar = 20; Glib::ustring aa_label = CORE::get_aamanager()->get_label( id ); std::string shortcut = CORE::get_aamanager()->id2shortcut( id ); if( ! shortcut.empty() ) aa_label = "[" + shortcut + "] " + aa_label; std::string actname = "aa" + MISC::itostr( id ); if( actiongroup->get_action( actname ) ) return; // 登録済み #ifdef _DEBUG std::cout << actname << " label = " << aa_label << std::endl; #endif Glib::RefPtr< Gtk::Action > action = Gtk::Action::create( actname, aa_label.substr( 0, maxchar ) ); action->set_accel_group( m_parent.get_accel_group() ); Gtk::MenuItem* item = Gtk::manage( action->create_menu_item() ); actiongroup->add( action, sigc::bind< Gtk::MenuItem* >( sigc::mem_fun( *this, &AAMenu::slot_aainput_menu_clicked ), item ) ); item->signal_select().connect( sigc::bind< Gtk::MenuItem* >( sigc::mem_fun( *this, &AAMenu::slot_select_item ), item ) ); menu->append( *item ); m_map_items.insert( std::make_pair( item, id ) ); } // メニュー作成 void AAMenu::create_popupmenu() { std::string aa_lines; if( ! CACHE::load_rawdata( CACHE::path_aalist(), aa_lines ) ) return; Glib::RefPtr< Gtk::ActionGroup > actiongroup = Gtk::ActionGroup::create(); // 履歴 for( int i = 0 ; i < CORE::get_aamanager()->get_historysize() ; ++i ){ int org_id = CORE::get_aamanager()->history2id( i ); create_menuitem( actiongroup, this, org_id ); } if( CORE::get_aamanager()->get_historysize() ){ Gtk::MenuItem* item = Gtk::manage( new Gtk::SeparatorMenuItem() ); append( *item ); m_map_items.insert( std::make_pair( item, -1 ) ); } for( int i = 0 ; i < CORE::get_aamanager()->get_size() ; ++i ) create_menuitem( actiongroup, this, i ); show_all_children(); } void AAMenu::on_map() { #ifdef _DEBUG std::cout << "AAMenu::on_realize\n"; #endif Gtk::Menu::on_map(); select_item( items()[ 0 ] ); } void AAMenu::on_hide() { #ifdef _DEBUG std::cout << "AAMenu::on_hide\n"; #endif m_popup.hide(); Gtk::Menu::on_hide(); } // 下移動 bool AAMenu::move_down() { #ifdef _DEBUG std::cout << "AAMenu::move_down\n"; #endif Gtk::Menu_Helpers::MenuList::iterator it = items().begin(); for( ; it != items().end() && &(*it) != m_activeitem; ++it ); ++it; if( m_map_items[ &(*it) ] == -1 ) ++it; // セパレータ if( it == items().end() ) it = items().begin(); // 一番下まで行ったら上に戻る select_item( *it ); return true; } // 上移動 bool AAMenu::move_up() { #ifdef _DEBUG std::cout << "AAMenu::move_up\n"; #endif Gtk::Menu_Helpers::MenuList::iterator it = items().begin(); for( ; it != items().end() && &(*it) != m_activeitem; ++it ); if( it != items().begin() ){ --it; if( m_map_items[ &(*it) ] == -1 && it != items().begin() ) --it; // セパレータ select_item( *it ); } else select_item( items().back() ); // 一番上に行ったら下に戻る return true; } // キー入力のフック bool AAMenu::on_key_press_event( GdkEventKey* event ) { #ifdef _DEBUG std::cout << "AAMenu::on_key_press_event key = " << event->keyval << std::endl; #endif // 下移動 if( event->keyval == GDK_j || ( ( event->state & GDK_CONTROL_MASK ) && event->keyval == GDK_n ) || event->keyval == GDK_space ){ move_down(); return true; } // 上移動 else if( event->keyval == GDK_k || ( ( event->state & GDK_CONTROL_MASK ) && event->keyval == GDK_p ) ){ move_up(); return true; } // ショートカット else{ int id = CORE::get_aamanager()->shortcut2id( event->string[ 0 ] ); #ifdef _DEBUG std::cout << "id = " << id << " key = " << event->string[ 0 ] << std::endl; #endif if( id >= 0 ){ std::string aa = CORE::get_aamanager()->get_aa( id ); if( ! aa.empty() ){ m_sig_selected.emit( aa ); CORE::get_aamanager()->append_history( id ); hide(); } } } return Gtk::Menu::on_key_press_event( event ); } // // ポップアップウィンドウのサイズが変わった // void AAMenu::slot_configured_popup( int width, int height ) { int sw = get_screen()->get_width(); int x, y; get_window()->get_root_origin( x, y ); #ifdef _DEBUG std::cout << " AAMenu::slot_configured_popup w = " << width << " h = " << height << " x = " << x << " screen width = " << sw << std::endl; #endif y -= height; if( x + width > sw ) x = sw - width; m_popup.move( x, y ); } // // メニューの行を選択 // void AAMenu::slot_select_item( Gtk::MenuItem* item ) { if( ! get_active() ) return; int id = m_map_items[ item ]; m_activeitem = item; #ifdef _DEBUG std::cout << "AAMenu::slot_select_item id = " << id << std::endl; #endif set_text( CORE::get_aamanager()->get_aa( id ) ); } // // アスキーアート入力 // void AAMenu::slot_aainput_menu_clicked( Gtk::MenuItem* item ) { if( ! get_active() ) return; int id = m_map_items[ item ]; m_activeitem = item; #ifdef _DEBUG std::cout << "AAMenu::slot_aainput_menu_clicked id = " << id << std::endl; std::cout << CORE::get_aamanager()->get_aa( id ) << std::endl; #endif m_sig_selected.emit( CORE::get_aamanager()->get_aa( id ) ); CORE::get_aamanager()->append_history( id ); } jd-2.8.7-140104/src/skeleton/aamenu.h0000644000076400010400000000255710632774613013644 0ustar // ライセンス: GPL2 // // AA 選択ポップアップメニュークラス // #ifndef _AAMENU_H #define _AAMENU_H #include #include #include "popupwinbase.h" namespace SKELETON { typedef sigc::signal< void, const std::string& > SIG_AAMENU_SELECTED; class AAMenu : public Gtk::Menu { SIG_AAMENU_SELECTED m_sig_selected; Gtk::Window& m_parent; SKELETON::PopupWinBase m_popup; Gtk::TextView m_textview; std::map< Gtk::MenuItem*, int > m_map_items; Gtk::MenuItem* m_activeitem; public: AAMenu( Gtk::Window& parent ); virtual ~AAMenu(); // 選択されたらemitされる SIG_AAMENU_SELECTED sig_selected() { return m_sig_selected; } protected: virtual void on_map(); virtual void on_hide(); virtual bool on_key_press_event (GdkEventKey* event); private: const int get_size(); void set_text( const std::string& text ); void create_menuitem( Glib::RefPtr< Gtk::ActionGroup > actiongroup, Gtk::Menu* menu, const int id ); void create_popupmenu(); bool move_down(); bool move_up(); void slot_select_item( Gtk::MenuItem* item ); void slot_configured_popup( int width, int height ); void slot_aainput_menu_clicked( Gtk::MenuItem* item ); }; } #endif jd-2.8.7-140104/src/skeleton/aboutdiag.cpp0000644000076400010400000002043611344230050014643 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "aboutdiag.h" #include "command.h" #include "environment.h" #include "session.h" #include "config/globalconf.h" #include "icons/iconmanager.h" #include "jdlib/miscgtk.h" using namespace SKELETON; enum { MARGIN = 8 }; AboutDiag::AboutDiag( const Glib::ustring& title ) : Gtk::Dialog( title ), m_button_copy_environment( "クリップボードへコピー" ) { set_transient_for( *CORE::get_mainwindow() ); set_resizable( false ); Gtk::Button* button = add_button( Gtk::Stock::CLOSE, Gtk::RESPONSE_CLOSE ); button->signal_clicked().connect( sigc::mem_fun( *this, &AboutDiag::slot_close_clicked ) ); set_default_response( Gtk::RESPONSE_CLOSE ); set_logo( ICON::get_icon( ICON::JD96 ) ); set_version( ENVIRONMENT::get_jdversion() ); set_comments( ENVIRONMENT::get_jdcomments() ); set_website( CONFIG::get_url_jdhp() ); set_copyright( ENVIRONMENT::get_jdcopyright() ); set_license( ENVIRONMENT::get_jdlicense() ); set_environment_list(); } // // run() // int AboutDiag::run() { #ifdef _DEBUG std::cout << "AboutDiag::run start\n"; #endif init(); SESSION::set_dialog_shown( true ); CORE::core_set_command( "dialog_shown" ); int ret = Gtk::Dialog::run(); SESSION::set_dialog_shown( false ); CORE::core_set_command( "dialog_hidden" ); #ifdef _DEBUG std::cout << "AboutDiag::run fin\n"; #endif return ret; } // // 各ウィジェットを配置して初期化 // void AboutDiag::init() { // 情報タブの追加 m_label_tab_info.set_label( "情報" ); m_vbox_info.set_spacing( MARGIN ); m_vbox_info.set_border_width( MARGIN ); // ロゴ if( get_logo() ) { m_vbox_info.pack_start( m_image_logo, Gtk::PACK_SHRINK ); } // バージョン if( ! get_version().empty() ) { m_vbox_info.pack_start( m_label_version, Gtk::PACK_EXPAND_WIDGET, MARGIN ); } // コメント if( ! get_comments().empty() ) { m_vbox_info.pack_start( m_label_comments, Gtk::PACK_SHRINK ); } // コピーライト if( ! get_copyright().empty() ) { m_vbox_info.pack_start( m_label_copyright, Gtk::PACK_SHRINK ); } // Webサイト if( ! get_website_label().empty() ) { m_hbox_url.pack_start( m_button_website, Gtk::PACK_EXPAND_PADDING ); m_vbox_info.pack_start( m_hbox_url, Gtk::PACK_SHRINK ); } m_notebook.append_page( m_vbox_info, m_label_tab_info ); // ライセンスタブの追加 if( ! get_license().empty() ) { m_label_tab_license.set_label( "ライセンス" ); m_notebook.append_page( m_scrollwindow_license, m_label_tab_license ); } // 動作環境タブの追加 m_label_tab_environment.set_label( "動作環境" ); m_notebook.append_page( m_vbox_environment, m_label_tab_environment ); // 動作環境一覧 m_vbox_environment.pack_start( m_scrollwindow_environment, Gtk::PACK_EXPAND_WIDGET ); // クリップボードへコピーのボタン m_button_copy_environment.signal_clicked().connect( sigc::mem_fun( *this, &AboutDiag::slot_copy_environment ) ); m_hbuttonbox_environment.set_layout( Gtk::BUTTONBOX_END ); m_hbuttonbox_environment.pack_start( m_button_copy_environment, Gtk::PACK_SHRINK ); m_vbox_environment.pack_start( m_hbuttonbox_environment, Gtk::PACK_SHRINK ); get_vbox()->pack_start( m_notebook, Gtk::PACK_EXPAND_WIDGET, MARGIN ); show_all_children(); // バージョンの文字列の長さが短い( x.x.x-YYMMDD )と // ウィンドウの幅が狭すぎるので"幅/高さ"いずれかの大 // きい方に合わせて4:3を保持するようにする。 int win_w, win_h; get_size( win_w, win_h ); if( win_w * 3 / 4 < win_h ) set_size_request( win_h * 4 / 3, -1 ); else set_size_request( -1, win_w * 3 / 4 ); } // // ロゴ // void AboutDiag::set_logo( const Glib::RefPtr< Gdk::Pixbuf >& logo ) { m_image_logo.set( logo ); } Glib::RefPtr< Gdk::Pixbuf > AboutDiag::get_logo() { return m_image_logo.get_pixbuf(); } // // バージョン表示 // void AboutDiag::set_version( const Glib::ustring& version ) { m_label_version.set_label( version ); Pango::FontDescription font_discription_version = m_label_version.get_style()->get_font(); const int label_version_font_size = font_discription_version.get_size(); font_discription_version.set_size( label_version_font_size * 5 / 3 ); font_discription_version.set_weight( Pango::WEIGHT_BOLD ); m_label_version.modify_font( font_discription_version ); } Glib::ustring AboutDiag::get_version() { return m_label_version.get_label(); } // // コメント // void AboutDiag::set_comments( const Glib::ustring& comments ) { m_label_comments.set_label( comments ); } Glib::ustring AboutDiag::get_comments() { return m_label_comments.get_label(); } // // コピーライト // void AboutDiag::set_copyright( const Glib::ustring& copyright ) { m_label_copyright.set_label( copyright ); } Glib::ustring AboutDiag::get_copyright() { return m_label_copyright.get_label(); } // // Webサイト // void AboutDiag::set_website( const Glib::ustring& website ) { if( m_button_website.get_label().empty() ) m_button_website.set_label( website ); m_button_website.set_relief( Gtk::RELIEF_NONE ); m_button_website.signal_clicked().connect( sigc::mem_fun( this, &AboutDiag::slot_button_website_clicked ) ); m_website_url = website; } Glib::ustring AboutDiag::get_website() { return m_website_url; } // // Webサイトラベル // void AboutDiag::set_website_label( const Glib::ustring& website_label ) { m_button_website.set_label( website_label ); } Glib::ustring AboutDiag::get_website_label() { return m_button_website.get_label(); } // // Webサイトのボタンがクリックされた // void AboutDiag::slot_button_website_clicked() { CORE::core_set_command( "open_url_browser", m_website_url ); } // // ライセンス // void AboutDiag::set_license( const Glib::ustring& license ) { m_textview_license.get_buffer()->set_text( license ); m_textview_license.set_editable( false ); m_textview_license.set_cursor_visible( false ); m_textview_license.set_accepts_tab( false ); m_textview_license.set_wrap_mode( Gtk::WRAP_WORD_CHAR ); m_scrollwindow_license.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); m_scrollwindow_license.add( m_textview_license ); } Glib::ustring AboutDiag::get_license() { return m_textview_license.get_buffer()->get_text(); } // // 動作環境一覧 // void AboutDiag::set_environment_list() { Gtk::TreeModelColumn< Glib::ustring > column_name; Gtk::TreeModelColumn< Glib::ustring > column_value; Gtk::TreeModel::ColumnRecord record; Glib::RefPtr< Gtk::ListStore > liststore; record.add( column_name ); record.add( column_value ); liststore = Gtk::ListStore::create( record ); m_treeview_environment.set_model( liststore ); Gtk::TreeModel::Row row; m_treeview_environment.append_column( "項目", column_name ); m_treeview_environment.append_column( "内容", column_value ); row = *( liststore->append() ); row[ column_name ] = "JDのバージョン"; row[ column_value ] = ENVIRONMENT::get_jdversion(); row = *( liststore->append() ); row[ column_name ] = "ディストリビューション"; row[ column_value ] = ENVIRONMENT::get_distname(); row = *( liststore->append() ); row[ column_name ] = "デスクトップ環境等"; row[ column_value ] = ENVIRONMENT::get_wm_str(); row = *( liststore->append() ); row[ column_name ] = "gtkmmのバージョン"; row[ column_value ] = ENVIRONMENT::get_gtkmm_version(); row = *( liststore->append() ); row[ column_name ] = "glibmmのバージョン"; row[ column_value ] = ENVIRONMENT::get_glibmm_version(); row = *( liststore->append() ); row[ column_name ] = "主なオプション"; row[ column_value ] = ENVIRONMENT::get_configure_args( ENVIRONMENT::CONFIGURE_OMITTED ); m_scrollwindow_environment.add( m_treeview_environment ); } // // 動作環境をクリップボードにコピー // void AboutDiag::slot_copy_environment() { std::string jdinfo = ENVIRONMENT::get_jdinfo(); if( ! jdinfo.empty() ) MISC::CopyClipboard( jdinfo ); } jd-2.8.7-140104/src/skeleton/aboutdiag.h0000644000076400010400000000411511122746051014313 0ustar // ライセンス: GPL2 // Gtk::AboutDialog( gtkmm >= 2.6 )の代わりのクラス #ifndef _ABOUTDIAG_H #define _ABOUTDIAG_H #include namespace SKELETON { class AboutDiag : public Gtk::Dialog { Gtk::Notebook m_notebook; // 情報タブ Gtk::Label m_label_tab_info; Gtk::Image m_image_logo; Gtk::Label m_label_version; Gtk::VBox m_vbox_info; Gtk::Label m_label_info; Gtk::Label m_label_comments; Gtk::HBox m_hbox_url; Gtk::Button m_button_website; Gtk::Label m_label_copyright; // ライセンスタブ Gtk::Label m_label_tab_license; Gtk::ScrolledWindow m_scrollwindow_license; Gtk::TextView m_textview_license; // 動作環境タブ Gtk::Label m_label_tab_environment; Gtk::VBox m_vbox_environment; Gtk::HButtonBox m_hbuttonbox_environment; Gtk::Button m_button_copy_environment; Gtk::ScrolledWindow m_scrollwindow_environment; Gtk::TreeView m_treeview_environment; void set_environment_list(); Glib::ustring m_website_url; void init(); void slot_button_website_clicked(); void slot_close_clicked() {} void slot_copy_environment(); public: AboutDiag( const Glib::ustring& title ); ~AboutDiag(){} int run(); void set_logo( const Glib::RefPtr< Gdk::Pixbuf >& logo ); Glib::RefPtr< Gdk::Pixbuf > get_logo(); void set_version( const Glib::ustring& version ); Glib::ustring get_version(); void set_comments( const Glib::ustring& comments ); Glib::ustring get_comments(); void set_website( const Glib::ustring& website ); Glib::ustring get_website(); void set_website_label( const Glib::ustring& website_label ); Glib::ustring get_website_label(); void set_copyright( const Glib::ustring& copyright ); Glib::ustring get_copyright(); void set_license( const Glib::ustring& license ); Glib::ustring get_license(); }; } #endif jd-2.8.7-140104/src/skeleton/admin.cpp0000644000076400010400000023546412177057552014030 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "admin.h" #include "window.h" #include "view.h" #include "dragnote.h" #include "msgdiag.h" #include "tabswitchmenu.h" #include "dbtree/interface.h" #include "jdlib/miscutil.h" #include "jdlib/miscgtk.h" #include "history/historymanager.h" #include "history/viewhistoryitem.h" #include "control/controlutil.h" #include "control/controlid.h" #include "config/globalconf.h" #include "command.h" #include "session.h" #include "global.h" #include "updatemanager.h" #include enum { MAX_TABS = 50 }; // open_view で使うモード enum { OPEN_MODE_AUTO = 1, OPEN_MODE_NOSWITCH = 2, OPEN_MODE_LOCK = 4, OPEN_MODE_OFFLINE = 8, OPEN_MODE_REGET = 16 }; using namespace SKELETON; Admin::Admin( const std::string& url ) : m_url( url ), m_win( NULL ), m_notebook( NULL ), m_focus( false ), m_move_menu( NULL ), m_tabswitchmenu( NULL ), m_use_viewhistory( false ), m_use_switchhistory( false ) { m_notebook = new DragableNoteBook(); m_notebook->signal_switch_page().connect( sigc::mem_fun( *this, &Admin::slot_switch_page ) ); m_notebook->set_scrollable( true ); m_notebook->sig_tab_clicked().connect( sigc::mem_fun( *this, &Admin::slot_tab_clicked ) ); m_notebook->sig_tab_scrolled().connect( sigc::mem_fun( *this, &Admin::slot_tab_scrolled ) ); m_notebook->sig_tab_close().connect( sigc::mem_fun( *this, &Admin::slot_tab_close ) ); m_notebook->sig_tab_reload().connect( sigc::mem_fun( *this, &Admin::slot_tab_reload ) ); m_notebook->sig_tab_menu().connect( sigc::mem_fun( *this, &Admin::slot_tab_menu ) ); m_notebook->get_tabswitch_button().signal_clicked().connect( sigc::mem_fun(*this, &Admin::slot_show_tabswitchmenu ) ); // D&D m_notebook->sig_drag_data_get().connect( sigc::mem_fun(*this, &Admin::slot_drag_data_get ) ); m_list_command.clear(); } Admin::~Admin() { #ifdef _DEBUG std::cout << "Admin::~Admin " << m_url << std::endl; #endif // デストラクタの中からdispatchを呼ぶと落ちるので dispatch不可にする set_dispatchable( false ); const int pages = m_notebook->get_n_pages(); #ifdef _DEBUG std::cout << "pages = " << pages << std::endl; #endif if( pages ){ for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( 0 ) ); m_notebook->remove_page( 0, false ); if( view ) delete view; } } m_list_command.clear(); close_window(); delete_jdwin(); if( m_notebook ) delete m_notebook; if( m_move_menu ) delete m_move_menu; if( m_tabswitchmenu ) delete m_tabswitchmenu; } void Admin::save_session() { std::list< SKELETON::View* > list_view = get_list_view(); std::list< SKELETON::View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); if( view ) view->save_session(); } } // // メニューのセットアップ // void Admin::setup_menu() { // 右クリックメニュー m_action_group = Gtk::ActionGroup::create(); m_action_group->add( Gtk::Action::create( "Quit", "Quit" ), sigc::mem_fun( *this, &Admin::slot_close_tab ) ); m_action_group->add( Gtk::ToggleAction::create( "LockTab", "タブをロックする(_K)", std::string(), false ), sigc::mem_fun( *this, &Admin::slot_lock ) ); m_action_group->add( Gtk::Action::create( "Close_Tab_Menu", "複数のタブを閉じる(_T)" ) ); m_action_group->add( Gtk::Action::create( "CloseOther", "他のタブ(_O)" ), sigc::mem_fun( *this, &Admin::slot_close_other_tabs ) ); m_action_group->add( Gtk::Action::create( "CloseLeft", "左←のタブ(_L)" ), sigc::mem_fun( *this, &Admin::slot_close_left_tabs ) ); m_action_group->add( Gtk::Action::create( "CloseRight", "右→のタブ(_R)" ), sigc::mem_fun( *this, &Admin::slot_close_right_tabs ) ); m_action_group->add( Gtk::Action::create( "CloseAll", "全てのタブ(_A)" ), sigc::mem_fun( *this, &Admin::slot_close_all_tabs ) ); m_action_group->add( Gtk::Action::create( "CloseSameIcon", "同じアイコンのタブ(_I)" ), sigc::mem_fun( *this, &Admin::slot_close_same_icon_tabs ) ); m_action_group->add( Gtk::Action::create( "Reload_Tab_Menu", "全てのタブの再読み込み(_A)" ) ); m_action_group->add( Gtk::Action::create( "CheckUpdateAll", "更新チェックのみ(_U)" ), sigc::mem_fun( *this, &Admin::slot_check_update_all_tabs ) ); m_action_group->add( Gtk::Action::create( "CheckUpdateReloadAll", "更新されたタブを再読み込み(_A)" ), sigc::mem_fun( *this, &Admin::slot_check_update_reload_all_tabs ) ); m_action_group->add( Gtk::Action::create( "ReloadAll", "再読み込み(_R)" ), sigc::mem_fun( *this, &Admin::slot_reload_all_tabs ) ); m_action_group->add( Gtk::Action::create( "CancelReloadAll", "キャンセル(_C)" ), sigc::mem_fun( *this, &Admin::slot_cancel_reload_all_tabs ) ); m_action_group->add( Gtk::Action::create( "OpenBrowser", ITEM_NAME_OPEN_BROWSER "(_W)" ), sigc::mem_fun( *this, &Admin::slot_open_by_browser ) ); m_action_group->add( Gtk::Action::create( "CopyURL", ITEM_NAME_COPY_URL "(_U)" ), sigc::mem_fun( *this, &Admin::slot_copy_url ) ); m_action_group->add( Gtk::Action::create( "CopyTitleURL", ITEM_NAME_COPY_TITLE_URL "(_L)" ), sigc::mem_fun( *this, &Admin::slot_copy_title_url ) ); m_action_group->add( Gtk::Action::create( "Preference", "プロパティ(_P)..."), sigc::mem_fun( *this, &Admin::show_preference ) ); // 戻る、進む m_action_group->add( Gtk::Action::create( "PrevView", "PrevView"), sigc::bind< int >( sigc::mem_fun( *this, &Admin::back_clicked_viewhistory ), 1 ) ); m_action_group->add( Gtk::Action::create( "NextView", "NextView"), sigc::bind< int >( sigc::mem_fun( *this, &Admin::forward_clicked_viewhistory ), 1 ) ); m_ui_manager = Gtk::UIManager::create(); m_ui_manager->insert_action_group( m_action_group ); // ポップアップメニューのレイアウト Glib::ustring str_ui = "" // 通常 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; m_ui_manager->add_ui_from_string( str_ui ); Gtk::Menu* popupmenu = dynamic_cast< Gtk::Menu* >( m_ui_manager->get_widget( "/popup_menu" ) ); Gtk::MenuItem* item; // 移動サブメニュー m_move_menu = new SKELETON::TabSwitchMenu( m_notebook, this ); // 進む、戻る Glib::RefPtr< Gtk::Action > act; act = m_action_group->get_action( "PrevView" ); act->set_accel_group( m_ui_manager->get_accel_group() ); item = Gtk::manage( act->create_menu_item() ); m_move_menu->append( *item ); act = m_action_group->get_action( "NextView" ); act->set_accel_group( m_ui_manager->get_accel_group() ); item = Gtk::manage( act->create_menu_item() ); m_move_menu->append( *item ); m_move_menu->append( *Gtk::manage( new Gtk::SeparatorMenuItem() ) ); // 先頭、最後に移動 item = Gtk::manage( new Gtk::MenuItem( "先頭のタブに移動(_H)", true ) ); m_move_menu->append( *item ); item->signal_activate().connect( sigc::mem_fun( *this, &Admin::tab_head_focus ) ); item = Gtk::manage( new Gtk::MenuItem( "最後のタブに移動(_T)", true ) ); m_move_menu->append( *item ); item->signal_activate().connect( sigc::mem_fun( *this, &Admin::tab_tail_focus ) ); m_move_menu->append( *Gtk::manage( new Gtk::SeparatorMenuItem() ) ); m_move_menuitem = Gtk::manage( new Gtk::MenuItem( "移動" ) ); m_move_menuitem->set_submenu( *m_move_menu ); popupmenu->insert( *m_move_menuitem, 0 ); m_move_menuitem->show_all(); item = Gtk::manage( new Gtk::SeparatorMenuItem() ); popupmenu->insert( *item, 1 ); item->show_all(); // ポップアップメニューにアクセレータを表示 CONTROL::set_menu_motion( popupmenu ); popupmenu->signal_deactivate().connect( sigc::mem_fun( *this, &Admin::slot_popupmenu_deactivate ) ); } void Admin::slot_popupmenu_deactivate() { if( m_move_menu ) m_move_menu->deactivate(); } Gtk::Widget* Admin::get_widget() { return dynamic_cast< Gtk::Widget*>( m_notebook ); } Gtk::Window* Admin::get_win() { return dynamic_cast< Gtk::Window*>( m_win ); } void Admin::delete_jdwin() { if( m_win ){ delete m_win; m_win = NULL; } } const bool Admin::is_booting() { if( get_jdwin() && get_jdwin()->is_booting() ) return true; return ( has_commands() ); } // // ページが含まれていないか // bool Admin::empty() { return ( m_notebook->get_n_pages() == 0 ); } // タブの数 int Admin::get_tab_nums() { if( m_notebook ) return m_notebook->get_n_pages(); return 0; } // // 含まれているページのURLのリスト取得 // const std::list Admin::get_URLs() { std::list urls; const int pages = m_notebook->get_n_pages(); if( pages ){ for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( m_notebook->get_nth_page( i ) ); if( view ) urls.push_back( view->get_url() ); } } return urls; } // // クロック入力 // void Admin::clock_in() { // アクティブなビューにクロックを送る SKELETON::View* view = get_current_view(); if( view ) view->clock_in(); // 全てのビューにクロックを送る // clock_in_always()には軽い処理だけを含めること const int pages = m_notebook->get_n_pages(); if( pages ){ for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< SKELETON::View* >( m_notebook->get_nth_page( i ) ); if( view ) view->clock_in_always(); } } m_notebook->clock_in(); if( m_win ) m_win->clock_in(); } // // コマンド受付(通常) // void Admin::set_command( const std::string& command, const std::string& url, const std::string& arg1, const std::string& arg2, const std::string& arg3, const std::string& arg4, const std::string& arg5, const std::string& arg6, const std::string& arg7, const std::string& arg8 ) { COMMAND_ARGS command_arg; command_arg.command = command; command_arg.url = url; command_arg.arg1 = arg1; command_arg.arg2 = arg2; command_arg.arg3 = arg3; command_arg.arg4 = arg4; command_arg.arg5 = arg5; command_arg.arg6 = arg6; command_arg.arg7 = arg7; command_arg.arg8 = arg8; set_command_impl( false, command_arg ); } // // コマンド受付(即実行) // void Admin::set_command_immediately( const std::string& command, const std::string& url, const std::string& arg1, const std::string& arg2, const std::string& arg3, const std::string& arg4, const std::string& arg5, const std::string& arg6, const std::string& arg7, const std::string& arg8 ) { COMMAND_ARGS command_arg; command_arg.command = command; command_arg.url = url; command_arg.arg1 = arg1; command_arg.arg2 = arg2; command_arg.arg3 = arg3; command_arg.arg4 = arg4; command_arg.arg5 = arg5; command_arg.arg6 = arg6; command_arg.arg7 = arg7; command_arg.arg8 = arg8; set_command_impl( true, command_arg ); } // // コマンド受付 // // immediately = false の場合はすぐにコマンドを実行しないで一旦Dispatcherで // メインスレッドにコマンドを渡してからメインスレッドで実行する。通常は // immediately = false で呼び出して、緊急にコマンドを実行させたい場合は // immediately = true とすること。 // void Admin::set_command_impl( const bool immediately, const COMMAND_ARGS& command_arg ) { #ifdef _DEBUG std::cout << "Admin::set_command : immediately = " << immediately << " command = " << command_arg.command << " url = " << command_arg.url << std::endl << command_arg.arg1 << " " << command_arg.arg2 << std::endl << command_arg.arg3 << " " << command_arg.arg4 << std::endl << command_arg.arg5 << " " << command_arg.arg6 << std::endl << command_arg.arg7 << " " << command_arg.arg8 << std::endl; #endif if( immediately ){ m_list_command.push_front( command_arg ); exec_command(); } else{ m_list_command.push_back( command_arg ); dispatch(); // 一度メインループに戻った後にcallback_dispatch() が呼び戻される } } // // ディスパッチャのコールバック関数 // void Admin::callback_dispatch() { while( m_list_command.size() ) exec_command(); } // // コマンド実行 // void Admin::exec_command() { if( m_list_command.size() == 0 ) return; COMMAND_ARGS command = m_list_command.front(); m_list_command.pop_front(); // コマンドリストが空になったことをcoreに知らせる if( m_list_command.size() == 0 ) CORE::core_set_command( "empty_command", m_url ); #ifdef _DEBUG std::cout << "Admin::exec_command " << m_url << " : " << command.command << " " << command.url << " " << std::endl << command.arg1 << " " << command.arg2 << std::endl << command.arg3 << " " << command.arg4 << std::endl << command.arg5 << " " << command.arg6 << std::endl; #endif // 前回終了時の状態を回復 if( command.command == "restore" ){ restore( ( command.arg1 == "only_locked" ) ); } // 移転などでホストの更新 else if( command.command == "update_url" ){ update_url( command.url, command.arg1 ); } // 板名更新 else if( command.command == "update_boardname" ){ update_boardname( command.url ); } // viewを開く else if( command.command == "open_view" ){ open_view( command ); } // リストで開く // arg1 にはdatファイルを空白で区切って指定する // else if( command.command == "open_list" ){ open_list( command ); } else if( command.command == "switch_view" ){ switch_view( command.url ); } else if( command.command == "reload_view" ){ reload_view( command.url ); } else if( command.command == "tab_left" ){ tab_left( false ); } else if( command.command == "tab_right" ){ tab_right( false ); } else if( command.command == "tab_left_updated" ){ tab_left( true ); } else if( command.command == "tab_right_updated" ){ tab_right( true ); } else if( command.command == "tab_num" ){ tab_num( command.arg1 ); } else if( command.command == "tab_head" ){ tab_head(); } else if( command.command == "tab_tail" ){ tab_tail(); } else if( command.command == "set_tab_operating" ){ #ifdef _DEBUG std::cout << command.command << " " << m_url << " " << command.arg1 << std::endl; #endif if( command.arg1 == "true" ) SESSION::set_tab_operating( m_url, true ); else{ SESSION::set_tab_operating( m_url, false ); if( ! empty() ){ // 現在開いているタブへの switch 処理 const bool focus_tmp = m_focus; m_focus = true; slot_switch_page( NULL, m_notebook->get_current_page() ); m_focus = focus_tmp; } } } else if( command.command == "redraw" ){ redraw_view( command.url ); } else if( command.command == "redraw_current_view" ){ redraw_current_view(); } else if( command.command == "relayout_current_view" ){ relayout_current_view(); } // command.url を含むview全てを検索して表示中なら再描画 else if( command.command == "redraw_views" ){ redraw_views( command.url ); } else if( command.command == "update_view" ){ // ビュー全体を更新 update_view( command.url ); } else if( command.command == "update_item" ){ // ビューの一部を更新 update_item( command.url, command.arg1 ); } else if( command.command == "update_finish" ){ update_finish( command.url ); } // 全ロック解除 else if( command.command == "unlock_views" ){ unlock_all_view( command.url ); } // ビューを閉じる else if( command.command == "close_view" ){ if( command.arg1 == "closeall" ) close_all_view( command.url ); // command.url を含むタブを全て閉じる else if( command.arg1 == "closealltabs" ) slot_close_all_tabs(); // 全て閉じる else if( command.arg1 == "closeother" ) close_other_views( command.url ); else close_view( command.url ); } else if( command.command == "close_currentview" ){ close_current_view(); } // 最後に閉じたタブを復元する else if( command.command == "restore_lasttab" ){ restore_lasttab(); } else if( command.command == "set_page" ){ set_current_page( atoi( command.arg1.c_str() ) ); } // フォーカスイン、アウト else if( command.command == "focus_current_view" ){ m_focus = true; focus_current_view(); } else if( command.command == "focus_out" ){ m_focus = false; focus_out(); } else if( command.command == "restore_focus" ){ m_focus = true; restore_focus(); } // adminクラスを前面に出す else if( command.command == "switch_admin" ){ switch_admin(); } // タブに文字をセット、タブ幅調整 else if( command.command == "set_tablabel" ){ set_tablabel( command.url, command.arg1 ); } else if( command.command == "adjust_tabwidth" ){ m_notebook->adjust_tabwidth(); } // 全てのビューを再描画 else if( command.command == "relayout_all" ) relayout_all(); // タイトル表示 // アクティブなviewから依頼が来たらコアに渡す else if( command.command == "set_title" ){ const bool force = ( command.arg2 == "force" ); set_title( command.url, command.arg1, force ); } // ステータス表示 // アクティブなviewから依頼が来たらコアに渡す else if( command.command == "set_status" ){ const bool force = ( command.arg2 == "force" ); set_status( command.url, command.arg1, force ); } // ステータスの色を変える else if( command.command == "set_status_color" ){ const bool force = ( command.arg2 == "force" ); set_status_color( command.url, command.arg1, force ); } // マウスジェスチャ else if( command.command == "set_mginfo" ){ if( m_win ) m_win->set_mginfo( command.arg1 ); } // 全タブオートリロード else if( command.command == "reload_all_tabs" ){ reload_all_tabs(); } // 全タブ更新チェックして開く else if( command.command == "check_update_reload_all_tabs" ){ check_update_all_tabs( true ); } // オートリロードのキャンセル else if( command.command == "cancel_reload" ){ slot_cancel_reload_all_tabs(); } // タブを隠す else if( command.command == "hide_tabs" ) m_notebook->set_show_tabs( false ); // window 開け閉じ else if( command.command == "open_window" ){ open_window(); return; } else if( command.command == "close_window" ){ close_window(); return; } // ツールバーの検索ボックスをフォーカス else if( command.command == "focus_toolbar_search" ){ focus_toolbar_search(); } // ツールバー表示/非表示切り替え else if( command.command == "toggle_toolbar" ){ toggle_toolbar(); } // ツールバーのアドレスを更新 else if( command.command == "update_toolbar_url" ){ m_notebook->update_toolbar_url( command.url, command.arg1 ); } // ツールバーのラベルを更新 else if( command.command == "redraw_toolbar" ){ redraw_toolbar(); } // ツールバーボタン表示更新 else if( command.command == "update_toolbar_button" ){ update_toolbar_button(); } // 検索バー表示 else if( command.command == "open_searchbar" ){ open_searchbar(); } // 検索バー非表示 else if( command.command == "close_searchbar" ){ close_searchbar(); } // タブ表示切り替え else if( command.command == "toggle_tab" ){ toggle_tab(); } // アイコン表示切り替え else if( command.command == "toggle_icon" ){ toggle_icon( command.url ); } // window 開け閉じ可能/不可 else if( command.command == "enable_fold_win" ){ if( get_jdwin() ) get_jdwin()->set_enable_fold( true ); } else if( command.command == "disable_fold_win" ){ if( get_jdwin() ) get_jdwin()->set_enable_fold( false ); } // プロパティ表示 else if( command.command == "show_preferences" ){ SKELETON::View* view = get_view( command.url ); if( view ) view->show_preference(); } else if( command.command == "show_current_preferences" ){ SKELETON::View* view = get_current_view(); if( view ) view->show_preference(); } // View履歴:戻る else if( command.command == "back_viewhistory" ){ back_viewhistory( command.url, atoi( command.arg1.c_str() ) ); } // View履歴:進む else if( command.command == "forward_viewhistory" ){ forward_viewhistory( command.url, atoi( command.arg1.c_str() ) ); } // View履歴削除 else if( command.command == "clear_viewhistory" ){ clear_viewhistory(); } // オートリロード開始 else if( command.command == "start_autoreload" ){ int mode = AUTORELOAD_ON; if( command.arg1 == "once" ) mode = AUTORELOAD_ONCE; int sec = atoi( command.arg2.c_str() ); set_autoreload_mode( command.url, mode, sec ); } // オートリロード停止 else if( command.command == "stop_autoreload" ){ set_autoreload_mode( command.url, AUTORELOAD_NOT, 0 ); } // ポップアップを隠す(インスタンスは削除しない) else if( command.command == "hide_popup" ) hide_popup(); else{ // ツールバー関係 SKELETON::View* view = get_view( command.url ); if( view && command.command == "toolbar_exec_search" ) view->exec_search(); else if( view && command.command == "toolbar_operate_search" ) view->operate_search( command.arg1 ); else if( view && command.command == "toolbar_set_search_query" ) view->set_search_query( command.arg1 ); if( view && command.command == "toolbar_up_search" ) view->up_search(); if( view && command.command == "toolbar_down_search" ) view->down_search(); else if( view && command.command == "toolbar_write" ) view->write(); else if( view && command.command == "toolbar_reload" ) view->reload(); else if( view && command.command == "toolbar_stop" ) view->stop(); else if( view && command.command == "toolbar_close_view" ) view->close_view(); else if( view && command.command == "toolbar_delete_view" ) view->delete_view(); else if( view && command.command == "toolbar_set_favorite" ) view->set_favorite(); // ロック/アンロック else if( view && command.command == "toolbar_lock_view" ){ if( view->is_locked() ) unlock( get_current_page() ); else lock( get_current_page() ); } // 子クラス別のコマンド処理 else command_local( command ); } } // リストで与えられたページをタブで連続して開く // // 連続してリロードかけるとサーバに負担をかけるので、オフラインで開いて // タイミングをずらしながらリロードする // void Admin::open_list( const COMMAND_ARGS& command_list ) { #ifdef _DEBUG std::cout << "Admin::open_list " << m_url << std::endl; #endif const std::string& str_list = command_list.arg1; std::list< std::string > list_url = MISC::split_line( str_list ); if( list_url.empty() ) return; int waittime = 0; const bool online = SESSION::is_online(); SESSION::set_tab_operating( m_url, true ); std::list< std::string >::iterator it = list_url.begin(); for( ; it != list_url.end(); ++it, waittime += AUTORELOAD_MINSEC ){ // 各admin別の引数をセット COMMAND_ARGS command_arg = get_open_list_args( ( *it ), command_list ); // 共通の引数をセット command_arg.command = "open_view"; command_arg.url = (*it); command_arg.arg1 = "true"; // タブで開く command_arg.arg2 = "false"; // 既に開いているかチェック command_arg.arg3 = "noswitch"; // タブを切り替えない if( ! command_list.arg2.empty() ) command_arg.arg3 += " " + command_list.arg2; #ifdef _DEBUG std::cout << "url = " << command_arg.url << std::endl; #endif open_view( command_arg ); // 一番最初のページは普通にオンラインで開く // 二番目からは ウェイトを入れてリロード if( online ){ if( !waittime ) SESSION::set_online( false ); else set_autoreload_mode( command_arg.url, AUTORELOAD_ONCE, waittime ); } } SESSION::set_online( online ); set_command( "set_tab_operating", "", "false" ); switch_admin(); switch_view( *( list_url.begin() ) ); } // // 移転などでviewのurlを更新 // void Admin::update_url( const std::string& url_old, const std::string& url_new ) { #ifdef _DEBUG std::cout << "Admin::update_url " << url_old << " -> " << url_new << std::endl; #endif const int pages = m_notebook->get_n_pages(); if( pages ){ for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view && view->get_url().find( url_old ) == 0 ){ std::list< std::string >::iterator it = std::find( m_list_switchhistory.begin(), m_list_switchhistory.end(), view->get_url() ); view->update_url( url_old, url_new ); if( it != m_list_switchhistory.end() ) (*it) = view->get_url(); } } } } // // urlを含むviewの板名を更新 // void Admin::update_boardname( const std::string& url ) { #ifdef _DEBUG std::cout << "Admin::update_boardname url = " << url << std::endl; #endif const int pages = m_notebook->get_n_pages(); if( pages ){ for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view && view->get_url().find( url ) == 0 ) view->update_boardname(); } redraw_toolbar(); } } // // URLやステータスを更新 // void Admin::update_status( View* view, const bool force ) { if( view ){ set_title( view->get_url(), view->get_title(), force ); set_url( view->get_url(), view->url_for_copy(), force ); set_status( view->get_url(), view->get_status(), force ); set_status_color( view->get_url(), view->get_color(), force ); } } // // ビューを開く // // command.arg1: 開く位置 // // "false" ならアクティブなタブを置き換える ( デフォルト ) // "true" なら一番右側に新しいタブを開く // "right" ならアクティブなタブの右に開く // "newtab" なら設定によってアクティブなタブの右に開くか一番右側に開くか切り替える // "left" ならアクティブなタブの左に開く // "page数字" なら指定した位置にタブで開く // "replace" なら arg3 に指定したタブがあれば置き換え、なければ "newtab" で動作する // // command.arg2: "true" なら既に command.url を開いているかチェックしない // // command.arg3: モード ( 複数指定する場合は空白で空ける ) // // "auto"なら表示されていればリロードせずに切替える // されていなければarg1で指定した場所に新しいタブで開いてロード // スレ番号ジャンプなどで使用する // "noswitch"ならタブを切り替えない(連続して開くときに使用) // "lock" なら開いてからロックする // "offline" なら オフラインで開く // "reget" なら読み込み時にキャッシュ等を消してから再読み込みする // "boardnext" など、 "replace" で置き換えるタブの種類を指定する // // その他のargは各ビュー別の設定 // void Admin::open_view( const COMMAND_ARGS& command ) { #ifdef _DEBUG std::cout << "Admin::open_view : " << command.url << std::endl << "arg1 = " << command.arg1 << std::endl << "arg2 = " << command.arg2 << std::endl << "arg3 = " << command.arg3 << std::endl; #endif SKELETON::View* view; SKELETON::View* current_view = get_current_view(); const bool online = SESSION::is_online(); const bool nocheck_opened = ( command.arg2 == "true" ); int mode = 0; if( ! command.arg3.empty() ){ if( command.arg3.find( "auto" ) != std::string::npos ) mode |= OPEN_MODE_AUTO; if( command.arg3.find( "noswitch" ) != std::string::npos ) mode |= OPEN_MODE_NOSWITCH; if( command.arg3.find( "lock" ) != std::string::npos ) mode |= OPEN_MODE_LOCK; if( command.arg3.find( "offline" ) != std::string::npos ) mode |= OPEN_MODE_OFFLINE; if( command.arg3.find( "reget" ) != std::string::npos ) mode |= OPEN_MODE_REGET; } if( current_view ) current_view->focus_out(); // urlを既に開いていたら表示してリロード if( ! nocheck_opened ){ view = get_view( command_to_url( command ) ); if( view ){ // タブの切り替え if( ! ( mode & OPEN_MODE_NOSWITCH ) ){ int page = m_notebook->page_num( *view ); #ifdef _DEBUG std::cout << "page = " << page << std::endl; #endif set_current_page( page ); switch_admin(); } // オートモードは切り替えのみ if( mode & OPEN_MODE_AUTO ) return; // ロック if( mode & OPEN_MODE_LOCK ) lock( m_notebook->page_num( *view ) ); // オフラインで開く if( mode & OPEN_MODE_OFFLINE ) SESSION::set_online( false ); // ロード時にキャッシュを削除してからスレを再読み込みする if( mode & OPEN_MODE_REGET ) view->set_reget( true ); view->show_view(); SESSION::set_online( online ); return; } } // 開く位置の基準を、アクティブなタブに仮定 int page = m_notebook->get_current_page(); std::string open_method = command.arg1; if( open_method.empty() ){ open_method = "false"; } // 置き替えるページを探す if( open_method == "replace" ){ // 該当するタブが見つからない場合のために、新しいタブで開くモードに仮設定 open_method = "newtab"; // タブの種類 (command.arg3) に該当するタブを探す int find_page = find_view( command.arg3 ); #ifdef _DEBUG std::cout << "replace mode = " << command.arg3 << " page = " << page << " find = " << find_page << std::endl; #endif if( find_page >= 0 ){ SKELETON::View* found_view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( found_view ){ // 指定したタブを置き換えるモードに設定 open_method = "false"; // 開く位置の基準を、見つかったタブに設定 page = find_page; current_view = found_view; } } } view = create_view( command ); if( !view ) return; const bool open_tab = ( page == -1 || open_method != "false" || ( mode & OPEN_MODE_AUTO ) // オートモードの時もタブで開く || is_locked( page ) ); // ツールバー表示 if( page == -1 ) show_toolbar(); // タブで表示 if( open_tab ){ int openpage = -1; // 現在のページの右に表示 if( open_method == "right" ) openpage = page +1; // 設定によって切り替える if( open_method == "newtab" ){ switch( CONFIG::get_newtab_pos() ){ case 1: openpage = page +1; break; case 2: openpage = page; break; } } // 現在のページの左に表示 else if( open_method == "left" ) openpage = page; // 指定した位置に表示 else if( open_method.find( "page" ) == 0 ) openpage = atoi( open_method.c_str() + 4 ); // ロックされていたら右に表示 else if( open_method != "true" && page != -1 && is_locked( page ) ) openpage = page +1; #ifdef _DEBUG std::cout << "append openpage = " << openpage << " / page = " << page << std::endl; #endif if( page != -1 ) m_notebook->insert_page( command.url, *view, openpage ); // 最後に表示 else m_notebook->append_page( command.url, *view ); if( m_use_viewhistory ){ if( m_last_closed_url.empty() ) HISTORY::get_history_manager()->create_viewhistory( view->get_url() ); // 直前に閉じたViewの履歴を次に開いたViewに引き継ぐ else{ HISTORY::get_history_manager()->append_viewhistory( m_last_closed_url, view->get_url() ); m_last_closed_url = std::string(); } } } // 開いてるviewを消してその場所に表示 else{ #ifdef _DEBUG std::cout << "replace page\n"; #endif // タブを入れ替えたときに隣のタブの再描画を防ぐ set_command_immediately( "set_tab_operating", "", "true" ); // タブ入れ替え m_notebook->insert_page( command.url, *view, page ); m_notebook->remove_page( page + 1, false ); if( current_view ){ const std::string url_current = current_view->get_url(); delete current_view; remove_switchhistory( url_current ); if( m_use_viewhistory ){ // Aを開く -> B をタブで開く -> A を閉じる -> A を開いて B と置き換える(*) -> B をタブで開く // とすると、History_Manager::get_viewhistory()のキャッシュが誤作動して // ビューの戻る進むが変になるので、(*)の所で進む戻るの履歴を引き継ぐのをキャンセルする if( ! m_last_closed_url.empty() && view->get_url() == m_last_closed_url ){ HISTORY::get_history_manager()->delete_viewhistory( m_last_closed_url ); m_last_closed_url = std::string(); } HISTORY::get_history_manager()->append_viewhistory( url_current, view->get_url() ); } } #ifdef _DEBUG std::cout << "replace done\n"; #endif set_command( "set_tab_operating", "", "false" ); } m_notebook->show_all(); view->show(); // オフラインで開く if( mode & OPEN_MODE_OFFLINE ) SESSION::set_online( false ); // ロード時にキャッシュを削除してからスレを再読み込みする if( mode & OPEN_MODE_REGET ) view->set_reget( true ); view->show_view(); SESSION::set_online( online ); // ツールバーの情報更新 m_notebook->set_current_toolbar( view->get_id_toolbar(), view ); // タブの切り替え if( ! ( mode & OPEN_MODE_NOSWITCH ) ){ switch_admin(); set_current_page( m_notebook->page_num( *view ) ); } // ロック if( mode & OPEN_MODE_LOCK ) lock( m_notebook->page_num( *view ) ); } // // ツールバーの検索ボックスをフォーカス // void Admin::focus_toolbar_search() { m_notebook->focus_toolbar_search(); } // // ツールバー表示更新 // void Admin::redraw_toolbar() { SKELETON::View* view = get_current_view(); if( view ) m_notebook->set_current_toolbar( view->get_id_toolbar(), view ); } // // ツールバーのボタン表示更新 // void Admin::update_toolbar_button() { m_notebook->update_toolbar_button(); redraw_toolbar(); } // // ビュー切り替え // // 指定したURLのビューに切り替える // void Admin::switch_view( const std::string& url ) { SKELETON::View* view = get_view( url ); if( view ){ int page = m_notebook->page_num( *view ); set_current_page( page ); } } // // 指定したURLのビューを再読み込み // void Admin::reload_view( const std::string& url ) { SKELETON::View* view = get_view( url ); if( view ) view->reload(); } // // タブ左移動 // // updated == true の時は更新されたタブに移動 // void Admin::tab_left( const bool updated ) { const int pages = m_notebook->get_n_pages(); if( pages == 1 ) return; int page = m_notebook->get_current_page(); if( page == -1 ) return; #ifdef _DEBUG std::cout << "Admin::tab_left updated << " << updated << " page = " << page; #endif for( int i = 0; i < pages ; ++i ){ --page; if( page < 0 ) page = pages -1; if( ! updated ) break; SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( ! view ) return; // updated アイコンが表示されているタブを見つける if( get_notebook()->get_tabicon( page ) == view->get_icon( "updated" ) ) break; } #ifdef _DEBUG std::cout << " -> " << page << std::endl; #endif if( page != m_notebook->get_current_page() ) set_current_page( page ); } // // タブ右移動 // // updated == true の時は更新されたタブに移動 // void Admin::tab_right( const bool updated ) { const int pages = m_notebook->get_n_pages(); if( pages == 1 ) return; int page = m_notebook->get_current_page(); if( page == -1 ) return; #ifdef _DEBUG std::cout << "Admin::tab_right updated << " << updated << " page = " << page; #endif for( int i = 0; i < pages; ++i ){ ++page; if( page >= pages ) page = 0; if( ! updated ) break; SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( ! view ) return; // updated アイコンが表示されているタブを見つける if( get_notebook()->get_tabicon( page ) == view->get_icon( "updated" ) ) break; } #ifdef _DEBUG std::cout << " -> " << page << std::endl; #endif if( page != m_notebook->get_current_page() ) set_current_page( page ); } // // タブ位置(1-9)で移動 // void Admin::tab_num( const std::string& str_num ) { if( str_num.empty() ) return; const int num = strtol( str_num.c_str(), NULL, 10 ); // Firefoxの動作に合わせた // 0 → 無視 // 8以下で存在する数より多い → 無視 // 9(存在しない) → 最後のタブ if ( num < 1 || num > 9 || ( num < 9 && num > get_tab_nums() ) ) return; // 9は存在しなくてもそのまま渡してしまう set_current_page( num - 1 ); } // // タブ先頭移動 // void Admin::tab_head() { const int pages = m_notebook->get_n_pages(); if( pages == 1 ) return; set_current_page( 0 ); } // // フォーカスしてタブ先頭移動 // void Admin::tab_head_focus() { if( ! m_focus ) switch_admin(); tab_head(); } // // タブ最後に移動 // void Admin::tab_tail() { const int pages = m_notebook->get_n_pages(); if( pages == 1 ) return; set_current_page( pages-1 ); } // // タブ最後に移動 // void Admin::tab_tail_focus() { if( ! m_focus ) switch_admin(); tab_tail(); } // // ビューを再描画 // void Admin::redraw_view( const std::string& url ) { #ifdef _DEBUG std::cout << "Admin::redraw_view : " << m_url << " : url = " << url << std::endl; #endif SKELETON::View* view = get_view( url ); if( view ) view->redraw_view(); } // // 現在のビューを再描画 // void Admin::redraw_current_view() { #ifdef _DEBUG std::cout << "Admin::redraw_current_view : " << m_url << std::endl; #endif SKELETON::View* view = get_current_view(); if( view ) view->redraw_view(); } // // 現在のビューを再レイアウト // void Admin::relayout_current_view() { #ifdef _DEBUG std::cout << "Admin::relayout_current_view : " << m_url << std::endl; #endif SKELETON::View* view = get_current_view(); if( view ) view->relayout(); } // // urlを含むビューを検索してそれがカレントならば再描画 // void Admin::redraw_views( const std::string& url ) { #ifdef _DEBUG std::cout << "Admin::redraw_view : " << m_url << " : url = " << url << std::endl; #endif SKELETON::View* current_view = get_current_view(); std::list< SKELETON::View* > list_view = get_list_view( url ); std::list< SKELETON::View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ if( ( *it ) == current_view ) ( *it )->redraw_view(); } } // // ビューを閉じる // void Admin::close_view( const std::string& url ) { #ifdef _DEBUG std::cout << "Admin::close_view : " << url << std::endl; #endif SKELETON::View* view = get_view( url ); close_view( view ); } void Admin::close_view( SKELETON::View* view ) { if( !view ) return; int page = m_notebook->page_num( *view ); int current_page = m_notebook->get_current_page(); if( is_locked( page ) ) return; remove_switchhistory( view->get_url() ); if( page == current_page ){ // その前に開いていたビューに切り替える const std::string hist_url = get_valid_switchhistory(); if( ! hist_url.empty() ) switch_view( hist_url ); // もし現在表示中のビューを消すときは予めひとつ右のビューにスイッチしておく // そうしないと左のビューを一度表示してしまうので遅くなる else{ SKELETON::View* newview = dynamic_cast< View* >( m_notebook->get_nth_page( page + 1 ) ); if( newview ) switch_view( newview->get_url() ); } } m_notebook->remove_page( page, true ); if( m_use_viewhistory ){ // 直前に閉じたViewの履歴を次に開いたViewに引き継ぐ if( ! m_last_closed_url.empty() ) HISTORY::get_history_manager()->delete_viewhistory( m_last_closed_url ); m_last_closed_url = view->get_url(); } delete view; #ifdef _DEBUG std::cout << "Admin::close_view : delete page = " << page << std::endl; #endif // 全てのビューが無くなったらコアに知らせる if( empty() ){ #ifdef _DEBUG std::cout << "empty\n"; #endif m_notebook->hide_toolbar(); CORE::core_set_command( "empty_page", m_url ); } } // // url を含むビューを全てアンロック // void Admin::unlock_all_view( const std::string& url ) { #ifdef _DEBUG std::cout << "Admin::unlock_all_view : " << url << std::endl; #endif std::list< View* > list_view = get_list_view( url ); std::list< View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); if( view && view->is_locked() ){ view->unlock(); redraw_toolbar(); } } } // // url を含むビューを全て閉じる // void Admin::close_all_view( const std::string& url ) { #ifdef _DEBUG std::cout << "Admin::close_all_view : " << url << std::endl; #endif std::list< View* > list_view = get_list_view( url ); std::list< View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); close_view( view ); } } // // url 以外のビューを全て閉じる // void Admin::close_other_views( const std::string& url ) { const int pages = m_notebook->get_n_pages(); for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view && view->get_url() != url ) set_command( "close_view", view->get_url() ); } } // // 現在のビューを閉じる // void Admin::close_current_view() { #ifdef _DEBUG std::cout << "Admin::close_current_view : " << m_url << std::endl; #endif SKELETON::View* view = get_current_view(); if( view ) close_view( view->get_url() ); } // // ビューを更新する // void Admin::update_view( const std::string& url ) { #ifdef _DEBUG std::cout << "Admin::update_view : " << url << std::endl; #endif SKELETON::View* view = get_view( url ); if( view ) view->update_view(); } // // ビューの一部(例えばBoardViewなら行など)を更新 // void Admin::update_item( const std::string& url, const std::string& id ) { #ifdef _DEBUG std::cout << "Admin::update_item : " << url << " " << id << std::endl; #endif std::list< SKELETON::View* > list_view = get_list_view(); std::list< SKELETON::View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); if( view ) view->update_item( url, id ); } } // // ビューに更新終了を知らせる // // update_view はデータロード時などの更新途中でも呼び出されるが // update_finish は最後に一度だけ呼び出される // void Admin::update_finish( const std::string& url ) { #ifdef _DEBUG std::cout << "Admin::update_finish : " << url << std::endl; #endif SKELETON::View* view = get_view( url ); if( view ) view->update_finish(); } // // タイトル表示 // void Admin::set_title( const std::string& url, const std::string& title, const bool force ) { if( m_win ) m_win->set_title( "JD - " + title ); else{ SKELETON::View* view = get_current_view(); if( view ){ // アクティブなviewからコマンドが来たら表示する if( force || ( m_focus && view->get_url() == url ) ) CORE::core_set_command( "set_title", url, title ); } } } // // URLバーにアドレス表示 // void Admin::set_url( const std::string& url, const std::string& url_show, const bool force ) { if( m_win ){} else{ SKELETON::View* view = get_current_view(); if( view ){ // アクティブなviewからコマンドが来たら表示する if( force || ( m_focus && view->get_url() == url ) ){ CORE::core_set_command( "set_url", url_show ); // ツリービューのURLを選択 if( CONFIG::get_select_item_sync() != 0 ){ CORE::core_set_command( "select_sidebar_item", url ); CORE::core_set_command( "select_board_item", url ); } } } } } // // ステータス表示 // // virtual void Admin::set_status( const std::string& url, const std::string& stat, const bool force ) { if( m_win ) m_win->set_status( stat ); else{ SKELETON::View* view = get_current_view(); if( view ){ // アクティブなviewからコマンドが来たら表示する if( force || ( m_focus && view->get_url() == url ) ){ CORE::core_set_command( "set_status", url, stat ); CORE::core_set_command( "set_mginfo", "", "" ); } } } } // // ステータスの色を変える // void Admin::set_status_color( const std::string& url, const std::string& color, const bool force ) { if( m_win ) m_win->set_status_color( color ); else{ SKELETON::View* view = get_current_view(); if( view ){ // アクティブなviewからコマンドが来たら色を変える if( force || ( m_focus && view->get_url() == url ) ){ CORE::core_set_command( "set_status_color", url, color ); } } } } // // フォーカスする // // タイトルやURLバーやステータス表示も更新する // void Admin::focus_view( int page ) { #ifdef _DEBUG std::cout << "Admin::focus_view : " << m_url << " page = " << page << std::endl; #endif if( m_win ) m_win->focus_in(); SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( view ) { view->focus_view(); update_status( view, false ); } } // // 現在のviewをフォーカスする // void Admin::focus_current_view() { if( ! m_focus ) return; #ifdef _DEBUG std::cout << "Admin::focus_current_view : " << m_url << std::endl; #endif int page = m_notebook->get_current_page(); focus_view( page ); } // // フォーカスアウトしたあとにフォーカス状態を回復する // // focus_current_view()と違ってURLバーやステータスを再描画しない // void Admin::restore_focus() { #ifdef _DEBUG std::cout << "Admin::restore_focus : " << m_url << std::endl; #endif int page = m_notebook->get_current_page(); SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( view ) view->focus_view(); } // // 現在のviewをフォーカスアウトする // メインウィンドウがフォーカスアウトしたときなどに呼ばれる // void Admin::focus_out() { #ifdef _DEBUG std::cout << "Admin::focus_out : " << m_url << std::endl; #endif // ウィンドウ表示の時、ビューが隠れないようにフォーカスアウトする前に transient 指定をしておく if( get_jdwin() ) get_jdwin()->set_transient( true ); SKELETON::View* view = get_current_view(); if( view ) view->focus_out(); m_notebook->focus_out(); } // // タブラベル更新 // void Admin::set_tablabel( const std::string& url, const std::string& str_label ) { #ifdef _DEBUG std::cout << "Admin::set_tablabel : " << url << std::endl; #endif SKELETON::View* view = get_view( url ); if( view ){ m_notebook->set_tab_fulltext( str_label, m_notebook->page_num( *view ) ); // View履歴のタイトルも更新 if( m_use_viewhistory ){ HISTORY::get_history_manager()->replace_current_title_viewhistory( view->get_url(), str_label ); } } } // // 再レイアウト実行 // void Admin::relayout_all() { std::list< SKELETON::View* > list_view = get_list_view(); std::list< SKELETON::View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); if( view ) view->relayout(); } } // // タブ表示切り替え // void Admin::toggle_tab() { if( m_notebook->get_show_tabs() ) m_notebook->set_show_tabs( false ); else m_notebook->set_show_tabs( true ); } // // アイコン表示切り替え // void Admin::toggle_icon( const std::string& url ) { #ifdef _DEBUG std::cout << "Admin::toggle_icon url = " << url << std::endl; #endif SKELETON::View* view = get_view( url ); if( view ){ std::string iconname = "default"; // まだロード中 if( view->is_loading() ) iconname = "loading"; // オートリロードモードでロード待ち else if( view->get_autoreload_mode() != AUTORELOAD_NOT ) iconname = "loading_stop"; // 古い else if( view->is_old() ) iconname = "old"; // 更新チェックして更新可能 ( 更新はしていない ) else if( view->is_check_update() ) iconname = "update"; // 更新済み ( HTTP_OK 又は HTTP_PARTIAL_CONTENT ) else if( view->is_updated() ){ // タブがアクティブの時は通常アイコンを表示 if( get_notebook()->page_num( *view ) == get_notebook()->get_current_page() ) iconname = "default"; else iconname = "updated"; } #ifdef _DEBUG std::cout << "name = " << iconname << std::endl; #endif const int id = view->get_icon( iconname ); get_notebook()->set_tabicon( iconname, get_notebook()->page_num( *view ), id ); if( m_move_menu ) m_move_menu->update_icons(); if( m_tabswitchmenu ) m_tabswitchmenu->update_icons(); } } // // オートリロードのモード設定 // // 成功したらtrueを返す // // mode : モード (global.h 参照) // sec : リロードまでの秒数 // bool Admin::set_autoreload_mode( const std::string& url, int mode, int sec ) { SKELETON::View* view = get_view( url ); if( view ){ if( mode == AUTORELOAD_NOT && view->get_autoreload_mode() == AUTORELOAD_NOT ) return false; view->set_autoreload_mode( mode, sec ); // モード設定が成功したらアイコン変更 if( view->get_autoreload_mode() == mode ){ toggle_icon( view->get_url() ); return true; } } return false; } // ポップアップを隠す(インスタンスは削除しない) void Admin::hide_popup() { SKELETON::View* view = get_current_view(); if( view ) view->set_command( "hide_popup" ); } // // ビュークラス取得 // View* Admin::get_view( const std::string& url ) { SKELETON::View* view = get_current_view(); if( view && view->get_url() == url ) return view; const int pages = m_notebook->get_n_pages(); if( pages ){ for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view && view->get_url() == url ) return view; } } return NULL; } // // ビュークラスのリスト取得 // // url を含むビューのリストを返す // std::list< View* > Admin::get_list_view( const std::string& url ) { std::list< View* > list_view; const int pages = m_notebook->get_n_pages(); if( pages ){ for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view && view->get_url().find ( url ) != std::string::npos ) list_view.push_back( view ); } } return list_view; } // // 全てのビュークラスのリスト取得 // // std::list< View* > Admin::get_list_view() { std::list< View* > list_view; const int pages = m_notebook->get_n_pages(); if( pages ){ for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view ) list_view.push_back( view ); } } return list_view; } // // 現在表示されているビュークラス取得 // View* Admin::get_current_view() { int page = m_notebook->get_current_page(); if( page == -1 ) return NULL; SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); return view; } // // 指定したページに表示切替え // void Admin::set_current_page( const int page ) { m_notebook->set_current_page( page ); } // // フォーカスしてから指定したページに表示切替え // void Admin::set_current_page_focus( const int page ) { if( ! m_focus ) switch_admin(); m_notebook->set_current_page( page ); } // // 現在表示されているページ番号 // int Admin::get_current_page() { return m_notebook->get_current_page(); } // // 現在表示されているページのURL // const std::string Admin::get_current_url() { SKELETON::View* view = get_current_view(); if( ! view ) return std::string(); return view->get_url(); } // // notebookのタブのページが切り替わったら呼ばれるslot // void Admin::slot_switch_page( GtkNotebookPage*, guint page ) { // 起動中とシャットダウン中は処理しない if( SESSION::is_booting() ) return; if( SESSION::is_quitting() ) return; // タブ操作中 if( SESSION::is_tab_operating( m_url ) ) return; #ifdef _DEBUG std::cout << "Admin::slot_switch_page : " << m_url << " page = " << page << " focus = " << m_focus << std::endl; #endif SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( view ){ #ifdef _DEBUG std::cout << "url = " << view->get_url() << std::endl; #endif // ツールバー表示切り替え m_notebook->set_current_toolbar( view->get_id_toolbar(), view ); // タブのアイコンを通常に戻して再描画 toggle_icon( view->get_url() ); view->redraw_view(); if( m_focus ){ update_status( view, false ); focus_current_view(); } append_switchhistory( view->get_url() ); CORE::core_set_command( "page_switched", m_url, view->get_url() ); } } // // タブをクリックした // void Admin::slot_tab_clicked( const int page ) { #ifdef _DEBUG std::cout << "Admin::slot_tab_clicked " << page << std::endl; #endif if( ! m_focus ) switch_admin(); } // タブの上でホイールを回した void Admin::slot_tab_scrolled( GdkEventScroll* event ) { #ifdef _DEBUG std::cout << "Admin::slot_tab_scrolled\n"; #endif if( ! m_focus ) switch_admin(); } // // タブを閉じる // void Admin::slot_tab_close( const int page ) { #ifdef _DEBUG std::cout << "Admin::slot_tab_close " << page << std::endl; #endif // 閉じる SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( view ) close_view( view->get_url() ); } // // タブ再読み込み // void Admin::slot_tab_reload( const int page ) { #ifdef _DEBUG std::cout << "Admin::slot_tab_reload " << page << std::endl; #endif SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( view ) view->reload(); } // // タブメニュー表示 // void Admin::slot_tab_menu( int page, int x, int y ) { if( ! m_ui_manager ) return; #ifdef _DEBUG std::cout << "Admin::slot_tab_menu " << page << std::endl; #endif Glib::RefPtr< Gtk::Action > act; m_clicked_page = -1; // メニューのactive状態を変えたときにslot関数が呼び出されるのをキャンセル SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); // ロック act = m_action_group->get_action( "LockTab" ); if( page >= 0 && act ){ if( ! is_lockable( page ) ) act->set_sensitive( false ); else{ act->set_sensitive( true ); Glib::RefPtr< Gtk::ToggleAction > tact = Glib::RefPtr< Gtk::ToggleAction >::cast_dynamic( act ); if( is_locked( page ) ) tact->set_active( true ); else tact->set_active( false ); } } // 閉じる act = m_action_group->get_action( "Quit" ); if( act ){ if( is_locked( page ) ) act->set_sensitive( false ); else act->set_sensitive( true ); } // 進む、戻る if( view ){ act = m_action_group->get_action( "PrevView" ); if( act ){ if( HISTORY::get_history_manager()->can_back_viewhistory( view->get_url(), 1 ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } act = m_action_group->get_action( "NextView" ); if( act ){ if( HISTORY::get_history_manager()->can_forward_viewhistory( view->get_url(), 1 ) ) act->set_sensitive( true ); else act->set_sensitive( false ); } } m_clicked_page = page; Gtk::Menu* popupmenu = dynamic_cast< Gtk::Menu* >( m_ui_manager->get_widget( "/popup_menu" ) ); if( popupmenu && m_move_menu ){ m_move_menu->remove_items(); m_move_menu->append_items(); m_move_menu->update_labels(); m_move_menu->update_icons(); Gtk::Label* label = dynamic_cast< Gtk::Label* >( m_move_menuitem->get_child() ); if( label ) label->set_text_with_mnemonic( ITEM_NAME_GO + std::string( " [ タブ数 " ) + MISC::itostr( m_notebook->get_n_pages() ) +" ](_M)" ); popupmenu->popup( 0, gtk_get_current_event_time() ); } } // タブ切り替えメニュー表示 void Admin::slot_show_tabswitchmenu() { #ifdef _DEBUG std::cout << "Admin::slot_show_tabswitchmenu\n"; #endif if( ! m_tabswitchmenu ) m_tabswitchmenu = new SKELETON::TabSwitchMenu( m_notebook, this ); m_tabswitchmenu->remove_items(); m_tabswitchmenu->append_items(); m_tabswitchmenu->update_labels(); m_tabswitchmenu->update_icons(); m_tabswitchmenu->popup( Gtk::Menu::SlotPositionCalc( sigc::mem_fun( *this, &Admin::slot_popup_pos ) ), 0, gtk_get_current_event_time() ); } // タブ切り替えメニューの位置決め void Admin::slot_popup_pos( int& x, int& y, bool& push_in ) { if( ! m_tabswitchmenu ) return; if( ! m_notebook ) return; const int mrg = 16; m_notebook->get_tabswitch_button().get_pointer( x, y ); int ox, oy; m_notebook->get_tabswitch_button().get_window()->get_origin( ox, oy ); const Gdk::Rectangle rect = m_notebook->get_tabswitch_button().get_allocation(); x += ox + rect.get_x() - mrg; y = oy + rect.get_y() + rect.get_height(); push_in = false; } // // 右クリックメニューの閉じる // void Admin::slot_close_tab() { if( m_clicked_page < 0 ) return; #ifdef _DEBUG std::cout << "Admin::slot_close_tab " << m_clicked_page << std::endl; #endif SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( m_clicked_page ) ); if( view ) close_view( view->get_url() ); } // // ロック // void Admin::slot_lock() { if( m_clicked_page < 0 ) return; if( is_locked( m_clicked_page ) ) unlock( m_clicked_page ); else lock( m_clicked_page ); } // // 右クリックメニューの他を閉じる // void Admin::slot_close_other_tabs() { #ifdef _DEBUG std::cout << "Admin::slot_close_other_tabs " << m_clicked_page << std::endl; #endif set_command( "set_tab_operating", "", "true" ); std::string url; SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( m_clicked_page ) ); if( view ) url = view->get_url(); close_other_views( url ); set_command( "set_tab_operating", "", "false" ); } // // 右クリックメニューの左を閉じる // void Admin::slot_close_left_tabs() { #ifdef _DEBUG std::cout << "Admin::slot_close_left_tabs " << m_clicked_page << std::endl; #endif set_command( "set_tab_operating", "", "true" ); for( int i = 0; i < m_clicked_page; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view ) set_command( "close_view", view->get_url() ); } set_command( "set_tab_operating", "", "false" ); } // // 右クリックメニューの右を閉じる // void Admin::slot_close_right_tabs() { #ifdef _DEBUG std::cout << "Admin::slot_close_right_tabs " << m_clicked_page << std::endl; #endif set_command( "set_tab_operating", "", "true" ); const int pages = m_notebook->get_n_pages(); for( int i = m_clicked_page +1; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view ) set_command( "close_view", view->get_url() ); } set_command( "set_tab_operating", "", "false" ); } // // 右クリックメニューの全てを閉じる // void Admin::slot_close_all_tabs() { #ifdef _DEBUG std::cout << "Admin::slot_close_all_tabs " << m_clicked_page << std::endl; #endif set_command( "set_tab_operating", "", "true" ); const int pages = m_notebook->get_n_pages(); for( int i = 0; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view ) set_command( "close_view", view->get_url() ); } set_command( "set_tab_operating", "", "false" ); } // // 右クリックメニューの同じアイコンのタブを閉じる // void Admin::slot_close_same_icon_tabs() { const int id = get_notebook()->get_tabicon( m_clicked_page ); #ifdef _DEBUG std::cout << "Admin::slot_close_same_icon_tabs page = " << m_clicked_page << " id = " << id << std::endl; #endif set_command( "set_tab_operating", "", "true" ); const int pages = m_notebook->get_n_pages(); for( int i = 0; i < pages; ++i ){ if( get_notebook()->get_tabicon( i ) == id ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view ) set_command( "close_view", view->get_url() ); } } set_command( "set_tab_operating", "", "false" ); } // // 右クリックメニューの全てのタブの更新チェック // void Admin::slot_check_update_all_tabs() { check_update_all_tabs( m_clicked_page, false ); } // // 右クリックメニューの全てのタブの更新チェックと再読み込み // void Admin::slot_check_update_reload_all_tabs() { check_update_all_tabs( m_clicked_page, true ); } // // 開いているタブから全てのタブの更新チェックと再読み込み // void Admin::check_update_all_tabs( const bool open ) { check_update_all_tabs( m_notebook->get_current_page(), open ); } // // from_page から全てのタブを更新チェック // void Admin::check_update_all_tabs( const int from_page, const bool open ) { #ifdef _DEBUG std::cout << "Admin::check_update_all_tabs from = " << from_page << std::endl; #endif if( ! SESSION::is_online() ) return; const int pages = m_notebook->get_n_pages(); // 開始タブから右側 for( int i = from_page ; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view && view->get_enable_autoreload() ) CORE::get_checkupdate_manager()->push_back( view->get_url(), open ); } // 開始タブから左側 for( int i = 0 ; i < from_page; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view && view->get_enable_autoreload() ) CORE::get_checkupdate_manager()->push_back( view->get_url(), open ); } CORE::get_checkupdate_manager()->run(); } // // 右クリックメニューの全ての再読み込み // void Admin::slot_reload_all_tabs() { #ifdef _DEBUG std::cout << "Admin::slot_reload_all_tabs " << m_clicked_page << std::endl; #endif reload_all_tabs( m_clicked_page ); } // // 開いているタブから全てのタブを再読み込み // void Admin::reload_all_tabs() { reload_all_tabs( m_notebook->get_current_page() ); } // // from_page から全てのタブを再読み込み // void Admin::reload_all_tabs( const int from_page ) { #ifdef _DEBUG std::cout << "Admin::reload_all_tabs from = " << from_page << std::endl; #endif if( ! SESSION::is_online() ) return; int waittime = 0; const int pages = m_notebook->get_n_pages(); // クリックしたタブから右側 for( int i = from_page ; i < pages; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view ){ if( set_autoreload_mode( view->get_url(), AUTORELOAD_ONCE, waittime ) ) waittime += AUTORELOAD_MINSEC; } } // クリックしたタブから左側 for( int i = 0 ; i < from_page; ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view ){ if( set_autoreload_mode( view->get_url(), AUTORELOAD_ONCE, waittime ) ) waittime += AUTORELOAD_MINSEC; } } } // // 右クリックメニューの更新キャンセル // void Admin::slot_cancel_reload_all_tabs() { for( int i = 0 ; i < m_notebook->get_n_pages(); ++i ){ SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( i ) ); if( view ) set_autoreload_mode( view->get_url(), AUTORELOAD_NOT, 0 ); } CORE::get_checkupdate_manager()->stop(); } // // 右クリックメニューのブラウザで開く // void Admin::slot_open_by_browser() { #ifdef _DEBUG std::cout << "Admin::slot_open_by_browser " << m_clicked_page << std::endl; #endif SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( m_clicked_page ) ); if( view ) CORE::core_set_command( "open_url_browser", view->url_for_copy() ); } // // 右クリックメニューのURLコピー // void Admin::slot_copy_url() { SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( m_clicked_page ) ); if( view ) MISC::CopyClipboard( view->url_for_copy() ); } // // 右クリックメニューのタイトルとURLコピー // void Admin::slot_copy_title_url() { std::string str = m_notebook->get_tab_fulltext( m_clicked_page ); SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( m_clicked_page ) ); if( view ) str += "\n" + view->url_for_copy(); MISC::CopyClipboard( str ); } // ページがロックされているかリストで取得 std::list< bool > Admin::get_locked() { std::list< bool > locked; const int pages = m_notebook->get_n_pages(); if( pages ){ for( int i = 0; i < pages; ++i ) locked.push_back( is_locked( i ) ); } return locked; } // タブのロック/アンロック const bool Admin::is_lockable( const int page ) { SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( view ) return view->is_lockable(); return false; } const bool Admin::is_locked( const int page ) { SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( view ) return view->is_locked(); return false; } const bool Admin::is_locked( const std::string& url ) { SKELETON::View* view = get_view( url ); if( view ) return view->is_locked(); return false; } void Admin::lock( const int page ) { SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( view ){ view->lock(); redraw_toolbar(); } } void Admin::unlock( const int page ) { SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( page ) ); if( view ){ view->unlock(); redraw_toolbar(); } } // urlで指定されるタブが存在するか const bool Admin::exist_tab( const std::string& url ) { SKELETON::View* view = get_view( url ); if( view ) return true; return false; } // プロパティ表示 void Admin::show_preference() { SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( m_clicked_page ) ); if( view ) view->show_preference(); } // // View履歴:戻る // bool Admin::back_viewhistory( const std::string& url, const int count ) { return back_forward_viewhistory( url, true, count ); } void Admin::back_clicked_viewhistory( const int count ) { if( m_clicked_page < 0 ) return; SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( m_clicked_page ) ); if( ! view ) return; set_current_page( m_clicked_page ); back_forward_viewhistory( view->get_url(), true, count ); } // // View履歴進む // bool Admin::forward_viewhistory( const std::string& url, const int count ) { return back_forward_viewhistory( url, false, count ); } void Admin::forward_clicked_viewhistory( const int count ) { if( m_clicked_page < 0 ) return; SKELETON::View* view = dynamic_cast< View* >( m_notebook->get_nth_page( m_clicked_page ) ); if( ! view ) return; set_current_page( m_clicked_page ); back_forward_viewhistory( view->get_url(), false, count ); } // // 戻る、進む // const bool Admin::back_forward_viewhistory( const std::string& url, const bool back, const int count ) { if( ! m_use_viewhistory ) return false; #ifdef _DEBUG std::cout << "Admin::back_forward_viewhistory back = " << back << "count = " << count << " tab = " << url << std::endl; #endif SKELETON::View* view = get_view( url ); if( view ){ if( view->is_locked() ) return false; const HISTORY::ViewHistoryItem* historyitem; if( back ) historyitem = HISTORY::get_history_manager()->back_viewhistory( url, count, false ); else historyitem = HISTORY::get_history_manager()->forward_viewhistory( url, count, false ); if( historyitem && ! historyitem->url.empty() ){ #ifdef _DEBUG std::cout << "open : " << historyitem->url << std::endl; #endif // 既にタブで開いている場合 if( get_view( historyitem->url) ){ // 次のviewを開けるかチェック bool enable_next = false; if( back ) enable_next = HISTORY::get_history_manager()->can_back_viewhistory( url, count +1 ); else enable_next = HISTORY::get_history_manager()->can_forward_viewhistory( url, count +1 ); SKELETON::MsgDiag mdiag( get_win(), historyitem->title + "\n\nは既にタブで開いています", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE ); mdiag.add_button( "タブを開く(_T)", Gtk::RESPONSE_YES ); if( enable_next ) mdiag.add_button( "次を開く(_N)", Gtk::RESPONSE_NO ); mdiag.add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ); int ret = mdiag.run(); mdiag.hide(); switch( ret ){ case Gtk::RESPONSE_YES: switch_view( historyitem->url ); return false; case Gtk::RESPONSE_NO: return back_forward_viewhistory( url, back, count + 1 ); default: break; } return false; } // Admin::open_view() 中の append_viewhistory() を実行しないでここで View履歴の現在位置を変更する // Admin::Open_view()も参照すること const bool use_history = get_use_viewhistory(); set_use_viewhistory( false ); if( use_history ){ if( back ) HISTORY::get_history_manager()->back_viewhistory( url, count, true ); else HISTORY::get_history_manager()->forward_viewhistory( url, count, true ); } const COMMAND_ARGS command_arg = url_to_openarg( historyitem->url, false, false ); open_view( command_arg ); set_use_viewhistory( use_history ); return true; } } return false; } // // View履歴削除 // void Admin::clear_viewhistory() { if( ! m_use_viewhistory ) return; std::list< SKELETON::View* > list_view = get_list_view(); std::list< SKELETON::View* >::iterator it = list_view.begin(); for( ; it != list_view.end(); ++it ){ SKELETON::View* view = ( *it ); if( view ){ HISTORY::get_history_manager()->delete_viewhistory( (*it)->get_url() ); HISTORY::get_history_manager()->create_viewhistory( (*it)->get_url() ); int page = m_notebook->page_num( *(*it) ); std::string str_label = m_notebook->get_tab_fulltext( page ); HISTORY::get_history_manager()->replace_current_title_viewhistory( (*it)->get_url(), str_label ); } } if( ! m_last_closed_url.empty() ) HISTORY::get_history_manager()->delete_viewhistory( m_last_closed_url ); m_last_closed_url = std::string(); update_toolbar_button(); } // // タブの切り替え履歴を更新 // void Admin::append_switchhistory( const std::string& url ) { if( ! m_use_switchhistory ) return; // 起動中とシャットダウン中は処理しない if( SESSION::is_booting() ) return; if( SESSION::is_quitting() ) return; #ifdef _DEBUG std::cout << "Admin::append_switchhistory url = " << url << std::endl; #endif m_list_switchhistory.remove( url ); m_list_switchhistory.push_back( url ); #ifdef _DEBUG std::list< std::string >::iterator it = m_list_switchhistory.begin(); for( ; it != m_list_switchhistory.end(); ++it ){ std::cout << (*it) << std::endl; } #endif } void Admin::remove_switchhistory( const std::string& url ) { if( ! m_use_switchhistory ) return; // 起動中とシャットダウン中は処理しない if( SESSION::is_booting() ) return; if( SESSION::is_quitting() ) return; #ifdef _DEBUG std::cout << "Admin::remove_switchhistory url = " << url << std::endl; #endif m_list_switchhistory.remove( url ); #ifdef _DEBUG std::list< std::string >::iterator it = m_list_switchhistory.begin(); for( ; it != m_list_switchhistory.end(); ++it ){ std::cout << (*it) << std::endl; } #endif } // // タブの切り替え履歴から、有効な最後のURLを返す // // 表示されているビューに存在しないURLは履歴から削除して、表示されているビューのURLを返す。 // 見つからないときは空文字列を返す。 // // NOTE: // タブの切り替え履歴にあるビューは、表示されているビューのうちのどれかであるはずだが、 // 検索ビューなどでURLが変更になる場合があり、 ( View::set_url()で変更できてしまう。 ) // タブの切り替え履歴にあるURLと、表示されているビューのURLが不一致となることがある。 // また、その不一致なタブの切り替え履歴を、セッション情報 ( article_switchhistoryなど ) に // 保存してしまっていたため、ここで不一致な履歴の削除を行うことで、履歴を修復する。 // const std::string Admin::get_valid_switchhistory() { if( ! m_use_switchhistory ) return std::string(); while( m_list_switchhistory.size() > 0 ){ // タブの切り替え履歴から、最後のURLを取り出す const std::string url = m_list_switchhistory.back(); // 表示されているビューであれば、そのURLを返す SKELETON::View* view = get_view( url ); if( view ) return url; // 表示されていないので、最後のURLを削除する m_list_switchhistory.pop_back(); #ifdef _DEBUG std::cout << "Admin::get_valid_switchhistory remove = " << url << std::endl; #endif } return std::string(); } jd-2.8.7-140104/src/skeleton/admin.h0000644000076400010400000003212512141137275013452 0ustar // ライセンス: GPL2 // Viewを管理するクラス // 派生クラスはcreate_view()をオーバロードすること // Adminへの命令はすべてset_command()を通じておこなうこと #ifndef _ADMIN_H #define _ADMIN_H #include "dispatchable.h" #include #include #include #include "command_args.h" namespace SKELETON { class JDWindow; class View; class DragableNoteBook; class TabSwitchMenu; class Admin : public Dispatchable { std::string m_url; JDWindow * m_win; protected: DragableNoteBook* m_notebook; private: bool m_focus; std::list< COMMAND_ARGS > m_list_command; // 右クリックメニュー用 Glib::RefPtr< Gtk::ActionGroup > m_action_group; Glib::RefPtr< Gtk::UIManager > m_ui_manager; int m_clicked_page; // 移動サブメニュー Gtk::MenuItem* m_move_menuitem; TabSwitchMenu* m_move_menu; // タブ切り替えメニュー TabSwitchMenu* m_tabswitchmenu; // view履歴使用 bool m_use_viewhistory; std::string m_last_closed_url; // タブの切り替え履歴 bool m_use_switchhistory; std::list< std::string > m_list_switchhistory; public: Admin( const std::string& url ); virtual ~Admin(); virtual void save_session(); void setup_menu(); virtual bool empty(); const std::string& get_url() const{ return m_url; } virtual Gtk::Widget* get_widget(); virtual Gtk::Window* get_win(); // 起動中 const bool is_booting(); // フォーカスされているか virtual const bool has_focus() const { return m_focus; } // タブの数 virtual int get_tab_nums(); // 含まれているページのURLのリスト取得 virtual const std::list< std::string > get_URLs(); // Core からのクロック入力。 // Coreでタイマーをひとつ動かして全体の同期を取るようにしているので // 一定時間毎に clock_in() が Core から呼び出される virtual void clock_in(); // コマンド入力(通常) void set_command( const std::string& command, const std::string& url = std::string(), const std::string& arg1 = std::string(), const std::string& arg2 = std::string(), const std::string& arg3 = std::string(), const std::string& arg4 = std::string(), const std::string& arg5 = std::string(), const std::string& arg6 = std::string(), const std::string& arg7 = std::string(), const std::string& arg8 = std::string() ); // コマンド入力(即時実行) void set_command_immediately( const std::string& command, const std::string& url = std::string(), const std::string& arg1 = std::string(), const std::string& arg2 = std::string(), const std::string& arg3 = std::string(), const std::string& arg4 = std::string(), const std::string& arg5 = std::string(), const std::string& arg6 = std::string(), const std::string& arg7 = std::string(), const std::string& arg8 = std::string() ); // コマンドがセットされているか const bool has_commands() const { return ( m_list_command.size() ); } // 現在表示してるページ番号およびURL // 表示ページを指定したいときは "set_page" コマンドを使う virtual int get_current_page(); const std::string get_current_url(); // urlで指定されるタブがロックされているか const bool is_locked( const std::string& url ); // urlで指定されるタブが存在するか const bool exist_tab( const std::string& url ); // 指定したページに表示切替え void set_current_page( const int page ); // フォーカスしてから指定したページに表示切替え void set_current_page_focus( const int page ); virtual View* get_current_view(); protected: void set_use_viewhistory( const bool use ){ m_use_viewhistory = use; } const bool get_use_viewhistory() const { return m_use_viewhistory; } void set_use_switchhistory( const bool use ){ m_use_switchhistory = use; } JDWindow* get_jdwin(){ return m_win; } void set_jdwin( JDWindow* win ){ m_win = win; } void delete_jdwin(); // URLやステータスを更新 void update_status( View* view, const bool force ); DragableNoteBook* get_notebook(){ return m_notebook; } // コマンド入力 // immediately = true のときディスパッチャを呼ばずにすぐさま実行 void set_command_impl( const bool immediately, const COMMAND_ARGS& command_arg ); virtual void callback_dispatch(); // admin共通コマンド実行 virtual void exec_command(); // 派生クラス固有のコマンドを実行 virtual void command_local( const COMMAND_ARGS& command ) = 0; // 起動時に前回の状態を回復 virtual void restore( const bool only_locked ) = 0; // url から Viewを開くための COMMAND_ARGS を取得する // restore() などで使用する virtual COMMAND_ARGS url_to_openarg( const std::string& url, const bool tab, const bool lock ) = 0; // COMMAND_ARGS からビューの URL を取得する virtual const std::string command_to_url( const COMMAND_ARGS& command ){ return command.url; } // view_modeに該当するページを探す virtual int find_view( const std::string& view_mode ){ return -1; }; virtual void open_view( const COMMAND_ARGS& command ); virtual void switch_admin() = 0; // CORE::core_set_command( "switch_*" ) を送る virtual void switch_view( const std::string& url ); void reload_view( const std::string& url ); // タブ左右移動 // updated == true の時は更新されたタブに移動 virtual void tab_left( const bool updated ); virtual void tab_right( const bool updated ); virtual void tab_num( const std::string& str_num ); virtual void tab_head(); void tab_head_focus(); virtual void tab_tail(); void tab_tail_focus(); virtual void redraw_view( const std::string& url ); virtual void redraw_current_view(); virtual void relayout_current_view(); virtual void redraw_views( const std::string& url ); virtual void update_view( const std::string& url ); virtual void update_item( const std::string& url, const std::string& id ); virtual void update_finish( const std::string& url ); virtual void close_view( const std::string& url ); virtual void close_view( View* view ); virtual void unlock_all_view( const std::string& url ); virtual void close_all_view( const std::string& url ); virtual void close_other_views( const std::string& url ); virtual void close_current_view(); virtual void restore_lasttab(){} virtual void set_title( const std::string& url, const std::string& title, const bool force ); virtual void set_url( const std::string& url, const std::string& url_show, const bool force ); virtual void set_status( const std::string& url, const std::string& stat, const bool force ); void set_status_color( const std::string& url, const std::string& color, const bool force ); virtual void focus_view( int page ); virtual void focus_current_view(); virtual void restore_focus(); virtual void focus_out(); virtual void set_tablabel( const std::string& url, const std::string& str_label ); virtual void relayout_all(); virtual void open_window(){} virtual void close_window(){} virtual void toggle_tab(); virtual void toggle_icon( const std::string& url ); // オートリロードのモード設定 virtual bool set_autoreload_mode( const std::string& url, int mode, int sec ); // ポップアップを隠す(インスタンスは削除しない) void hide_popup(); // タブをお気に入りにドロップした時にお気に入りがデータ送信を要求してきた virtual void slot_drag_data_get( Gtk::SelectionData& selection_data, const int page ) = 0; void open_list( const COMMAND_ARGS& command_list ); virtual COMMAND_ARGS get_open_list_args( const std::string& url, const COMMAND_ARGS& command_list ){ return COMMAND_ARGS(); } virtual View* create_view( const COMMAND_ARGS& command ){ return NULL; }; virtual View* get_view( const std::string& url ); // url を含むビュークラスをリストで取得 ( url と一致するビューでは無い ) std::list< View* > get_list_view( const std::string& url ); // 全てのビュークラスをリストで取得 std::list< View* > get_list_view(); // ツールバー virtual void show_toolbar(){} virtual void toggle_toolbar(){} void focus_toolbar_search(); void redraw_toolbar(); void update_toolbar_button(); virtual void open_searchbar(){} virtual void close_searchbar(){} // タブの更新チェック void check_update_all_tabs( const bool open ); void check_update_all_tabs( const int from_page, const bool open ); // タブの再読み込み void reload_all_tabs(); void reload_all_tabs( const int from_page ); // notebookのタブが切り替わったときに呼ばれるslot void slot_switch_page( GtkNotebookPage*, guint page ); // タブをクリックした void slot_tab_clicked( const int page ); // タブの上でホイールを回した void slot_tab_scrolled( GdkEventScroll* event ); // タブを閉じる void slot_tab_close( const int page ); // タブ再読み込み void slot_tab_reload( const int page ); // タブメニュー表示 virtual void slot_tab_menu( int page, int x, int y ); // タブ切り替えメニュー表示 void slot_show_tabswitchmenu(); // タブ切り替えメニューの位置決め void slot_popup_pos( int& x, int& y, bool& push_in ); // 右クリックメニュー virtual void slot_close_tab(); virtual void slot_lock(); virtual void slot_close_other_tabs(); virtual void slot_close_left_tabs(); virtual void slot_close_right_tabs(); virtual void slot_close_all_tabs(); virtual void slot_close_same_icon_tabs(); virtual void slot_check_update_all_tabs(); virtual void slot_check_update_reload_all_tabs(); virtual void slot_reload_all_tabs(); virtual void slot_cancel_reload_all_tabs(); virtual void slot_open_by_browser(); virtual void slot_copy_url(); virtual void slot_copy_title_url(); // ページがロックされているかリストで取得 virtual std::list< bool > get_locked(); // タブのロック/アンロック virtual const bool is_lockable( const int page ); virtual const bool is_locked( const int page ); virtual void lock( const int page ); virtual void unlock( const int page ); // プロパティ表示 void show_preference(); // View履歴戻る / 進む bool back_viewhistory( const std::string& url, const int count ); void back_clicked_viewhistory( const int count ); bool forward_viewhistory( const std::string& url, const int count ); void forward_clicked_viewhistory( const int count ); // View履歴削除 void clear_viewhistory(); // タブの切り替え履歴 const std::list< std::string >& get_switchhistory() const { return m_list_switchhistory; } void set_switchhistory( const std::list< std::string >& hist ){ m_list_switchhistory = hist; } private: void slot_popupmenu_deactivate(); const bool back_forward_viewhistory( const std::string& url, const bool back, const int count ); // 移転などでviewのurlを更新 void update_url( const std::string& url_old, const std::string& url_new ); // urlを含むviewの板名を更新 void update_boardname( const std::string& url ); // タブの切り替え履歴を更新 void append_switchhistory( const std::string& url ); void remove_switchhistory( const std::string& url ); const std::string get_valid_switchhistory(); }; } #endif jd-2.8.7-140104/src/skeleton/backforwardbutton.cpp0000644000076400010400000000370511506370702016436 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "backforwardbutton.h" #include "history/historymanager.h" #include "history/viewhistoryitem.h" #include "icons/iconmanager.h" using namespace SKELETON; BackForwardButton::BackForwardButton( const std::string& url, const bool back ) : SKELETON::MenuButton( true, ( back ? ICON::BACK : ICON::FORWARD ) ), m_url( url ), m_back( back ) {} void BackForwardButton::set_url( const std::string& url ) { m_url = url; #ifdef _DEBUG std::cout << "BackForwardButton::set_url back = " << m_back << " url = " << m_url << std::endl; #endif if( m_back ){ if( HISTORY::get_history_manager()->can_back_viewhistory( m_url, 1 ) ) set_sensitive( true ); else set_sensitive( false ); } else{ if( HISTORY::get_history_manager()->can_forward_viewhistory( m_url, 1 ) ) set_sensitive( true ); else set_sensitive( false ); } } // // ポップアップメニュー表示 // // virtual void BackForwardButton::show_popupmenu() { #ifdef _DEBUG std::cout << "BackForwardButton::show_popupmenu back = " << m_back << " url = " << m_url << std::endl; #endif std::vector< std::string > items; // 戻る更新 if( m_back ){ std::vector< HISTORY::ViewHistoryItem* >& histitems = HISTORY::get_history_manager()->get_items_back_viewhistory( m_url, MAX_MENU_SIZE ); std::vector< HISTORY::ViewHistoryItem* >::iterator it = histitems.begin(); for( ; it != histitems.end(); ++it ) items.push_back( (*it)->title ); } else{ std::vector< HISTORY::ViewHistoryItem* >& histitems = HISTORY::get_history_manager()->get_items_forward_viewhistory( m_url, MAX_MENU_SIZE ); std::vector< HISTORY::ViewHistoryItem* >::iterator it = histitems.begin(); for( ; it != histitems.end(); ++it ) items.push_back( (*it)->title ); } append_menu( items ); SKELETON::MenuButton::show_popupmenu(); } jd-2.8.7-140104/src/skeleton/backforwardbutton.h0000644000076400010400000000104311007350165016071 0ustar // ライセンス: GPL2 // 「戻る」「進む」履歴付きボタン #ifndef _BACKFORWARDBUTTON_H #define _BACKFORWARDBUTTON_H #include "menubutton.h" namespace SKELETON { class BackForwardButton : public SKELETON::MenuButton { std::string m_url; bool m_back; public: BackForwardButton( const std::string& url, const bool back ); void set_url( const std::string& url ); protected: // ポップアップメニュー表示 virtual void show_popupmenu(); }; } #endif jd-2.8.7-140104/src/skeleton/compentry.cpp0000644000076400010400000001537211505374764014753 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "compentry.h" #include "control/controlid.h" #include "compmanager.h" using namespace SKELETON; enum { POPUP_SIZE = 5 }; CompletionEntry::CompletionEntry( const int mode ) : m_mode( mode ), m_enable_changed( true ), m_focused( false ), m_show_popup( false ), m_popup_win( true ) { m_entry.signal_key_press().connect( sigc::mem_fun( *this, &CompletionEntry::slot_entry_key_press ) ); m_entry.signal_button_press().connect( sigc::mem_fun(*this, &CompletionEntry::slot_entry_button_press ) ); m_entry.signal_operate().connect( sigc::mem_fun( *this, &CompletionEntry::slot_entry_operate ) ); m_entry.signal_activate().connect( sigc::mem_fun( *this, &CompletionEntry::slot_entry_acivate ) ); m_entry.signal_changed().connect( sigc::mem_fun( *this, &CompletionEntry::slot_entry_changed ) ); m_entry.signal_focus_out_event().connect( sigc::mem_fun(*this, &CompletionEntry::slot_entry_focus_out ) ); pack_start( m_entry ); // ポップアップ m_column_record.add( m_column ); m_liststore = Gtk::ListStore::create( m_column_record ); m_treeview.set_model( m_liststore ); m_treeview.append_column( "", m_column ); m_treeview.set_headers_visible( false ); m_treeview.sig_motion_notify().connect( sigc::mem_fun(*this, &CompletionEntry::slot_treeview_motion ) ); m_treeview.sig_button_release().connect( sigc::mem_fun(*this, &CompletionEntry::slot_treeview_button_release ) ); m_scr_win.add( m_treeview ); m_scr_win.set_policy( Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC ); m_scr_win.set_size_request( 1, 1 ); m_popup_win.add( m_scr_win ); set_size_request( 0 ); } CompletionEntry::~CompletionEntry() {} // 補完実行 bool CompletionEntry::completion() { bool ret = false; if( m_show_popup ){ Gtk::TreeModel::Row row = m_treeview.get_current_row(); if( row ){ set_text( row[ m_column ] ); ret = true; } } hide_popup(); return ret; } Glib::ustring CompletionEntry::get_text() { return m_entry.get_text(); } void CompletionEntry::set_text( const Glib::ustring& text ) { m_enable_changed = false; m_entry.set_text( text ); m_entry.set_position( text.length() ); m_enable_changed = true; } void CompletionEntry::grab_focus() { #ifdef _DEBUG std::cout << "CompletionEntry::grab_focus\n"; #endif m_focused = true; m_entry.grab_focus(); } // // ポップアップ表示 // // show_all == true なら候補を全て表示する // void CompletionEntry::show_popup( const bool show_all ) { const int mrg = 2; std::string query = m_entry.get_text(); if( ! show_all && query.empty() ){ hide_popup(); return; } if( show_all ) query = std::string(); CORE::COMPLIST complist = CORE::get_completion_manager()->get_list( m_mode, query ); if( ! complist.size() ) hide_popup(); m_liststore->clear(); Gtk::TreeModel::Row row; CORE::COMPLIST_ITERATOR it = complist.begin(); for( ; it != complist.end(); ++it ){ if( *it != m_entry.get_text() ){ row = *( m_liststore->append() ); row[ m_column ] = *it; } } const int size = m_liststore->children().size(); if( ! size ){ hide_popup(); return; } // 座標と大きさを計算してポップアップ表示 const int cell_h = m_treeview.get_row_height() + mrg; int x, y; get_window()->get_origin( x, y ); Gdk::Rectangle rect = get_allocation(); m_popup_win.move( x + rect.get_x(), y + rect.get_y() + rect.get_height() ); m_popup_win.resize( get_width(), cell_h * MIN( POPUP_SIZE, size ) + mrg ); m_popup_win.show_all(); m_show_popup = true; m_treeview.unset_cursor(); m_treeview.scroll_to_point( -1, 0 ); m_treeview.get_column_cell_renderer( 0 )->property_cell_background_gdk() = get_style()->get_bg( Gtk::STATE_NORMAL ); } // ポップアップ閉じる void CompletionEntry::hide_popup() { if( m_show_popup ){ m_popup_win.hide(); m_show_popup = false; } } // entryでキーが押された void CompletionEntry::slot_entry_key_press( int keyval ) { #ifdef _DEBUG std::cout << "CompletionEntry::slot_entry_key_press keyval = " << keyval << std::endl; #endif } // entryでボタンを押した void CompletionEntry::slot_entry_button_press( GdkEventButton* event ) { if( event->type != GDK_BUTTON_PRESS ) return; #ifdef _DEBUG std::cout << "CompletionEntry::slot_entry_button_press button = " << event->button << " focused = " << m_focused << std::endl; #endif if( m_show_popup ) hide_popup(); else if( m_focused ) show_popup( m_entry.get_text().empty() ); m_focused = true; } // entry操作 void CompletionEntry::slot_entry_operate( int controlid ) { #ifdef _DEBUG std::cout << "CompletionEntry::slot_entry_operate id = " << controlid << std::endl; #endif switch( controlid ){ case CONTROL::Up: if( ! m_treeview.row_up() ) m_treeview.goto_bottom(); break; case CONTROL::Down: if( ! m_treeview.row_down() ) m_treeview.goto_top(); break; case CONTROL::Cancel: if( m_show_popup ) hide_popup(); else m_sig_operate.emit( controlid ); break; default: m_sig_operate.emit( controlid ); } } // entry からsignal_activateを受け取った void CompletionEntry::slot_entry_acivate() { #ifdef _DEBUG std::cout << "CompletionEntry::slot_entry_acivate\n"; #endif if( ! completion() ) m_sig_activate.emit(); } // entry からsignal_changedを受け取った void CompletionEntry::slot_entry_changed() { if( m_enable_changed ){ if( m_entry.get_text().empty() ) hide_popup(); else show_popup( false ); } m_sig_changed.emit(); } // entryのフォーカスが外れた bool CompletionEntry::slot_entry_focus_out( GdkEventFocus* ) { #ifdef _DEBUG std::cout << "CompletionEntry::slot_entry_focus_out\n"; #endif hide_popup(); m_focused = false; return true; } // ポップアップ内をマウスを動かした bool CompletionEntry::slot_treeview_motion( GdkEventMotion* ) { Gtk::TreeModel::Path path = m_treeview.get_path_under_mouse(); if( path.get_depth() > 0 ) m_treeview.set_cursor( path ); return true; } // ポップアップクリック bool CompletionEntry::slot_treeview_button_release( GdkEventButton* ) { #ifdef _DEBUG std::cout << "CompletionEntry::slot_treeview_button_release\n"; #endif hide_popup(); Gtk::TreeModel::Row row = m_treeview.get_current_row(); if( row ){ set_text( row[ m_column ] ); hide_popup(); } return true; } jd-2.8.7-140104/src/skeleton/compentry.h0000644000076400010400000000534711125705250014403 0ustar // ライセンス: GPL2 // // 補完 Entryクラス // #ifndef _COMPENTRY_H #define _COMPENTRY_H #include "entry.h" #include "popupwinbase.h" #include "treeviewbase.h" #include "imgbutton.h" #include namespace SKELETON { class CompletionEntry : public Gtk::HBox { typedef sigc::signal< void, int > SIG_OPERATE; typedef sigc::signal< void > SIG_ACTIVATE; typedef sigc::signal< void > SIG_CHANGED; SIG_OPERATE m_sig_operate; SIG_ACTIVATE m_sig_activate; SIG_CHANGED m_sig_changed; int m_mode; JDEntry m_entry; bool m_enable_changed; bool m_focused; // ポップアップ bool m_show_popup; PopupWinBase m_popup_win; Gtk::ScrolledWindow m_scr_win; JDTreeViewBase m_treeview; Gtk::TreeModelColumn< Glib::ustring > m_column; Gtk::TreeModel::ColumnRecord m_column_record; Glib::RefPtr< Gtk::ListStore > m_liststore; public: // mode は補完モード ( compmanager.h 参照 ) CompletionEntry( const int mode ); virtual ~CompletionEntry(); SIG_OPERATE signal_operate(){ return m_sig_operate; } SIG_ACTIVATE signal_activate(){ return m_sig_activate; } SIG_CHANGED signal_changed(){ return m_sig_changed; } // m_entry の入力コントローラのモード設定 // 補完モード(m_mode)とは異なる void add_control_mode( int mode ){ m_entry.add_mode( mode ); } // 補完実行 bool completion(); Glib::ustring get_text(); void set_text( const Glib::ustring& text ); void grab_focus(); void modify_font( Pango::FontDescription& pfd ){ m_entry.modify_font( pfd ); } private: // ポップアップ表示 // show_all == true なら候補を全て表示する void show_popup( const bool show_all ); // ポップアップ閉じる void hide_popup(); // entryでキーが押された void slot_entry_key_press( int keyval ); // entryでボタンを押した void slot_entry_button_press( GdkEventButton* event ); // entry操作 void slot_entry_operate( int controlid ); // entry からsignal_activateを受け取った void slot_entry_acivate(); // entry からsignal_changedを受け取った void slot_entry_changed(); // entryのフォーカスが外れた bool slot_entry_focus_out( GdkEventFocus* ); // ポップアップ内をマウスを動かした bool slot_treeview_motion( GdkEventMotion* ); // ポップアップクリック bool slot_treeview_button_release( GdkEventButton* ); }; } #endif jd-2.8.7-140104/src/skeleton/detaildiag.cpp0000644000076400010400000000303112006761301014767 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "gtkmmversion.h" #include "detaildiag.h" #include "view.h" #include "viewfactory.h" using namespace SKELETON; DetailDiag::DetailDiag( Gtk::Window* parent, const std::string& url, const bool add_cancel, const std::string& message, const std::string& tab_message, const std::string& detail_html, const std::string& tab_detail ) : SKELETON::PrefDiag( parent, url, add_cancel ), m_message( message ), m_detail( NULL ) { #if GTKMM_CHECK_VERSION(2,6,0) m_message.set_width_chars( 60 ); #endif m_message.set_line_wrap( true ); m_message.set_padding( 8, 8 ); m_message.set_selectable( true ); m_message.property_can_focus() = false; m_detail = CORE::ViewFactory( CORE::VIEW_ARTICLEINFO, get_url() ); if( ! detail_html.empty() ) m_detail->set_command( "append_html", detail_html ); m_notebook.append_page( m_message, tab_message ); m_notebook.append_page( *m_detail, tab_detail ); m_notebook.signal_switch_page().connect( sigc::mem_fun( *this, &DetailDiag::slot_switch_page ) ); get_vbox()->pack_start( m_notebook ); show_all_children(); grab_ok(); } DetailDiag::~DetailDiag() { if( m_detail ) delete m_detail; } void DetailDiag::timeout() { if( m_detail ) m_detail->clock_in(); } void DetailDiag::slot_switch_page( GtkNotebookPage*, guint page ) { if( get_notebook().get_nth_page( page ) == m_detail ) m_detail->redraw_view(); } jd-2.8.7-140104/src/skeleton/detaildiag.h0000644000076400010400000000163311531461011014437 0ustar // ライセンス: GPL2 // 詳細表示ダイアログ #ifndef _DETAILDIAG_H #define _DETAILDIAG_H #include "prefdiag.h" namespace SKELETON { class View; class DetailDiag : public SKELETON::PrefDiag { Gtk::Notebook m_notebook; Gtk::Label m_message; SKELETON::View* m_detail; public: DetailDiag( Gtk::Window* parent, const std::string& url, const bool add_cancel, const std::string& message, const std::string& tab_message, const std::string& detail_html, const std::string& tab_detail ); virtual ~DetailDiag(); protected: Gtk::Notebook& get_notebook(){ return m_notebook; } SKELETON::View* get_detail(){ return m_detail; } private: virtual void slot_switch_page( GtkNotebookPage*, guint page ); virtual void timeout(); }; } #endif jd-2.8.7-140104/src/skeleton/dispatchable.cpp0000644000076400010400000000115511515322702015332 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "dispatchable.h" #include "dispatchmanager.h" using namespace SKELETON; Dispatchable::Dispatchable() : m_dispatchable( true ) {} Dispatchable::~Dispatchable() { #ifdef _DEBUG std::cout << "Dispatchable::~Dispatchable\n"; #endif set_dispatchable( false ); } void Dispatchable::set_dispatchable( const bool dispatchable ) { m_dispatchable = dispatchable; if( ! m_dispatchable ) CORE::get_dispmanager()->remove( this ); } void Dispatchable::dispatch() { if( m_dispatchable ) CORE::get_dispmanager()->add( this ); } jd-2.8.7-140104/src/skeleton/dispatchable.h0000644000076400010400000000201211515322702014770 0ustar // ライセンス: GPL2 // // Dispatchクラス // // Core::DispatchManagerと組み合わせて使う。詳しくはCore::DispatchManagerの説明を見ること // // なお派生クラスのデストラクタの中からdispatchを呼ぶと落ちるので、特にスレッドを使用している // 派生クラスのデストラクタの先頭に set_dispatchable( false ) を入れてdispatch不可にすること // #ifndef _DISPATCHABLE_H #define _DISPATCHABLE_H #include namespace CORE { class DispatchManager; } namespace SKELETON { class Dispatchable { friend class CORE::DispatchManager; bool m_dispatchable; public: Dispatchable(); virtual ~Dispatchable(); protected: void dispatch(); void set_dispatchable( const bool dispatchable ); // dispacth() で DispatchManager に登録されて // DispatchManager が callback_dispatch() を呼び戻す virtual void callback_dispatch() = 0; }; } #endif jd-2.8.7-140104/src/skeleton/dragnote.cpp0000644000076400010400000005640711570441710014526 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "dragnote.h" #include "tablabel.h" #include "toolbar.h" #include "view.h" #include "iconpopup.h" #include "icons/iconmanager.h" #include "control/controlid.h" #include "dndmanager.h" #include "session.h" #include using namespace SKELETON; DragableNoteBook::DragableNoteBook() : Gtk::VBox() , m_notebook_tab( this ) , m_notebook_toolbar( this ) , m_notebook_view( this ) , m_bt_tabswitch( this ) , m_page( -1 ) , m_dragging_tab( false ) , m_dragable( false ) , m_down_arrow( NULL ) { set_spacing( 0 ); m_notebook_tab.signal_switch_page().connect( sigc::mem_fun( *this, &DragableNoteBook::slot_switch_page_tab ) ); m_notebook_tab.sig_button_press().connect( sigc::mem_fun( *this, &DragableNoteBook::slot_button_press_event ) ); m_notebook_tab.sig_button_release().connect( sigc::mem_fun( *this, &DragableNoteBook::slot_button_release_event ) ); m_notebook_tab.sig_tab_motion_event().connect( sigc::mem_fun(*this, &DragableNoteBook::slot_motion_event ) ); m_notebook_tab.sig_tab_leave_event().connect( sigc::mem_fun(*this, &DragableNoteBook::slot_leave_event ) ); m_notebook_tab.sig_tab_drag_motion().connect( sigc::mem_fun(*this, &DragableNoteBook::slot_drag_motion ) ); m_notebook_tab.sig_scroll_event().connect( sigc::mem_fun(*this, &DragableNoteBook::slot_scroll_event ) ); m_hbox_tab.pack_start( m_notebook_tab ); m_hbox_tab.pack_start( m_bt_tabswitch, Gtk::PACK_SHRINK ); m_tooltip_tabswitch.set_tip( m_bt_tabswitch, "タブの一覧表示" ); pack_start( m_hbox_tab, Gtk::PACK_SHRINK ); pack_start( m_notebook_toolbar, Gtk::PACK_SHRINK ); pack_start( m_notebook_view ); m_show_tabs = true; m_show_toolbar = true; memset( &m_alloc_old, 0, sizeof( Alloc_NoteBook ) ); show_all_children(); } DragableNoteBook::~DragableNoteBook() { if( m_down_arrow ) delete m_down_arrow; } // // クロック入力 // void DragableNoteBook::clock_in() { m_notebook_tab.clock_in(); m_tooltip.clock_in(); } // // フォーカスアウト // void DragableNoteBook::focus_out() { m_tooltip.hide_tooltip(); } // // Auroraなどテーマによっては m_notebook_toolbar が m_notebook_view に上書きされて // 消えてしまうのでもう一度 m_notebook_toolbar を描画する // bool DragableNoteBook::on_expose_event( GdkEventExpose* event ) { const bool ret = Gtk::VBox::on_expose_event( event ); // ツールバー再描画 if( m_notebook_toolbar.get_parent() == this ){ const int min_toolbar_height = 4; const Alloc_NoteBook alloc = get_alloc_notebook(); const int y_start = get_show_tabs() ? alloc.y_tabbar + alloc.height_tabbar : alloc.y_toolbar; const int y_end = y_start + alloc.height_toolbar; if( alloc.height_toolbar > min_toolbar_height // ツールバーの中身が表示されている && y_start <= event->area.y + event->area.height && y_end >= event->area.y ){ GdkEventExpose event_toolbar = *event; if( event_toolbar.area.y < y_start ){ event_toolbar.area.height -= ( y_start - event_toolbar.area.y ); event_toolbar.area.y = y_start; } if( event_toolbar.area.y + event_toolbar.area.height > y_end ) event_toolbar.area.height = y_end - event_toolbar.area.y; #ifdef _DEBUG std::cout << "DragableNoteBook::on_expose_event" << " y_s = " << y_start << " y_e = " << y_end << " x = " << event->area.x << " y = " << event->area.y << " w = " << event->area.width << " h = " << event->area.height << "\n-> x_t = " << event_toolbar.area.x << " y_t = " << event_toolbar.area.y << " w_t = " << event_toolbar.area.width << " h_t = " << event_toolbar.area.height << std::endl; #endif if( event_toolbar.area.height ){ propagate_expose( m_notebook_toolbar, &event_toolbar ); // (注意) Auroraなどテーマによってはクリップ領域( event->area )を無視するものがあり // ビューのスクロールバーが消えてしまう時があるので明示的に再描画する m_notebook_view.redraw_scrollbar(); } } } return ret; } // // DragableNoteBook を構成している各Notebookの高さ // 及びタブの高さと位置を取得 ( 枠の描画用 ) // const Alloc_NoteBook DragableNoteBook::get_alloc_notebook() { Alloc_NoteBook alloc; m_notebook_tab.get_alloc_tab( alloc ); alloc.y_tabbar = m_notebook_tab.get_allocation().get_y(); alloc.height_tabbar = m_notebook_tab.get_allocation().get_height(); alloc.y_toolbar = m_notebook_toolbar.get_allocation().get_y(); alloc.height_toolbar = m_notebook_toolbar.get_allocation().get_height(); const int offset_tabbar = ( get_show_tabs() ? alloc.height_tabbar - ( alloc.y_tab + alloc.height_tab ) : 0 ); alloc.x_box = m_notebook_view.get_allocation().get_x(); alloc.y_box = m_notebook_view.get_allocation().get_y() - alloc.height_toolbar - offset_tabbar; alloc.width_box =m_notebook_view.get_allocation().get_width(); alloc.height_box = offset_tabbar + alloc.height_toolbar + m_notebook_view.get_allocation().get_height(); #ifdef _DEBUG std::cout << "DragableNoteBook::get_alloc_notebook" << " x_tab = " << alloc.x_tab << " w_tab = " << alloc.width_tab << " h_tab = " << alloc.height_tab << " y_tabbar = " << alloc.y_tabbar << " h_tabbar = " << alloc.height_tabbar << " y_toolbar = " << alloc.y_toolbar << " h_toolbar = " << alloc.height_toolbar << " x_box = " << alloc.x_box << " y_box = " << alloc.y_box << " w_box = " << alloc.width_box << " h_box = " << alloc.height_box << std::endl; #endif return alloc; } // // 枠描画 // // gtknotebook.c( Revision 19593, Sat Feb 16 04:09:15 2008 UTC ) からのハック。環境やバージョンによっては問題が出るかもしれないので注意 // void DragableNoteBook::draw_box( Gtk::Widget* widget, GdkEventExpose* event ) { const Glib::RefPtr win = widget->get_window(); const Gdk::Rectangle rect( &(event->area) ); Alloc_NoteBook alloc = get_alloc_notebook(); if( alloc.height_box > 0 ){ if( get_show_tabs() ){ // gtk2.18以降?では新しいタブを開くときに一瞬タブが消える場合がある // その場合は保存しておいた座標と高さを利用してboxを描画する if( ! alloc.height_tab ){ if( ! m_alloc_old.height_tab ) return; alloc.y_box = m_alloc_old.y_box; alloc.height_box = m_alloc_old.height_box; } else m_alloc_old = alloc; widget->get_style()->paint_box_gap( win, Gtk::STATE_NORMAL, Gtk::SHADOW_OUT, rect, *widget, "notebook", alloc.x_box, alloc.y_box, alloc.width_box, alloc.height_box, Gtk::POS_TOP, alloc.x_tab, alloc.width_tab ); } else{ widget->get_style()->paint_box( win, Gtk::STATE_NORMAL, Gtk::SHADOW_OUT, rect, *widget, "notebook", alloc.x_box, alloc.y_box, alloc.width_box, alloc.height_box ); } } } void DragableNoteBook::set_show_tabs( bool show_tabs ) { #ifdef _DEBUG std::cout << "DragableNoteBook::set_show_tabs show_tabs = " << show_tabs << std::endl; #endif if( m_show_tabs ){ remove( m_hbox_tab ); m_show_tabs = false; } else{ remove( m_notebook_toolbar ); remove( m_notebook_view ); pack_start( m_hbox_tab, Gtk::PACK_SHRINK ); pack_start( m_notebook_toolbar, Gtk::PACK_SHRINK ); pack_start( m_notebook_view ); m_show_tabs = true; } } void DragableNoteBook::set_scrollable( bool scrollable ) { m_notebook_tab.set_scrollable( scrollable ); } const int DragableNoteBook::get_n_pages() { return m_notebook_view.get_n_pages(); } Gtk::Widget* DragableNoteBook::get_nth_page( int page_num ) { return m_notebook_view.get_nth_page( page_num ); } const int DragableNoteBook::page_num( const Gtk::Widget& child ) { return m_notebook_view.page_num( child ); } const int DragableNoteBook::get_current_page() { return m_notebook_view.get_current_page(); } void DragableNoteBook::set_current_page( int page_num ) { if( get_current_page() == page_num ) return; if( page_num >= get_n_pages() ) page_num = get_n_pages()-1; m_notebook_tab.set_current_page( page_num ); m_notebook_view.set_current_page( page_num ); SKELETON::View* view = dynamic_cast< View* >( get_nth_page( page_num ) ); if( view ) set_current_toolbar( view->get_id_toolbar(), view ); } // // ページのappendとinsert // int DragableNoteBook::append_page( const std::string& url, Gtk::Widget& child ) { m_notebook_view.append_page( child ); m_bt_tabswitch.show_button(); SKELETON::TabLabel* tablabel = create_tablabel( url ); return m_notebook_tab.append_tab( *tablabel ); } int DragableNoteBook::insert_page( const std::string& url, Gtk::Widget& child, int page ) { m_notebook_view.insert_page( child, page ); m_bt_tabswitch.show_button(); SKELETON::TabLabel* tablabel = create_tablabel( url ); return m_notebook_tab.insert_tab( *tablabel, page ); } // // タブの文字列取得 // const std::string DragableNoteBook::get_tab_fulltext( const int page ) { return m_notebook_tab.get_tab_fulltext( page ); } // // タブに文字列をセットとタブ幅調整 // void DragableNoteBook::set_tab_fulltext( const std::string& str, const int page ) { m_notebook_tab.set_tab_fulltext( str, page ); } // // ページ取り除き // void DragableNoteBook::remove_page( const int page, const bool adjust_tab ) { SKELETON::TabLabel* tablabel = m_notebook_tab.get_tablabel( page ); m_notebook_tab.remove_tab( page, adjust_tab ); m_notebook_view.remove_page( page ); if( tablabel ) delete tablabel; m_tooltip.hide_tooltip(); if( ! get_n_pages() ) m_bt_tabswitch.hide_button(); } // // ツールバー取得 // SKELETON::ToolBar* DragableNoteBook::get_toolbar( int page ) { return dynamic_cast< SKELETON::ToolBar* >( m_notebook_toolbar.get_nth_page( page ) ); } // // ツールバー全体を表示 // // タブにビューが表示されたら admin から呼び出される // void DragableNoteBook::show_toolbar() { #ifdef _DEBUG std::cout << "DragableNoteBook::show_toolbar\n"; #endif if( ! m_show_toolbar && m_notebook_toolbar.get_n_pages() ){ remove( m_notebook_view ); pack_start( m_notebook_toolbar, Gtk::PACK_SHRINK ); pack_start( m_notebook_view ); m_show_toolbar = true; } } // // ツールバー全体を非表示 // // タブに全てのビューが無くなったら admin から呼び出される // void DragableNoteBook::hide_toolbar() { #ifdef _DEBUG std::cout << "DragableNoteBook::hide_toolbar\n"; #endif if( m_show_toolbar && m_notebook_toolbar.get_n_pages() ){ remove( m_notebook_toolbar ); m_show_toolbar = false; } } // // ツールバーセット // // 各Adminクラスの virtual void show_toolbar() でセットされる // void DragableNoteBook::append_toolbar( Gtk::Widget& toolbar ) { #ifdef _DEBUG std::cout << "DragableNoteBook::append_toolbar\n"; #endif m_notebook_toolbar.append_page( toolbar ); } // // ツールバー切り替え // void DragableNoteBook::set_current_toolbar( const int id_toolbar, SKELETON::View* view ) { // タブ操作中 if( SESSION::is_tab_operating( view->get_url_admin() ) ) return; #ifdef _DEBUG std::cout << "DragableNoteBook::set_current_toolbar id = " << id_toolbar << " / " << m_notebook_toolbar.get_n_pages() << std::endl << "url = " << view->get_url() << std::endl; #endif if( m_notebook_toolbar.get_n_pages() <= id_toolbar ) return; m_notebook_toolbar.set_current_page( id_toolbar ); // ツールバーのラベルなどの情報を更新 SKELETON::ToolBar* toolbar = get_toolbar( id_toolbar ); if( toolbar ){ toolbar->set_view( view ); toolbar->show_toolbar(); } } const int DragableNoteBook::get_current_toolbar() { return m_notebook_toolbar.get_current_page(); } // // ツールバー内の検索ボックスにフォーカスを移す // void DragableNoteBook::focus_toolbar_search() { SKELETON::ToolBar* toolbar = get_toolbar( m_notebook_toolbar.get_current_page() ); if( toolbar ) toolbar->focus_entry_search(); } // // ツールバーURL更新 // void DragableNoteBook::update_toolbar_url( std::string& url_old, std::string& url_new ) { for( int i = 0; i < m_notebook_toolbar.get_n_pages(); ++i ){ SKELETON::ToolBar* toolbar = get_toolbar( i ); if( toolbar && toolbar->get_url() == url_old ) toolbar->set_url( url_new ); } } // // ツールバーボタン表示更新 // void DragableNoteBook::update_toolbar_button() { for( int i = 0; i < m_notebook_toolbar.get_n_pages(); ++i ){ SKELETON::ToolBar* toolbar = get_toolbar( i ); if( toolbar ) toolbar->update_button(); } } // // タブのアイコンを取得する // const int DragableNoteBook::get_tabicon( const int page ) { SKELETON::TabLabel* tablabel = m_notebook_tab.get_tablabel( page ); if( tablabel ) return tablabel->get_id_icon(); return ICON::NONE; } // // タブにアイコンをセットする // void DragableNoteBook::set_tabicon( const std::string& iconname, const int page, const int id ) { SKELETON::TabLabel* tablabel = m_notebook_tab.get_tablabel( page ); if( tablabel && id != ICON::NONE ) tablabel->set_id_icon( id ); } // // タブ作成 // SKELETON::TabLabel* DragableNoteBook::create_tablabel( const std::string& url ) { SKELETON::TabLabel *tablabel = new SKELETON::TabLabel( url ); // ドラッグ設定 GdkEventButton event; m_control.get_eventbutton( CONTROL::DragStartButton, event ); tablabel->set_dragable( m_dragable, event.button ); tablabel->sig_tab_motion_event().connect( sigc::mem_fun(*this, &DragableNoteBook::slot_motion_event ) ); tablabel->sig_tab_leave_event().connect( sigc::mem_fun(*this, &DragableNoteBook::slot_leave_event ) ); tablabel->sig_tab_drag_begin().connect( sigc::mem_fun(*this, &DragableNoteBook::slot_drag_begin ) ); tablabel->sig_tab_drag_data_get().connect( sigc::mem_fun(*this, &DragableNoteBook::slot_drag_data_get ) ); tablabel->sig_tab_drag_end().connect( sigc::mem_fun(*this, &DragableNoteBook::slot_drag_end ) ); return tablabel; } // // タブの幅を固定するか // void DragableNoteBook::set_fixtab( bool fix ) { m_notebook_tab.set_fixtab( fix ); } // // タブ幅調整 // bool DragableNoteBook::adjust_tabwidth() { return m_notebook_tab.adjust_tabwidth(); } // // notebook_tabのタブが切り替わったときに呼ばれるslot // void DragableNoteBook::slot_switch_page_tab( GtkNotebookPage* bookpage, guint page ) { // view も切り替える m_notebook_view.set_current_page( page ); // ツールバー(枠) 再描画 m_notebook_toolbar.queue_draw(); m_sig_switch_page.emit( bookpage, page ); } // // タブの上でボタンを押した // bool DragableNoteBook::slot_button_press_event( GdkEventButton* event ) { // ボタンを押した時点でのページ番号を記録しておく m_page = m_notebook_tab.get_page_under_mouse(); m_dragging_tab = false; // ダブルクリック // button_release_eventでは event->type に必ず GDK_BUTTON_RELEASE が入る m_dblclick = false; if( event->type == GDK_2BUTTON_PRESS ) m_dblclick = true; #ifdef _DEBUG std::cout << "DragableNoteBook::on_button_press_event page = " << m_page << std::endl; std::cout << "x = " << (int)event->x_root << " y = " << (int)event->y_root << " dblclick = " << m_dblclick << std::endl; #endif if( m_page >= 0 && m_page < get_n_pages() ){ // ページ切替え if( m_control.button_alloted( event, CONTROL::ClickButton ) ){ set_current_page( m_page ); m_sig_tab_clicked.emit( m_page ); } return true; } else m_page = -1; return false; } // // タブの上でボタンを離した // bool DragableNoteBook::slot_button_release_event( GdkEventButton* event ) { const int page = m_notebook_tab.get_page_under_mouse(); const int x = (int)event->x_root; const int y = (int)event->y_root; #ifdef _DEBUG std::cout << "DragableNoteBook::on_button_release_event\n"; std::cout << "x = " << (int)event->x_root << " y = " << (int)event->y_root << std::endl; #endif if( ! m_dragging_tab && m_page >= 0 && m_page < get_n_pages() ){ // ダブルクリックの処理のため一時的にtypeを切替える GdkEventType type_copy = event->type; if( m_dblclick ) event->type = GDK_2BUTTON_PRESS; // タブを閉じる if( page == m_page && m_control.button_alloted( event, CONTROL::CloseTabButton ) ){ m_sig_tab_close.emit( m_page ); // タブにページが残ってなかったらtrueをreturnしないと落ちる // TabNotebook::on_button_release_event() も参照せよ // // (注意) なぜか m_notebook_tab.get_n_pages() < m_notebook_view.get_n_pages() の時があって // 以前の様に // if( get_n_pages() == 0 ) // という条件では m_notebook_tab.get_n_pages() = 0 でも get_n_pages() != 0 になって落ちることがある if( m_notebook_tab.get_n_pages() == 0 ){ m_page = -1; return true; } } // タブを再読み込み else if( m_control.button_alloted( event, CONTROL::ReloadTabButton ) ) m_sig_tab_reload.emit( m_page ); // ポップアップメニュー else if( m_control.button_alloted( event, CONTROL::PopupmenuButton ) ) m_sig_tab_menu.emit( m_page, x, y ); m_page = -1; event->type = type_copy; } return false; } // // タブの中でマウスを動かした // void DragableNoteBook::slot_motion_event() { const int page = m_notebook_tab.get_page_under_mouse(); #ifdef _DEBUG std::cout << "DragableNoteBook::slot_motion_event page = " << page << std::endl; #endif // ツールチップにテキストをセット if( page >= 0 && page < m_notebook_tab.get_n_pages() ){ SKELETON::TabLabel* tab = m_notebook_tab.get_tablabel( page ); if( tab ) m_tooltip.set_text( tab->get_fulltext() ); } else m_tooltip.hide_tooltip(); } // // タブからマウスが出た // void DragableNoteBook::slot_leave_event() { #ifdef _DEBUG std::cout << "DragableNoteBook::slot_leave_event page\n"; #endif m_tooltip.hide_tooltip(); } // notebook_tab の上でホイールを回した bool DragableNoteBook::slot_scroll_event( GdkEventScroll* event ) { #ifdef _DEBUG std::cout << "DragableNoteBook::slot_scroll_event direction = " << event->direction << " page = " << get_current_page() << std::endl; #endif bool ret = false; // タブの循環 if( event->direction == GDK_SCROLL_UP && get_current_page() == 0 ){ set_current_page( get_n_pages() -1 ); ret = true; } else if( event->direction == GDK_SCROLL_DOWN && get_current_page() == get_n_pages() -1 ){ set_current_page( 0 ); ret = true; } m_sig_tab_scrolled.emit( event ); return ret; } // // タブのドラッグを開始 // void DragableNoteBook::slot_drag_begin() { #ifdef _DEBUG std::cout << "DragableNoteBook::slot_drag_begin page = " << m_page << std::endl; #endif CORE::DND_Begin(); m_dragging_tab = true; } // // タブをドラッグ中 // // 矢印アイコンをタブの上に表示する // void DragableNoteBook::slot_drag_motion( const int page, const int tab_x, const int tab_y, const int tab_width ) { #ifdef _DEBUG std::cout << "DragableNoteBook::slot_drag_motion page = " << page << " tab_x = " << tab_x << " tab_y = " << tab_y << " tab_w " << tab_width << std::endl; #endif if( page < 0 || page == m_page ){ if( m_down_arrow ) m_down_arrow->hide(); } else if( m_dragging_tab ){ if( ! m_down_arrow ) m_down_arrow = new SKELETON::IconPopup( ICON::DOWN ); m_down_arrow->show(); const int space = 4; int x, y; m_notebook_tab.get_window()->get_origin( x, y ); x += tab_x - m_down_arrow->get_img_width()/2; y += tab_y - m_down_arrow->get_img_height() - space; if( page > m_page ) x += tab_width; m_down_arrow->move( x , y ); } } // // D&Dで受信側がデータ送信を要求してきた // void DragableNoteBook::slot_drag_data_get( Gtk::SelectionData& selection_data ) { #ifdef _DEBUG std::cout << "DragableNoteBook::slot_drag_data_get target = " << selection_data.get_target() << " page = " << m_page << std::endl; #endif // お気に入りがデータ送信を要求してきた if( selection_data.get_target() == DNDTARGET_FAVORITE ) m_sig_drag_data_get.emit( selection_data, m_page ); // タブの入れ替え処理 else if( selection_data.get_target() == DNDTARGET_TAB ){ int page = m_notebook_tab.get_page_under_mouse(); if( page >= m_notebook_tab.get_n_pages() ) page = m_notebook_tab.get_n_pages()-1; // ドラッグ前とページが変わっていたら入れ替え if( m_page != -1 && page != -1 && m_page != page ){ #ifdef _DEBUG std::cout << "reorder_chiled " << m_page << " -> " << page << std::endl; #endif m_notebook_tab.reorder_child( m_page, page ); m_notebook_tab.queue_draw(); m_notebook_view.reorder_child( *m_notebook_view.get_nth_page( m_page ), page ); m_page = -1; } if( m_down_arrow ) m_down_arrow->hide(); } } // // タブのドラッグを終了 // void DragableNoteBook::slot_drag_end() { #ifdef _DEBUG std::cout << "DragableNoteBook::slot_drag_end\n"; #endif m_dragging_tab = false; if( m_down_arrow ) m_down_arrow->hide(); CORE::DND_End(); } jd-2.8.7-140104/src/skeleton/dragnote.h0000644000076400010400000001505211517313451014163 0ustar // ライセンス: GPL2 // // タブをドラッグしてページを入れ替え可能なNoteBook // // DragableNoteBook は 下の3つの notebook から構成されている // // タブ : TabNotebook // ツールバー : ToolBarNotebook // ビュー : ViewNotebook #ifndef _DRAGNOTE_H #define _DRAGNOTE_H #include "tabnote.h" #include "toolbarnote.h" #include "viewnote.h" #include "tabswitchbutton.h" #include "tooltip.h" #include "control/control.h" #include namespace SKELETON { class View; class ToolBar; class TabLabel; class IconPopup; typedef sigc::signal< void, GtkNotebookPage*, int > SIG_SWITCH_PAGE; typedef sigc::signal< void, int > SIG_TAB_CLICKED; typedef sigc::signal< void, int > SIG_TAB_CLOSE; typedef sigc::signal< void, int > SIG_TAB_RELOAD; typedef sigc::signal< void, int, int , int > SIG_TAB_MENU; typedef sigc::signal< void, GdkEventScroll* > SIG_TAB_SCROLLED; typedef sigc::signal< void, Gtk::SelectionData&, const int > SIG_DRAG_DATA_GET; // DragableNoteBook を構成している各Notebookの高さ // 及びタブの高さや位置の情報 struct Alloc_NoteBook { int y_tab; int x_tab; int height_tab; int width_tab; int y_tabbar; int height_tabbar; int y_toolbar; int height_toolbar; int x_box; int y_box; int width_box; int height_box; }; class DragableNoteBook : public Gtk::VBox { SIG_SWITCH_PAGE m_sig_switch_page; SIG_TAB_CLICKED m_sig_tab_clicked; SIG_TAB_CLOSE m_sig_tab_close; SIG_TAB_RELOAD m_sig_tab_reload; SIG_TAB_MENU m_sig_tab_menu; SIG_TAB_SCROLLED m_sig_tab_scrolled; SIG_DRAG_DATA_GET m_sig_drag_data_get; // DragableNoteBook は 下の3つのノートブックから出来ている TabNotebook m_notebook_tab; // タブ ToolBarNotebook m_notebook_toolbar; // ツールバー ViewNotebook m_notebook_view; // ビュー Gtk::HBox m_hbox_tab; TabSwitchButton m_bt_tabswitch; // タブの切り替えボタン Gtk::Tooltips m_tooltip_tabswitch; bool m_show_tabs; bool m_show_toolbar; int m_page; // タブをドラッグ中 bool m_dragging_tab; bool m_dblclick; // 入力コントローラ CONTROL::Control m_control; Tooltip m_tooltip; bool m_dragable; SKELETON::IconPopup* m_down_arrow; Alloc_NoteBook m_alloc_old; public: SIG_SWITCH_PAGE signal_switch_page(){ return m_sig_switch_page; } SIG_TAB_CLICKED sig_tab_clicked() { return m_sig_tab_clicked; } SIG_TAB_CLOSE sig_tab_close() { return m_sig_tab_close; } SIG_TAB_RELOAD sig_tab_reload(){ return m_sig_tab_reload; } SIG_TAB_MENU sig_tab_menu() { return m_sig_tab_menu; } SIG_TAB_SCROLLED sig_tab_scrolled(){ return m_sig_tab_scrolled; } SIG_DRAG_DATA_GET sig_drag_data_get() { return m_sig_drag_data_get; } DragableNoteBook(); virtual ~DragableNoteBook(); void clock_in(); void focus_out(); // 枠描画 void draw_box( Gtk::Widget* widget, GdkEventExpose* event ); const bool get_show_tabs() const{ return m_show_tabs; } void set_show_tabs( bool show_tabs ); void set_scrollable( bool scrollable ); const int get_n_pages(); Gtk::Widget* get_nth_page( int page_num ); const int page_num( const Gtk::Widget& child ); const int get_current_page(); void set_current_page( int page_num ); int append_page( const std::string& url, Gtk::Widget& child ); int insert_page( const std::string& url, Gtk::Widget& child, int page ); void remove_page( const int page, const bool adust_tab ); // ツールバー関係 // 各Adminクラスの virtual void show_toolbar()でツールバーを作成してappend_toolbar()で登録する void show_toolbar(); void hide_toolbar(); void append_toolbar( Gtk::Widget& toolbar ); void set_current_toolbar( const int id_toolbar, SKELETON::View* view ); const int get_current_toolbar(); void focus_toolbar_search(); // ツールバー内の検索entryにフォーカスを移す void update_toolbar_url( std::string& url_old, std::string& url_new ); void update_toolbar_button(); // タブの文字列取得/セット const std::string get_tab_fulltext( const int page ); void set_tab_fulltext( const std::string& str, const int page ); // タブのアイコン取得/セット const int get_tabicon( const int page ); void set_tabicon( const std::string& iconname, const int page, const int icon ); // ドラッグ可/不可切り替え(デフォルト false ); void set_dragable( bool dragable ){ m_dragable = dragable; } // タブの幅を固定するか void set_fixtab( bool fix ); // タブ幅調整 bool adjust_tabwidth(); // タブ切り替えボタン Gtk::Button& get_tabswitch_button(){ return m_bt_tabswitch.get_button(); } private: virtual bool on_expose_event( GdkEventExpose* event ); // DragableNoteBook を構成している各Notebookの高さ // 及びタブの高さと位置を取得 ( 枠の描画用 ) const Alloc_NoteBook get_alloc_notebook(); // ツールバー取得 SKELETON::ToolBar* get_toolbar( int page ); // タブ作成 SKELETON::TabLabel* create_tablabel( const std::string& url ); // notebook_tabのタブが切り替わったときに呼び出されるslot void slot_switch_page_tab( GtkNotebookPage*, guint page ); // notebook_tab の上でボタンを押した/離した bool slot_button_press_event( GdkEventButton* event ); bool slot_button_release_event( GdkEventButton* event ); // notebook_tab の上でホイールを回した bool slot_scroll_event( GdkEventScroll* event ); protected: // コントローラ CONTROL::Control& get_control(){ return m_control; } // タブからくるシグナルにコネクトする void slot_motion_event(); void slot_leave_event(); void slot_drag_begin(); void slot_drag_motion( const int page, const int tab_x, const int tab_y, const int tab_width ); void slot_drag_data_get( Gtk::SelectionData& selection_data ); void slot_drag_end(); }; } #endif jd-2.8.7-140104/src/skeleton/dragtreeview.cpp0000644000076400010400000003726512060652435015417 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "dragtreeview.h" #include "view.h" #include "popupwin.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" #include "control/controlid.h" #include "command.h" #include "colorid.h" #include "dndmanager.h" #include "session.h" #ifndef MAX #define MAX( a, b ) ( a > b ? a : b ) #endif #ifndef MIN #define MIN( a, b ) ( a < b ? a : b ) #endif using namespace SKELETON; DragTreeView::DragTreeView( const std::string& url, const std::string& dndtarget, const bool use_usr_fontcolor, const std::string& fontname, const int colorid_text, const int colorid_bg, const int colorid_bg_even ) : JDTreeViewBase(), m_url( url ), m_dndtarget( dndtarget ), m_dragging( false ), m_use_bg_even( false ), m_popup_win( NULL ), m_popup_shown( false ) { #ifdef _DEBUG std::cout << "DragTreeView::DragTreeView\n"; #endif set_enable_search( false ); set_rules_hint( CONFIG::get_use_tree_gtkrc() ); add_events( Gdk::LEAVE_NOTIFY_MASK ); if( use_usr_fontcolor ){ init_color( colorid_text, colorid_bg, colorid_bg_even ); init_font( fontname ); } get_selection()->set_mode( Gtk::SELECTION_MULTIPLE ); get_selection()->signal_changed().connect( sigc::mem_fun( *this, &DragTreeView::slot_selection_changed ) ); // D&D 設定 std::list< Gtk::TargetEntry > targets; targets.push_back( Gtk::TargetEntry( get_dndtarget(), Gtk::TARGET_SAME_APP, 0 ) ); // ドラッグ開始ボタン設定 Gdk::ModifierType type = Gdk::BUTTON1_MASK; GdkEventButton event; m_control.get_eventbutton( CONTROL::DragStartButton, event ); switch( event.button ){ case 1: type = Gdk::BUTTON1_MASK; break; case 2: type = Gdk::BUTTON2_MASK; break; case 3: type = Gdk::BUTTON3_MASK; break; case 4: type = Gdk::BUTTON4_MASK; break; case 5: type = Gdk::BUTTON5_MASK; break; } drag_source_set( targets, type ); } DragTreeView::~DragTreeView() { delete_popup(); } // // 他のアプリからの text/url-list のドロップを有効にする // ドロップされるとSIG_DROPPED_URI_LIST を発行する // void DragTreeView::set_enable_drop_uri_list() { std::list< Gtk::TargetEntry > targets_drop; targets_drop.push_back( Gtk::TargetEntry( "text/uri-list" ) ); // ドロップされると on_drag_data_received() が呼び出される drag_dest_set( targets_drop, Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_COPY ); } // // 再描画 // void DragTreeView::redraw_view() { // 今のところ特に何もしない // ポップアップが表示されていたらポップアップを再描画 if( is_popup_shown() && m_popup_win->view() ) m_popup_win->view()->redraw_view(); } // // 色初期化 // void DragTreeView::init_color( const int colorid_text, const int colorid_bg, const int colorid_bg_even ) { if( CONFIG::get_use_tree_gtkrc() ) return; // 文字色 m_color_text.set( CONFIG::get_color( colorid_text ) ); modify_text( get_state(), m_color_text ); // 背景色 m_color_bg.set( CONFIG::get_color( colorid_bg ) ); modify_base( get_state(), m_color_bg ); m_use_bg_even = ! ( CONFIG::get_color( colorid_bg ) == CONFIG::get_color( colorid_bg_even ) ); m_color_bg_even.set( CONFIG::get_color( colorid_bg_even ) ); } // // フォント初期化 // void DragTreeView::init_font( const std::string& fontname ) { Pango::FontDescription pfd( fontname ); pfd.set_weight( Pango::WEIGHT_NORMAL ); modify_font( pfd ); m_tooltip.modify_font_label( fontname ); } // // クロック入力 // void DragTreeView::clock_in() { // ポップアップ表示中はそちらにクロックを回す if( is_popup_shown() && m_popup_win->view() ){ m_popup_win->view()->clock_in(); return; } m_tooltip.clock_in(); } // // ツールチップに文字をセット // void DragTreeView::set_str_tooltip( const std::string& text ) { m_tooltip.set_text( text ); } // // ツールチップ最小幅設定 // void DragTreeView::set_tooltip_min_width( const int& min_width ) { m_tooltip.set_min_width( min_width); } // // ツールチップを表示 // void DragTreeView::show_tooltip() { m_tooltip.show_tooltip(); } // // ツールチップ隠す // void DragTreeView::hide_tooltip() { m_tooltip.hide_tooltip(); } // // ポップアップが表示されていてかつマウスがその上にあるか // const bool DragTreeView::is_mouse_on_popup() { if( ! is_popup_shown() ) return false; if( ! m_popup_win->view() ) return false; return m_popup_win->view()->is_mouse_on_view(); } // // ポップアップウィンドウ表示 // void DragTreeView::show_popup( const std::string& url, View* view ) { const int mrg_x = 10; const int mrg_y = 10; #ifdef _DEBUG std::cout << "DragTreeView::show_popup url = " << url << std::endl; #endif delete_popup(); m_popup_win = new PopupWin( this, view, mrg_x, mrg_y ); m_popup_win->signal_leave_notify_event().connect( sigc::mem_fun( *this, &DragTreeView::slot_popup_leave_notify_event ) ); m_popup_win->sig_hide_popup().connect( sigc::mem_fun( *this, &DragTreeView::hide_popup ) ); m_pre_popup_url = url; m_popup_shown = true; } // // popup windowの外にポインタが出た // const bool DragTreeView::slot_popup_leave_notify_event( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "DragTreeView::slot_popup_leave_notify_event\n"; #endif // クリックしたときやホイールを回すと event->mode に GDK_CROSSING_GRAB // か GDK_CROSSING_UNGRAB がセットされてイベントが発生する場合がある if( event->mode == GDK_CROSSING_GRAB ) return false; if( event->mode == GDK_CROSSING_UNGRAB ) return false; // ポインタがポップアップ上にある場合はポップアップは消さない // 時々ポインタがポップアップの上にあってもイベントが発生する場合がある if( is_mouse_on_popup() ) return false; hide_popup(); return true; } // // ポップアップを隠す // void DragTreeView::hide_popup() { if( ! is_popup_shown() ) return; // ポップアップメニューが表示されてたらhideしない if( SESSION::is_popupmenu_shown() ) return; #ifdef _DEBUG std::cout << "DragTreeView::hide_popup\n"; #endif m_popup_win->hide(); if( m_popup_win->view() ) m_popup_win->view()->stop(); if( get_path_under_mouse().empty() ) m_pre_popup_url = std::string(); m_popup_shown = false; } // // ポップアップウィンドウ削除 // void DragTreeView::delete_popup() { if( m_popup_win ){ #ifdef _DEBUG std::cout << "DragTreeView::delete_popup\n"; #endif delete m_popup_win; m_popup_win = NULL; m_pre_popup_url = std::string(); m_popup_shown = false; } } // // マウスボタンを押した // bool DragTreeView::on_button_press_event( GdkEventButton* event ) { Gtk::TreeModel::Path path = get_path_under_xy( (int)event->x, (int)event->y ); m_dragging = false; m_selection_canceled = false; sig_button_press().emit( event ); // ドラッグして範囲選択 // m_path_dragstart が empty でない時に範囲選択を行う // on_motion_notify_event()も参照せよ if( m_control.button_alloted( event, CONTROL::TreeRowSelectionButton ) ) m_path_dragstart = m_path_dragpre = path; else m_path_dragstart = m_path_dragpre = Gtk::TreeModel::Path(); // 複数行選択時の動作 if( get_selection()->get_selected_rows().size() >= 2 ){ // D&Dのため、ctrlやshiftなしで普通にクリックしたときも選択解除しない if( !( event->state & GDK_CONTROL_MASK ) && !( event->state & GDK_SHIFT_MASK ) ){ // ただし範囲選択外をクリックしたとき、または範囲選択開始ボタンを押したときは選択解除 if( ! get_selection()->is_selected( path ) || ! m_path_dragstart.empty() ){ get_selection()->unselect_all(); if( get_row( path ) ) set_cursor( path ); m_selection_canceled = true; // ボタンを離したときにシグナルをemitしないようにする } else return true; } } return Gtk::TreeView::on_button_press_event( event ); } // // マウスボタンを離した // bool DragTreeView::on_button_release_event( GdkEventButton* event ) { bool emit_sig = false; // true なら m_sig_button_release をemitする Gtk::TreeModel::Path path = get_path_under_xy( (int)event->x, (int)event->y ); if( ! m_dragging // ドラッグ中ではない && !m_selection_canceled // on_button_press_event()で選択状態を解除していない && !( event->state & GDK_CONTROL_MASK ) && !( event->state & GDK_SHIFT_MASK ) // ctrl/shift + クリックで複数行選択操作をしてない場合 && !( !m_path_dragstart.empty() && ! path.empty() && path != m_path_dragstart ) // 範囲選択操作をしていない場合 ){ // 以上の場合はシグナルをemitする emit_sig = true; // 範囲選択状態でポップアップメニュー以外のボタンを離したら選択解除 if( get_selection()->get_selected_rows().size() >= 2 && ! m_control.button_alloted( event, CONTROL::PopupmenuButton ) ){ get_selection()->unselect_all(); if( get_row( path ) ) set_cursor( path ); emit_sig = false; } } // ポップアップメニューボタンを押したら必ずシグナルをemit if( m_control.button_alloted( event, CONTROL::PopupmenuButton ) ) emit_sig = true; m_path_dragstart = m_path_dragpre = Gtk::TreeModel::Path(); const bool expanded = row_expanded( path ); const bool ret = Gtk::TreeView::on_button_release_event( event ); // 左の△ボタンを押してディレクトリを開け閉めした場合は信号のemitをキャンセル if( expanded != row_expanded( path ) ) emit_sig = false; if( emit_sig ) sig_button_release().emit( event ); return ret; } // // D&D開始 // // このtreeがソースで無い時は呼ばれないのに注意 // void DragTreeView::on_drag_begin( const Glib::RefPtr< Gdk::DragContext >& context ) { #ifdef _DEBUG Gtk::TreeModel::Path path = get_path_under_mouse(); std::cout << "DragTreeView::on_drag_begin path = " << path.to_string() << std::endl; #endif m_dragging = true; CORE::DND_Begin(); Gtk::TreeView::on_drag_begin( context ); } // // D&D 終了 // // このtreeがソースでない時は呼び出されない // void DragTreeView::on_drag_end( const Glib::RefPtr< Gdk::DragContext >& context ) { #ifdef _DEBUG std::cout << "DragTreeView::on_drag_end\n"; #endif m_dragging = false; CORE::DND_End(); Gtk::TreeView::on_drag_end( context ); } // // ドロップされた void DragTreeView::on_drag_data_received( const Glib::RefPtr< Gdk::DragContext >& context, int x, int y, const Gtk::SelectionData& selection, guint info, guint time ) { #ifdef _DEBUG std::cout << "DragTreeView::on_drag_data_received type = " << selection.get_data_type() << std::endl; #endif if( selection.get_data_type() == "text/uri-list" ){ #ifdef _DEBUG std::cout << selection.get_data_as_string() << std::endl; #endif std::list< std::string > uri_list = MISC::get_lines( MISC::url_decode( selection.get_data_as_string() ) ); m_sig_dropped_url_list.emit( uri_list ); } context->drag_finish( true, false, time ); } // // キーボードのキーを押した // bool DragTreeView::on_key_press_event( GdkEventKey* event ) { #ifdef _DEBUG std::cout << "DragTreeView::on_key_press_event\n"; #endif // ポップアップ表示中はそちらにクロックを回す if( is_popup_shown() && m_popup_win->view() ) return m_popup_win->view()->slot_key_press( event ); return JDTreeViewBase::on_key_press_event( event ); } // // マウスを動かした // bool DragTreeView::on_motion_notify_event( GdkEventMotion* event ) { #ifdef _DEBUG // std::cout << "DragTreeView::on_motion_notify_event x = " << event->x << " y = " << event->y << std::endl; #endif // drag_source_set() でセットしたボタン以外でドラッグして範囲選択 // m_path_dragstart が empty で無いときに実行 // DragTreeView::on_button_press_event() も参照せよ Gtk::TreeModel::Path path = get_path_under_xy( (int)event->x, (int)event->y ); if( ! m_path_dragstart.empty() && !path.empty() && path != m_path_dragpre ){ get_selection()->unselect_all(); get_selection()->select( path, m_path_dragstart ); m_path_dragpre = path; } sig_motion_notify().emit( event ); return Gtk::TreeView::on_motion_notify_event( event ); } // マウスのwheelを回した bool DragTreeView::on_scroll_event( GdkEventScroll* event ) { sig_scroll_event().emit( event ); return true; } // // マウスホイールの処理 // void DragTreeView::wheelscroll( GdkEventScroll* event ) { Gtk::Adjustment *adj = get_vadjustment(); double val = adj->get_value(); int scr_inc = get_row_height() * CONFIG::get_tree_scroll_size(); if( event->direction == GDK_SCROLL_UP ) val = MAX( 0, val - scr_inc ); else if( event->direction == GDK_SCROLL_DOWN ) val = MIN( adj->get_upper() - adj->get_page_size(), val + scr_inc ); adj->set_value( val ); #ifdef _DEBUG std::cout << "DragTreeView::on_scroll_event\n"; std::cout << "scr_inc = " << scr_inc << std::endl; std::cout << "lower = " << adj->get_lower() << std::endl; std::cout << "upper = " << adj->get_upper() << std::endl; std::cout << "value = " << val << std::endl; std::cout << "step = " << adj->get_step_increment() << std::endl; std::cout << "page = " << adj->get_page_increment() << std::endl; std::cout << "page_size = " << adj->get_page_size() << std::endl; #endif } bool DragTreeView::on_leave_notify_event( GdkEventCrossing* event ) { m_tooltip.hide_tooltip(); if( ! is_mouse_on_popup() ){ hide_popup(); m_pre_popup_url = std::string(); } return Gtk::TreeView::on_leave_notify_event( event ); } // // 範囲選択更新 // void DragTreeView::slot_selection_changed() { int size = get_selection()->get_selected_rows().size(); std::string str; if( size >= 2 ) str = "選択数 " + MISC::itostr( size ); CORE::core_set_command( "set_info" ,"", str ); } // // 実際の描画の際に cellrenderer のプロパティをセットするスロット関数 // void DragTreeView::slot_cell_data( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ) { if( ! m_use_bg_even ){ cell->property_cell_background_set() = false; return; } Gtk::TreeModel::Row row = *it; Gtk::TreePath path = get_model()->get_path( row ); std::string path_str = path.to_string(); #ifdef _DEBUG std::cout << "DragTreeView::slot_cell_data path = " << path_str << std::endl; #endif bool even = false; int rownum = atoi( path_str.c_str() ); if( rownum %2 ) even = true; size_t pos = path_str.find( ":" ); while( pos != std::string::npos ){ path_str = path_str.substr( pos+1 ); rownum = atoi( path_str.c_str() ); if( ( even && ( rownum %2 ) ) || ( ! even && !( rownum %2 ) ) ) even = true; else even = false; pos = path_str.find( ":" ); } // 偶数行に色を塗る if( even ){ cell->property_cell_background_gdk() = m_color_bg_even; cell->property_cell_background_set() = true; } else cell->property_cell_background_set() = false; } jd-2.8.7-140104/src/skeleton/dragtreeview.h0000644000076400010400000001253011261540411015040 0ustar // ライセンス: GPL2 // // ドラッグ開始可能なtreeviewクラス // // set_enable_drop_uri_list() で他のアプリから text/uri-list のドロップを受け付ける // // フォント変更、偶数、奇数行別に色分けも可能。コンストラクタの use_usr_fontcolor を trueにしてフォントや色を指定する // 複数行選択、ツールチップ、ポップアップの表示も可能 // #ifndef _DRAGTREEVIEW_H #define _DRAGTREEVIEW_H #include "treeviewbase.h" #include "tooltip.h" #include "control/control.h" #include namespace SKELETON { class View; class PopupWin; typedef sigc::signal< void, const std::list< std::string >& > SIG_DROPPED_URI_LIST; class DragTreeView : public JDTreeViewBase { std::string m_url; std::string m_dndtarget; bool m_dragging; // ドラッグ中 // 範囲選択に使用 bool m_selection_canceled; // 範囲選択を解除したときにsig_button_release()を発行しないようにする Gtk::TreeModel::Path m_path_dragstart; Gtk::TreeModel::Path m_path_dragpre; Tooltip m_tooltip; // 色 bool m_use_bg_even; Gdk::Color m_color_text; Gdk::Color m_color_bg; Gdk::Color m_color_bg_even; // ポップアップウィンドウ用 PopupWin* m_popup_win; std::string m_pre_popup_url; bool m_popup_shown; // 入力コントローラ CONTROL::Control m_control; // text/uri-list をドロップされた SIG_DROPPED_URI_LIST m_sig_dropped_url_list; public: // use_usr_fontcolor が true の時はフォントや色を指定する DragTreeView( const std::string& url, const std::string& dndtarget, const bool use_usr_fontcolor, const std::string& fontname, const int colorid_text, const int colorid_bg, const int colorid_bg_even ); virtual ~DragTreeView(); virtual void clock_in(); SIG_DROPPED_URI_LIST sig_dropped_uri_list(){ return m_sig_dropped_url_list; } const std::string& get_dndtarget() const { return m_dndtarget; } // 他のアプリからの text/url-list のドロップを有効にする // ドロップされるとSIG_DROPPED_URI_LIST を発行する void set_enable_drop_uri_list(); void redraw_view(); // 色初期化 void init_color( const int colorid_text, const int colorid_bg, const int colorid_bg_even ); // フォント初期化 void init_font( const std::string& fontname ); // ツールチップ表示 // set_tooltip_min_width()で指定した幅よりもツールチップが広い場合は表示 void set_str_tooltip( const std::string& str ); void set_tooltip_min_width( const int& min_width ); void hide_tooltip(); void show_tooltip(); // ポップアップウィンドウ表示 const std::string& pre_popup_url() const { return m_pre_popup_url; } void reset_pre_popupurl( const std::string& url ){ if( ! m_pre_popup_url.empty() && m_pre_popup_url != url ) m_pre_popup_url = std::string(); } void show_popup( const std::string& url, View* view ); void hide_popup(); // マウスホイールの処理 void wheelscroll( GdkEventScroll* event ); // 実際の描画の際に cellrenderer のプロパティをセットするスロット関数 void slot_cell_data( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it ); protected: // drag_source_set() でセットしたボタンでドラッグした時に呼び出される順番は // // (1) on_button_press_event // (2) on_drag_begin // (3) on_drag_motion // (4) on_button_release_event // (5) on_drag_drop // (6) on_drag_end // // drag_source_set() でセットしたボタン以外でドラッグしたときは on_drag_motion() // ではなくて普通に on_motion_notify_event() が呼ばれるのに注意 // virtual bool on_button_press_event( GdkEventButton* event ); virtual bool on_button_release_event( GdkEventButton* event ); virtual void on_drag_begin( const Glib::RefPtr< Gdk::DragContext>& context ); virtual void on_drag_end( const Glib::RefPtr< Gdk::DragContext>& context ); virtual void on_drag_data_received( const Glib::RefPtr< Gdk::DragContext >& context, int x, int y, const Gtk::SelectionData& selection, guint info, guint time ); virtual bool on_key_press_event( GdkEventKey* event ); virtual bool on_motion_notify_event( GdkEventMotion* event ); virtual bool on_scroll_event( GdkEventScroll* event ); virtual bool on_leave_notify_event( GdkEventCrossing* event ); private: // ポップアップが表示されているか const bool is_popup_shown() const { return ( m_popup_win && m_popup_shown ); } // ポップアップ削除 void delete_popup(); // ポップアップが表示されていてかつマウスがその上にあるか const bool is_mouse_on_popup(); const bool slot_popup_leave_notify_event( GdkEventCrossing* event ); void slot_selection_changed(); }; } #endif jd-2.8.7-140104/src/skeleton/editcolumns.cpp0000644000076400010400000000233211350440352015232 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "editcolumns.h" #include "xml/tools.h" #include "type.h" using namespace SKELETON; EditColumns::EditColumns() { add( m_name ); add( m_image ); add( m_type ); add( m_url ); add( m_data ); add( m_underline ); add( m_expand ); add( m_fgcolor ); add( m_dirid ); } EditColumns::~EditColumns() {} void EditColumns::setup_row( Gtk::TreeModel::Row& row, const Glib::ustring url, const Glib::ustring name, const Glib::ustring data, const int type, const size_t dirid ) { row[ m_name ] = name; row[ m_image ] = XML::get_icon( type ); row[ m_type ] = type; row[ m_url ] = url; row[ m_data ] = data; row[ m_expand ] = false; row[ m_underline ] = false; row[ m_dirid ] = dirid; } void EditColumns::copy_row( const Gtk::TreeModel::Row& row_src, Gtk::TreeModel::Row& row_dest ) { const Glib::ustring url = row_src[ m_url ]; const Glib::ustring name = row_src[ m_name ]; const Glib::ustring data = row_src[ m_data ]; const int type = row_src[ m_type ]; const size_t dirid = row_src[ m_dirid ]; setup_row( row_dest, url, name, data, type, dirid ); } jd-2.8.7-140104/src/skeleton/editcolumns.h0000644000076400010400000000316611350440352014705 0ustar // ライセンス: GPL2 // // 編集可能な ColumnRecord クラス // // SKELETON::EditTreeView と組み合わせて使う // #ifndef _EDITCOLUMNS_H #define _EDITCOLUMNS_H #include namespace SKELETON { // 列ID enum { EDITCOL_NAME = 0, EDITCOL_IMAGE, // 以下不可視 EDITCOL_TYPE, EDITCOL_URL, EDITCOL_DATA, EDITCOL_UNDERLINE, EDITCOL_EXPAND, EDITCOL_FGCOLOR, EDITCOL_DIRID, EDITCOL_NUM_COL }; class EditColumns : public Gtk::TreeModel::ColumnRecord { public: Gtk::TreeModelColumn< Glib::ustring > m_name; // サブジェクト Gtk::TreeModelColumn< Glib::RefPtr< Gdk::Pixbuf > > m_image; // アイコン画像 Gtk::TreeModelColumn< int > m_type; // 行のタイプ Gtk::TreeModelColumn< Glib::ustring > m_url; // アドレス Gtk::TreeModelColumn< Glib::ustring > m_data; // ユーザデータ Gtk::TreeModelColumn< bool > m_underline; // 行に下線を引く Gtk::TreeModelColumn< bool > m_expand; // Dom::parse() で使用 Gtk::TreeModelColumn< Gdk::Color > m_fgcolor; // 文字色 Gtk::TreeModelColumn< size_t > m_dirid; // ディレクトリID EditColumns(); virtual ~EditColumns(); virtual void setup_row( Gtk::TreeModel::Row& row, const Glib::ustring url, const Glib::ustring name, const Glib::ustring data, const int type, const size_t dirid ); virtual void copy_row( const Gtk::TreeModel::Row& row_src, Gtk::TreeModel::Row& row_dest ); }; } #endif jd-2.8.7-140104/src/skeleton/edittreeview.cpp0000644000076400010400000015307012006761301015411 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "gtkmmversion.h" #include "edittreeview.h" #include "editcolumns.h" #include "msgdiag.h" #include "undobuffer.h" #include "dbtree/interface.h" #include "config/globalconf.h" #include "xml/document.h" #include "sharedbuffer.h" #include "global.h" #ifndef MAX #define MAX( a, b ) ( a > b ? a : b ) #endif #ifndef MIN #define MIN( a, b ) ( a < b ? a : b ) #endif enum { DNDSCROLLSPEED = 250 // D&D 時のスクロール速度 }; // // 行の最新アドレスを取得 // const std::string get_uptodate_url( const std::string& url_org, const int type ) { std::string url = url_org; if( type == TYPE_BOARD || type == TYPE_BOARD_UPDATE ){ url = DBTREE::url_boardbase( url ); } else if( type == TYPE_THREAD || type == TYPE_THREAD_UPDATE || type == TYPE_THREAD_OLD ){ url = DBTREE::url_dat( url ); } return url; } // // 行の最新状態を取得 // const int get_uptodate_type( const std::string& url, const int type_org ) { int type = type_org; if( type == TYPE_BOARD || type == TYPE_BOARD_UPDATE ){ if( DBTREE::board_status( url ) & STATUS_UPDATE ) type = TYPE_BOARD_UPDATE; else if( type != TYPE_BOARD ) type = TYPE_BOARD; } else if( type == TYPE_THREAD || type == TYPE_THREAD_UPDATE || type == TYPE_THREAD_OLD ){ if( DBTREE::article_status( url ) & STATUS_OLD ) type = TYPE_THREAD_OLD; else if( DBTREE::article_status( url ) & STATUS_UPDATE ) type = TYPE_THREAD_UPDATE; else if( type != TYPE_THREAD ) type = TYPE_THREAD; } return type; } // // ソート用比較クラス // // EditTreeView::sort()で使用 // class compare_path { SKELETON::JDTreeViewBase& m_treeview; SKELETON::EditColumns& m_columns; int m_mode; const int type_to_order( const int type ) { int order[]={ TYPE_DIR, TYPE_VBOARD, TYPE_BOARD_UPDATE, TYPE_BOARD, TYPE_THREAD_UPDATE, TYPE_THREAD, TYPE_IMAGE, TYPE_COMMENT, TYPE_THREAD_OLD, TYPE_UNKNOWN }; int i = 0; for( ; order[ i ] != TYPE_UNKNOWN; ++i ){ if( type == order[ i ] ) return i; } return i; } public: compare_path( SKELETON::JDTreeViewBase& treeview, SKELETON::EditColumns& columns, const int mode ) : m_treeview( treeview ), m_columns( columns ), m_mode( mode ){} // path_a が上ならtrue path_b が上ならfalse bool operator () ( const Gtk::TreePath& path_a, const Gtk::TreePath& path_b ) { const Gtk::TreeRow row_a = m_treeview.get_row( path_a ); const Gtk::TreeRow row_b = m_treeview.get_row( path_b ); if( ! row_a || ! row_b ) return false; // 名前でソート if( m_mode == SKELETON::SORT_BY_NAME ){ const Glib::ustring name_a = row_a[ m_columns.m_name ]; const Glib::ustring name_b = row_b[ m_columns.m_name ]; if( name_a > name_b ) return false; else if( name_a < name_b ) return true; } // タイプでソート const Glib::ustring url_a = row_a[ m_columns.m_url ]; const Glib::ustring url_b = row_b[ m_columns.m_url ]; const int type_a = get_uptodate_type( url_a.raw(), row_a[ m_columns.m_type ] ); const int type_b = get_uptodate_type( url_b.raw(), row_b[ m_columns.m_type ] ); const int order_a = type_to_order( type_a ); const int order_b = type_to_order( type_b ); if( order_a == order_b ) return false; return ( order_a < order_b ); } }; ///////////////////////////////////////////////// using namespace SKELETON; EditTreeView::EditTreeView( const std::string& url, const std::string& dndtarget, EditColumns& columns, const bool use_usr_fontcolor, const std::string& fontname, const int colorid_text, const int colorid_bg, const int colorid_bg_even ) : DragTreeView( url, dndtarget, use_usr_fontcolor, fontname, colorid_text, colorid_bg, colorid_bg_even ), m_url( url ), m_columns( columns ) { setup(); } EditTreeView::EditTreeView( const std::string& url, const std::string& dndtarget, EditColumns& columns ) : DragTreeView( url, dndtarget, false, "", 0, 0, 0 ), m_url( url ), m_columns( columns ) { setup(); } void EditTreeView::setup() { #ifdef _DEBUG std::cout << "EditTreeView::Setup url = " << m_url << std::endl; #endif m_parent_win = NULL; m_updated = false; m_dragging_on_tree = false; m_editable = false; m_undo_buffer = NULL; m_dnd_counter = 0; m_row_dest = Gtk::TreeRow(); m_pre_adjust_upper = 0; m_jump_path = Gtk::TreePath(); } EditTreeView::~EditTreeView() { #ifdef _DEBUG std::cout << "EditTreeView::~EditTreeView url = " << m_url << std::endl; #endif } // // 編集可能にする // void EditTreeView::set_editable_view( const bool editable ) { m_editable = editable; if( m_editable ){ // D&D のドロップを可能にする std::list< Gtk::TargetEntry > targets; targets.push_back( Gtk::TargetEntry( get_dndtarget(), Gtk::TARGET_SAME_APP, 0 ) ); drag_dest_set( targets ); } } // // クロック入力 // void EditTreeView::clock_in() { DragTreeView::clock_in(); // D&D 中にカーソルが画面の上か下の方にある場合はスクロールさせる if( m_editable && m_dragging_on_tree ){ ++m_dnd_counter; if( m_dnd_counter >= DNDSCROLLSPEED / TIMER_TIMEOUT ){ m_dnd_counter = 0; Gtk::TreePath path = get_path_under_mouse(); Gtk::Adjustment* adjust = get_vadjustment(); if( get_row( path ) && adjust ){ const int height = get_height(); const int step = (int)adjust->get_step_increment() / 2; int val = -1; int x,y; get_pointer( x, y ); if( y < step * 2 ){ val = MAX( 0, (int)adjust->get_value() - step ); } else if( y > height - step * 2 ){ val = MIN( (int)adjust->get_value() + step, (int)( adjust->get_upper() - adjust->get_page_size() ) ); } if( val != -1 ){ adjust->set_value( val ); path = get_path_under_mouse(); draw_underline_while_dragging( path ); } } } } // 行を追加した直後に scroll_to_row() を呼んでもまだツリーが更新されてなくて // 正しくスクロールしないので更新されてからスクロールする else if( m_pre_adjust_upper && ! m_jump_path.empty() ){ const int upper = ( int )( get_vadjustment()->get_upper() ); #ifdef _DEBUG std::cout << "adjust_upper : " << m_pre_adjust_upper << " -> " << upper << " count = " << m_jump_count << std::endl; #endif // 時間切れ const int max_jump_count = 200 / TIMER_TIMEOUT; ++m_jump_count; if( m_pre_adjust_upper != upper || m_jump_count >= max_jump_count ){ #ifdef _DEBUG std::cout << "scroll to " << m_jump_path.to_string() << std::endl; #endif Gtk::TreeRow row = get_row( Gtk::TreePath( m_jump_path ) ); if( row ) scroll_to_row( m_jump_path, 0.5 ); m_pre_adjust_upper = 0; m_jump_path = Gtk::TreePath(); m_jump_count = 0; } } } // // path にスクロール // // 遅延させてツリー構造が変わってからスクロールする // clock_in()を参照 // void EditTreeView::set_scroll( const Gtk::TreePath& path ) { m_pre_adjust_upper = ( int )( get_vadjustment()->get_upper() ); m_jump_path = path; m_jump_count = 0; } // // treestoreのセット // void EditTreeView::set_treestore( const Glib::RefPtr< Gtk::TreeStore >& treestore ) { set_model( treestore ); set_headers_visible( false ); } // // xml -> tree 展開して treestore をセットする // void EditTreeView::xml2tree( XML::Document& document, Glib::RefPtr< Gtk::TreeStore >& treestore, const std::string& root_name ) { #ifdef _DEBUG std::cout << "EditTreeView::xml2tree "; std::cout << " root = " << root_name; std::cout << " size = " << document.childNodes().size() << std::endl; #endif treestore->clear(); #if GTKMM_CHECK_VERSION(2,8,0) unset_model(); #endif // 開いてるツリーの格納用 std::list< Gtk::TreePath > list_path_expand; // Domノードから Gtk::TreeStore をセット document.set_treestore( treestore, m_columns, root_name, list_path_expand ); #if GTKMM_CHECK_VERSION(2,8,0) set_treestore( treestore ); #endif // ディレクトリIDのセット(まだセットされていない場合) get_max_dirid(); set_dirid(); // ディレクトリオープン std::list< Gtk::TreePath >::iterator it_path = list_path_expand.begin(); while( it_path != list_path_expand.end() ) { expand_parents( *it_path ); expand_row( *it_path, false ); ++it_path; } } // // tree -> XML 変換 // void EditTreeView::tree2xml( XML::Document& document, const std::string& root_name ) { Glib::RefPtr< Gtk::TreeStore > treestore = Glib::RefPtr< Gtk::TreeStore >::cast_dynamic( get_model() ); if( ! treestore || treestore->children().empty() ){ document.clear(); return; } // 全てのツリーに row[ m_columns.expand ] の値をセットする set_expanded_row( treestore, treestore->children() ); // m_treestore からノードツリーを作成 document.init( treestore, m_columns, root_name ); #ifdef _DEBUG std::cout << "EditTreeView::tree2xml "; std::cout << " root = " << root_name; std::cout << " size = " << document.childNodes().size() << std::endl; #endif } // ディレクトリIDの最大値を取得 void EditTreeView::get_max_dirid() { m_max_dirid = 0; SKELETON::EditTreeViewIterator it( *this, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; if( row[ m_columns.m_type ] == TYPE_DIR ){ const size_t dirid = row[ m_columns.m_dirid ]; if( dirid > m_max_dirid ) m_max_dirid = dirid; } } ++m_max_dirid; #ifdef _DEBUG std::cout << "EditTreeView::get_max_dirid id = " << m_max_dirid << std::endl; #endif } // IDがついていないディレクトリにIDをセットする void EditTreeView::set_dirid() { #ifdef _DEBUG std::cout << "EditTreeView::set_dirid\n"; #endif SKELETON::EditTreeViewIterator it( *this, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; if( row[ m_columns.m_type ] == TYPE_DIR ){ const size_t dirid = row[ m_columns.m_dirid ]; if( ! dirid ){ row[ m_columns.m_dirid ] = m_max_dirid++; #ifdef _DEBUG std::cout << row[ m_columns.m_name ] << " id = " << row[ m_columns.m_dirid ] << std::endl; #endif } } } } // // 全てのツリーに m_columns.m_expand の値をセットする( tree2xml()で使用 ) // void EditTreeView::set_expanded_row( Glib::RefPtr< Gtk::TreeStore >& treestore, const Gtk::TreeModel::Children& children ) { Gtk::TreeModel::iterator it = children.begin(); while( it != children.end() ) { const Gtk::TreePath path = treestore->get_path( *it ); // ツリーが開いているか if( row_expanded( path ) ) (*it)[ m_columns.m_expand ] = true; else (*it)[ m_columns.m_expand ] = false; // 再帰 if( ! (*it)->children().empty() ) set_expanded_row( treestore, (*it)->children() ); ++it; } } // // 列の作成 // // ypad : 行間スペース // Gtk::TreeViewColumn* EditTreeView::create_column( const int ypad ) { // Gtk::mange してるのでdeleteしなくてもよい Gtk::TreeViewColumn* col = Gtk::manage( new Gtk::TreeViewColumn( "name" ) ); col->pack_start( m_columns.m_image, Gtk::PACK_SHRINK ); m_ren_text = Gtk::manage( new Gtk::CellRendererText() ); m_ren_text->signal_edited().connect( sigc::mem_fun( *this, &EditTreeView::slot_ren_text_on_edited ) ); m_ren_text->signal_editing_canceled().connect( sigc::mem_fun( *this, &EditTreeView::slot_ren_text_on_canceled ) ); m_ren_text->property_underline() = Pango::UNDERLINE_SINGLE; // 行間スペース if( ypad >= 0 ) m_ren_text->property_ypad() = ypad; col->pack_start( *m_ren_text, true ); col->add_attribute( *m_ren_text, "text", EDITCOL_NAME ); col->add_attribute( *m_ren_text, "underline", EDITCOL_UNDERLINE ); col->add_attribute( *m_ren_text, "foreground_gdk", EDITCOL_FGCOLOR ); col->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED ); // 実際の描画時に偶数行に色を塗る col->set_cell_data_func( *col->get_first_cell_renderer(), sigc::mem_fun( *this, &DragTreeView::slot_cell_data ) ); col->set_cell_data_func( *m_ren_text, sigc::mem_fun( *this, &DragTreeView::slot_cell_data ) ); append_column( *col ); return col; } // // 新規ディレクトリ作成 // const Gtk::TreePath EditTreeView::create_newdir( const Gtk::TreePath& path ) { CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; info.type = TYPE_DIR; info.name = "新規ディレクトリ"; info.path = path.to_string(); while( ! dirid_to_path( m_max_dirid ).empty() ) ++m_max_dirid; info.dirid = m_max_dirid; list_info.push_back( info ); const bool before = false; const bool scroll = false; const bool force = false; // append_info 内でundoのコミットをしないで名前を変更してからslot_ren_text_on_canceled()でコミットする const bool cancel_undo_commit = true; const int check_dup = 0; // 項目の重複チェックをしない append_info( list_info, path, before, scroll, force, cancel_undo_commit, check_dup ); Gtk::TreePath path_new = get_current_path(); set_cursor( path_new ); rename_row( path_new ); return path_new; } // ディレクトリIDとパスを相互変換 const Gtk::TreePath EditTreeView::dirid_to_path( const size_t dirid ) { if( ! dirid ) return Gtk::TreePath(); SKELETON::EditTreeViewIterator it( *this, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; if( row[ m_columns.m_type ] == TYPE_DIR ){ if( row[ m_columns.m_dirid ] == dirid ) return get_model()->get_path( row ); } } return Gtk::TreePath(); } const size_t EditTreeView::path_to_dirid( const Gtk::TreePath path ) { Gtk::TreeModel::Row row = get_row( Gtk::TreePath( path ) ); if( row ) return row[ m_columns.m_dirid ]; return 0; } // // コメント挿入 // const Gtk::TreePath EditTreeView::create_newcomment( const Gtk::TreePath& path ) { CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; info.type = TYPE_COMMENT; info.name = "コメント"; info.path = path.to_string(); list_info.push_back( info ); const bool before = false; const bool scroll = false; const bool force = false; // append_info 内でundoのコミットをしないで名前を変更してからslot_ren_text_on_canceled()でコミットする const bool cancel_undo_commit = true; const int check_dup = 0; // 項目の重複チェックをしない append_info( list_info, path, before, scroll, force, cancel_undo_commit, check_dup ); Gtk::TreePath path_new = get_current_path(); set_cursor( path_new ); rename_row( path_new ); return path_new; } // // pathで指定した行の名前変更 // void EditTreeView::rename_row( const Gtk::TreePath& path ) { if( path.empty() ) return; // edit可 slot_ren_text_on_edited() と slot_ren_text_on_canceled で false にする m_ren_text->property_editable() = true; set_cursor( path, *get_column( 0 ), true ); } // // 行の名前を変更したときにCellRendererTextから呼び出される // void EditTreeView::slot_ren_text_on_edited( const Glib::ustring& path, const Glib::ustring& text ) { #ifdef _DEBUG std::cout << "EditTreeView::slot_ren_text_on_edited\n" << "path = " << path << std::endl << "text = " << text << std::endl; #endif Gtk::TreeRow row = get_row( Gtk::TreePath( path ) ); if( row ){ const Glib::ustring text_before = row[ m_columns.m_name ]; row[ m_columns.m_name ] = text; if( m_editable && m_undo_buffer ) m_undo_buffer->set_name( Gtk::TreePath( path ), text, text_before ); } slot_ren_text_on_canceled(); } // // 行の名前変更をキャンセルしたときにCellRendererTextから呼び出される // void EditTreeView::slot_ren_text_on_canceled() { #ifdef _DEBUG std::cout << "EditTreeView::slot_ren_text_on_canceld\n"; #endif m_ren_text->property_editable() = false; if( m_editable && m_undo_buffer ) m_undo_buffer->commit(); } // // D&D中の受信側上でマウスを動かした // // 編集可能の時は下線を引く // 他のwidgetがソースの時も呼び出される。ドラッグ中は on_motion_notify_event() は呼び出されない // bool EditTreeView::on_drag_motion( const Glib::RefPtr& context, int x, int y, guint time ) { const Gtk::TreePath path = get_path_under_mouse(); #ifdef _DEBUG if( ! m_dragging_on_tree ) std::cout << "EditTreeView::on_drag_enter"; else std::cout << "EditTreeView::on_drag_motion"; std::cout << " x = " << x << " y = " << y; if( ! path.empty() ) std::cout << " path = " << path.to_string(); std::cout << std::endl; #endif const bool ret = DragTreeView::on_drag_motion( context, x, y, time ); m_dragging_on_tree = true; draw_underline_while_dragging( path ); return ret; } // // D&D中に受信側からマウスが出た // void EditTreeView::on_drag_leave( const Glib::RefPtr& context, guint time ) { #ifdef _DEBUG std::cout << "EditTreeView::on_drag_leave\n"; #endif DragTreeView::on_drag_leave( context, time ); m_dragging_on_tree = false; draw_underline( m_drag_path_uline, false ); } // // D&Dで受信側がデータ送信を要求してきた // void EditTreeView::on_drag_data_get( const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time ) { #ifdef _DEBUG std::cout << "EditTreeView::on_drag_data_get target = " << selection_data.get_target() << std::endl; #endif DragTreeView::on_drag_data_get( context, selection_data, info, time ); // 範囲選択行を共有バッファに入れる if( selection_data.get_target() == get_dndtarget() ){ CORE::DATA_INFO_LIST list_info; const bool dir = true; get_info_in_selection( list_info, dir ); if( list_info.size() ){ CORE::SBUF_set_list( list_info ); // 受信側の on_drag_data_received() を呼び出す selection_data.set( get_dndtarget(), m_url ); } } } // // D&Dの受信側がデータを取得 // void EditTreeView::on_drag_data_received( const Glib::RefPtr& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time ) { const std::string url_from = selection_data.get_data_as_string(); #ifdef _DEBUG std::cout << "EditTreeView::on_drag_data_received target = " << selection_data.get_target() << " url = " << m_url << " url_from = " << url_from << std::endl; #endif DragTreeView::on_drag_data_received( context, x, y, selection_data, info, time ); draw_underline( m_drag_path_uline, false ); m_exec_drop = false; m_row_dest = Gtk::TreeRow(); m_row_dest_before = false; m_dropped_from_other = false; // 挿入先のrowを保存 if( m_editable && selection_data.get_target() == get_dndtarget() ){ CORE::DATA_INFO_LIST list_info = CORE::SBUF_list_info(); if( ! list_info.size() ) return; const Gtk::TreePath path_dest = get_path_under_mouse(); m_row_dest = get_row( path_dest ); // セル内の座標を見て真ん中より上だったら上に挿入 if( m_row_dest ){ int cell_x, cell_y, cell_w, cell_h; get_cell_xy_wh( cell_x, cell_y, cell_w, cell_h ); if( cell_y < cell_h / 2 ) m_row_dest_before = true; } if( url_from != m_url ) m_dropped_from_other = true; #ifdef _DEBUG std::cout << "x = " << x << " y = " << y << " path_dest = " << path_dest.to_string() << " before = " << m_row_dest_before << " other = " << m_dropped_from_other << std::endl; #endif // 同じ widget からドロップされた場合は上書きになっていないかチェックする if( m_row_dest && ! m_dropped_from_other ){ CORE::DATA_INFO_LIST::iterator it = list_info.begin(); for( ; it != list_info.end(); ++it ){ #ifdef _DEBUG std::cout << ( *it ).name << " path = " << ( *it ).path << std::endl; #endif if( ( *it ).path.empty() ) continue; // 移動先と送り側が同じならキャンセル if( ( *it ).path == path_dest.to_string() ) return; // 移動先がサブディレクトリに含まれないかチェック if( Gtk::TreePath( ( *it ).path ).is_ancestor( path_dest ) ){ SKELETON::MsgDiag mdiag( get_parent_win(), "移動先は送り側のディレクトリのサブディレクトリです", false, Gtk::MESSAGE_ERROR ); mdiag.run(); return; } } } m_exec_drop = true; // 送信側の on_drag_data_delete()を呼び出す context->drag_finish( true, true, time ); } } // // D&Dの送信側がデータを削除 // void EditTreeView::on_drag_data_delete( const Glib::RefPtr& context ) { #ifdef _DEBUG std::cout << "EditTreeView::on_drag_data_delete\n"; #endif DragTreeView::on_drag_data_delete( context ); // 選択行の削除 if( m_editable ){ CORE::DATA_INFO_LIST list_info = CORE::SBUF_list_info(); delete_rows( list_info, Gtk::TreePath() ); if( m_editable && m_undo_buffer ){ m_undo_buffer->set_list_info_selected( list_info ); // undo したときに選択する列 m_undo_buffer->set_list_info( CORE::DATA_INFO_LIST(), list_info ); } } } // // D&Dで受信側にデータがドロップされた // // 他のwidgetがソースの時も呼ばれるのに注意 // bool EditTreeView::on_drag_drop( const Glib::RefPtr& context, int x, int y, guint time ) { #ifdef _DEBUG std::cout << "EditTreeView::on_drag_drop\n"; #endif const bool ret = DragTreeView::on_drag_drop( context, x, y, time ); if( ! get_model() ) return ret; if( ! m_editable ) return ret; if( ! m_exec_drop ) return ret; Gtk::TreePath path_dest = Gtk::TreePath(); bool before = false; if( m_row_dest ){ path_dest = get_model()->get_path( m_row_dest ); before = m_row_dest_before; } #ifdef _DEBUG std::cout << "path_dest = " << path_dest.to_string() << " before = " << before << std::endl; #endif // 共有バッファ内の行を追加 const bool scroll = false; const bool force = false; const bool cancel_undo_commit = false; const int check_dup = m_dropped_from_other ? CONFIG::get_check_favorite_dup() : 0; const CORE::DATA_INFO_LIST list_info = append_info( CORE::SBUF_list_info(), path_dest, before, scroll, force, cancel_undo_commit, check_dup ); CORE::SBUF_clear_info(); if( m_dropped_from_other ) m_sig_dropped_from_other.emit( list_info ); return ret; } // // D&Dで受信側に終了を知らせる // // この widget がソースでない時は呼び出されない // void EditTreeView::on_drag_end( const Glib::RefPtr< Gdk::DragContext >& context ) { #ifdef _DEBUG std::cout << "EditTreeView::on_drag_end\n"; #endif draw_underline( m_drag_path_uline, false ); DragTreeView::on_drag_end( context ); } // // ドラッグ中にマウスカーソルの下に下線を引く // void EditTreeView::draw_underline_while_dragging( Gtk::TreePath path ) { if( ! m_editable ) return; if( path.empty() ) return; bool draw = true; int cell_x, cell_y, cell_w, cell_h; get_cell_xy_wh( cell_x, cell_y, cell_w, cell_h ); // 真ん中より上の場合 if( cell_y < cell_h / 2 ){ path.prev(); if( is_dir( path ) || path == Gtk::TreePath( "0" ) // 先頭行 ) draw = false; } draw_underline( m_drag_path_uline, false ); if( draw ) draw_underline( path, true ); m_drag_path_uline = path; } // // draw == true なら pathに下線を引く // void EditTreeView::draw_underline( const Gtk::TreePath& path, const bool draw ) { if( ! m_editable ) return; Gtk::TreeRow row = get_row( path ); if( ! row ) return; row[ m_columns.m_underline ] = draw; } // // path は ディレクトリか // const bool EditTreeView::is_dir( Gtk::TreeModel::iterator& it ) { const Gtk::TreeRow row = ( *it ); if( ! row ) return false; if( row[ m_columns.m_type ] == TYPE_DIR ) return true; return false; } const bool EditTreeView::is_dir( const Gtk::TreePath& path ) { if( path.get_depth() <= 0 ) return false; Gtk::TreeModel::iterator it = get_model()->get_iter( path ); return is_dir( it ); } // 前のディレクトリに移動 void EditTreeView::prev_dir() { Gtk::TreePath path = get_current_path(); for(;;){ Gtk::TreePath new_path = prev_path( path ); if( path == new_path ){ goto_top(); return; } path = new_path; if( is_dir( path ) ) break; } set_cursor( path ); } // 次のディレクトリに移動 void EditTreeView::next_dir() { Gtk::TreePath path = get_current_path(); for(;;){ path = next_path( path ); if( ! path.get_depth() || ! get_row( path ) ){ goto_bottom(); return; } if( is_dir( path ) ) break; } set_cursor( path ); } // // 指定したアドレスの行が含まれているか // const bool EditTreeView::exist_row( const std::string& url, const int type ) { if( url.empty() ) return false; const std::string url_target = get_uptodate_url( url, type ); SKELETON::EditTreeViewIterator it( *this, m_columns, Gtk::TreePath() ); for( ; ! it.end(); ++it ){ Gtk::TreeModel::Row row = *it; const Glib::ustring url_row = row[ m_columns.m_url ]; if( ! url_row.empty() ){ if( url_target == get_uptodate_url( url_row.raw(), row[ m_columns.m_type ] ) ) return true; } } return false; } // // ディレクトリ内を全選択 // void EditTreeView::select_all_dir( Gtk::TreePath path_dir ) { if( ! is_dir( path_dir ) ) return; get_selection()->select( path_dir ); path_dir.down(); while( get_row( path_dir ) ){ get_selection()->select( path_dir ); select_all_dir( path_dir ); path_dir.next(); } } // // list_info を path_dest 以下に追加 // // list_info の各path にあらかじめ値をセットしておくこと // // scroll = true なら追加した行にスクロールする // // force = true なら m_editable が false でも追加 // // cancel_undo_commit = true なら undo バッファをコミットしない // // check_dup == 0 ならチェックせず追加 1 なら重複チェックをして重複してたらダイアログ表示、2なら重複チェックして重複してたら追加しない // // (1) path_dest が empty なら一番最後 // // (2) before = true なら path_dest の前 // // (3) path_destがディレクトリなら path_dest の下 // // (4) そうでなければ path_dest の後 // CORE::DATA_INFO_LIST EditTreeView::append_info( const CORE::DATA_INFO_LIST& list_info, const Gtk::TreePath& path_dest, const bool before, const bool scroll, const bool force, const bool cancel_undo_commit, int check_dup ) { CORE::DATA_INFO_LIST list_info_src; if( ! force && ! m_editable ) return list_info_src; if( ! list_info.size() ) return list_info_src; #ifdef _DEBUG std::cout << "EditTreeView::append_info" << " path_dest = " << path_dest.to_string() << " before = " << before << " check_dup = " << check_dup << std::endl; #endif if( ! check_dup ) list_info_src = list_info; // 重複がないかチェック else{ #ifdef _DEBUG std::cout << "checking duplicatiion\n"; #endif CORE::DATA_INFO_LIST::const_iterator it_info = list_info.begin(); for( ; it_info != list_info.end(); ++it_info ){ const CORE::DATA_INFO& info = ( *it_info ); if( exist_row( info.url, info.type ) ){ if( check_dup == 2 ) continue; SKELETON::MsgCheckDiag mdiag( get_parent_win(), info.name + "\n\nは既に含まれています。追加しますか?", "今後表示しない(常に追加しない) (_D)", Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, Gtk::RESPONSE_NO ); mdiag.set_title( "お気に入り追加確認" ); const int ret = mdiag.run(); if( mdiag.get_chkbutton().get_active() ){ CONFIG::set_check_favorite_dup( 2 ); check_dup = 2; } if( ret != Gtk::RESPONSE_YES ) continue; } list_info_src.push_back( info ); } } if( ! list_info_src.size() ) return list_info_src; if( m_editable && m_undo_buffer ){ CORE::DATA_INFO_LIST list_info_selected; const bool dir = false; get_info_in_selection( list_info_selected, dir ); m_undo_buffer->set_list_info_selected( list_info_selected ); // undo したときに選択する列 } replace_infopath( list_info_src, path_dest, before ); expand_parents( path_dest ); append_rows( list_info_src ); select_info( list_info_src ); if( m_editable && m_undo_buffer ){ m_undo_buffer->set_list_info( list_info_src, CORE::DATA_INFO_LIST() ); m_undo_buffer->set_list_info_selected( list_info_src ); // redo したときに選択する列 if( ! cancel_undo_commit ) m_undo_buffer->commit(); } // 遅延させてツリー構造が変わってからスクロールする // clock_in()を参照 if( scroll ) set_scroll( Gtk::TreePath( list_info_src.front().path ) ); return list_info_src; } // // pathをまとめて削除 // // force = true なら m_editable が false でも削除 // void EditTreeView::delete_path( std::list< Gtk::TreePath >& list_path, const bool force ) { if( ! list_path.size() ) return; if( ! force && ! m_editable ) return; #ifdef _DEBUG std::cout << "EditTreeView::delete_path\n"; #endif // 削除範囲に現在のカーソルがある時はカーソルの位置を変更する bool selected = false; const Gtk::TreePath path_selected = get_current_path(); CORE::DATA_INFO_LIST list_info; std::list< Gtk::TreePath >::iterator it = list_path.begin(); for( ; it != list_path.end(); ++it ){ if( path_selected == ( *it ) ) selected = true; #ifdef _DEBUG std::cout << "path = " << ( *it ).to_string() << std::endl; #endif CORE::DATA_INFO info; path2info( info, *it ); list_info.push_back( info ); } // カーソルを最後の行の次の行に移動するため、あらかじめ削除範囲の最後の行に移動しておく Gtk::TreePath next = path_selected; if( selected ) next = next_path( Gtk::TreePath( ( list_info.back() ).path ), true ); delete_rows( list_info, next ); if( m_editable && m_undo_buffer ){ m_undo_buffer->set_list_info_selected( list_info ); // undo したときに選択する列 m_undo_buffer->set_list_info( CORE::DATA_INFO_LIST(), list_info ); CORE::DATA_INFO_LIST list_info_selected; const bool dir = false; get_info_in_selection( list_info_selected, dir ); m_undo_buffer->set_list_info_selected( list_info_selected ); // redo したときに選択する列 m_undo_buffer->commit(); } } // // 選択した行をまとめて削除 // // force = true なら m_editable が false でも削除 // void EditTreeView::delete_selected_rows( const bool force ) { if( ! force && ! m_editable ) return; std::list< Gtk::TreeModel::iterator > list_selected = get_selected_iterators(); if( ! list_selected.size() ) return; // ディレクトリが含まれていないか無いか確認 std::list< Gtk::TreeModel::iterator >::iterator it_selected = list_selected.begin(); for( ; it_selected != list_selected.end(); ++it_selected ){ if( is_dir( ( *it_selected ) ) ){ SKELETON::MsgDiag mdiag( get_parent_win(), "ディレクトリを削除するとディレクトリ内の行も全て削除されます。削除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; break; } } #ifdef _DEBUG std::cout << "EditTreeView::delete_selected_rows" << " path = " << get_model()->get_path( *list_selected.begin() ).to_string() << std::endl; #endif // 削除する行を取得 CORE::DATA_INFO_LIST list_info; const bool dir = true; get_info_in_selection( list_info, dir ); // カーソルを最後の行の次の行に移動するため、あらかじめ削除範囲の最後の行に移動しておく const Gtk::TreePath next = next_path( Gtk::TreePath( ( list_info.back() ).path ), true ); delete_rows( list_info, next ); if( m_editable && m_undo_buffer ){ m_undo_buffer->set_list_info_selected( list_info ); // undo したときに選択する列 m_undo_buffer->set_list_info( CORE::DATA_INFO_LIST(), list_info ); CORE::DATA_INFO_LIST list_info_selected; const bool dir = false; get_info_in_selection( list_info_selected, dir ); m_undo_buffer->set_list_info_selected( list_info_selected ); // redo したときに選択する列 m_undo_buffer->commit(); } } // // UNDO // void EditTreeView::undo() { if( ! m_undo_buffer ) return; if( ! m_undo_buffer->get_enable_undo() ) return; m_undo_buffer->undo(); const UNDO_DATA& data = m_undo_buffer->get_undo_data(); const int size = data.size(); #ifdef _DEBUG std::cout << "EditTreeView::undo size = " << size << std::endl; #endif for( int i = size-1; i >=0; --i ){ if( ! data[ i ].list_info_selected.empty() ){ set_scroll( Gtk::TreePath( data[ i ].list_info_selected.front().path ) ); select_info( data[ i ].list_info_selected ); } // 追加キャンセル if( ! data[ i ].list_info_append.empty() ) delete_rows( data[ i ].list_info_append, Gtk::TreePath() ); // 削除キャンセル if( ! data[ i ].list_info_delete.empty() ){ expand_rows( data[ i ].list_info_delete ); append_rows( data[ i ].list_info_delete ); } // 名前変更キャンセル Gtk::TreeRow row = get_row( data[ i ].path_renamed ); if( row ){ scroll_to_row( data[ i ].path_renamed, 0.5 ); // ツリー構造に変化は無いのですぐにスクロールする set_cursor( data[ i ].path_renamed ); if( ! data[ i ].name_before.empty() ) row[ m_columns.m_name ] = data[ i ].name_before; } } } // // REDO // void EditTreeView::redo() { #ifdef _DEBUG std::cout << "EditTreeView::redo\n"; #endif if( ! m_undo_buffer ) return; if( ! m_undo_buffer->get_enable_redo() ) return; const UNDO_DATA& data = m_undo_buffer->get_undo_data(); const int size = data.size(); #ifdef _DEBUG std::cout << "EditTreeView::redo size = " << size << std::endl; #endif for( int i = 0; i < size; ++i ){ if( ! data[ i ].list_info_selected.empty() ){ set_scroll( Gtk::TreePath( data[ i ].list_info_selected.front().path ) ); select_info( data[ i ].list_info_selected ); } // 削除 if( ! data[ i ].list_info_delete.empty() ) delete_rows( data[ i ].list_info_delete, Gtk::TreePath() ); // 追加 if( ! data[ i ].list_info_append.empty() ){ expand_rows( data[ i ].list_info_append ); append_rows( data[ i ].list_info_append ); } // 名前変更 Gtk::TreeRow row = get_row( data[ i ].path_renamed ); if( row ){ scroll_to_row( data[ i ].path_renamed, 0.5 ); // ツリー構造に変化は無いのですぐにスクロールする set_cursor( data[ i ].path_renamed ); if( ! data[ i ].name_new.empty() ) row[ m_columns.m_name ] = data[ i ].name_new; } } m_undo_buffer->redo(); } // // list_info の各要素の path を path_dest 以下に変更 // // list_info の各要素の path にあらかじめ値をセットしておくこと // // (1) path_dest が empty なら一番最後 // // (2) before = true なら path_dest の前 // // (3) path_destがディレクトリなら path_dest の下 // // (4) そうでなければ path_dest の後 // void EditTreeView::replace_infopath( CORE::DATA_INFO_LIST& list_info, const Gtk::TreePath& path_dest, const bool before ) { if( ! list_info.size() ) return; if( ! get_model() ) return; Gtk::TreePath path = path_dest; // path の初期値を求める if( path.empty() ){ Gtk::TreeModel::Children children = get_model()->children(); if( children.empty() ) path = Gtk::TreePath( "0" ); else{ path = get_model()->get_path( *( children.rbegin() ) ); path.next(); } } else if( before ); else if( is_dir( path ) ) path.down(); else path.next(); // list_infoの先頭に path をセット CORE::DATA_INFO_LIST::iterator it = list_info.begin(); Gtk::TreePath path_prev( ( *it ).path ); ( *it ).path = path.to_string(); const size_t max_pathsize_org = path_prev.size(); const size_t max_pathsize = path.size(); #ifdef _DEBUG std::cout << "EditTreeView::replace_infopath\n" << "max_pathsize_org = " << max_pathsize_org << " max_pathsize = " << max_pathsize << std::endl << "path_prev = " << path_prev.to_string() << " -> " << ( *it ).path << " type = " << ( *it ).type << " name = " << ( *it ).name << std::endl; #endif for( ++it; it != list_info.end() ; ++it ){ CORE::DATA_INFO& info = ( *it ); // list_infoの構造と合わせて path を更新していく do{ // 次 Gtk::TreePath path_tmp = path_prev; path_tmp.next(); if( path_tmp.to_string() == info.path ){ path.next(); break; } // ディレクトリ下がる path_tmp = path_prev; path_tmp.down(); if( path_tmp.to_string() == info.path ){ path.down(); break; } // ディレクトリ上がる bool reset = true; int count_up = 0; path_tmp = path_prev; while( path_tmp.size() != max_pathsize_org ){ ++count_up; path_tmp.up(); path_tmp.next(); if( path_tmp.to_string() == info.path ){ while( count_up-- ) path.up(); path.next(); reset = false; break; } } // どれにも該当しない場合には一番上のレベルまで戻る if( reset ){ while( path.size() != max_pathsize ) path.up(); path.next(); } } while(0); path_prev = Gtk::TreePath( info.path ); info.path = path.to_string(); #ifdef _DEBUG std::cout << "path_prev = " << path_prev.to_string() << " -> " << info.path << " type = " << info.type << " name = " << info.name << " data = " << info.data << std::endl; #endif } } // // 選択行をlist_infoにセット // // dir : trueの時はディレクトリが選択されているときはディレクトリ内の行もlist_infoに再帰的にセットする // void EditTreeView::get_info_in_selection( CORE::DATA_INFO_LIST& list_info, const bool dir ) { list_info.clear(); if( ! get_model() ) return; std::list< Gtk::TreeModel::iterator > list_selected = get_selected_iterators(); if( ! list_selected.size() ) return; std::list< Gtk::TreeModel::iterator >::iterator it = list_selected.begin(); for( ; it != list_selected.end(); ++it ){ Gtk::TreePath path = get_model()->get_path( *it ); CORE::DATA_INFO info; path2info( info, path ); // 既に path が list_info に登録されていたら登録しない bool cancel = false; CORE::DATA_INFO_LIST::iterator it_info = list_info.begin(); for( ; it_info != list_info.end(); ++it_info ){ if( ( *it_info ).path == info.path ){ cancel = true; break; } } if( cancel ) continue; list_info.push_back( info ); if( dir ) get_info_in_dir( list_info, path ); } } // // ディレクトリ(path_dir)内の行を全てlist_infoにセットする // // path_dir が empty() ならルートの行を全てセット // void EditTreeView::get_info_in_dir( CORE::DATA_INFO_LIST& list_info, const Gtk::TreePath& path_dir ) { if( ! path_dir.empty() && ! is_dir( path_dir ) ) return; CORE::DATA_INFO info; Gtk::TreePath path = path_dir; if( path_dir.empty() ) path = Gtk::TreePath( "0" ); else path.down(); while( get_row( path ) ){ path2info( info, path ); list_info.push_back( info ); get_info_in_dir( list_info, path ); path.next(); } } // // path から info を取得 // void EditTreeView::path2info( CORE::DATA_INFO& info, const Gtk::TreePath& path ) { Glib::ustring tmp_str; Gtk::TreeRow row = get_row( path ); info.type = row[ m_columns.m_type ]; info.parent = NULL; tmp_str = row[ m_columns.m_url ]; info.url = tmp_str.raw(); tmp_str = row[ m_columns.m_name ]; info.name = tmp_str.raw(); tmp_str = row[ m_columns.m_data ]; info.data = tmp_str.raw(); info.path = path.to_string(); info.dirid = row[ m_columns.m_dirid ]; info.expanded = row_expanded( path ); } // // 一行追加 // // 戻り値は追加した行のpath // // (1) path_dest が empty なら一番最後に作る // // (2) before = true なら前に作る // // (3) path_dest がディレクトリかつ sudir == true なら path_dest の下に追加。 // // (4) そうでなければ path_dest の後に追加 // const Gtk::TreePath EditTreeView::append_one_row( const std::string& url, const std::string& name, const int type, const size_t dirid, const std::string& data, const Gtk::TreePath& path_dest, const bool before, const bool subdir ) { Glib::RefPtr< Gtk::TreeStore > treestore = Glib::RefPtr< Gtk::TreeStore >::cast_dynamic( get_model() ); if( ! treestore ) return Gtk::TreePath(); #ifdef _DEBUG std::cout << "EditTreeView::append_one_row : " << name << " path = " << path_dest.to_string() << " before = " << before << " subdir = " << subdir << std::endl; #endif Gtk::TreeRow row_dest = get_row( path_dest ); Gtk::TreeRow row_new; // 一番下に追加 if( ! row_dest ) row_new = *( treestore->append() ); // 前に追加 else if( before ) row_new = *( treestore->insert( row_dest ) ); // ディレクトリの下に追加 else if( subdir && row_dest[ m_columns.m_type ] == TYPE_DIR ){ row_new = *( treestore->prepend( row_dest.children() ) ); } // 後ろに追加 else row_new = *( treestore->insert_after( row_dest ) ); // 行のアドレスや状態を最新にする const std::string url_new = get_uptodate_url( url, type ); const int type_new = get_uptodate_type( url_new, type ); m_columns.setup_row( row_new, url_new, name, data, type_new, dirid ); return treestore->get_path( row_new ); } // // list_info に示した行の親を再起的にexpandする // list_info の各要素の path にあらかじめ値をセットしておくこと // void EditTreeView::expand_rows( const CORE::DATA_INFO_LIST& list_info ) { #ifdef _DEBUG std::cout << "EditTreeView::expand_rows\n"; #endif if( ! list_info.size() ) return; CORE::DATA_INFO_LIST::const_iterator it = list_info.begin(); for( ; it != list_info.end(); ++it ){ const CORE::DATA_INFO& info = ( *it ); #ifdef _DEBUG std::cout << "path = " << info.path << std::endl; #endif expand_parents( Gtk::TreePath( info.path ) ); } } // // list_info に示した行を追加 // // list_info の各要素の path にあらかじめ値をセットしておくこと // void EditTreeView::append_rows( const CORE::DATA_INFO_LIST& list_info ) { #ifdef _DEBUG std::cout << "EditTreeView::append_rows\n"; #endif if( ! list_info.size() ) return; Gtk::TreePath path_parent; bool expand_parent = false; bool head_info = true; CORE::DATA_INFO_LIST::const_iterator it = list_info.begin(); for( ; it != list_info.end(); ++it ){ const CORE::DATA_INFO& info = ( *it ); Gtk::TreePath path( info.path ); #ifdef _DEBUG std::cout << "path = " << path.to_string() << " type = " << info.type << " name = " << info.name << " data = " << info.data << std::endl; #endif bool before = false; bool subdir = false; const bool prev = path.prev(); if( ! prev ){ // 先頭行 if( path == Gtk::TreePath( "0" ) ) before = true; // ディレクトリの先頭 else { path.up(); subdir = true; // 最初の info なら親のディレクトリを開く if( head_info ){ #ifdef _DEBUG std::cout << "expand parent dir\n"; #endif path_parent = path; expand_parent = true; } } } append_one_row( info.url, info.name, info.type, info.dirid, info.data, path, before, subdir ); head_info = false; } // ディレクトリを開く if( expand_parent ) expand_row( path_parent, false ); it = list_info.begin(); for( ; it != list_info.end(); ++it ){ const CORE::DATA_INFO& info = ( *it ); if( info.expanded ){ const Gtk::TreePath path( info.path ); expand_row( path, false ); } } m_updated = true; } // // list_info に示した行を削除 // // list_info の各要素の path にあらかじめ値をセットしておくこと // // 削除した後、path_select にカーソルを移動する(emptyの場合は移動しない) // void EditTreeView::delete_rows( const CORE::DATA_INFO_LIST& list_info, const Gtk::TreePath& path_select ) { #ifdef _DEBUG std::cout << "EditTreeView::delete_rows"; if( ! path_select.empty() ) std::cout << " path_select = " << path_select.to_string(); std::cout << std::endl; #endif if( ! list_info.size() ) return; Glib::RefPtr< Gtk::TreeStore > treestore = Glib::RefPtr< Gtk::TreeStore >::cast_dynamic( get_model() ); if( ! treestore ) return; // あらかじめ path_select にカーソルを移動しておく // もし path_select が存在しなかったら削除してから一番下に移動 bool gotobottom = false; if( ! path_select.empty() ){ gotobottom = ( ! get_row( path_select ) ); if( ! gotobottom ) set_cursor( path_select ); } CORE::DATA_INFO_LIST::const_iterator it = list_info.end(); do{ --it; const CORE::DATA_INFO& info = ( *it ); Gtk::TreePath path( info.path ); #ifdef _DEBUG std::cout << path.to_string() << " type = " << info.type << " name = " << info.name << " url = " << info.url << " data = " << info.data << std::endl; #endif Gtk::TreeRow row = get_row( path ); treestore->erase( row ); } while( it != list_info.begin() ); m_updated = true; if( gotobottom ) goto_bottom(); } // // list_infoに示した行を選択 // void EditTreeView::select_info( const CORE::DATA_INFO_LIST& list_info ) { get_selection()->unselect_all(); CORE::DATA_INFO_LIST::const_iterator it = list_info.begin(); for( ; it != list_info.end(); ++it ){ Gtk::TreePath path( ( *it ).path ); get_selection()->select( path ); } } // // ソート実行 // // path : ディレクトリなら中をソート、そうでなければそのレベルでソート // mode : ソートのモード。詳しくは class compare_path を参照 // void EditTreeView::sort( const Gtk::TreePath& path, const int mode ) { if( ! m_editable ) return; if( ! get_row( path ) ) return; CORE::DATA_INFO_LIST list_info; Gtk::TreePath path_head = path; if( is_dir( path_head ) ) path_head.down(); else while( path_head.prev() ); if( ! get_row( path_head ) ) return; Gtk::TreePath path_parent = path_head; if( path_parent.get_depth() >= 2 ) path_parent.up(); else path_parent = Gtk::TreePath(); #ifdef _DEBUG std::cout << "EditTreeView::sort head = " << path_head.to_string() << " parent = " << path_parent.to_string() << std::endl; #endif // ソート std::list< Gtk::TreePath > list_path; Gtk::TreePath path_tmp = path_head; while( get_row( path_tmp ) ){ list_path.push_back( path_tmp ); path_tmp.next(); } list_path.sort( compare_path( *this, m_columns, mode ) ); std::list< Gtk::TreePath >::const_iterator it_path = list_path.begin(); for( ; it_path != list_path.end(); ++it_path ){ const Gtk::TreeRow row = get_row( *it_path ); if( row ){ #ifdef _DEBUG std::cout << ( *it_path ).to_string() << " type = " << row[ m_columns.m_type ] << " name = " << row[ m_columns.m_name ] << std::endl; #endif CORE::DATA_INFO info; path2info( info, *it_path ); list_info.push_back( info ); get_info_in_dir( list_info, *it_path ); } } // path_parent の中を全て削除 if( m_undo_buffer ){ CORE::DATA_INFO_LIST list_info_selected; const bool dir = false; get_info_in_selection( list_info_selected, dir ); m_undo_buffer->set_list_info_selected( list_info_selected ); // undo したときに選択する列 } CORE::DATA_INFO_LIST list_info_delete; get_info_in_dir( list_info_delete, path_parent ); delete_rows( list_info_delete, Gtk::TreePath() ); if( m_undo_buffer ){ m_undo_buffer->set_list_info( CORE::DATA_INFO_LIST(), list_info_delete ); } // list_info を path_parent の中に追加 const bool before = false; const bool scroll = false; const bool force = false; const bool cancel_undo_commit = false; const int check_dup = 0; // 項目の重複チェックをしない append_info( list_info, path_parent, before, scroll, force, cancel_undo_commit, check_dup ); set_scroll( path_parent ); } //////////////////////////////// // // EditTreeViewの項目の反復子 // // path から反復開始 // path が empty の時はルートから反復する // EditTreeViewIterator::EditTreeViewIterator( EditTreeView& treeview, EditColumns& columns, const Gtk::TreePath path ) : m_treeview( treeview ), m_columns( columns ), m_end( false ), m_path( path ) { const bool root = ( m_path.empty() ); if( root ){ Gtk::TreeModel::Children children = m_treeview.get_model()->children(); if( ! children.empty() ) m_path = m_treeview.get_model()->get_path( children.begin() ); else{ m_end = true; return; } } Gtk::TreeModel::Row row = m_treeview.get_row( m_path ); if( ! row ) m_end = true; else{ m_depth = m_path.get_depth(); if( ! root ) ++m_depth; } } Gtk::TreeModel::Row EditTreeViewIterator::operator * () { return m_treeview.get_row( m_path ); } void EditTreeViewIterator::operator ++ () { if( m_end ) return; Gtk::TreeModel::Row row = m_treeview.get_row( m_path ); while( 1 ){ if( row ){ switch( row[ m_columns.m_type ] ){ case TYPE_DIR: m_path.down(); break; default: m_path.next(); break; } } else{ if( m_path.get_depth() > m_depth ){ m_path.up(); m_path.next(); } else{ m_end = true; break; } } row = m_treeview.get_row( m_path ); if( row ) break; } } jd-2.8.7-140104/src/skeleton/edittreeview.h0000644000076400010400000002667011500720464015066 0ustar // ライセンス: GPL2 // // D&Dによって行の編集が可能なtreeviewクラス // // set_editable_view() で true を指定すると編集可能になる // #ifndef _EDITTREEVIEW_H #define _EDITTREEVIEW_H #include "dragtreeview.h" #include "jdlib/constptr.h" #include "type.h" #include "data_info.h" #include #include namespace XML { class Document; } namespace SKELETON { // ソートのモード enum { SORT_BY_TYPE = 0, SORT_BY_NAME }; // 他のwidgetからドロップされた typedef sigc::signal< void, const CORE::DATA_INFO_LIST& > SIG_DROPPED_FROM_OTHER; class EditColumns; class UNDO_BUFFER; class EditTreeView : public DragTreeView { SIG_DROPPED_FROM_OTHER m_sig_dropped_from_other; std::string m_url; Gtk::Window* m_parent_win; EditColumns& m_columns; JDLIB::ConstPtr< Gtk::CellRendererText > m_ren_text; // 編集可能 bool m_editable; // UNDO 用のバッファ UNDO_BUFFER* m_undo_buffer; // D&D用変数 Gtk::TreePath m_drag_path_uline; // D&D時に下線を引いている行 int m_dnd_counter; // D&D時のスクロールのタイミング用 bool m_exec_drop; // D&D時のドロップ処理で挿入するか Gtk::TreeRow m_row_dest; // ドロップ先 bool m_row_dest_before; // m_row_dest の前に挿入するか bool m_dropped_from_other; // 他のwidgetからドロップされた // スクロール用変数 // 詳しくは EditTreeView::clock_in() を参照 int m_pre_adjust_upper; Gtk::TreePath m_jump_path; int m_jump_count; // 更新された bool m_updated; // ドラッグがこのツリー上で行われている bool m_dragging_on_tree; // ディレクトリIDの最大値 size_t m_max_dirid; public: // ColumnRecord として SKELETON::EditColumns を派生したものを使用すること EditTreeView( const std::string& url, const std::string& dndtarget, EditColumns& columns, const bool use_usr_fontcolor, const std::string& fontname, const int colorid_text, const int colorid_bg, const int colorid_bg_even ); EditTreeView( const std::string& url, const std::string& dndtarget, EditColumns& columns ); virtual ~EditTreeView(); virtual void clock_in(); SIG_DROPPED_FROM_OTHER sig_dropped_from_other(){ return m_sig_dropped_from_other; } void set_parent_win( Gtk::Window* parent_win ){ m_parent_win = parent_win; } Gtk::Window* get_parent_win(){ return m_parent_win; } void set_undo_buffer( UNDO_BUFFER* undo_buffer ){ m_undo_buffer = undo_buffer; } const bool is_updated() const { return m_updated; }; void set_updated( const bool set ){ m_updated = set; } // treestoreのセット void set_treestore( const Glib::RefPtr< Gtk::TreeStore >& treestore ); // xml -> tree 展開して treestore をセットする void xml2tree( XML::Document& document, Glib::RefPtr< Gtk::TreeStore >& treestore, const std::string& root_name ); // tree -> XML 変換 void tree2xml( XML::Document& document, const std::string& root_name ); // 列の作成 // ypad : 行間スペース Gtk::TreeViewColumn* create_column( const int ypad ); // 編集可能にする void set_editable_view( const bool editable ); // 指定した path のタイプは ディレクトリか const bool is_dir( Gtk::TreeModel::iterator& it ); const bool is_dir( const Gtk::TreePath& path ); // 次のディレクトリに移動 void prev_dir(); void next_dir(); // 指定したアドレスの行が含まれているか const bool exist_row( const std::string& url, const int type ); // ディレクトリ内を全選択 void select_all_dir( Gtk::TreePath path_dir ); // 新規ディレクトリ作成 const Gtk::TreePath create_newdir( const Gtk::TreePath& path ); // ディレクトリIDとパスを相互変換 const Gtk::TreePath dirid_to_path( const size_t dirid ); const size_t path_to_dirid( const Gtk::TreePath path ); // コメント挿入 const Gtk::TreePath create_newcomment( const Gtk::TreePath& path ); // pathで指定した行の名前の変更 void rename_row( const Gtk::TreePath& path ); const bool is_renaming_row(){ return m_ren_text->property_editable(); } // list_info を path_dest 以下に追加 // // list_info の各path にあらかじめ値をセットしておくこと // scroll = true なら追加した行にスクロールする // force = true なら m_editable が false でも追加 // cancel_undo_commit = true なら undo バッファをコミットしない // check_dup == 0 ならチェックせず追加 1 なら重複チェックをして重複してたらダイアログ表示、2なら重複チェックして重複してたら追加しない // // (1) path_dest が empty なら一番最後 // (2) before = true なら path_dest の前 // (3) path_destがディレクトリなら path_dest の下 // (4) そうでなければ path_dest の後 CORE::DATA_INFO_LIST append_info( const CORE::DATA_INFO_LIST& list_info, const Gtk::TreePath& path_dest, const bool before, const bool scroll, const bool force, const bool cancel_undo_commit, int check_dup ); // pathをまとめて削除 // force = true なら m_editable が false でも削除 void delete_path( std::list< Gtk::TreePath >& list_path, const bool force ); // 選択した行をまとめて削除 // force = true なら m_editable が false でも削除 virtual void delete_selected_rows( const bool force ); void undo(); void redo(); // 選択行をlist_infoにセットする // dir : true の時はディレクトリが選択されているときはディレクトリ内の行もlist_infoに再帰的にセットする void get_info_in_selection( CORE::DATA_INFO_LIST& list_info, const bool dir ); // 一行追加 // 戻り値は追加した行のpath // (1) path_dest が empty なら一番最後に作る // (2) before = true なら前に作る // (3) path_dest がディレクトリかつ sudir == true なら path_dest の下に追加。 // (4) そうでなければ path_dest の後に追加 const Gtk::TreePath append_one_row( const std::string& url, const std::string& name, const int type, const size_t dirid, const std::string& data, const Gtk::TreePath& path_dest,const bool before, const bool subdir ); // ソート実行 void sort( const Gtk::TreePath& path, const int mode ); protected: virtual bool on_drag_motion( const Glib::RefPtr& context, int x, int y, guint time ); virtual void on_drag_leave( const Glib::RefPtr& context, guint time ); virtual bool on_drag_drop( const Glib::RefPtr& context, int x, int y, guint time ); virtual void on_drag_data_get( const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time ); virtual void on_drag_data_received( const Glib::RefPtr& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time ); virtual void on_drag_data_delete( const Glib::RefPtr& context ); virtual void on_drag_end( const Glib::RefPtr< Gdk::DragContext>& context ); private: // path にスクロール void set_scroll( const Gtk::TreePath& path ); // set_model()をprivate化して使用不可にする。代わりにset_treestore()を使用すること void set_model( const Glib::RefPtr< Gtk::TreeModel >& model ){ Gtk::TreeView::set_model( model ); } void setup(); // ディレクトリIDの最大値を取得 void get_max_dirid(); // ディレクトリにIDをセットする void set_dirid(); // 全てのツリーに m_columns.m_expand の値をセットする( tree2xml()で使用 ) void set_expanded_row( Glib::RefPtr< Gtk::TreeStore >& treestore, const Gtk::TreeModel::Children& children ); void slot_ren_text_on_edited( const Glib::ustring& path, const Glib::ustring& text ); void slot_ren_text_on_canceled(); // ドラッグ中にマウスカーソルの下に下線を引く void draw_underline_while_dragging( Gtk::TreePath path ); // draw == true なら pathに下線を引く void draw_underline( const Gtk::TreePath& path, bool const draw ); // list_info の各要素の path を path_dest 以下に変更 // list_info の各様の path にあらかじめ値をセットしておくこと // (1) path_dest が empty なら一番最後 // (2) before = true なら path_dest の前 // (3) path_destがディレクトリなら path_dest の下 // (4) そうでなければ path_dest の後 void replace_infopath( CORE::DATA_INFO_LIST& list_info, const Gtk::TreePath& path_dest, const bool before ); // ディレクトリ(path_dir)内の行を全てlist_infoにセットする void get_info_in_dir( CORE::DATA_INFO_LIST& list_info, const Gtk::TreePath& path_dir ); // path から info を取得 void path2info( CORE::DATA_INFO& info, const Gtk::TreePath& path ); // list_info に示した行の親を再起的にexpandする // list_info の各要素の path にあらかじめ値をセットしておくこと void expand_rows( const CORE::DATA_INFO_LIST& list_info ); // list_info に示した行を追加 // list_info の各要素の path にあらかじめ値をセットしておくこと void append_rows( const CORE::DATA_INFO_LIST& list_info ); // list_info に示した行を削除 // list_info の各要素の path にあらかじめ値をセットしておくこと // 削除した後、path_select にカーソルを移動する(emptyの場合は移動しない) void delete_rows( const CORE::DATA_INFO_LIST& list_info, const Gtk::TreePath& path_select ); // list_infoに示した行を選択 void select_info( const CORE::DATA_INFO_LIST& list_info ); }; //////////////////////////////// // EditTreeViewの項目の反復子 class EditTreeViewIterator { EditTreeView& m_treeview; EditColumns& m_columns; int m_depth; bool m_end; Gtk::TreePath m_path; public: // path から反復開始 // path が empty の時はルートから反復する EditTreeViewIterator( EditTreeView& treeview, EditColumns& columns, const Gtk::TreePath path ); Gtk::TreeModel::Row operator * (); const Gtk::TreePath get_path() const { return m_path; } void operator ++ (); const bool end() const { return m_end; } }; } #endif jd-2.8.7-140104/src/skeleton/editview.cpp0000644000076400010400000004357011534715101014536 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "editview.h" #include "aamenu.h" #include "control/controlid.h" #include "control/controlutil.h" #include "aamanager.h" #include "environment.h" #include "session.h" #include "jdlib/miscutil.h" #include "config/globalconf.h" #include "gtk/gtktextview.h" using namespace SKELETON; enum { MIN_AAMENU_LINES = 12 }; EditTextView::EditTextView() : Gtk::TextView(), m_cancel_change( false ), m_line_offset( -1 ), m_context_menu( NULL ), m_aapopupmenu( NULL ) { // コントロールモード設定 m_control.add_mode( CONTROL::MODE_EDIT ); m_control.add_mode( CONTROL::MODE_MESSAGE ); get_buffer()->signal_changed().connect( sigc::mem_fun( *this, &EditTextView::slot_buffer_changed ) ); } EditTextView::~EditTextView() { if( m_aapopupmenu ) delete m_aapopupmenu; m_aapopupmenu = NULL; } // // カーソルの位置に挿入 // // use_br == true なら改行を入れる // void EditTextView::insert_str( const std::string& str, bool use_br ) { std::string br; if( use_br ){ Gtk::TextIter it = get_buffer()->get_insert()->get_iter(); if( it.get_chars_in_line() > 1 ) br = "\n\n"; else if( it.backward_char() && it.get_chars_in_line() > 1 ) br = "\n"; } get_buffer()->insert_at_cursor( br + str ); scroll_to( get_buffer()->get_insert(), 0.0 ); } void EditTextView::cursor_up_down( bool up ) { Gtk::TextIter it = get_buffer()->get_insert()->get_iter(); int line = it.get_line(); int offset = it.get_line_offset(); it.set_line_offset( 0 ); // 上 if( up ){ if( ! it.backward_line() ) return; } // 下 else{ if( ! it.forward_line() ){ // 最終行に文字が無い場合 if( get_buffer()->get_line_count() -1 == it.get_line() ) it.forward_to_end(); else return; } } if( m_line_offset >= 0 && offset == m_pre_offset && line == m_pre_line ) offset = m_line_offset; if( offset < it.get_chars_in_line() ){ it.set_line_offset( offset ); m_line_offset = -1; } // 文字数オーバー else{ m_line_offset = offset; if( it.get_chars_in_line() > 1 && ! it.forward_to_line_end() ) it.forward_to_end(); } get_buffer()->place_cursor( it ); scroll_to( get_buffer()->get_insert(), 0.0 ); m_pre_line = get_buffer()->get_insert()->get_iter().get_line(); m_pre_offset = get_buffer()->get_insert()->get_iter().get_line_offset(); } void EditTextView::cursor_up() { cursor_up_down( true ); } void EditTextView::cursor_down() { cursor_up_down( false ); } void EditTextView::cursor_left() { Gtk::TextIter it = get_buffer()->get_insert()->get_iter(); if( it.backward_char() ) get_buffer()->place_cursor( it ); } void EditTextView::cursor_right() { Gtk::TextIter it = get_buffer()->get_insert()->get_iter(); if( ! it.forward_char() ) it.forward_to_end(); get_buffer()->place_cursor( it ); } void EditTextView::cursor_home() { Gtk::TextIter it = get_buffer()->get_insert()->get_iter(); it.set_line_offset( 0 ); get_buffer()->place_cursor( it ); } void EditTextView::cursor_end() { Gtk::TextIter it = get_buffer()->get_insert()->get_iter(); if( ! it.forward_to_line_end() ) it.forward_to_end(); get_buffer()->place_cursor( it ); } void EditTextView::delete_char() { // 範囲選択消去 if( get_buffer()->erase_selection() ) return; Gtk::TextIter it = get_buffer()->get_insert()->get_iter(); Gtk::TextIter it2 = it; if( ! it2.forward_char() ) it2.forward_to_end(); m_delete_pushed = true; get_buffer()->erase( it, it2 ); } void EditTextView::backsp_char() { // 範囲選択消去 if( get_buffer()->erase_selection() ) return; Gtk::TextIter it = get_buffer()->get_insert()->get_iter(); Gtk::TextIter it2 = it; if( it2.backward_char() ) get_buffer()->erase( it2, it ); } // // バッファの文字列が変化したときに UNDO バッファを変更する // void EditTextView::slot_buffer_changed() { if( m_cancel_change ) return; #ifdef _DEBUG std::cout << "EditTextView::slot_buffer_changed\n"; #endif Glib::ustring text = get_buffer()->get_text(); unsigned int lng = text.length(); unsigned int pre_lng = m_pre_text.length(); unsigned int size = lng > pre_lng ? lng - pre_lng : pre_lng - lng; if( size ){ UNDO_DATA udata; udata.pos = 0; udata.append = false; // diff を取る for( ; udata.pos < MIN( lng, pre_lng ) && text.at( udata.pos ) == m_pre_text.at( udata.pos ); ++udata.pos ); // 追加 if( lng > pre_lng ){ udata.append = true; udata.str_diff = text.substr( udata.pos, size ); } // 削除 else udata.str_diff = m_pre_text.substr( udata.pos, size ); // カーソルの位置を取得 udata.pos_cursor = get_buffer()->get_insert()->get_iter().get_offset(); if( udata.append ) udata.pos_cursor -= size; else { if( size > 1 // 範囲選択で消した場合 || ! m_delete_pushed // backspaceで消した場合 ) udata.pos_cursor += size; } #ifdef _DEBUG std::cout << "size = " << size << " offset = " << udata.pos << " cursor = " << udata.pos_cursor; if( udata.append ) std::cout << " + "; else std::cout << " - "; std::cout << "pre = " << m_pre_text << " text = " << text << " diff = " << udata.str_diff << std::endl; #endif m_undo_tree.push_back( udata ); m_undo_pos = m_undo_tree.size() -1; } m_pre_text = text; } // // undo // void EditTextView::undo() { if( ! m_undo_tree.size() ) return; if( m_undo_pos < 0 ){ // 根元まで来たらツリーの先頭に戻る m_undo_pos = m_undo_tree.size() -1; return; } UNDO_DATA udata = m_undo_tree[ m_undo_pos-- ]; #ifdef _DEBUG std::cout << "EditTextView::undo pos = " << m_undo_pos << " size = " << m_undo_tree.size() << std::endl; std::cout << "offset = " << udata.pos << " cursor = " << udata.pos_cursor; if( udata.append ) std::cout << " - "; else std::cout << " + "; std::cout << udata.str_diff << std::endl; #endif Glib::ustring text; Glib::ustring text_head = get_buffer()->get_text().substr( 0, udata.pos ); m_cancel_change = true; // slot_buffer_changed() の呼出をキャンセル // 追加と削除を逆転 udata.append = ! udata.append; // 追加 if( udata.append ) get_buffer()->insert( get_buffer()->get_iter_at_offset( udata.pos ), udata.str_diff ); // 削除 else get_buffer()->erase( get_buffer()->get_iter_at_offset( udata.pos ), get_buffer()->get_iter_at_offset( udata.pos + udata.str_diff.length() ) ); // カーソル移動 Gtk::TextIter it = get_buffer()->get_iter_at_offset( udata.pos_cursor ); get_buffer()->place_cursor( it ); m_cancel_change = false; m_pre_text = get_buffer()->get_text(); // 逆方向にツリーを延ばす if( udata.append ) udata.pos_cursor += udata.str_diff.length(); m_undo_tree.push_back( udata ); } void EditTextView::clear_undo() { m_undo_tree.clear(); } // // マウスボタン入力のフック // bool EditTextView::on_button_press_event( GdkEventButton* event ) { m_sig_button_press.emit( event ); return Gtk::TextView::on_button_press_event( event ); } // // キー入力のフック // bool EditTextView::on_key_press_event( GdkEventKey* event ) { #ifdef _DEBUG std::cout << "EditTextView::on_key_press_event key = " << event->keyval << std::endl; #endif bool cancel_event = false; m_delete_pushed = false; if( event->keyval == GDK_Delete ) m_delete_pushed = true; const int controlid = m_control.key_press( event ); switch( controlid ){ case CONTROL::ExecWrite: case CONTROL::CancelWrite: case CONTROL::FocusWrite: case CONTROL::TabLeft: case CONTROL::TabRight: case CONTROL::TabLeftUpdated: case CONTROL::TabRightUpdated: case CONTROL::ToggleSage: case CONTROL::HomeEdit: case CONTROL::EndEdit: case CONTROL::UpEdit: case CONTROL::DownEdit: case CONTROL::RightEdit: case CONTROL::LeftEdit: case CONTROL::DeleteEdit: case CONTROL::BackspEdit: case CONTROL::UndoEdit: case CONTROL::InputAA: { GtkTextView *textview = gobj(); if( gtk_im_context_filter_keypress( textview->im_context, event ) ) { #ifdef _DEBUG std::cout << "gtk_im_context_filter_keypress\n"; #endif textview->need_im_reset = TRUE; return true; } } } switch( controlid ){ // MessageViewでショートカットで書き込むと文字が挿入されてしまうので // キャンセルする case CONTROL::ExecWrite: case CONTROL::CancelWrite: case CONTROL::FocusWrite: case CONTROL::TabLeft: case CONTROL::TabRight: case CONTROL::ToggleSage: cancel_event = true; break; case CONTROL::HomeEdit: cursor_home(); return true; case CONTROL::EndEdit: cursor_end(); return true; case CONTROL::UpEdit: cursor_up(); return true; case CONTROL::DownEdit: cursor_down(); return true; case CONTROL::RightEdit: cursor_right(); return true; case CONTROL::LeftEdit: cursor_left(); return true; case CONTROL::DeleteEdit: delete_char(); return true; case CONTROL::BackspEdit: backsp_char(); return true; case CONTROL::UndoEdit: undo(); return true; case CONTROL::EnterEdit: event->keyval = GDK_Return; event->state &= ~GDK_CONTROL_MASK; event->state &= ~GDK_SHIFT_MASK; event->state &= ~GDK_MOD1_MASK; break; case CONTROL::InputAA: show_aalist_popup(); return true; } m_sig_key_press.emit( event ); if( cancel_event ) return true; return Gtk::TextView::on_key_press_event( event ); } bool EditTextView::on_key_release_event( GdkEventKey* event ) { #ifdef _DEBUG std::cout << "EditTextView::on_key_release_event key = " << event->keyval << std::endl; #endif bool cancel_event = false; switch( m_control.key_press( event ) ){ // MessageViewでショートカットで書き込むと文字が挿入されてしまうので // キャンセルする case CONTROL::ExecWrite: case CONTROL::CancelWrite: case CONTROL::FocusWrite: case CONTROL::TabLeft: case CONTROL::TabRight: case CONTROL::ToggleSage: cancel_event = true; break; case CONTROL::HomeEdit: case CONTROL::EndEdit: case CONTROL::UpEdit: case CONTROL::DownEdit: case CONTROL::RightEdit: case CONTROL::LeftEdit: case CONTROL::DeleteEdit: case CONTROL::BackspEdit: case CONTROL::UndoEdit: case CONTROL::InputAA: return true; } m_sig_key_release.emit( event ); if( cancel_event ) return true; return Gtk::TextView::on_key_release_event( event ); } // // コンテキストメニュー表示 // void EditTextView::on_populate_popup( Gtk::Menu* menu ) { #ifdef _DEBUG std::cout << "EditTextView::on_populate_popup\n"; #endif m_context_menu = menu; menu->signal_map().connect( sigc::mem_fun( *this, &EditTextView::slot_map_popupmenu ) ); menu->signal_hide().connect( sigc::mem_fun( *this, &EditTextView::slot_hide_popupmenu ) ); // セパレータ Gtk::MenuItem* menuitem = Gtk::manage( new Gtk::SeparatorMenuItem() ); menu->prepend( *menuitem ); // JDの動作環境を記入 menuitem = Gtk::manage( new Gtk::MenuItem( "JDの動作環境を記入" ) ); menuitem->signal_activate().connect( sigc::mem_fun( *this, &EditTextView::slot_write_jdinfo ) ); menu->prepend( *menuitem ); // 変換(スペース⇔ ) menuitem = Gtk::manage( new Gtk::MenuItem( "変換(スペース⇔ )" ) ); menuitem->signal_activate().connect( sigc::mem_fun( *this, &EditTextView::slot_convert_space ) ); menu->prepend( *menuitem ); // クリップボードから引用 menuitem = Gtk::manage( new Gtk::MenuItem( "クリップボードから引用" ) ); menuitem->signal_activate().connect( sigc::mem_fun( *this, &EditTextView::slot_quote_clipboard ) ); Glib::RefPtr< Gtk::Clipboard > clip = Gtk::Clipboard::get(); if( clip->wait_is_text_available() ) menuitem->set_sensitive( true ); else menuitem->set_sensitive( false ); menu->prepend( *menuitem ); // AA入力メニュー追加 if( CORE::get_aamanager()->get_size() ){ menuitem = Gtk::manage( new Gtk::MenuItem( CONTROL::get_label_motions( CONTROL::InputAA ) ) ); menuitem->signal_activate().connect( sigc::mem_fun( *this, &EditTextView::slot_select_aamenu ) ); menu->prepend( *menuitem ); } menu->show_all_children(); Gtk::TextView::on_populate_popup( menu ); } // // AA追加メニュー // void EditTextView::slot_select_aamenu() { if( m_context_menu ) m_context_menu->hide(); show_aalist_popup(); } // // クリップボードから引用して貼り付け // void EditTextView::slot_quote_clipboard() { if( m_context_menu ) m_context_menu->hide(); Glib::RefPtr< Gtk::Clipboard > clip = Gtk::Clipboard::get(); Glib::ustring text = clip->wait_for_text(); std::string str_res; str_res = CONFIG::get_ref_prefix(); text = MISC::replace_str( text, "\n", "\n" + str_res ); insert_str( str_res + text, false ); } // // 変換(スペース⇔ ) // void EditTextView::slot_convert_space() { if( m_context_menu ) m_context_menu->hide(); Glib::RefPtr< Gtk::TextBuffer > buffer = get_buffer(); std::string text = buffer->get_text(); std::string converted; //  が含まれていたらスペースに変換する if( text.find( " ", 0 ) != std::string::npos ) { converted = MISC::replace_str( text, " ", " " ); } else { size_t rpos = std::string::npos; size_t nlpos = std::string::npos; // 改行前のスペースを取り除く while( ( nlpos = text.rfind( "\n", rpos ) ) != std::string::npos ) { if( nlpos == 0 ) break; rpos = nlpos; while( text[ rpos - 1 ] == ' ' ) rpos--; text.erase( rpos, nlpos - rpos ); rpos--; } // 最後のスペースを取り除く rpos = text.length(); while( text[ rpos - 1 ] == ' ' ) rpos--; text.erase( rpos, std::string::npos ); converted = MISC::replace_str( text, " ", " " ); } buffer->set_text( converted ); } // // JDの動作環境を記入 // void EditTextView::slot_write_jdinfo() { if( m_context_menu ) m_context_menu->hide(); std::string jdinfo = ENVIRONMENT::get_jdinfo(); insert_str( jdinfo, false ); } // // ポップアップメニューがmapしたときに呼ばれるslot // void EditTextView::slot_map_popupmenu() { #ifdef _DEBUG std::cout << "EditTextView::slot_map_popupmenu\n"; #endif SESSION::set_popupmenu_shown( true ); } // // コンテキストメニューが閉じた // void EditTextView::slot_hide_popupmenu() { #ifdef _DEBUG std::cout << "EditTextView::slot_hide_popupmenu\n"; #endif m_context_menu = NULL; SESSION::set_popupmenu_shown( false ); } // // カーソルの画面上の座標 // Gdk::Rectangle EditTextView::get_cursor_root_origin() { Gdk::Rectangle rect; int wx, wy; int x, y; get_iter_location( get_buffer()->get_insert()->get_iter(), rect ); buffer_to_window_coords( Gtk::TEXT_WINDOW_TEXT, rect.get_x(), rect.get_y(), wx, wy ); get_window( Gtk::TEXT_WINDOW_TEXT )->get_origin( x, y ); rect.set_x( x + wx ); rect.set_y( y + wy ); return rect; } // // AA ポップアップメニュー表示 // void EditTextView::show_aalist_popup() { if( CORE::get_aamanager()->get_size() ) { if( m_aapopupmenu ) delete m_aapopupmenu; m_aapopupmenu = Gtk::manage( new AAMenu( *dynamic_cast< Gtk::Window* >( get_toplevel() ) ) ); m_aapopupmenu->sig_selected().connect( sigc::mem_fun( *this, &EditTextView::slot_aamenu_selected ) ); m_aapopupmenu->signal_map().connect( sigc::mem_fun( *this, &EditTextView::slot_map_aamenu ) ); m_aapopupmenu->signal_hide().connect( sigc::mem_fun( *this, &EditTextView::slot_hide_aamenu ) ); m_aapopupmenu->popup( Gtk::Menu::SlotPositionCalc( sigc::mem_fun( *this, &EditTextView::slot_popup_aamenu_pos ) ), 0, gtk_get_current_event_time() ); } } // // AA ポップアップの表示位置を決定 // void EditTextView::slot_popup_aamenu_pos( int& x, int& y, bool& push_in ) { push_in = false; const Gdk::Rectangle rect = get_cursor_root_origin(); const int line_height = rect.get_height(); const int sh = get_screen()->get_height(); const int min_height = MIN( CORE::get_aamanager()->get_size(), MIN_AAMENU_LINES ) * line_height; x = rect.get_x(); y = rect.get_y() + line_height; // 最低でも MIN_AAMENU_LINES 行よりも表示領域が高くなるようにする if( y + min_height > sh ) y = sh - min_height; } // // AAポップアップで選択された // void EditTextView::slot_aamenu_selected( const std::string& aa ) { insert_str( aa, false ); } // // AAポップアップメニューがmapしたときに呼ばれるslot // void EditTextView::slot_map_aamenu() { #ifdef _DEBUG std::cout << "EditTextView::slot_map_aamenu\n"; #endif SESSION::set_popupmenu_shown( true ); } // // AAポップアップが閉じた void EditTextView::slot_hide_aamenu() { #ifdef _DEBUG std::cout << "EditTextView::slot_hide_aamenu\n"; #endif SESSION::set_popupmenu_shown( false ); } jd-2.8.7-140104/src/skeleton/editview.h0000644000076400010400000001160711465271544014212 0ustar // ライセンス: GPL2 #ifndef _EDITVIEW_H #define _EDITVIEW_H #include #include "control/control.h" #include "jdlib/miscutil.h" namespace SKELETON { class AAMenu; typedef sigc::signal< bool, GdkEventKey* > SIG_KEY_PRESS; typedef sigc::signal< bool, GdkEventKey* > SIG_KEY_RELEASE; typedef sigc::signal< bool, GdkEventButton* > SIG_BUTTON_PRESS; // undo 用のバッファ struct UNDO_DATA { Glib::ustring str_diff; unsigned int pos; unsigned int pos_cursor; bool append; }; // キーのプレスとリリースをフックする class EditTextView : public Gtk::TextView { SIG_KEY_PRESS m_sig_key_press; SIG_KEY_RELEASE m_sig_key_release; SIG_BUTTON_PRESS m_sig_button_press; // 入力コントローラ CONTROL::Control m_control; // undo 用 std::vector< UNDO_DATA > m_undo_tree; int m_undo_pos; Glib::ustring m_pre_text; bool m_cancel_change; bool m_delete_pushed; // カーソル移動用 int m_pre_offset; int m_pre_line; int m_line_offset; // コンテキストメニュー Gtk::Menu* m_context_menu; // AAポップアップ AAMenu* m_aapopupmenu; public: SIG_KEY_PRESS sig_key_press(){ return m_sig_key_press; } SIG_KEY_RELEASE sig_key_release(){ return m_sig_key_release; } SIG_BUTTON_PRESS sig_button_press() { return m_sig_button_press; } EditTextView(); virtual ~EditTextView(); void insert_str( const std::string& str, bool use_br ); void cursor_up(); void cursor_down(); void cursor_left(); void cursor_right(); void cursor_home(); void cursor_end(); void delete_char(); void backsp_char(); void undo(); void clear_undo(); // カーソルの画面上の座標 Gdk::Rectangle get_cursor_root_origin(); protected: virtual bool on_button_press_event( GdkEventButton* event ); virtual bool on_key_press_event( GdkEventKey* event ); virtual bool on_key_release_event( GdkEventKey* event ); virtual void on_populate_popup( Gtk::Menu* menu ); void slot_buffer_changed(); private: void cursor_up_down( bool up ); void slot_select_aamenu(); void slot_map_popupmenu(); void slot_hide_popupmenu(); // クリップボードから引用 void slot_quote_clipboard(); // 変換(スペース⇔ ) void slot_convert_space(); // JDの動作環境を記入 void slot_write_jdinfo(); // AA ポップアップ void slot_popup_aamenu_pos( int& x, int& y, bool& push_in ); void show_aalist_popup(); void slot_aamenu_selected( const std::string& aa ); void slot_map_aamenu(); void slot_hide_aamenu(); }; class EditView : public Gtk::ScrolledWindow { EditTextView m_textview; public: EditView(){ set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC ); add( m_textview ); show_all_children(); } virtual ~EditView(){} SIG_BUTTON_PRESS sig_button_press(){ return m_textview.sig_button_press(); } SIG_KEY_PRESS sig_key_press(){ return m_textview.sig_key_press(); } SIG_KEY_RELEASE sig_key_release(){ return m_textview.sig_key_release(); } Glib::RefPtr< Gtk::TextBuffer > get_buffer(){ return m_textview.get_buffer(); } void set_text( const Glib::ustring& text ){ m_textview.get_buffer()->set_text( text ); } Glib::ustring get_text(){ #ifdef _WIN32 return MISC::utf8_fix_wavedash( m_textview.get_buffer()->get_text(), MISC::WINtoUNIX ); #else return m_textview.get_buffer()->get_text(); #endif } void set_wrap_mode( Gtk::WrapMode wrap_mode ){ m_textview.set_wrap_mode( wrap_mode ); } void modify_text( Gtk::StateType state, const Gdk::Color& color ){ m_textview.modify_text( state, color ); } void modify_base( Gtk::StateType state, const Gdk::Color& color ){ m_textview.modify_base( state, color ); } void insert_str( const std::string& str, bool use_br ){ m_textview.insert_str( str, use_br ); } void set_editable( bool editable ){ m_textview.set_editable( editable ); } void set_accepts_tab( bool accept ){ m_textview.set_accepts_tab( accept ); } void modify_font( const Pango::FontDescription& font_desc ){ m_textview.modify_font( font_desc ); } void focus_view(){ m_textview.grab_focus(); } void undo(){ m_textview.undo(); } void clear_undo(){ m_textview.clear_undo(); } // カーソルの画面上の座標 Gdk::Rectangle get_cursor_root_origin(){ return m_textview.get_cursor_root_origin(); } }; } #endif jd-2.8.7-140104/src/skeleton/editviewdialog.h0000644000076400010400000000122110550416534015353 0ustar // ライセンス: GPL2 #ifndef _EDITVIEWDIALOG_H #define _EDITVIEWDIALOG_H #include #include "editview.h" namespace SKELETON { class EditViewDialog : public Gtk::Dialog { SKELETON::EditView m_edit; public: EditViewDialog( const std::string& str, const std::string& title, bool editable ){ m_edit.set_text( str ); m_edit.set_editable( editable ); add_button( Gtk::Stock::OK, Gtk::RESPONSE_OK ); get_vbox()->pack_start( m_edit ); set_title( title ); show_all_children(); } }; } #endif jd-2.8.7-140104/src/skeleton/entry.cpp0000644000076400010400000000427311512465304014057 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "entry.h" #include "control/controlid.h" #include using namespace SKELETON; // ボタン入力のフック bool JDEntry::on_button_press_event( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "JDEntry::on_button_press_event\n"; #endif m_sig_button_press.emit( event ); return Gtk::Entry::on_button_press_event( event ); } // キー入力のフック bool JDEntry::on_key_press_event( GdkEventKey* event ) { #ifdef _DEBUG std::cout << "JDEntry::on_key_press_event key = " << event->keyval << std::endl; #endif m_controlid = CONTROL::None; const guint key = event->keyval; const bool ctrl = ( event->state ) & GDK_CONTROL_MASK; const bool up = ( key == GDK_Up || ( ctrl && key == 'p' ) ); const bool down = ( key == GDK_Down || ( ctrl && key == 'n' ) ); const bool esc = ( key == GDK_Escape ); // 上下をキャンセル // gtkentry.cpp からのハック。環境やバージョンによっては問題が出るかもしれないので注意 if( up || down || esc ){ GtkEntry *entry = gobj(); if( gtk_im_context_filter_keypress( entry->im_context, event ) ) { #ifdef _DEBUG std::cout << "gtk_im_context_filter_keypress\n"; #endif entry->need_im_reset = TRUE; return TRUE; } else if( up || down ){ if( up ) m_sig_operate.emit( CONTROL::Up ); else m_sig_operate.emit( CONTROL::Down ); return TRUE; } } m_sig_key_press.emit( event->keyval ); m_controlid = m_control.key_press( event ); return Gtk::Entry::on_key_press_event( event ); } bool JDEntry::on_key_release_event( GdkEventKey* event ) { const bool ret = Gtk::Entry::on_key_release_event( event ); #ifdef _DEBUG std::cout << "JDEntry::on_key_release_event id = " << m_controlid << std::endl; #endif switch( m_controlid ){ case CONTROL::DrawOutAnd: case CONTROL::SearchCache: case CONTROL::Cancel: m_sig_operate.emit( m_controlid ); break; } m_controlid = CONTROL::None; return ret; } jd-2.8.7-140104/src/skeleton/entry.h0000644000076400010400000000271011505374764013531 0ustar // ライセンス: GPL2 // // キーボードフックしたentryクラス // #ifndef _ENTRY_H #define _ENTRY_H #include "control/control.h" #include namespace SKELETON { class JDEntry : public Gtk::Entry { typedef sigc::signal< void, GdkEventButton* > SIG_BUTTON_PRESS; typedef sigc::signal< void, int > SIG_KEY_PRESS; typedef sigc::signal< void, int > SIG_OPERATE; SIG_BUTTON_PRESS m_sig_button_press; SIG_KEY_PRESS m_sig_key_press; SIG_OPERATE m_sig_operate; // 入力コントローラ CONTROL::Control m_control; int m_controlid; public: SIG_BUTTON_PRESS signal_button_press(){ return m_sig_button_press; } SIG_KEY_PRESS signal_key_press(){ return m_sig_key_press; } SIG_OPERATE signal_operate(){ return m_sig_operate; } JDEntry() : Gtk::Entry(){} virtual ~JDEntry(){} // CONTROL::Control のモード設定( controlid.h 参照 ) // キー入力をフックして JDEntry::on_key_release_event() で SIG_OPERATE をemitする void add_mode( const int mode ){ m_control.add_mode( mode ); } protected: // マウスクリックのフック virtual bool on_button_press_event( GdkEventButton* event ); // キー入力のフック virtual bool on_key_press_event( GdkEventKey* event ); virtual bool on_key_release_event( GdkEventKey* event ); }; } #endif jd-2.8.7-140104/src/skeleton/filediag.h0000644000076400010400000000344510656346426014142 0ustar // ライセンス: GPL2 // ファイル選択ダイアログの基底クラス #ifndef _FILEDIAG_H #define _FILEDIAG_H #include #include "command.h" #include "session.h" namespace SKELETON { class FileDiag : public Gtk::FileChooserDialog { Gtk::FileChooserAction m_action; public: // ボタン追加 + saveボタンをデフォルトボタンにセット void add_buttons(){ add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ); if( m_action == Gtk::FILE_CHOOSER_ACTION_OPEN ) add_button( Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT ); else add_button( Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT ); set_default_response( Gtk::RESPONSE_ACCEPT ); } FileDiag( Gtk::Window& parent, const Glib::ustring& title, Gtk::FileChooserAction action = Gtk::FILE_CHOOSER_ACTION_OPEN ) : Gtk::FileChooserDialog( parent, title, action ), m_action( action ) { add_buttons(); } // parent がポインタの時は NULL かどうかで場合分け FileDiag( Gtk::Window* parent, const Glib::ustring& title, Gtk::FileChooserAction action = Gtk::FILE_CHOOSER_ACTION_OPEN ) : Gtk::FileChooserDialog( title, action ), m_action( action ) { add_buttons(); if( parent ) set_transient_for( *parent ); else set_transient_for( *CORE::get_mainwindow() ); } virtual ~FileDiag(){} virtual int run(){ SESSION::set_dialog_shown( true ); CORE::core_set_command( "dialog_shown" ); int ret = Gtk::FileChooserDialog::run(); SESSION::set_dialog_shown( false ); CORE::core_set_command( "dialog_hidden" ); return ret; } }; } #endif jd-2.8.7-140104/src/skeleton/hpaned.cpp0000644000076400010400000000217211571212223014144 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "hpaned.h" using namespace SKELETON; JDHPaned::JDHPaned( const int fixmode ) : Gtk::HPaned(), m_pctrl( *this, fixmode ) {} void JDHPaned::on_realize() { Gtk::HPaned::on_realize(); m_pctrl.update_position(); } bool JDHPaned::on_button_press_event( GdkEventButton* event ) { m_pctrl.button_press_event( event ); return Gtk::HPaned::on_button_press_event( event ); } bool JDHPaned::on_button_release_event( GdkEventButton* event ) { m_pctrl.button_release_event( event ); return Gtk::HPaned::on_button_release_event( event ); } bool JDHPaned::on_motion_notify_event( GdkEventMotion* event ) { m_pctrl.motion_notify_event( event ); return Gtk::HPaned::on_motion_notify_event( event ); } bool JDHPaned::on_enter_notify_event( GdkEventCrossing* event ) { m_pctrl.enter_notify_event( event ); return Gtk::HPaned::on_enter_notify_event( event ); } bool JDHPaned::on_leave_notify_event( GdkEventCrossing* event ) { m_pctrl.leave_notify_event( event ); return Gtk::HPaned::on_leave_notify_event( event ); } jd-2.8.7-140104/src/skeleton/hpaned.h0000644000076400010400000000143011571212223013605 0ustar // ライセンス: GPL2 // // HPaneeクラス // #ifndef _HPANED_H #define _HPANED_H #include #include "panecontrol.h" namespace SKELETON { class JDHPaned : public Gtk::HPaned { HPaneControl m_pctrl; public: JDHPaned( const int fixmode ); virtual ~JDHPaned(){} HPaneControl& get_ctrl(){ return m_pctrl; } protected: virtual void on_realize(); virtual bool on_button_press_event( GdkEventButton* event ); virtual bool on_button_release_event( GdkEventButton* event ); virtual bool on_motion_notify_event( GdkEventMotion* event ); virtual bool on_enter_notify_event( GdkEventCrossing* event ); virtual bool on_leave_notify_event( GdkEventCrossing* event ); }; } #endif jd-2.8.7-140104/src/skeleton/iconpopup.h0000644000076400010400000000155410753603330014375 0ustar // ライセンス: GPL2 #ifndef _ICONPOPUP_H #define _ICONPOPUP_H #include #include "icons/iconmanager.h" namespace SKELETON { class IconPopup : public Gtk::Window { Glib::RefPtr< Gdk::Pixbuf > m_pixbuf; Gtk::Image m_img; public: IconPopup( const int icon_id ) : Gtk::Window( Gtk::WINDOW_POPUP ){ Glib::RefPtr< Gdk::Pixmap > pixmap; Glib::RefPtr< Gdk::Bitmap > bitmap; m_pixbuf = ICON::get_icon( icon_id ); m_img.set( m_pixbuf ); m_pixbuf->render_pixmap_and_mask( pixmap, bitmap, 255 ); shape_combine_mask( bitmap, 0, 0 ); add( m_img ); show_all_children(); } const int get_img_width(){ return m_pixbuf->get_width(); } const int get_img_height(){ return m_pixbuf->get_height(); } }; } #endif jd-2.8.7-140104/src/skeleton/imgbutton.cpp0000644000076400010400000000152411001660150014707 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imgbutton.h" #include "icons/iconmanager.h" using namespace SKELETON; ImgButton::ImgButton( const int id, const std::string label ) { m_img = Gtk::manage( new Gtk::Image( ICON::get_icon( id ) ) ); set( label ); } ImgButton::ImgButton( const Gtk::StockID& stock_id, const std::string label, const Gtk::BuiltinIconSize icon_size ) { m_img = Gtk::manage( new Gtk::Image( stock_id, icon_size ) ); set( label ); } void ImgButton::set( const std::string& label ) { if( ! m_img ) return; if( label.empty() ) add( *m_img ); else { m_label.set_text( label ); m_hbox.pack_start( *m_img ); m_hbox.pack_start( m_label, Gtk::PACK_SHRINK, 2 ); add( m_hbox ); } set_focus_on_click( false ); } jd-2.8.7-140104/src/skeleton/imgbutton.h0000644000076400010400000000120411001416216014351 0ustar // ライセンス: GPL2 // 画像つきボタン #ifndef _IMGBUTTON_H #define _IMGBUTTON_H #include #include namespace SKELETON { class ImgButton : public Gtk::Button { Gtk::Image* m_img; Gtk::Label m_label; Gtk::HBox m_hbox; public: ImgButton( const int id, const std::string label = std::string() ); ImgButton( const Gtk::StockID& stock_id, const std::string label = std::string(), const Gtk::BuiltinIconSize icon_size = Gtk::ICON_SIZE_MENU ); private: void set( const std::string& label ); }; } #endif jd-2.8.7-140104/src/skeleton/imgtogglebutton.cpp0000644000076400010400000000160511001660150016111 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imgtogglebutton.h" #include "icons/iconmanager.h" using namespace SKELETON; ImgToggleButton::ImgToggleButton( const int id, const std::string label ) { m_img = Gtk::manage( new Gtk::Image( ICON::get_icon( id ) ) ); set( label ); } ImgToggleButton::ImgToggleButton( const Gtk::StockID& stock_id, const std::string label, const Gtk::BuiltinIconSize icon_size ) { m_img = Gtk::manage( new Gtk::Image( stock_id, icon_size ) ); set( label ); } void ImgToggleButton::set( const std::string& label ) { if( ! m_img ) return; if( label.empty() ) add( *m_img ); else { m_label.set_text( label ); m_hbox.pack_start( *m_img ); m_hbox.pack_start( m_label, Gtk::PACK_SHRINK, 2 ); add( m_hbox ); } set_focus_on_click( false ); } jd-2.8.7-140104/src/skeleton/imgtogglebutton.h0000644000076400010400000000127711001416216015565 0ustar // ライセンス: GPL2 // 画像つきドグルボタン #ifndef _IMGTOGGLEBUTTON_H #define _IMGTOGGLEBUTTON_H #include #include namespace SKELETON { class ImgToggleButton : public Gtk::ToggleButton { Gtk::Image* m_img; Gtk::Label m_label; Gtk::HBox m_hbox; public: ImgToggleButton( const int id, const std::string label = std::string() ); ImgToggleButton( const Gtk::StockID& stock_id, const std::string label = std::string(), const Gtk::BuiltinIconSize icon_size = Gtk::ICON_SIZE_MENU ); private: void set( const std::string& label ); }; } #endif jd-2.8.7-140104/src/skeleton/imgtoggletoolbutton.cpp0000644000076400010400000000047511506370702017026 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imgtoggletoolbutton.h" #include "icons/iconmanager.h" using namespace SKELETON; ImgToggleToolButton::ImgToggleToolButton( const int id ) { m_img = Gtk::manage( new Gtk::Image( ICON::get_icon( id ) ) ); set_icon_widget( *m_img ); } jd-2.8.7-140104/src/skeleton/imgtoggletoolbutton.h0000644000076400010400000000055411506370702016471 0ustar // ライセンス: GPL2 // 画像つきドグルツールボタン #ifndef _IMGTOGGLETOOLBUTTON_H #define _IMGTOGGLETOOLBUTTON_H #include #include namespace SKELETON { class ImgToggleToolButton : public Gtk::ToggleToolButton { Gtk::Image* m_img; public: ImgToggleToolButton( const int id ); }; } #endif jd-2.8.7-140104/src/skeleton/imgtoolbutton.cpp0000644000076400010400000000051311506370702015615 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "imgtoolbutton.h" #include "icons/iconmanager.h" #include "config/globalconf.h" using namespace SKELETON; ImgToolButton::ImgToolButton( const int id ) { m_img = Gtk::manage( new Gtk::Image( ICON::get_icon( id ) ) ); set_icon_widget( *m_img ); } jd-2.8.7-140104/src/skeleton/imgtoolbutton.h0000644000076400010400000000050511506370702015263 0ustar // ライセンス: GPL2 // 画像つきツールボタン #ifndef _IMGTOOLBUTTON_H #define _IMGTOOLBUTTON_H #include #include namespace SKELETON { class ImgToolButton : public Gtk::ToolButton { Gtk::Image* m_img; public: ImgToolButton( const int id ); }; } #endif jd-2.8.7-140104/src/skeleton/jdtoolbar.cpp0000644000076400010400000001131311224113455014664 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "jdtoolbar.h" #include "jdlib/miscmsg.h" #include "config/globalconf.h" #include /////////////////////////////////////////// // // gtk+-2.12.9/gtk/gtktoolbar.c より引用 // // gtkのバージョンが上がったときに誤動作しないかどうか注意 // typedef struct _GtkToolbarPrivate GtkToolbarPrivate; typedef struct _ToolbarContent ToolbarContent; typedef enum { DONT_KNOW, OLD_API, NEW_API } ApiMode; typedef enum { TOOL_ITEM, COMPATIBILITY } ContentType; typedef enum { NOT_ALLOCATED, NORMAL, HIDDEN, OVERFLOWN } ItemState; struct _GtkToolbarPrivate { GList * content; GtkWidget * arrow; GtkWidget * arrow_button; GtkMenu * menu; GdkWindow * event_window; ApiMode api_mode; GtkSettings * settings; int idle_id; GtkToolItem * highlight_tool_item; gint max_homogeneous_pixels; GTimer * timer; gulong settings_connection; guint show_arrow : 1; guint need_sync : 1; guint is_sliding : 1; guint need_rebuild : 1; /* whether the overflow menu should be regenerated */ guint animation : 1; }; struct _ToolbarContent { ContentType type; ItemState state; union { struct { GtkToolItem * item; GtkAllocation start_allocation; GtkAllocation goal_allocation; guint is_placeholder : 1; guint disappearing : 1; guint has_menu : 2; } tool_item; struct { GtkToolbarChild child; GtkAllocation space_allocation; guint space_visible : 1; } compatibility; } u; }; #define GTK_TOOLBAR_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TOOLBAR, GtkToolbarPrivate)) static void customized_toolbar_content_expose (ToolbarContent *content, GtkContainer *container, GdkEventExpose *expose) { GtkToolbarChild *child; GtkWidget *widget = NULL; /* quiet gcc */ switch (content->type) { case TOOL_ITEM: if (!content->u.tool_item.is_placeholder) widget = GTK_WIDGET (content->u.tool_item.item); break; case COMPATIBILITY: child = &(content->u.compatibility.child); if (child->type == GTK_TOOLBAR_CHILD_SPACE) { MISC::ERRMSG( "customized_toolbar_content_expose : CHILD_SPACE is not implemented" ); return; } widget = child->widget; break; } if (widget) gtk_container_propagate_expose (container, widget, expose); } static gint customized_gtk_toolbar_expose (GtkWidget *widget, GdkEventExpose *event) { #ifdef _DEBUG std::cout << "customized_gtk_toolbar_expose\n"; #endif GtkToolbar *toolbar = GTK_TOOLBAR (widget); GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar); GList *list; // 背景描画をキャンセル /* gint border_width; border_width = GTK_CONTAINER (widget)->border_width; if (GTK_WIDGET_DRAWABLE (widget)) { gtk_paint_box (widget->style, widget->window, (GtkStateType)GTK_WIDGET_STATE (widget), get_shadow_type(toolbar), &event->area, widget, "toolbar", border_width + widget->allocation.x, border_width + widget->allocation.y, widget->allocation.width - 2 * border_width, widget->allocation.height - 2 * border_width // widget->allocation.height + 36 ); } */ for (list = priv->content; list != NULL; list = list->next) { ToolbarContent *content = (ToolbarContent*)list->data; customized_toolbar_content_expose (content, GTK_CONTAINER (widget), event); } gtk_container_propagate_expose (GTK_CONTAINER (widget), priv->arrow_button, event); return false; } /////////////////////////////////////////////////// using namespace SKELETON; bool JDToolbar::on_expose_event( GdkEventExpose* event ) { #ifdef _DEBUG std::cout << "JDToolbar::on_expose_event\n"; #endif if( CONFIG::get_draw_toolbarback() ){ return Gtk::Toolbar::on_expose_event( event ); } // 自前で描画処理( 背景の描画をしない ) GtkWidget* widget = dynamic_cast< Gtk::Widget* >( this )->gobj(); if( widget ) return customized_gtk_toolbar_expose( widget, event ); return FALSE; } jd-2.8.7-140104/src/skeleton/jdtoolbar.h0000644000076400010400000000065611007350165014341 0ustar // ライセンス: GPL2 // // カスタマイズした Gtk::Toolbar ( 背景を描画しない ) // // (注) DragableNoteBookにappendするのは SKELETON::ToolBar // #ifndef JDTOOLBAR_H #define JDTOOLBAR_H #include namespace SKELETON { class JDToolbar : public Gtk::Toolbar { public: JDToolbar(){} protected: virtual bool on_expose_event( GdkEventExpose* event ); }; } #endif jd-2.8.7-140104/src/skeleton/label_entry.cpp0000644000076400010400000000361011302144375015207 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "label_entry.h" #include "view.h" using namespace SKELETON; LabelEntry::LabelEntry( const bool editable, const std::string& label, const std::string& text ) : m_editable( editable ) { set_label( label ); m_label.set_mnemonic_widget ( m_entry ); m_entry.signal_activate().connect( sigc::mem_fun( *this, &LabelEntry::slot_entry_acivate ) ); pack_start( m_label, Gtk::PACK_SHRINK ); m_info.set_size_request( 0, 0 ); m_info.set_alignment( Gtk::ALIGN_LEFT ); m_info.set_selectable( true ); setup(); set_text( text ); } void LabelEntry::setup() { if( m_editable ) pack_start( m_entry ); else pack_start( m_info ); show_all_children(); } void LabelEntry::set_editable( const bool editable ) { if( m_editable == editable ) return; #ifdef _DEBUG std::cout << "LabelEntry::set_editable editable = " << editable << std::endl; #endif if( m_editable ) remove( m_entry ); else remove( m_info ); m_editable = editable; setup(); } void LabelEntry::set_visibility( bool visibility ) { if( m_editable ) m_entry.set_visibility( visibility ); } void LabelEntry::set_label( const std::string& label ) { m_label.set_text_with_mnemonic( label ); } void LabelEntry::set_text( const std::string& text ) { m_entry.set_text( text ); m_info.set_text( text ); } const Glib::ustring LabelEntry::get_text() { if( m_editable ) return m_entry.get_text(); return m_info.get_text(); } void LabelEntry::grab_focus() { if( m_editable ) m_entry.grab_focus(); } const bool LabelEntry::has_grab() { if( m_editable ) return m_entry.has_grab(); return false; } // entry からsignal_activateを受け取った void LabelEntry::slot_entry_acivate() { #ifdef _DEBUG std::cout << "LabelEntry::slot_entry_acivate\n"; #endif m_sig_activate.emit(); } jd-2.8.7-140104/src/skeleton/label_entry.h0000644000076400010400000000210311302144375014650 0ustar // ライセンス: GPL2 // // ラベル + ラベル / エントリー // // プロパティの表示用 // #ifndef _LABEL_ENTRY_H #define _LABEL_ENTRY_H #include namespace SKELETON { class LabelEntry : public Gtk::HBox { typedef sigc::signal< void > SIG_ACTIVATE; SIG_ACTIVATE m_sig_activate; bool m_editable; Gtk::Label m_label; Gtk::Label m_info; Gtk::Entry m_entry; public: LabelEntry( const bool editable, const std::string& label, const std::string& text = std::string() ); SIG_ACTIVATE signal_activate(){ return m_sig_activate; } void set_editable( const bool editable ); void set_visibility( const bool visibility ); void set_label( const std::string& label ); void set_text( const std::string& text ); const Glib::ustring get_text(); void grab_focus(); const bool has_grab(); private: void setup(); // entry からsignal_activateを受け取った void slot_entry_acivate(); }; } #endif jd-2.8.7-140104/src/skeleton/loadable.cpp0000644000076400010400000001265411213463116014460 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "loadable.h" #include "jdlib/loader.h" #include "jdlib/misctime.h" #include "httpcode.h" using namespace SKELETON; Loadable::Loadable() : m_loader( 0 ), m_low_priority( false ) { clear_load_data(); } Loadable::~Loadable() { terminate_load(); // 一応デストラクタ内部でも実行しておく } // ロード強制停止 void Loadable::terminate_load() { #ifdef _DEBUG std::cout << "Loadable::terminate_load\n"; #endif // loadableを delete する前に terminate_load() を呼び出さないと // スレッド実行中にメモリなどが初期化されてしまうため落ちる時がある // デストラクタ内から terminate_load() しても落ちる時があるので // デストラクタの外から呼び出すこと set_dispatchable( false ); delete_loader(); } // 完全クリア void Loadable::clear_load_data() { m_code = HTTP_INIT; m_str_code = std::string(); m_date_modified = std::string(); m_cookies.clear(); m_location = std::string(); m_total_length = 0; m_current_length = 0; } const bool Loadable::is_loading() { if( ! m_loader ) return false; // m_loader != NULL ならローダ起動中ってこと return true; } // // 更新時刻 // const time_t Loadable::get_time_modified() { time_t time_out; time_out = MISC::datetotime( m_date_modified ); if( time_out == 0 ) time_out = time( NULL ) - 600; #ifdef _DEBUG std::cout << "Loadable::get_time_modified " << m_date_modified << std::endl << " -> " << time_out << std::endl; #endif return time_out; } void Loadable::delete_loader() { if( m_loader ) delete m_loader; m_loader = NULL; } // // ロード開始 // bool Loadable::start_load( const JDLIB::LOADERDATA& data ) { if( is_loading() ) return false; #ifdef _DEBUG std::cout << "Loadable::start_load url = " << data.url << std::endl; #endif assert( m_loader == NULL ); m_loader = new JDLIB::Loader( m_low_priority ); // 情報初期化 // m_date_modified, m_cookie は初期化しない m_code = HTTP_INIT; m_str_code = std::string(); m_location = std::string(); m_total_length = 0; m_current_length = 0; if( !m_loader->run( this, data ) ){ m_code = get_loader_code(); m_str_code = get_loader_str_code(); delete_loader(); return false; } return true; } // // ロード中止 // void Loadable::stop_load() { if( m_loader ) m_loader->stop(); } // ローダーからコールバックされてコードなどを取得してから // receive_data() を呼び出す void Loadable::receive( const char* data, size_t size ) { m_code = get_loader_code(); if( ! m_total_length && m_code != HTTP_INIT ) m_total_length = get_loader_length(); m_current_length += size; receive_data( data, size ); } // 別スレッドで動いているローダからfinish()を呼ばれたらディスパッチして // メインスレッドに制御を戻してから callback_dispatch()を呼び出す。 // そうしないと色々不具合が生じる void Loadable::finish() { #ifdef _DEBUG std::cout << "Loadable::finish\n"; #endif dispatch(); } // // ローダを削除してreceive_finish()をコール // void Loadable::callback_dispatch() { #ifdef _DEBUG std::cout << "Loadable::callback_dispatch\n"; #endif // ローダを削除する前に情報保存 m_code = get_loader_code(); if( ! get_loader_str_code().empty() ) m_str_code = get_loader_str_code(); if( ! get_loader_contenttype().empty() ) m_contenttype = get_loader_contenttype(); if( ! get_loader_modified().empty() ) m_date_modified = get_loader_modified(); if( ! get_loader_cookies().empty() ) m_cookies = get_loader_cookies(); if( ! get_loader_location().empty() ) m_location = get_loader_location(); #ifdef _DEBUG std::cout << "delete_loader\n"; #endif delete_loader(); #ifdef _DEBUG std::cout << "code = " << m_code << std::endl; std::cout << "str_code = " << m_str_code << std::endl; std::cout << "contenttype = " << m_contenttype << std::endl; std::cout << "modified = " << m_date_modified << std::endl; std::cout << "location = " << m_location << std::endl; std::cout << "total_length = " << m_total_length << std::endl; std::cout << "current length = " << m_current_length << std::endl; #endif receive_finish(); } // ローダから各種情報の取得 const int Loadable::get_loader_code() { if( ! m_loader ) return HTTP_INIT; return m_loader->data().code; } const std::string Loadable::get_loader_str_code() { if( ! m_loader ) return std::string(); return m_loader->data().str_code; } const std::string Loadable::get_loader_contenttype() { if( ! m_loader ) return std::string(); return m_loader->data().contenttype; } const std::string Loadable::get_loader_modified() { if( ! m_loader ) return std::string(); return m_loader->data().modified; } const std::list< std::string > Loadable::get_loader_cookies() { if( ! m_loader ) return std::list< std::string >(); return m_loader->data().list_cookies; } const std::string Loadable::get_loader_location() { if( ! m_loader ) return std::string(); return m_loader->data().location; } const size_t Loadable::get_loader_length() { if( ! m_loader ) return 0; return m_loader->data().length; } jd-2.8.7-140104/src/skeleton/loadable.h0000644000076400010400000001222211361602607014120 0ustar // ライセンス: GPL2 // // ロード可能クラスの基底クラス // JDLIB::Loaderを使ってデータを受信する // // ・start_load() でロード開始。JDLIB::LOADERDATA data を引数に渡す // ・stop_load() で停止 // // ロード中はreceive_data()がコールバックされてデータが送られる // ロードが終わると receive_finish() がコールバックされる // // ・ delete する前に terminate_load() を明示的に呼び出すこと(terminate_load()のコメントを参照) // // 詳しい流れは次の通り /* (1) start_load() の JDLIB::create_loader() でローダが作成される (2) m_loader->run() でロード開始 --------ここから別スレッド内で実行 (3) ローダがデータを受け取るとreceive()がコールバックされてhttpコードやサイズを取得する (4) receive()からreceive_data()が呼び出される (5) ロードが終了したらfinish()が呼ばれて Dispatchable::dispatch()により ディスパッチャを使ってメインスレッドに制御を戻す --------ここからメインスレッドに戻る (6) ディスパッチャ経由で Dispatchable::callback_dispatch() が呼び出される (7) クッキー、更新時刻などを取得する (8) delete_loader()でローダの停止を待って削除する (9) receive_finish()を呼び出す 注意点 ・receive_data()は別スレッド内で実行される ・receive_finish() はメインスレッド内で実行される ・receive_finish()が呼ばれた時点で既にローダは削除されているので明示的に削除する必要はない */ #ifndef _LOADABLE_H #define _LOADABLE_H #include "dispatchable.h" #include #include #include namespace JDLIB { class Loader; class LOADERDATA; } namespace SKELETON { class Loadable : public Dispatchable { JDLIB::Loader* m_loader; bool m_low_priority; // ローダからコピーしたデータ int m_code; std::string m_str_code; std::string m_contenttype; std::string m_date_modified; std::list< std::string > m_cookies; std::string m_location; size_t m_total_length; size_t m_current_length; public: Loadable(); virtual ~Loadable(); // HTTPコードなどの完全クリア void clear_load_data(); // ロード中かどうか const bool is_loading(); const int get_code() const { return m_code; } void set_code( int code ){ m_code = code; } const std::string& get_str_code() const { return m_str_code; } void set_str_code( const std::string& str_code ){ m_str_code = str_code; } const std::string& get_contenttype() const { return m_contenttype; } const std::list< std::string >& cookies() { return m_cookies; } const std::string& location() const { return m_location; } const size_t total_length() const { return m_total_length; } void set_total_length( int length ){ m_total_length = length; } const size_t current_length() const { return m_current_length; } void set_current_length( int length ){ m_current_length = length; } // 更新時刻関係 const time_t get_time_modified(); const std::string& get_date_modified() const { return m_date_modified; } void set_date_modified( const std::string& date ){ m_date_modified = date; } // ローダーからコールバックされてコードなどを取得してから // receive_data() を呼び出す void receive( const char* data, size_t size ); // ディスパッチャ経由で Dispatchable::callback_dispatch()、 receive_finish()を呼ぶ // ロード直後に直接 receive_finish() は呼ばないこと void finish(); // ロード開始 // パラメータは Loader::run()の説明をみること bool start_load( const JDLIB::LOADERDATA& data ); // ロード停止 virtual void stop_load(); // ロード強制停止 // loadableを delete する前に terminate_load() を呼び出さないと // スレッド実行中にメモリなどが初期化されてしまうため落ちる時がある // デストラクタ内から terminate_load() しても落ちる時があるので // デストラクタの外から呼び出すこと void terminate_load(); // ローダがスレッド起動待ち状態になった時に、起動順のプライオリティを下げる void set_priority_low(){ m_low_priority = true; } private: virtual void receive_data( const char* , size_t ){}; virtual void receive_finish(){}; void delete_loader(); virtual void callback_dispatch(); const int get_loader_code(); const std::string get_loader_str_code(); const std::string get_loader_contenttype(); const std::string get_loader_modified(); const std::list< std::string > get_loader_cookies(); const std::string get_loader_location(); const size_t get_loader_length(); }; } #endif jd-2.8.7-140104/src/skeleton/lockable.h0000644000076400010400000000133610540252733014134 0ustar // ライセンス: GPL2 // // ロック可能クラス ( RefPtr と組み合わせて使う ) // // Lockable を継承したクラスを JDLIB::RefPtr_Lock 経由で呼ぶことによってロックを掛ける // ロックが外れたら unlook_impl が呼ばれる // #ifndef _LOCKABLE_H #define _LOCKABLE_H namespace SKELETON { class Lockable { int m_lock; public: Lockable() :m_lock( 0 ){} virtual ~Lockable(){} const int get_lock() const { return m_lock; } void lock(){ ++m_lock; } void unlock(){ --m_lock; if( m_lock == 0 ) unlock_impl(); } private: virtual void unlock_impl(){} }; } #endif jd-2.8.7-140104/src/skeleton/login.cpp0000644000076400010400000000357411207510426014026 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "login.h" #include "cache.h" #include "jdlib/confloader.h" #include #include #include // chmod #include using namespace SKELETON; Login::Login( const std::string& url ) : m_url( url ), m_login_now( 0 ), m_save_info( 0 ) { #ifdef _DEBUG std::cout << "Login::Login " << get_url() << std::endl; #endif read_info(); } Login::~Login() { #ifdef _DEBUG std::cout << "Login::~Login " << get_url() << std::endl; #endif if( m_save_info ) save_info(); } void Login::set_username( const std::string& username ) { if( username != m_username ){ m_username = username; m_save_info = true; } } void Login::set_passwd( const std::string& passwd ) { if( passwd != m_passwd ){ m_passwd = passwd; m_save_info = true; } } // // パスワードやユーザー名読み込み // void Login::read_info() { std::string path = CACHE::path_passwd( get_url().substr( strlen( "jdlogin://" ) ) ); #ifdef _DEBUG std::cout << "Login::read_info path = " << path << std::endl; #endif JDLIB::ConfLoader cf( path, std::string() ); m_username = cf.get_option_str( "username", "" ); m_passwd = cf.get_option_str( "passwd", "" ); #ifdef _DEBUG std::cout << "user = " << m_username << " ,passwd = " << m_passwd << std::endl; #endif } // // パスワードやユーザー名書き込み // void Login::save_info() { std::string path = CACHE::path_passwd( get_url().substr( strlen( "jdlogin://" ) ) ); #ifdef _DEBUG std::cout << "Login::save_info path = " << path << std::endl; #endif std::ostringstream oss; oss << "username = " << m_username<< std::endl << "passwd = " << m_passwd << std::endl; CACHE::save_rawdata( path, oss.str() ); chmod( path.c_str(), S_IWUSR | S_IRUSR ); } jd-2.8.7-140104/src/skeleton/login.h0000644000076400010400000000302011513340547013462 0ustar // ライセンス: GPL2 // // 2chなどへのログイン管理クラス // // セッション管理やログイン、パスワードの保存などを行う // #ifndef _LOGIN_H #define _LOGIN_H #include "loadable.h" namespace SKELETON { class Login : public SKELETON::Loadable { std::string m_url; bool m_login_now; bool m_save_info; std::string m_username; std::string m_passwd; std::string m_sessionid; // セッションID std::string m_sessiondata; // セッションデータ public: Login( const std::string& url ); virtual ~Login(); const bool login_now() const { return m_login_now; } void set_login_now( bool login_now ){ m_login_now = login_now; } const std::string& get_url() const { return m_url; } const std::string& get_username() const { return m_username; } void set_username( const std::string& username ); const std::string& get_passwd() const { return m_passwd; } void set_passwd( const std::string& passwd ); const std::string& get_sessionid() const { return m_sessionid; } void set_sessionid( const std::string& id ){ m_sessionid = id; } const std::string& get_sessiondata() const { return m_sessiondata; } void set_sessiondata( const std::string& data ){ m_sessiondata = data; } virtual void start_login()=0; virtual void logout()=0; private: void read_info(); void save_info(); }; } #endif jd-2.8.7-140104/src/skeleton/Makefile.am0000644000076400010400000000324512072045132014237 0ustar noinst_LIBRARIES = libskeleton.a libskeleton_a_SOURCES = \ window.cpp \ aamenu.cpp \ admin.cpp \ dispatchable.cpp \ loadable.cpp \ treeviewbase.cpp \ dragtreeview.cpp \ edittreeview.cpp \ editcolumns.cpp \ view.cpp \ editview.cpp \ dragnote.cpp \ tabnote.cpp \ toolbarnote.cpp \ viewnote.cpp \ tablabel.cpp \ tabswitchbutton.cpp \ tabswitchmenu.cpp \ imgbutton.cpp \ imgtoolbutton.cpp \ imgtogglebutton.cpp \ imgtoggletoolbutton.cpp \ menubutton.cpp \ toolmenubutton.cpp \ backforwardbutton.cpp \ popupwin.cpp \ tooltip.cpp \ entry.cpp \ compentry.cpp \ label_entry.cpp \ login.cpp \ prefdiag.cpp \ selectitempref.cpp \ msgdiag.cpp \ aboutdiag.cpp \ detaildiag.cpp \ panecontrol.cpp \ hpaned.cpp \ vpaned.cpp \ notebook.cpp \ vbox.cpp \ jdtoolbar.cpp \ toolbar.cpp \ textloader.cpp \ undobuffer.cpp noinst_HEADERS = \ window.h \ aamenu.h \ admin.h \ dispatchable.h \ loadable.h \ lockable.h \ treeviewbase.h \ dragtreeview.h \ edittreeview.h \ editcolumns.h \ view.h \ editview.h \ dragnote.h \ tabnote.h \ toolbarnote.h \ viewnote.h \ tablabel.h \ tabswitchbutton.h \ tabswitchmenu.h \ imgbutton.h \ imgtoolbutton.h \ imgtogglebutton.h \ imgtoggletoolbutton.h \ menubutton.h \ toolmenubutton.h \ backforwardbutton.h \ spinbutton.h \ popupwinbase.h \ popupwin.h \ iconpopup.h \ tooltip.h \ entry.h \ compentry.h \ label_entry.h \ prefdiag.h \ selectitempref.h \ msgdiag.h \ aboutdiag.h \ detaildiag.h \ filediag.h \ login.h \ panecontrol.h \ hpaned.h \ vpaned.h \ notebook.h \ vbox.h \ jdtoolbar.h \ toolbar.h \ textloader.h \ undobuffer.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/skeleton/menubutton.cpp0000644000076400010400000001401212006761301015101 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "gtkmmversion.h" #include "menubutton.h" #include "jdlib/miscutil.h" #include "icons/iconmanager.h" #include "command.h" using namespace SKELETON; enum { MENU_MAX_LNG = 50 // メニューに表示する文字数(半角) }; MenuButton::MenuButton( const bool show_arrow, Gtk::Widget& label ) : m_label( NULL ), m_arrow( NULL ) { setup( show_arrow, &label ); } MenuButton::MenuButton( const bool show_arrow, const int id ) : m_label( NULL ), m_arrow( NULL ) { setup( show_arrow, Gtk::manage( new Gtk::Image( ICON::get_icon( id ) ) ), Gtk::PACK_SHRINK ); } void MenuButton::setup( const bool show_arrow, Gtk::Widget* label, Gtk::PackOptions options, guint padding ) { const int space = 4; m_label = label; m_popupmenu = NULL; m_on_arrow = false; m_enable_sig_clicked = true; Gtk::HBox *hbox = Gtk::manage( new Gtk::HBox() ); hbox->set_spacing( space ); if( m_label ) hbox->pack_start( *m_label, options, padding ); if( show_arrow ){ m_arrow = Gtk::manage( new Gtk::Arrow( Gtk::ARROW_DOWN, Gtk::SHADOW_NONE ) ); hbox->pack_start( *m_arrow, Gtk::PACK_SHRINK ); } else m_enable_sig_clicked = false; add_events( Gdk::ENTER_NOTIFY_MASK ); add_events( Gdk::POINTER_MOTION_MASK ); add_events( Gdk::LEAVE_NOTIFY_MASK ); add_events( Gdk::SCROLL_MASK ); signal_enter_notify_event().connect( sigc::mem_fun( *this, &MenuButton::slot_enter ) ); signal_leave_notify_event().connect( sigc::mem_fun( *this, &MenuButton::slot_leave ) ); signal_motion_notify_event().connect( sigc::mem_fun( *this, &MenuButton::slot_motion ) ); add( *hbox ); show_all_children(); // メニュー項目作成 Glib::RefPtr< Gtk::ActionGroup > actiongroup = Gtk::ActionGroup::create(); Glib::RefPtr< Gtk::AccelGroup > agroup = CORE::get_mainwindow()->get_accel_group(); for( int i = 0 ; i < MAX_MENU_SIZE; ++i ){ Glib::RefPtr< Gtk::Action > action = Gtk::Action::create( "menu" + MISC::itostr( i ), "dummy" ); action->set_accel_group( agroup ); Gtk::MenuItem* item = Gtk::manage( action->create_menu_item() ); actiongroup->add( action, sigc::bind< int >( sigc::mem_fun( *this, &MenuButton::slot_menu_selected ), i ) ); m_menuitems.push_back( item ); } set_focus_on_click( false ); } // virtual MenuButton::~MenuButton() { if( m_popupmenu ) delete m_popupmenu; } void MenuButton::set_tooltip_arrow( const std::string& tooltip ) { #if GTKMM_CHECK_VERSION(2,13,0) if( m_arrow ) m_tooltip_arrow.set_tip( *m_arrow, tooltip ); #else // gtkmm-2.12.0より前のバージョンはボタンの中のWidgetにツールチップを設定できない m_tooltip_arrow.set_tip( *this, tooltip ); #endif } // // メニュー項目追加 // void MenuButton::append_menu( std::vector< std::string >& items ) { // 古いメニューからメニュー項目を取り除いてdelete if( m_popupmenu ){ const int menusize = m_popupmenu->get_children().size(); for( int i = 0; i < menusize; ++i ) m_popupmenu->remove( *m_menuitems[ i ] ); delete m_popupmenu; } m_popupmenu = NULL; if( ! items.size() ) return; // 新しくメニューを作成して項目追加 m_popupmenu = Gtk::manage( new Gtk::Menu() ); const int size = MIN( items.size(), MAX_MENU_SIZE ); for( int i = 0 ; i < size; ++i ){ Gtk::MenuItem* item = NULL; if( items[ i ] == "separator" ){ item = Gtk::manage( new Gtk::SeparatorMenuItem() ); } else{ item = m_menuitems[ i ]; dynamic_cast< Gtk::Label* >( item->get_child() )->set_text( MISC::cut_str( items[ i ], MENU_MAX_LNG ) ); } if( item ) m_popupmenu->append( *item ); } m_popupmenu->show_all(); } // // ポップアップメニュー表示 // // virtual void MenuButton::show_popupmenu() { if( ! m_popupmenu ) return; m_popupmenu->popup( Gtk::Menu::SlotPositionCalc( sigc::mem_fun( *this, &MenuButton::slot_popup_pos ) ), 0, gtk_get_current_event_time() ); } // // メニューが選ばれた // void MenuButton::slot_menu_selected( int i ) { #ifdef _DEBUG std::cout << "MenuButton::slot_menu_selected i = " << i << std::endl; #endif m_sig_selected.emit( i ); } // // ボタンがクリックされたらクリックした位置で処理を変える // void MenuButton::on_clicked() { #ifdef _DEBUG std::cout << "MenuButton::on_clicked\n"; #endif if( ! m_enable_sig_clicked || m_on_arrow ) show_popupmenu(); else m_sig_clicked.emit(); } // // ポップアップメニューの位置決め // void MenuButton::slot_popup_pos( int& x, int& y, bool& push_in ) { const int mrg = 16; get_pointer( x, y ); int ox, oy; get_window()->get_origin( ox, oy ); Gdk::Rectangle rect = get_allocation(); x += ox + rect.get_x() - mrg; y = oy + rect.get_y() + rect.get_height(); push_in = false; } bool MenuButton::slot_enter( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "MenuButton::slot_enter\n"; #endif check_on_arrow( (int)event->x ); return true; } bool MenuButton::slot_leave( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "MenuButton::slot_leave\n"; #endif m_on_arrow = false; return true; } bool MenuButton::slot_motion( GdkEventMotion* event ) { check_on_arrow( (int)event->x ); return true; } // // ポインタが矢印の下にあるかチェック // void MenuButton::check_on_arrow( int ex ) { if( ! m_arrow ){ m_on_arrow = false; return; } if( ! m_label ){ m_on_arrow = true; return; } Gdk::Rectangle rect = m_arrow->get_allocation(); int x = rect.get_x(); rect = get_allocation(); x -= rect.get_x(); if( ex >= x ) m_on_arrow = true; else m_on_arrow = false; #ifdef _DEBUG std::cout << "MenuButton::check_on_arrow x = " << ex << " / " << x << " on = " << m_on_arrow << std::endl; #endif } jd-2.8.7-140104/src/skeleton/menubutton.h0000644000076400010400000000413311506370702014556 0ustar // ライセンス: GPL2 // メニュー付きボタン #ifndef _MENUBUTTON_H #define _MENUBUTTON_H #include #include #include enum { MAX_MENU_SIZE = 20 }; namespace SKELETON { class MenuButton : public Gtk::Button { typedef sigc::signal< void > SIG_BUTTON_CLICKED; typedef sigc::signal< void, const int > SIG_SELECTED; SIG_BUTTON_CLICKED m_sig_clicked; SIG_SELECTED m_sig_selected; Gtk::Menu* m_popupmenu; std::vector< Gtk::MenuItem* > m_menuitems; Gtk::Widget* m_label; Gtk::Tooltips m_tooltip_arrow; Gtk::Arrow* m_arrow; bool m_on_arrow; bool m_enable_sig_clicked; public: MenuButton( const bool show_arrow, Gtk::Widget& label ); MenuButton( const bool show_arrow , const int id ); virtual ~MenuButton(); Gtk::Widget* get_label_widget(){ return m_label; } void set_tooltip_arrow( const std::string& tooltip ); SIG_BUTTON_CLICKED signal_button_clicked(){ return m_sig_clicked; } // メニューが選択されたらemitされる SIG_SELECTED signal_selected(){ return m_sig_selected; } // メニュー項目追加 void append_menu( std::vector< std::string >& items ); // 矢印ボタン以外をクリックしたときにSIG_BUTTON_CLICKEDをemitする // false の時はボタンのどこを押してもメニューを表示する void set_enable_sig_clicked( const bool enable ){ m_enable_sig_clicked = enable; } void on_clicked(); protected: // ポップアップメニュー表示 virtual void show_popupmenu(); private: void setup( const bool show_arrow, Gtk::Widget* label, Gtk::PackOptions options = Gtk::PACK_EXPAND_WIDGET, guint padding = 0 ); void slot_menu_selected( int i ); void slot_popup_pos( int& x, int& y, bool& push_in ); bool slot_enter( GdkEventCrossing* event ); bool slot_leave( GdkEventCrossing* event ); bool slot_motion( GdkEventMotion* event ); void check_on_arrow( int ex ); }; } #endif jd-2.8.7-140104/src/skeleton/msgdiag.cpp0000644000076400010400000001262711425037357014341 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "msgdiag.h" #include "command.h" #include "session.h" #include "dispatchmanager.h" #include "global.h" #include #include using namespace SKELETON; MsgDiag::MsgDiag( Gtk::Window& parent, const Glib::ustring& message, bool use_markup, Gtk::MessageType type, Gtk::ButtonsType buttons, bool modal ) : Gtk::MessageDialog( parent, message, use_markup, type, buttons, modal ) {} // parent がポインタの時は NULL かどうかで場合分け MsgDiag::MsgDiag( Gtk::Window* parent, const Glib::ustring& message, bool use_markup, Gtk::MessageType type, Gtk::ButtonsType buttons, bool modal ) : Gtk::MessageDialog( message, use_markup, type, buttons, modal ) { if( parent ) set_transient_for( *parent ); else set_transient_for( *CORE::get_mainwindow() ); // tab でラベルにフォーカスが移らないようにする ( messagedialog.ccg をハックした ) Gtk::Widget* wdt = Glib::wrap( gobj()->label ); if( wdt ){ Gtk::Label* label = dynamic_cast< Gtk::Label* >( wdt ); if( label ) label->property_can_focus() = false; } } void MsgDiag::add_default_button( const Gtk::StockID& stock_id, const int id ) { Gtk::Button* button = Gtk::manage( new Gtk::Button( stock_id ) ); add_default_button( button, id ); } void MsgDiag::add_default_button( const Glib::ustring& label, const int id ) { Gtk::Button* button = Gtk::manage( new Gtk::Button( label ) ); add_default_button( button, id ); } void MsgDiag::add_default_button( Gtk::Widget* button, const int id ) { if( ! button ) return; add_action_widget( *button, id ); button->show(); button->set_flags( Gtk::CAN_DEFAULT ); button->grab_default(); button->grab_focus(); } int MsgDiag::run() { #ifdef _DEBUG std::cout << "MsgDiag::run start\n"; #endif SESSION::set_dialog_shown( true ); CORE::core_set_command( "dialog_shown" ); // タイマーセット sigc::slot< bool > slot_timeout = sigc::bind( sigc::mem_fun(*this, &MsgDiag::slot_timeout), 0 ); m_conn_timer = JDLIB::Timeout::connect( slot_timeout, TIMER_TIMEOUT ); int ret = Gtk::MessageDialog::run(); SESSION::set_dialog_shown( false ); CORE::core_set_command( "dialog_hidden" ); #ifdef _DEBUG std::cout << "MsgDiag::run fin\n"; #endif return ret; } void MsgDiag::show() { #ifdef _DEBUG std::cout << "MsgDiag::show\n"; #endif SESSION::set_dialog_shown( true ); CORE::core_set_command( "dialog_shown" ); Gtk::MessageDialog::show(); } void MsgDiag::hide() { #ifdef _DEBUG std::cout << "MsgDiag::hide\n"; #endif SESSION::set_dialog_shown( false ); CORE::core_set_command( "dialog_hidden" ); Gtk::MessageDialog::hide(); } // タイマーのslot関数 bool MsgDiag::slot_timeout( int timer_number ) { // メインループが停止していて dispatcher が働かないため // タイマーから強制的に実行させる CORE::get_dispmanager()->slot_dispatch(); return true; } ///////////////////////////////////// MsgCheckDiag::MsgCheckDiag( Gtk::Window* parent, const Glib::ustring& message, const Glib::ustring& message_check, Gtk::MessageType type, Gtk::ButtonsType buttons, const int default_response ) : SKELETON::MsgDiag( parent, message, false, type, Gtk::BUTTONS_NONE, false ) , m_chkbutton( message_check, true ) { const int mrg = 16; Gtk::HBox* hbox = Gtk::manage( new Gtk::HBox ); hbox->pack_start( m_chkbutton, Gtk::PACK_EXPAND_WIDGET, mrg ); get_vbox()->pack_start( *hbox, Gtk::PACK_SHRINK ); Gtk::Button* button = NULL; if( buttons == Gtk::BUTTONS_OK ){ button = Gtk::manage( new Gtk::Button( Gtk::Stock::OK ) ); add_default_button( button, Gtk::RESPONSE_OK ); } else if( buttons == Gtk::BUTTONS_OK_CANCEL ){ add_button( Gtk::Stock::NO, Gtk::RESPONSE_CANCEL ); button = Gtk::manage( new Gtk::Button( Gtk::Stock::OK ) ); add_default_button( button, Gtk::RESPONSE_OK ); } else if( buttons == Gtk::BUTTONS_YES_NO ){ if( default_response == Gtk::RESPONSE_NO ){ button = Gtk::manage( new Gtk::Button( Gtk::Stock::NO ) ); add_default_button( button, Gtk::RESPONSE_NO ); add_button( Gtk::Stock::YES, Gtk::RESPONSE_YES ); } else{ add_button( Gtk::Stock::NO, Gtk::RESPONSE_NO ); button = Gtk::manage( new Gtk::Button( Gtk::Stock::YES ) ); add_default_button( button, Gtk::RESPONSE_YES ); } } show_all_children(); } ///////////////////////////////////// MsgOverwriteDiag::MsgOverwriteDiag( Gtk::Window* parent ) : SKELETON::MsgDiag( parent, "ファイルが存在します。ファイル名を変更して保存しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE ) { add_button( Gtk::Stock::NO, Gtk::RESPONSE_NO ); add_button( Gtk::Stock::YES, Gtk::RESPONSE_YES ); add_button( "上書き", OVERWRITE_YES ); add_button( "すべていいえ", OVERWRITE_NO_ALL ); add_button( "すべて上書き", OVERWRITE_YES_ALL ); }; jd-2.8.7-140104/src/skeleton/msgdiag.h0000644000076400010400000000454011425037357014001 0ustar // ライセンス: GPL2 // メッセージダイアログの基底クラス #ifndef _MSGDIAG_H #define _MSGDIAG_H #include #include "jdlib/timeout.h" namespace SKELETON { class MsgDiag : public Gtk::MessageDialog { JDLIB::Timeout* m_conn_timer; public: MsgDiag( Gtk::Window& parent, const Glib::ustring& message, bool use_markup = false, Gtk::MessageType type = Gtk::MESSAGE_INFO, Gtk::ButtonsType buttons = Gtk::BUTTONS_OK, bool modal = false); // parent がポインタの時は NULL かどうかで場合分け MsgDiag( Gtk::Window* parent, const Glib::ustring& message, bool use_markup = false, Gtk::MessageType type = Gtk::MESSAGE_INFO, Gtk::ButtonsType buttons = Gtk::BUTTONS_OK, bool modal = false); virtual ~MsgDiag(){} void add_default_button( const Gtk::StockID& stock_id, const int id ); void add_default_button( const Glib::ustring& label, const int id ); void add_default_button( Gtk::Widget* button, const int id ); virtual int run(); void show(); void hide(); private: // タイマーのslot関数 bool slot_timeout( int timer_number ); }; ///////////////////////////////////// // チェックボタン付き class MsgCheckDiag : public SKELETON::MsgDiag { Gtk::CheckButton m_chkbutton; public: MsgCheckDiag( Gtk::Window* parent, const Glib::ustring& message, const Glib::ustring& message_check, Gtk::MessageType type = Gtk::MESSAGE_INFO, Gtk::ButtonsType buttons = Gtk::BUTTONS_OK, const int default_response = -1 ); Gtk::CheckButton& get_chkbutton(){ return m_chkbutton; } }; ///////////////////////////////////// // 上書きチェックダイアログ enum { OVERWRITE_YES = Gtk::RESPONSE_YES + 100, OVERWRITE_YES_ALL = Gtk::RESPONSE_YES + 200, OVERWRITE_NO_ALL = Gtk::RESPONSE_NO + 200 }; class MsgOverwriteDiag : public SKELETON::MsgDiag { public: MsgOverwriteDiag( Gtk::Window* parent ); }; } #endif jd-2.8.7-140104/src/skeleton/notebook.cpp0000644000076400010400000000074010561115076014532 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "notebook.h" using namespace SKELETON; JDNotebook::JDNotebook() : Gtk::Notebook() {} JDNotebook::~JDNotebook() {} // unpack = true の時取り除く int JDNotebook::append_remove_page( bool unpack, Widget& child, const Glib::ustring& tab_label, bool use_mnemonic ) { if( unpack ){ remove( child ); return 0; } return append_page( child, tab_label, use_mnemonic ); } jd-2.8.7-140104/src/skeleton/notebook.h0000644000076400010400000000065510561115076014204 0ustar // ライセンス: GPL2 // // Notebook クラス // #ifndef _NOTEBOOK_H #define _NOTEBOOK_H #include namespace SKELETON { class JDNotebook : public Gtk::Notebook { public: JDNotebook(); ~JDNotebook(); // unpack = true の時取り除く int append_remove_page( bool unpack, Widget& child, const Glib::ustring& tab_label, bool use_mnemonic = false ); }; } #endif jd-2.8.7-140104/src/skeleton/panecontrol.cpp0000644000076400010400000001426011571212223015232 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "panecontrol.h" using namespace SKELETON; enum { PANE_PAGE_MINSIZE = 32 }; PaneControl::PaneControl( Gtk::Paned& paned, int fixmode ) : m_paned( paned ), m_click_fold( PANE_CLICK_NORMAL ), m_clicked( false ), m_drag( false ), m_on_paned( false ), m_fixmode( fixmode ), m_mode( PANE_NORMAL ) { m_pre_size = -1; } PaneControl::~PaneControl() {} // // クロック入力 // void PaneControl::clock_in() { // Gtk::Paned は configure_event()をキャッチ出来ないので // 応急処置としてタイマーの中でサイズが変更したか調べて // 変わっていたら仕切りの位置を調整する if( m_pre_size != get_size() ){ #ifdef _DEBUG int pos = m_paned.get_position(); std::cout << "PaneControl::clock_in resize pos = " << pos << " presize = " << m_pre_size << " size = " << get_size() << std::endl; #endif update_position(); m_pre_size = get_size(); } } // // モードにしたがってセパレータの位置を更新 // void PaneControl::update_position() { #ifdef _DEBUG std::cout << "PaneControl::update_position fixmode = " << m_fixmode << " mode = " << m_mode << " pos = " << m_pos << " size = " << get_size() << std::endl; #endif int pos = m_paned.get_position(); // PAGE1を最大化 if( m_mode == PANE_MAX_PAGE1 ) m_paned.set_position( get_size() ); // PAGE2を最大化 else if( m_mode == PANE_MAX_PAGE2 && pos > 0 ) m_paned.set_position( 0 ); // 通常状態 else if( m_mode == PANE_NORMAL ){ // ウィンドウをリサイズしたときの処理 // m_fixmode の値によりPAGE1とPAGE2のどちらのサイズを固定するか判断する int newpos = 0; if( m_fixmode == PANE_FIXSIZE_PAGE1 && pos != m_pos ){ newpos = MIN( m_pos, get_size() - PANE_PAGE_MINSIZE ); } else if( m_fixmode == PANE_FIXSIZE_PAGE2 && pos != get_size() - m_pos ){ newpos = MAX( get_size() - m_pos, PANE_PAGE_MINSIZE ); } if( newpos ) m_paned.set_position( newpos ); #ifdef _DEBUG std::cout << "newpos = " << newpos << " pos = " << m_paned.get_position() << std::endl; #endif } } int PaneControl::get_position() { if( ! m_pos ){ if( m_fixmode == PANE_FIXSIZE_PAGE1 ) m_pos = m_paned.get_position(); else if( m_fixmode == PANE_FIXSIZE_PAGE2 ) m_pos = get_size() - m_paned.get_position(); } #ifdef _DEBUG std::cout << "PaneControl::get_position " << m_pos << std::endl; #endif return m_pos; } void PaneControl::set_position( int position ) { if( position == m_pos ) return; #ifdef _DEBUG std::cout << "PaneControl::set_position position = " << position << " size = " << get_size() << std::endl; #endif m_pos = position; update_position(); } // // ページ最大化切り替え // void PaneControl::set_mode( int mode ) { if( mode == m_mode ) return; #ifdef _DEBUG int pos = m_paned.get_position(); int size = get_size(); std::cout << "PaneControl::set_mode = " << mode << " size = " << size << " current_pos = " << pos << " pos = " << get_position() << std::endl; #endif m_mode = mode; update_position(); m_sig_pane_modechanged.emit( m_mode ); } // unpack = true の時取り除く void PaneControl::add_remove1( bool unpack, Gtk::Widget& child ) { if( unpack ) m_paned.remove( child ); // paned.ccg Revision 2 , Tue Jan 21 13:41:59 2003 UTC をハック // pack1 を SHRINK、pack2 を EXPAND にしないとリサイズしたときに // 仕切りがバタつく else m_paned.pack1( child, Gtk::SHRINK ); } // unpack = true の時取り除く void PaneControl::add_remove2( bool unpack, Gtk::Widget& child ) { if( unpack ) m_paned.remove( child ); else m_paned.pack2( child, Gtk::EXPAND ); } void PaneControl::button_press_event( GdkEventButton* event ) { m_clicked = is_separater_clicked( event ); // 仕切りをクリックしたかチェック m_drag = false; #ifdef _DEBUG std::cout << "PaneControl::button_press_event" << " x = " << event->x << " y = " << event->y << " pos = " << m_pos << " current_pos = " << m_paned.get_position() << " click = " << m_clicked << std::endl; #endif } void PaneControl::button_release_event( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "PaneControl::butoon_release_event clicked = " << m_clicked << " drag = " << m_drag << std::endl; #endif // 仕切りをクリックしたら折りたたむ if( m_click_fold != PANE_CLICK_NORMAL && m_clicked && ! m_drag ){ if( m_click_fold == PANE_CLICK_FOLD_PAGE1 ){ if( m_mode == PANE_NORMAL ) set_mode( PANE_MAX_PAGE2 ); else set_mode( PANE_NORMAL ); } else if( m_click_fold == PANE_CLICK_FOLD_PAGE2 ){ if( m_mode == PANE_NORMAL ) set_mode( PANE_MAX_PAGE1 ); else set_mode( PANE_NORMAL ); } } // 仕切りをドラッグした場合 else if( m_clicked && m_drag ){ if( m_mode == PANE_NORMAL ){ if( m_fixmode == PANE_FIXSIZE_PAGE1 ) m_pos = m_paned.get_position(); else if( m_fixmode == PANE_FIXSIZE_PAGE2 ) m_pos = get_size() - m_paned.get_position(); #ifdef _DEBUG std::cout << "new pos = " << m_pos << std::endl; #endif set_mode( PANE_NORMAL ); } else if( m_mode == PANE_MAX_PAGE1 ) m_paned.set_position( get_size() ); else if( m_mode == PANE_MAX_PAGE2 ) m_paned.set_position( 0 ); } m_clicked = false; m_drag = false; } void PaneControl::motion_notify_event( GdkEventMotion* event ) { #ifdef _DEBUG // std::cout << "PaneControl::motion_notify_event\n"; #endif m_drag = true; } void PaneControl::enter_notify_event( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "PaneControl::enter_notify_event\n"; #endif m_on_paned = true; } void PaneControl::leave_notify_event( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "PaneControl::leave_notify_event\n"; #endif m_on_paned = false; } jd-2.8.7-140104/src/skeleton/panecontrol.h0000644000076400010400000000761111571212223014701 0ustar // ライセンス: GPL2 // // Paned widget の制御クラス // #ifndef _PANECONTROL_H #define _PANECONTROL_H #include namespace SKELETON { // コンストラクタで指定する m_fixmode の値 enum { PANE_FIXSIZE_PAGE1, // ウィンドウリサイズ時にPAGE1のサイズを固定する PANE_FIXSIZE_PAGE2 // ウィンドウリサイズ時にPAGE2のサイズを固定する }; // set_mode()で指定する m_mode の値 enum { PANE_NORMAL = 0, // どちらのページも折り畳んでいない通常状態 PANE_MAX_PAGE1, // PAGE1 最大化中 PANE_MAX_PAGE2 // PAGE2 最大化中 }; // set_click_fold()で指定する m_click_fold の値 enum { PANE_CLICK_NORMAL, // セパレータをクリックしても折り畳まない PANE_CLICK_FOLD_PAGE1, // セパレータをクリックするとPAGE1を折り畳む PANE_CLICK_FOLD_PAGE2 // セパレータをクリックするとPAGE2を折り畳む }; // ペーン表示が切り替えられた typedef sigc::signal< void, int > SIG_PANE_MODECHANGED; class PaneControl { SIG_PANE_MODECHANGED m_sig_pane_modechanged; Gtk::Paned& m_paned; int m_click_fold; bool m_clicked; bool m_drag; bool m_on_paned; int m_fixmode; int m_mode; int m_pos; int m_pre_size; public: PaneControl( Gtk::Paned& paned, int fixmode ); virtual ~PaneControl(); SIG_PANE_MODECHANGED& sig_pane_modechanged() { return m_sig_pane_modechanged; } void clock_in(); // セパレータの位置の取得やセット void update_position(); int get_position(); void set_position( int position ); // PANE_MAX_PAGE1 などを指定 void set_mode( int mode ); const int get_mode() const { return m_mode; } // PANE_CLICK_FOLD_PAGE1 などを指定 void set_click_fold( int mode ){ m_click_fold = mode; } const int get_click_fold() const { return m_click_fold; } void add_remove1( bool unpack, Gtk::Widget& child ); void add_remove2( bool unpack, Gtk::Widget& child ); void button_press_event( GdkEventButton* event ); void button_release_event( GdkEventButton* event ); void motion_notify_event( GdkEventMotion* event ); void enter_notify_event( GdkEventCrossing* event ); void leave_notify_event( GdkEventCrossing* event ); protected: const bool is_on_paned() const { return m_on_paned; } Gtk::Paned& get_paned(){ return m_paned; } virtual int get_size() = 0; virtual bool is_separater_clicked( GdkEventButton* event ) = 0; }; ///////////////////////////////////// class HPaneControl : public PaneControl { public: HPaneControl( Gtk::Paned& paned, int fixmode ) : PaneControl( paned, fixmode ) {} ~HPaneControl(){} protected: virtual int get_size(){ return get_paned().get_width(); } virtual bool is_separater_clicked( GdkEventButton* event ){ if( is_on_paned() && event->type == GDK_BUTTON_PRESS && event->button == 1 && event->x >= 0 && event->x <= 8 ) return true; return false; } }; ///////////////////////////////////// class VPaneControl : public PaneControl { public: VPaneControl( Gtk::Paned& paned, int fixmode ) : PaneControl( paned, fixmode ) {} ~VPaneControl(){} protected: virtual int get_size(){ return get_paned().get_height(); } virtual bool is_separater_clicked( GdkEventButton* event ){ if( is_on_paned() && event->type == GDK_BUTTON_PRESS && event->button == 1 && event->y >= 0 && event->y <= 8 ) return true; return false; } }; } #endif jd-2.8.7-140104/src/skeleton/popupwin.cpp0000644000076400010400000000535311501422316014571 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "popupwin.h" using namespace SKELETON; PopupWin::PopupWin( Gtk::Widget* parent, SKELETON::View* view, const int mrg_x, const int mrg_y ) : PopupWinBase( POPUPWIN_NOFRAME ), m_parent( parent ), m_view( view ), m_mrg_x( mrg_x ), m_mrg_y( mrg_y ) { #ifdef _DEBUG std::cout << "PopupWin::PopupWin\n"; #endif m_view->sig_resize_popup().connect( sigc::mem_fun( *this, &PopupWin::slot_resize_popup ) ); add( *m_view ); m_view->sig_hide_popup().connect( sigc::mem_fun( *this, &PopupWin::slot_hide_popup ) ); m_view->show_view(); Gtk::Widget* toplevel = m_parent->get_toplevel(); if( toplevel->is_toplevel() ) set_transient_for( *( ( Gtk::Window* )toplevel ) ); slot_resize_popup(); } PopupWin::~PopupWin() { if( m_view ) delete m_view; } // // ポップアップウィンドウの座標と幅と高さを計算して移動とリサイズ // void PopupWin::slot_resize_popup() { if( ! m_view ) return; // マウス座標 int x_mouse, y_mouse; Gdk::ModifierType mod; Gdk::Display::get_default()->get_pointer( x_mouse, y_mouse, mod ); // クライアントのサイズを取得 const int width_client = m_view->width_client(); const int height_client = m_view->height_client(); const int width_desktop = m_parent->get_screen()->get_width(); const int height_desktop = m_parent->get_screen()->get_height(); // x 座標と幅 const int width_popup = width_client; int x_popup; if( x_mouse + m_mrg_x + width_popup <= width_desktop ) x_popup = x_mouse + m_mrg_x; else x_popup = MAX( 0, width_desktop - width_popup ); // y 座標と高さ int y_popup; int height_popup; if( y_mouse - ( height_client + m_mrg_y ) >= 0 ){ // 上にスペースがある y_popup = y_mouse - height_client - m_mrg_y; height_popup = height_client; } else if( y_mouse + m_mrg_y + height_client <= height_desktop ){ // 下にスペースがある y_popup = y_mouse + m_mrg_y; height_popup = height_client; } else if( m_view->get_popup_upside() || y_mouse > height_desktop/2 ){ // スペースは無いが上に表示 y_popup = MAX( 0, y_mouse - ( height_client + m_mrg_y ) ); height_popup = y_mouse - ( y_popup + m_mrg_y ); } else{ // 下 y_popup = y_mouse + m_mrg_y; height_popup = height_desktop - y_popup; } #ifdef _DEBUG std::cout << "PopupWin::slot_resize_popup : x = " << x_popup << " y = " << y_popup << " w = " << width_popup << " h = " << height_popup << std::endl; #endif move( x_popup, y_popup ); resize( width_popup, height_popup ); show_all(); } jd-2.8.7-140104/src/skeleton/popupwin.h0000644000076400010400000000234311501422316014232 0ustar // ライセンス: GPL2 // // ポップアップウィンドウ // // SKELETON::Viewをポップアップ表示する。 // 表示するSKELETON::Viewはデストラクタでdeleteするので呼出元でdeleteしなくても良い // #ifndef _POPUPWIN_H #define _POPUPWIN_H #include "popupwinbase.h" #include "view.h" namespace SKELETON { class PopupWin : public PopupWinBase { SIG_HIDE_POPUP m_sig_hide_popup; Gtk::Widget* m_parent; SKELETON::View* m_view; int m_mrg_x; // ポップアップとマウスカーソルの間のマージン(水平方向) int m_mrg_y; // ポップアップとマウスカーソルの間のマージン(垂直方向) public: PopupWin( Gtk::Widget* parent, SKELETON::View* view, const int mrg_x, const int mrg_y ); virtual ~PopupWin(); // m_view からの hide シグナルをブリッジする SIG_HIDE_POPUP& sig_hide_popup() { return m_sig_hide_popup; } void slot_hide_popup(){ m_sig_hide_popup.emit(); } SKELETON::View* view(){ return m_view; } // ポップアップウィンドウの座標と幅と高さを計算して移動とリサイズ void slot_resize_popup(); }; } #endif jd-2.8.7-140104/src/skeleton/popupwinbase.h0000644000076400010400000000357510632774613015113 0ustar // ライセンス: GPL2 // // ポップアップウィンドウの基底クラス // #ifndef _POPUPWINBASE_H #define _POPUPWINBASE_H #include namespace SKELETON { enum { POPUPWIN_DRAWFRAME = true, POPUPWIN_NOFRAME = false }; // // Gtk::Windows は signal_configure_event()を発行しないようなので // 自前でconfigureイベントをフックしてシグナルを発行する // typedef sigc::signal< void, int, int > SIG_CONFIGURED_POPUP; class PopupWinBase : public Gtk::Window { SIG_CONFIGURED_POPUP m_sig_configured; Glib::RefPtr< Gdk::GC > m_gc; bool m_draw_frame; public: // draw_frame == true なら枠を描画する PopupWinBase( bool draw_frame ) : Gtk::Window( Gtk::WINDOW_POPUP ), m_draw_frame( draw_frame ){ if( m_draw_frame ) set_border_width( 1 ); } virtual ~PopupWinBase(){} SIG_CONFIGURED_POPUP sig_configured(){ return m_sig_configured; } protected: virtual void on_realize() { Gtk::Window::on_realize(); Glib::RefPtr< Gdk::Window > window = get_window(); m_gc = Gdk::GC::create( window ); } virtual bool on_expose_event( GdkEventExpose* event ) { bool ret = Gtk::Window::on_expose_event( event ); // 枠の描画 if( m_draw_frame ){ m_gc->set_foreground( Gdk::Color( "black" ) ); get_window()->draw_rectangle( m_gc, false, 0, 0, get_width()-1, get_height()-1 ); } return ret; } virtual bool on_configure_event( GdkEventConfigure* event ) { bool ret = Gtk::Window::on_configure_event( event ); m_sig_configured.emit( get_width(), get_height() ); return ret; } }; } #endif jd-2.8.7-140104/src/skeleton/prefdiag.cpp0000644000076400010400000000535411357364652014513 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "prefdiag.h" #include "label_entry.h" #include "command.h" #include "session.h" #include "dispatchmanager.h" #include "global.h" using namespace SKELETON; PrefDiag::PrefDiag( Gtk::Window* parent, const std::string& url, const bool add_cancel, const bool add_apply, const bool add_open ) : Gtk::Dialog(), m_url( url ), m_bt_ok( NULL ), m_bt_apply( Gtk::Stock::APPLY ) { if( add_apply ){ m_bt_apply.signal_clicked().connect( sigc::mem_fun(*this, &PrefDiag::slot_apply_clicked ) ); get_action_area()->pack_start( m_bt_apply ); } if( add_cancel ){ add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL ) ->signal_clicked().connect( sigc::mem_fun(*this, &PrefDiag::slot_cancel_clicked ) ); } if( add_open ) m_bt_ok = add_button( Gtk::Stock::OPEN, Gtk::RESPONSE_OK ); else m_bt_ok = add_button( Gtk::Stock::OK, Gtk::RESPONSE_OK ); m_bt_ok->signal_clicked().connect( sigc::mem_fun(*this, &PrefDiag::slot_ok_clicked ) ); if( parent ) set_transient_for( *parent ); else set_transient_for( *CORE::get_mainwindow() ); } PrefDiag::~PrefDiag() { if( m_conn_timer != NULL ) { delete m_conn_timer; } } // // okボタンをフォーカス // void PrefDiag::grab_ok() { if( ! m_bt_ok ) return; m_bt_ok->set_flags( Gtk::CAN_DEFAULT ); m_bt_ok->grab_default(); m_bt_ok->grab_focus(); } // // Entry、LabelEntryがactiveになったときにOKでダイアログを終了させる // void PrefDiag::set_activate_entry( Gtk::Entry& entry ) { entry.signal_activate().connect( sigc::mem_fun( *this, &PrefDiag::slot_activate_entry ) ); } void PrefDiag::set_activate_entry( LabelEntry& entry ) { entry.signal_activate().connect( sigc::mem_fun( *this, &PrefDiag::slot_activate_entry ) ); } void PrefDiag::slot_activate_entry() { #ifdef _DEBUG std::cout << "PrefDiag::slot_activate_entry\n"; #endif slot_ok_clicked(); response( Gtk::RESPONSE_OK ); } int PrefDiag::run(){ SESSION::set_dialog_shown( true ); CORE::core_set_command( "dialog_shown" ); // タイマーセット sigc::slot< bool > slot_timeout = sigc::bind( sigc::mem_fun(*this, &PrefDiag::slot_timeout), 0 ); m_conn_timer = JDLIB::Timeout::connect( slot_timeout, TIMER_TIMEOUT ); int ret = Gtk::Dialog::run(); SESSION::set_dialog_shown( false ); CORE::core_set_command( "dialog_hidden" ); return ret; } // タイマーのslot関数 bool PrefDiag::slot_timeout( int timer_number ) { // メインループが停止していて dispatcher が働かないため // タイマーから強制的に実行させる CORE::get_dispmanager()->slot_dispatch(); timeout(); return true; } jd-2.8.7-140104/src/skeleton/prefdiag.h0000644000076400010400000000267511357364652014163 0ustar // ライセンス: GPL2 // 設定ダイアログの基底クラス #ifndef _PREFDIAG_H #define _PREFDIAG_H #include #include "jdlib/timeout.h" namespace SKELETON { class LabelEntry; class PrefDiag : public Gtk::Dialog { std::string m_url; Gtk::Button* m_bt_ok; Gtk::Button m_bt_apply; JDLIB::Timeout* m_conn_timer; public: // parent == NULL のときはメインウィンドウをparentにする PrefDiag( Gtk::Window* parent, const std::string& url, const bool add_cancel = true, const bool add_apply = false, const bool add_open = false ); virtual ~PrefDiag(); const std::string& get_url() const { return m_url; } // okボタンをフォーカス void grab_ok(); // Entry、LabelEntryがactiveになったときにOKでダイアログを終了させる void set_activate_entry( Gtk::Entry& entry ); void set_activate_entry( LabelEntry& entry ); virtual int run(); protected: virtual void slot_ok_clicked(){} virtual void slot_cancel_clicked(){} virtual void slot_apply_clicked(){} private: // タイマーのslot関数 bool slot_timeout( int timer_number ); // 各設定ダイアログ別のタイムアウト処理 ( slot_timeout()から呼び出される ) virtual void timeout(){} void slot_activate_entry(); }; } #endif jd-2.8.7-140104/src/skeleton/selectitempref.cpp0000644000076400010400000004367611335616663015754 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "selectitempref.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" #include "global.h" #include "session.h" using namespace SKELETON; #define ROW_COLOR "WhiteSmoke" SelectItemPref::SelectItemPref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url, true, true ), m_button_top( Gtk::Stock::GOTO_TOP ), m_button_up( Gtk::Stock::GO_UP ), m_button_down( Gtk::Stock::GO_DOWN ), m_button_bottom( Gtk::Stock::GOTO_BOTTOM ), m_button_delete( Gtk::Stock::GO_FORWARD, std::string(), Gtk::ICON_SIZE_BUTTON ), m_button_add( Gtk::Stock::GO_BACK, std::string(), Gtk::ICON_SIZE_BUTTON ), m_button_default( Gtk::Stock::REVERT_TO_SAVED ) { m_list_default_data.clear(); pack_widgets(); } // // widgetのパック // void SelectItemPref::pack_widgets() { // 同一カラムにアイコンと項目名の両方を表示するので、手動で列を作成する // 表示項目リスト m_tree_shown.set_rules_hint( CONFIG::get_use_tree_gtkrc() ); m_tree_shown.get_selection()->set_mode( Gtk::SELECTION_MULTIPLE ); m_tree_shown.signal_focus_in_event().connect( sigc::mem_fun( *this, &SelectItemPref::slot_focus_in_shown ) ); m_store_shown = Gtk::ListStore::create( m_columns_shown ); m_tree_shown.set_model( m_store_shown ); // "表示"の列を作成 Gtk::TreeViewColumn* view_column_shown = Gtk::manage( new Gtk::TreeViewColumn( "表示" ) ); m_tree_shown.append_column( *view_column_shown ); // アイコン Gtk::CellRendererPixbuf* render_pixbuf_shown = Gtk::manage( new Gtk::CellRendererPixbuf() ); view_column_shown->pack_start( *render_pixbuf_shown, false ); view_column_shown->add_attribute( *render_pixbuf_shown, "pixbuf", 0 ); // 項目名 Gtk::CellRendererText* render_text_shown = Gtk::manage( new Gtk::CellRendererText() ); view_column_shown->pack_start( *render_text_shown, true ); view_column_shown->add_attribute( *render_text_shown, "text", 1 ); // ボタン(縦移動) m_vbuttonbox_v.pack_start( m_button_top, Gtk::PACK_SHRINK ); m_vbuttonbox_v.pack_start( m_button_up, Gtk::PACK_SHRINK ); m_vbuttonbox_v.pack_start( m_button_down, Gtk::PACK_SHRINK ); m_vbuttonbox_v.pack_start( m_button_bottom, Gtk::PACK_SHRINK ); // ボタン(横移動) m_vbuttonbox_h.pack_start( m_button_delete, Gtk::PACK_SHRINK ); m_vbuttonbox_h.pack_start( m_button_add, Gtk::PACK_SHRINK ); // ボタン(アクション) m_vbuttonbox_action.pack_start( m_button_default, Gtk::PACK_SHRINK ); // ボタン(スロット関数) m_button_top.signal_clicked().connect( sigc::mem_fun( *this, &SelectItemPref::slot_top ) ); m_button_up.signal_clicked().connect( sigc::mem_fun( *this, &SelectItemPref::slot_up ) ); m_button_down.signal_clicked().connect( sigc::mem_fun( *this, &SelectItemPref::slot_down ) ); m_button_bottom.signal_clicked().connect( sigc::mem_fun( *this, &SelectItemPref::slot_bottom ) ); m_button_delete.signal_clicked().connect( sigc::mem_fun( *this, &SelectItemPref::slot_delete ) ); m_button_add.signal_clicked().connect( sigc::mem_fun( *this, &SelectItemPref::slot_add ) ); m_button_default.signal_clicked().connect( sigc::mem_fun( *this, &SelectItemPref::slot_default ) ); // 非表示項目リスト m_tree_hidden.set_rules_hint( CONFIG::get_use_tree_gtkrc() ); m_tree_hidden.get_selection()->set_mode( Gtk::SELECTION_MULTIPLE ); m_tree_hidden.signal_focus_in_event().connect( sigc::mem_fun( *this, &SelectItemPref::slot_focus_in_hidden ) ); m_store_hidden = Gtk::ListStore::create( m_columns_hidden ); m_tree_hidden.set_model( m_store_hidden ); // "非表示"の列を作成 Gtk::TreeViewColumn* view_column_hidden = Gtk::manage( new Gtk::TreeViewColumn( "非表示" ) ); m_tree_hidden.append_column( *view_column_hidden ); // アイコン Gtk::CellRendererPixbuf* render_pixbuf_hidden = Gtk::manage( new Gtk::CellRendererPixbuf() ); view_column_hidden->pack_start( *render_pixbuf_hidden, false ); view_column_hidden->add_attribute( *render_pixbuf_hidden, "pixbuf", 0 ); // 項目名 Gtk::CellRendererText* render_text_hidden = Gtk::manage( new Gtk::CellRendererText() ); view_column_hidden->pack_start( *render_text_hidden, true ); view_column_hidden->add_attribute( *render_text_hidden, "text", 1 ); // 全体のパッキング m_scroll_shown.add( m_tree_shown ); m_scroll_shown.set_size_request( 250, 300 ); m_scroll_shown.set_policy( Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS ); m_hbox.pack_start( m_scroll_shown, Gtk::PACK_EXPAND_WIDGET ); m_vbuttonbox_v.set_layout( Gtk::BUTTONBOX_START ); m_vbuttonbox_v.set_spacing( 4 ); m_vbox.pack_start( m_vbuttonbox_v, Gtk::PACK_EXPAND_WIDGET ); m_vbuttonbox_h.set_layout( Gtk::BUTTONBOX_DEFAULT_STYLE ); m_vbuttonbox_h.set_spacing( 4 ); m_vbox.pack_start( m_vbuttonbox_h, Gtk::PACK_SHRINK ); m_vbuttonbox_action.set_layout( Gtk::BUTTONBOX_END ); m_vbuttonbox_action.set_spacing( 4 ); m_vbox.pack_start( m_vbuttonbox_action, Gtk::PACK_EXPAND_WIDGET ); m_hbox.pack_start( m_vbox, Gtk::PACK_SHRINK, 4 ); m_scroll_hidden.add( m_tree_hidden ); m_scroll_hidden.set_size_request( 250, 300 ); m_scroll_hidden.set_policy( Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS ); m_hbox.pack_start( m_scroll_hidden, Gtk::PACK_EXPAND_WIDGET ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_hbox ); show_all_children(); } // // フォーカスが外れたTreeViewから項目の選択をなくす // bool SelectItemPref::slot_focus_in_shown( GdkEventFocus* event ) { m_tree_hidden.get_selection()->unselect_all(); return true; } bool SelectItemPref::slot_focus_in_hidden( GdkEventFocus* event ) { m_tree_shown.get_selection()->unselect_all(); return true; } // // 項目名でデフォルトデータからアイコンを取得 // Glib::RefPtr< Gdk::Pixbuf > SelectItemPref::get_icon( const Glib::ustring& name ) { Glib::RefPtr< Gdk::Pixbuf > icon; std::list< DEFAULT_DATA >::iterator it = m_list_default_data.begin(); while( it != m_list_default_data.end() ) { if( (*it).name == name ) { icon = (*it).icon; break; } ++it; } return icon; } // // 表示項目のクリア // void SelectItemPref::clear() { m_store_shown->clear(); m_store_hidden->clear(); } // // デフォルトデータを追加( 項目名、アイコンID ) // void SelectItemPref::append_default_pair( const Glib::ustring& name, const Glib::RefPtr< Gdk::Pixbuf > icon ) { if( name.empty() ) return; DEFAULT_DATA default_data; default_data.name = name; default_data.icon = icon; m_list_default_data.push_back( default_data ); } // // 文字列を元に行を作成 // void SelectItemPref::append_rows( const std::string& str ) { clear(); bool found_separator = false; // "非表示"にデフォルトデータを全て追加 std::list< DEFAULT_DATA >::iterator def_it = m_list_default_data.begin(); while( def_it != m_list_default_data.end() ) { // 2つ以上セパレータを追加しない if( (*def_it).name == ITEM_NAME_SEPARATOR ) { if( ! found_separator ) append_hidden( (*def_it).name, false ); found_separator = true; } else append_hidden( (*def_it).name, false ); ++def_it; } if( str.empty() ) return; // "表示"に追加と不要な"非表示"を削除 std::list< std::string > items = MISC::split_line( str ); std::list< std::string >::iterator it = items.begin(); while( it != items.end() ) { if( append_shown( *it, false ) ) erase_hidden( *it ); ++it; } } // // 全ての有効な項目を文字列で取得 // std::string SelectItemPref::get_items() { std::string items; const Gtk::TreeModel::Children children = m_store_shown->children(); Gtk::TreeModel::iterator it = children.begin(); while( it != children.end() ) { Gtk::TreeModel::Row row = *it; items.append( row[ m_columns_shown.m_column_text ] + " " ); ++it; } return items; } // // 表示項目に指定した項目を追加 // Gtk::TreeRow SelectItemPref::append_shown( const std::string& name, const bool set_cursor ) { Gtk::TreeModel::Row row; if( SESSION::parse_item( name ) == ITEM_END ) return row; row = *( m_store_shown->append() ); Glib::RefPtr< Gdk::Pixbuf > icon = get_icon( name ); if( icon ) row[ m_columns_shown.m_column_icon ] = icon; row[ m_columns_shown.m_column_text ] = name; if( set_cursor ){ m_tree_shown.get_selection()->select( row ); m_tree_shown.set_cursor( m_store_shown->get_path( row ) ); } return row; } // // 非表示項目に指定した項目を追加 // Gtk::TreeRow SelectItemPref::append_hidden( const std::string& name, const bool set_cursor ) { Gtk::TreeModel::Row row = *( m_store_hidden->append() ); Glib::RefPtr< Gdk::Pixbuf > icon = get_icon( name ); if( icon ) row[ m_columns_hidden.m_column_icon ] = icon; row[ m_columns_hidden.m_column_text ] = name; if( set_cursor ){ m_tree_hidden.get_selection()->select( row ); m_tree_hidden.set_cursor( m_store_hidden->get_path( row ) ); } return row; } // // 非表示項目から指定した項目を削除 // void SelectItemPref::erase_hidden( const std::string& name ) { if( name == ITEM_NAME_SEPARATOR ) return; const Gtk::TreeModel::Children children = m_store_hidden->children(); Gtk::TreeModel::iterator it = children.begin(); while( it != children.end() ) { Gtk::TreeModel::Row row = *it; if( row[ m_columns_hidden.m_column_text ] == name ) { m_store_hidden->erase( *it ); break; } ++it; } } // // KeyPressのフック // bool SelectItemPref::on_key_press_event( GdkEventKey* event ) { bool hook = false; // "Gtk::Dialog"は"Esc"を押すと閉じられてしまうので // "GDK_Escape"をキャンセルする switch( event->keyval ) { case GDK_Escape : hook = true; break; } m_sig_key_press.emit( event ); if( hook ) return true; return Gtk::Dialog::on_key_press_event( event ); } // // KeyReleaseのフック // bool SelectItemPref::on_key_release_event( GdkEventKey* event ) { bool hook = false; switch( event->keyval ) { case GDK_Escape : hook = true; m_tree_shown.get_selection()->unselect_all(); m_tree_hidden.get_selection()->unselect_all(); break; case GDK_Right : slot_delete(); break; case GDK_Left : slot_add(); break; } m_sig_key_release.emit( event ); if( hook ) return true; return Gtk::Dialog::on_key_release_event( event ); } // // 上端へ移動 // void SelectItemPref::slot_top() { Gtk::TreeModel::Children children = m_store_shown->children(); if( children.empty() ) return; // 移動先のイテレータ Gtk::TreeIter upper_it = children.begin(); std::list< Gtk::TreePath > selection_path = m_tree_shown.get_selection()->get_selected_rows(); std::list< Gtk::TreePath >::iterator it = selection_path.begin(); while( it != selection_path.end() ) { Gtk::TreeIter src_it = m_store_shown->get_iter( *it ); Gtk::TreeIter dst_it = upper_it; // 元と先が同じでない if( src_it != dst_it ) { // 参照渡しなので書き換えられてしまう m_store_shown->move( src_it, dst_it ); upper_it = src_it; } // 移動先の位置を下げる if( upper_it != children.end() ) ++upper_it; ++it; } // フォーカスを移す set_focus( m_tree_shown ); } // // 上へ移動 // void SelectItemPref::slot_up() { Gtk::TreeModel::Children children = m_store_shown->children(); if( children.empty() ) return; // 上限のイテレータ Gtk::TreeIter upper_it = children.begin(); std::list< Gtk::TreePath > selection_path = m_tree_shown.get_selection()->get_selected_rows(); std::list< Gtk::TreePath >::iterator it = selection_path.begin(); while( it != selection_path.end() ) { Gtk::TreePath src = *it; Gtk::TreeIter src_it = m_store_shown->get_iter( src ); // 限度位置に達していなければ入れ替え if( src_it != upper_it ) { Gtk::TreePath dst( src ); if( dst.prev() ) { Gtk::TreeIter dst_it = m_store_shown->get_iter( dst ); m_store_shown->iter_swap( src_it, dst_it ); } } // 上限に達していたら次の限度位置を下げる else if( upper_it != children.end() ) ++upper_it; ++it; } // フォーカスを移す set_focus( m_tree_shown ); } // // 下へ移動 // void SelectItemPref::slot_down() { Gtk::TreeModel::Children children = m_store_shown->children(); if( children.empty() ) return; // 下限のイテレータ Gtk::TreeIter bottom_it = --children.end(); std::list< Gtk::TreePath > selection_path = m_tree_shown.get_selection()->get_selected_rows(); std::list< Gtk::TreePath >::reverse_iterator it = selection_path.rbegin(); while( it != selection_path.rend() ) { Gtk::TreePath src = *it; Gtk::TreeIter src_it = m_store_shown->get_iter( src ); // 限度位置に達していなければ入れ替え if( src_it != bottom_it ) { Gtk::TreePath dst( src ); dst.next(); Gtk::TreeIter dst_it = m_store_shown->get_iter( dst ); if( dst_it ) { m_store_shown->iter_swap( src_it, dst_it ); } } // 下限に達していたら次の限度位置を上げる else if( bottom_it != children.begin() ) --bottom_it; ++it; } // フォーカスを移す set_focus( m_tree_shown ); } // // 下端へ移動 // void SelectItemPref::slot_bottom() { Gtk::TreeModel::Children children = m_store_shown->children(); if( children.empty() ) return; // 移動先のイテレータ Gtk::TreeIter bottom_it = children.end(); std::list< Gtk::TreePath > selection_path = m_tree_shown.get_selection()->get_selected_rows(); std::list< Gtk::TreePath >::reverse_iterator it = selection_path.rbegin(); while( it != selection_path.rend() ) { Gtk::TreeIter src_it = m_store_shown->get_iter( *it ); Gtk::TreeIter dst_it = bottom_it; // 元と先が同じでない if( src_it != dst_it ) { // 参照渡しなので書き換えられてしまう m_store_shown->move( src_it, dst_it ); bottom_it = dst_it; } // 移動先の位置を上げる if( bottom_it != children.begin() ) --bottom_it; ++it; } // フォーカスを移す set_focus( m_tree_shown ); } // // 削除ボタン // void SelectItemPref::slot_delete() { std::list< Gtk::TreePath > selection_path = m_tree_shown.get_selection()->get_selected_rows(); // 選択したアイテムが無い場合はフォーカスだけ移して出る if( selection_path.empty() ) { set_focus( m_tree_hidden ); return; } std::list< Gtk::TreeRow > erase_rows; bool set_cursor = true; // 一番上の選択項目にカーソルをセット std::list< Gtk::TreePath >::iterator it = selection_path.begin(); while( it != selection_path.end() ) { Gtk::TreePath path = *it; Gtk::TreeRow row = *m_store_shown->get_iter( path ); if( row ) { Glib::ustring name = row[ m_columns_shown.m_column_text ]; // 非表示項目に追加 if( name != ITEM_NAME_SEPARATOR ) { append_hidden( name, set_cursor ); set_cursor = false; } // 表示項目から削除するリストに追加 erase_rows.push_back( row ); } ++it; } // 追加と削除を同時にすると滅茶苦茶になるので、分けて削除する std::list< Gtk::TreeRow >::iterator erase_it = erase_rows.begin(); while( erase_it != erase_rows.end() ) { m_store_shown->erase( *erase_it ); ++erase_it; } // フォーカスを移す set_focus( m_tree_hidden ); } // // 追加ボタン // void SelectItemPref::slot_add() { std::list< Gtk::TreePath > selection_path = m_tree_hidden.get_selection()->get_selected_rows(); // 選択したアイテムが無い場合はフォーカスだけ移して出る if( selection_path.empty() ) { set_focus( m_tree_shown ); return; } std::list< Gtk::TreeRow > erase_rows; bool set_cursor = true; // 一番上の選択項目にカーソルをセット // 選択したアイテムを追加 std::list< Gtk::TreePath >::iterator it = selection_path.begin(); while( it != selection_path.end() ) { Gtk::TreeRow row = *m_store_hidden->get_iter( *it ); if( row ) { Glib::ustring name = row[ m_columns_hidden.m_column_text ]; // 表示項目に追加 append_shown( name, set_cursor ); set_cursor = false; // 非表示項目から削除するリストに追加 if( name != ITEM_NAME_SEPARATOR ) erase_rows.push_back( row ); } ++it; } // 追加と削除を同時にすると滅茶苦茶になるので、分けて削除する std::list< Gtk::TreeRow >::iterator erase_it = erase_rows.begin(); while( erase_it != erase_rows.end() ) { m_store_hidden->erase( *erase_it ); ++erase_it; } // フォーカスを移す set_focus( m_tree_shown ); } jd-2.8.7-140104/src/skeleton/selectitempref.h0000644000076400010400000001040611335616663015402 0ustar // ライセンス: GPL2 // 表示項目設定 #ifndef _SELECTITEMPREF_H #define _SELECTITEMPREF_H #include "prefdiag.h" #include "imgbutton.h" #include #include namespace SKELETON { typedef struct { std::string name; Glib::RefPtr< Gdk::Pixbuf > icon; } DEFAULT_DATA; class SelectItemPref : public SKELETON::PrefDiag { // デフォルトの値を格納( 項目名, アイコンID, 有効/無効 ) std::list< DEFAULT_DATA > m_list_default_data; // ColumnRecord class TreeModelColumns : public Gtk::TreeModel::ColumnRecord { public: TreeModelColumns() { add( m_column_icon ); add( m_column_text ); } Gtk::TreeModelColumn< Glib::RefPtr< Gdk::Pixbuf > > m_column_icon; Gtk::TreeModelColumn< Glib::ustring > m_column_text; }; // 表示項目 Gtk::TreeView m_tree_shown; Glib::RefPtr< Gtk::ListStore > m_store_shown; TreeModelColumns m_columns_shown; Gtk::ScrolledWindow m_scroll_shown; // ボタン(縦移動) Gtk::Button m_button_top; Gtk::Button m_button_up; Gtk::Button m_button_down; Gtk::Button m_button_bottom; Gtk::VButtonBox m_vbuttonbox_v; // ボタン(横移動) SKELETON::ImgButton m_button_delete; SKELETON::ImgButton m_button_add; Gtk::VButtonBox m_vbuttonbox_h; // ボタン(アクション) Gtk::Button m_button_default; Gtk::VButtonBox m_vbuttonbox_action; // まとめ( m_vbuttonbox_* ) Gtk::VBox m_vbox; // 非表示項目 Gtk::TreeView m_tree_hidden; Glib::RefPtr< Gtk::ListStore > m_store_hidden; TreeModelColumns m_columns_hidden; Gtk::ScrolledWindow m_scroll_hidden; // まとめ( m_tree.shown, m_vbox, m_tree_hidden ) Gtk::HBox m_hbox; // キーフック用 typedef sigc::signal< bool, GdkEventKey* > SIG_KEY_PRESS; typedef sigc::signal< bool, GdkEventKey* > SIG_KEY_RELEASE; SIG_KEY_PRESS m_sig_key_press; SIG_KEY_RELEASE m_sig_key_release; public: SelectItemPref( Gtk::Window* parent, const std::string& url ); virtual ~SelectItemPref(){} private: // widgetのパック void pack_widgets(); // フォーカスが外れたTreeViewから項目の選択をなくす bool slot_focus_in_shown( GdkEventFocus* event ); bool slot_focus_in_hidden( GdkEventFocus* event ); // 項目名でデフォルトデータからアイコンを取得 Glib::RefPtr< Gdk::Pixbuf > get_icon( const Glib::ustring& name ); protected: // 表示項目のクリア void clear(); // デフォルトデータを追加 void append_default_pair( const Glib::ustring& name, const Glib::RefPtr< Gdk::Pixbuf > icon = Glib::RefPtr< Gdk::Pixbuf >() ); // 文字列を元に行を作成 void append_rows( const std::string& str ); // 全ての有効な項目を文字列で取得 std::string get_items(); // 表示項目に指定した項目を追加 Gtk::TreeRow append_shown( const std::string& name, const bool set_cursor ); // 非表示項目に指定した項目を追加 Gtk::TreeRow append_hidden( const std::string& name, const bool set_cursor ); // 非表示項目から指定した項目を削除 void erase_hidden( const std::string& name ); // KeyPressのフック virtual bool on_key_press_event( GdkEventKey* event ); // KeyReleaseのフック virtual bool on_key_release_event( GdkEventKey* event ); // 最上位へ移動 void slot_top(); // 上へ移動 void slot_up(); // 下へ移動 void slot_down(); // 最下位へ移動 void slot_bottom(); // 削除ボタン void slot_delete(); // 追加ボタン void slot_add(); // デフォルトボタン virtual void slot_default() = 0; // 適用ボタン void slot_apply_clicked(){ slot_ok_clicked(); } }; } #endif jd-2.8.7-140104/src/skeleton/spinbutton.h0000644000076400010400000000215612006761301014561 0ustar // ライセンス: GPL2 // スピンボタンのの基底クラス // // gtkのバージョンが2.4以下の時はスピンが回ったときに // 明示的に値をセットする必要があるらしい #ifndef _SPINBUTTON_H #define _SPINBUTTON_H #include #include "gtkmmversion.h" namespace SKELETON { class SpinButton : public Gtk::SpinButton { public: SpinButton() : Gtk::SpinButton(){} protected: #if !GTKMM_CHECK_VERSION(2,5,0) virtual void on_spinbutton_digits_changed(){ const size_t size = 256; char str[ size ]; snprintf( str, size, "%d", (int)get_value() ); set_text( str ); } #endif }; class SpinButtonDouble : public Gtk::SpinButton { public: SpinButtonDouble() : Gtk::SpinButton(){} protected: #if !GTKMM_CHECK_VERSION(2,5,0) virtual void on_spinbutton_digits_changed(){ const size_t size = 256; char str[ size ]; snprintf( str, size, "%4.3lf", get_value() ); set_text( str ); } #endif }; } #endif jd-2.8.7-140104/src/skeleton/tablabel.cpp0000644000076400010400000001152011517313451014455 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "tablabel.h" #include "icons/iconmanager.h" #include "config/globalconf.h" #include "dndmanager.h" using namespace SKELETON; enum { SPACING_LABEL = 3 // アイコンとラベルの間のスペース }; TabLabel::TabLabel( const std::string& url ) : m_url( url ), m_id_icon( ICON::NUM_ICONS ), m_image( NULL ) { #ifdef _DEBUG std::cout << "TabLabel::TabLabel " << m_url << std::endl; #endif // 背景透過 set_visible_window( false ); add_events( Gdk::POINTER_MOTION_MASK ); add_events( Gdk::LEAVE_NOTIFY_MASK ); add( m_hbox ); m_hbox.pack_start( m_label, Gtk::PACK_SHRINK ); show_all_children(); } TabLabel::~TabLabel() { #ifdef _DEBUG std::cout << "TabLabel::~TabLabel " << m_fulltext << std::endl; #endif if( m_image ) delete m_image; } // アイコンセット void TabLabel::set_id_icon( const int id ) { if( ! CONFIG::get_show_tab_icon() ) return; if( m_id_icon == id ) return; if( id == ICON::NONE ) return; if( !m_image ){ m_image = new Gtk::Image(); m_hbox.remove( m_label ); m_hbox.set_spacing( SPACING_LABEL ); m_hbox.pack_start( *m_image, Gtk::PACK_SHRINK ); m_hbox.pack_start( m_label, Gtk::PACK_SHRINK ); show_all_children(); } #ifdef _DEBUG std::cout << "TabLabel::set_icon " << m_fulltext << " id = " << id << std::endl; #endif m_id_icon = id; m_image->set( ICON::get_icon( id ) ); } // タブの文字列の文字数がlngになるようにリサイズする void TabLabel::resize_tab( const unsigned int lng ) { Glib::ustring ulabel( m_fulltext ); const unsigned int lng_org = ulabel.length(); ulabel.resize( lng ); if( lng < lng_org ) ulabel += "..."; m_label.set_text( ulabel ); } // // D&D設定 // void TabLabel::set_dragable( bool dragable, int button ) { if( dragable ){ std::list< Gtk::TargetEntry > targets; targets.push_back( Gtk::TargetEntry( DNDTARGET_FAVORITE, Gtk::TARGET_SAME_APP, 0 ) ); targets.push_back( Gtk::TargetEntry( DNDTARGET_TAB, Gtk::TARGET_SAME_APP, 0 ) ); // ドラッグ開始側にする switch( button ){ case 1: drag_source_set( targets, Gdk::BUTTON1_MASK ); break; case 2: drag_source_set( targets, Gdk::BUTTON2_MASK ); break; case 3: drag_source_set( targets, Gdk::BUTTON3_MASK ); break; default: return; } } else{ drag_source_unset(); drag_dest_unset(); } } // // 本体の横幅 - ラベルの横幅 // const int TabLabel::get_label_margin() { int label_margin; int x_pad, y_pad; m_label.get_padding( x_pad, y_pad ); label_margin = x_pad*2 + m_hbox.get_spacing() + m_hbox.get_border_width()*2 + get_border_width()*2; if( CONFIG::get_show_tab_icon() && m_id_icon < ICON::NUM_ICONS ) label_margin += ICON::get_icon( m_id_icon )->get_width(); #ifdef _DEBUG std::cout << "image_w = " << m_image->get_allocation().get_width() << " label_w = " << m_label.get_allocation().get_width() << " alloc_w = " << get_allocation().get_width() << " label_margine = " << label_margin << std::endl; #endif return label_margin; } // // マウスが動いた // bool TabLabel::on_motion_notify_event( GdkEventMotion* event ) { const bool ret = Gtk::EventBox::on_motion_notify_event( event ); m_sig_tab_motion_event.emit(); return ret; } // // マウスが出た // bool TabLabel::on_leave_notify_event( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "TabLabel::leave\n"; #endif const bool ret = Gtk::EventBox::on_leave_notify_event( event ); m_sig_tab_leave_event.emit(); return ret; } // // ドラッグ開始 // void TabLabel::on_drag_begin( const Glib::RefPtr< Gdk::DragContext >& context ) { #ifdef _DEBUG std::cout << "TabLabel::on_drag_begin " << m_fulltext << std::endl; #endif m_sig_tab_drag_begin.emit(); Gtk::EventBox::on_drag_begin( context ); } // // D&Dで受信側がデータ送信を要求してきた // void TabLabel::on_drag_data_get( const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time ) { #ifdef _DEBUG std::cout << "TabLabel::on_drag_data_get target = " << selection_data.get_target() << " " << m_fulltext << std::endl;; #endif Gtk::EventBox::on_drag_data_get( context, selection_data, info, time ); m_sig_tab_drag_data_get( selection_data ); } // // ドラッグ終了 // void TabLabel::on_drag_end( const Glib::RefPtr< Gdk::DragContext >& context ) { #ifdef _DEBUG std::cout << "TabLabel::on_drag_end " << m_fulltext << std::endl;; #endif Gtk::EventBox::on_drag_end( context ); m_sig_tab_drag_end.emit(); } jd-2.8.7-140104/src/skeleton/tablabel.h0000644000076400010400000000645212074575077014147 0ustar // ライセンス: GPL2 #ifndef _TABLABEL_H #define _TABLABEL_H #include #include namespace SKELETON { // マウス typedef sigc::signal< void > SIG_TAB_MOTION_EVENT; typedef sigc::signal< void > SIG_TAB_LEAVE_EVENT; // D&D typedef sigc::signal< void > SIG_TAB_DRAG_BEGIN; typedef sigc::signal< void, Gtk::SelectionData& > SIG_TAB_DRAG_DATA_GET; typedef sigc::signal< void > SIG_TAB_DRAG_END; class TabLabel : public Gtk::EventBox { SIG_TAB_MOTION_EVENT m_sig_tab_motion_event; SIG_TAB_LEAVE_EVENT m_sig_tab_leave_event; SIG_TAB_DRAG_BEGIN m_sig_tab_drag_begin; SIG_TAB_DRAG_DATA_GET m_sig_tab_drag_data_get; SIG_TAB_DRAG_END m_sig_tab_drag_end; int m_x; int m_y; int m_width; int m_height; std::string m_url; Gtk::HBox m_hbox; int m_id_icon; Gtk::Label m_label; // アイコン画像 Gtk::Image* m_image; // ラベルに表示する文字列の全体 std::string m_fulltext; public: TabLabel( const std::string& url ); virtual ~TabLabel(); SIG_TAB_MOTION_EVENT sig_tab_motion_event(){ return m_sig_tab_motion_event; } SIG_TAB_LEAVE_EVENT sig_tab_leave_event(){ return m_sig_tab_leave_event; } SIG_TAB_DRAG_BEGIN sig_tab_drag_begin() { return m_sig_tab_drag_begin; } SIG_TAB_DRAG_DATA_GET sig_tab_drag_data_get() { return m_sig_tab_drag_data_get; } SIG_TAB_DRAG_END sig_tab_drag_end() { return m_sig_tab_drag_end; } const int get_tab_x() const { return m_x; } const int get_tab_y() const { return m_y; } const int get_tab_width() const { return m_width; } const int get_tab_height() const { return m_height; } void set_tab_x( const int x ){ m_x = x; } void set_tab_y( const int y ){ m_y = y; } void set_tab_width( const int width ){ m_width = width; } void set_tab_height( const int height ){ m_height = height; } Pango::FontDescription get_label_font_description(){ return m_label.get_pango_context()->get_font_description(); } const std::string& get_url(){ return m_url; } void set_dragable( bool dragable, int button ); // 本体の横幅 - ラベルの横幅 const int get_label_margin(); // カットしていない全体の文字列 const std::string& get_fulltext() const { return m_fulltext; } void set_fulltext( const std::string& label ){ m_fulltext = label; } // アイコンセット void set_id_icon( const int id ); const int get_id_icon() const { return m_id_icon; } // タブの文字列の文字数をlngにセット void resize_tab( const unsigned int lng ); private: virtual bool on_motion_notify_event( GdkEventMotion* event ); virtual bool on_leave_notify_event( GdkEventCrossing* event ); virtual void on_drag_begin( const Glib::RefPtr< Gdk::DragContext>& context ); virtual void on_drag_data_get( const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time ); virtual void on_drag_end( const Glib::RefPtr< Gdk::DragContext>& context ); }; } #endif jd-2.8.7-140104/src/skeleton/tabnote.cpp0000644000076400010400000005663112006761301014352 0ustar // ライセンス: GPL2 //#define _DEBUG //#define _DEBUG_RESIZE_TAB #include "jddebug.h" #include "dragnote.h" #include "tabnote.h" #include "tablabel.h" #include "config/globalconf.h" #include "session.h" #include "dndmanager.h" #include #include "gtkmmversion.h" using namespace SKELETON; ////////////////////////////////////////// // // gtknotebook.c( Revision 19311, 2008-01-06 ) より引用 // // gtkのバージョンが上がったときに誤動作しないかどうか注意 // typedef enum { DRAG_OPERATION_NONE, DRAG_OPERATION_REORDER, DRAG_OPERATION_DETACH } GtkNotebookDragOperation; typedef enum { ARROW_NONE, ARROW_LEFT_BEFORE, ARROW_RIGHT_BEFORE, ARROW_LEFT_AFTER, ARROW_RIGHT_AFTER } GtkNotebookArrow; #define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data) #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate)) typedef struct _GtkNotebookPrivate GtkNotebookPrivate; struct _GtkNotebookPrivate { gpointer group; gint mouse_x; gint mouse_y; gint pressed_button; guint dnd_timer; guint switch_tab_timer; gint drag_begin_x; gint drag_begin_y; gint drag_offset_x; gint drag_offset_y; GtkWidget *dnd_window; GtkTargetList *source_targets; GtkNotebookDragOperation operation; GdkWindow *drag_window; gint drag_window_x; gint drag_window_y; GtkNotebookPage *detached_tab; guint32 timestamp; guint during_reorder : 1; guint during_detach : 1; guint has_scrolled : 1; }; struct _GtkNotebookPage { GtkWidget *child; GtkWidget *tab_label; GtkWidget *menu_label; GtkWidget *last_focus_child; /* Last descendant of the page that had focus */ guint default_menu : 1; /* If true, we create the menu label ourself */ guint default_tab : 1; /* If true, we create the tab label ourself */ guint expand : 1; guint fill : 1; guint pack : 1; guint reorderable : 1; guint detachable : 1; GtkRequisition requisition; GtkAllocation allocation; gulong mnemonic_activate_signal; gulong notify_visible_handler; }; ////////////////////////////////////////// // // gtknotebook.c ( Revision 19311, 2008-01-06 ) を参考にして作成した描画関係の関数 // 描画本体 const bool TabNotebook::paint( GdkEventExpose* event ) { GtkNotebook *notebook = gobj(); if( ! notebook || ! notebook->cur_page || ! GTK_WIDGET_VISIBLE( notebook->cur_page->child ) ) return true; GtkWidget *widget = GTK_WIDGET( notebook ); GdkRectangle *area = &event->area; const Gdk::Rectangle rect( area ); const Glib::RefPtr< Gdk::Window > win = get_window(); if( ! notebook->first_tab ) notebook->first_tab = notebook->children; GtkNotebookPage* page = NULL; if( ! GTK_WIDGET_MAPPED( notebook->cur_page->tab_label ) ) page = GTK_NOTEBOOK_PAGE( notebook->first_tab ); else page = notebook->cur_page; // ビュー領域の枠の描画 m_parent->draw_box( this, event ); // 現在のタブ以外のタブの描画 // 現在のタブは矢印マークを描いた後に描く bool show_arrow = FALSE; GList *children = notebook->children; while( children ){ page = ( GtkNotebookPage* ) children->data; children = children->next; if( ! GTK_WIDGET_VISIBLE( page->child ) ) continue; if( ! GTK_WIDGET_MAPPED( page->tab_label ) ) show_arrow = TRUE; else if( page != notebook->cur_page ) draw_tab( notebook, page, area, rect, win ); } // gtk2.18以降?では cur_page が表示されていないのに一瞬だけ状態が visible になる時がある // その時に矢印を描画すると画面にゴミが残るので描画しないようにする if( show_arrow && ( notebook->cur_page->allocation.width == 0 || notebook->cur_page->allocation.height == 0 ) ) show_arrow = FALSE; //矢印マーク描画 if( show_arrow ){ draw_arrow( widget, notebook, rect, win, ARROW_LEFT_BEFORE ); draw_arrow( widget, notebook, rect, win, ARROW_RIGHT_AFTER ); } draw_tab( notebook, notebook->cur_page, area, rect, win ); // タブの中のwidgetの描画 children = notebook->children; while( children ){ GtkNotebookPage* page = ( GtkNotebookPage* ) children->data; children = children->next; if( page->tab_label->window == event->window && GTK_WIDGET_DRAWABLE (page->tab_label)) gtk_container_propagate_expose( GTK_CONTAINER( notebook ), page->tab_label, event ); } return true; } // タブ描画 void TabNotebook::draw_tab( const GtkNotebook *notebook, const GtkNotebookPage *page, GdkRectangle *area, const Gdk::Rectangle& rect, const Glib::RefPtr< Gdk::Window >& win ) { GdkRectangle child_area; GdkRectangle page_area; if( ! GTK_WIDGET_MAPPED( page->tab_label ) || page->allocation.width == 0 || page->allocation.height == 0 ) return; page_area.x = page->allocation.x; page_area.y = page->allocation.y; page_area.width = page->allocation.width; page_area.height = page->allocation.height; if( gdk_rectangle_intersect( &page_area, area, &child_area ) ) { Gtk::StateType state_type; if( notebook->cur_page == page ) state_type = Gtk::STATE_NORMAL; else state_type = Gtk::STATE_ACTIVE; get_style()->paint_extension( win, state_type, Gtk::SHADOW_OUT, rect, *this, "tab", page_area.x, page_area.y, page_area.width, page_area.height, Gtk::POS_BOTTOM ); } } // 矢印(スクロール)マークの描画 void TabNotebook::draw_arrow( GtkWidget *widget, const GtkNotebook *notebook, const Gdk::Rectangle& rect, const Glib::RefPtr< Gdk::Window >& win, const int nbarrow ) { Gtk::StateType state_type; Gtk::ShadowType shadow_type; Gtk::ArrowType arrow; GdkRectangle arrow_rect; const bool before = ( nbarrow == ARROW_LEFT_BEFORE ? true : false ); get_arrow_rect( widget, notebook, &arrow_rect, before ); if( ( int ) notebook->in_child == nbarrow ){ if( ( int ) notebook->click_child == nbarrow ) state_type = Gtk::STATE_ACTIVE; else state_type = Gtk::STATE_PRELIGHT; } else state_type = get_state(); if( ( int ) notebook->click_child == nbarrow ) shadow_type = Gtk::SHADOW_IN; else shadow_type = Gtk::SHADOW_OUT; const int page = get_current_page(); if( ( nbarrow == ARROW_LEFT_BEFORE && page == 0 ) || ( nbarrow == ARROW_RIGHT_AFTER && page == get_n_pages() -1 ) ){ shadow_type = Gtk::SHADOW_ETCHED_IN; state_type = Gtk::STATE_INSENSITIVE; } if( nbarrow == ARROW_LEFT_BEFORE ) arrow = Gtk::ARROW_LEFT; else arrow = Gtk::ARROW_RIGHT; get_style()->paint_arrow( win, state_type, shadow_type, rect, *this, "notebook", arrow, TRUE, arrow_rect.x, arrow_rect.y, arrow_rect.width, arrow_rect.height ); } // 矢印マークの位置、幅、高さを取得 // before : true ならタブの左側に表示される矢印 void TabNotebook::get_arrow_rect( GtkWidget *widget, const GtkNotebook *notebook, GdkRectangle *rectangle, const gboolean before ) { GdkRectangle event_window_pos; if( get_event_window_position( widget, notebook, &event_window_pos ) ){ #if GTKMM_CHECK_VERSION(2,9,0) gtk_widget_style_get( widget, "scroll-arrow-hlength", &rectangle->width, "scroll-arrow-vlength", &rectangle->height, NULL ); #else // gtk+-2.9.1より前は 12 で固定 rectangle->width = rectangle->height = 12; #endif if( before ) rectangle->x = event_window_pos.x; else rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width; rectangle->y = event_window_pos.y + ( event_window_pos.height - rectangle->height ) / 2; } } // タブ描画領域の位置、幅、高さを取得 const gboolean TabNotebook::get_event_window_position( const GtkWidget *widget, const GtkNotebook *notebook, GdkRectangle *rectangle ) { GtkNotebookPage* visible_page = NULL; GList* children = notebook->children; while( children ){ GtkNotebookPage* page = ( GtkNotebookPage* ) children->data; children = children->next; if( GTK_WIDGET_VISIBLE( page->child ) ){ visible_page = page; break; } } if( visible_page ){ const gint border_width = get_border_width(); rectangle->x = widget->allocation.x + border_width; rectangle->y = widget->allocation.y + border_width; rectangle->width = widget->allocation.width - 2 * border_width; rectangle->height = visible_page->requisition.height; return TRUE; } return FALSE; } ////////////////////////////////////////// // ダミーWidgetを作成してtabにappend ( 表示はされない ) class DummyWidget : public Gtk::Widget { public: DummyWidget() : Gtk::Widget(){ set_flags(Gtk::NO_WINDOW); } virtual ~DummyWidget(){} }; ////////////////////////////////////////////// TabNotebook::TabNotebook( DragableNoteBook* parent ) : Gtk::Notebook(), m_parent( parent ), m_fixtab( false ) { m_layout_tab = create_pango_layout( "" ); set_border_width( 0 ); set_size_request( 1, -1 ); // これが無いと最大化を解除したときにウィンドウが勝手にリサイズする add_events( Gdk::POINTER_MOTION_MASK ); add_events( Gdk::LEAVE_NOTIFY_MASK ); // DnD設定 // ドロップ側に設定する drag_source_unset(); drag_dest_unset(); std::list< Gtk::TargetEntry > targets; targets.push_back( Gtk::TargetEntry( DNDTARGET_TAB, Gtk::TARGET_SAME_APP, 0 ) ); drag_dest_set( targets, Gtk::DEST_DEFAULT_MOTION | Gtk::DEST_DEFAULT_DROP ); Glib::RefPtr< Gtk::RcStyle > rcst = get_modifier_style(); Glib::RefPtr< Gtk::Style > st = get_style(); m_tab_mrg = rcst->get_xthickness() * 2; if( m_tab_mrg <= 0 ) m_tab_mrg = st->get_xthickness() * 2; m_pre_width = get_width(); } // // クロック入力 // void TabNotebook::clock_in() { // Gtk::NoteBook は on_configure_event() と on_window_state_event() をキャッチ出来ない // かつ、 on_size_allocate() は最大化、最小化の時に無反応なので // 応急処置としてタイマーの中でサイズが変更したか調べて // 変わっていたらタブ幅を調整する if( ! m_fixtab && get_n_pages() && m_pre_width != get_width() && ! SESSION::is_booting() && ! SESSION::is_quitting() ){ calc_tabsize(); adjust_tabwidth(); } } // // サイズ変更 // void TabNotebook::on_size_allocate( Gtk::Allocation& allocation ) { clock_in(); // タブ再描画の反応を良くする Gtk::Notebook::on_size_allocate( allocation ); } int TabNotebook::append_tab( Widget& tab ) { #ifdef _DEBUG std::cout << "TabNotebook::append_tab\n"; #endif // ダミーWidgetを作成してtabにappend (表示はされない ) // remove_tab()でdeleteする DummyWidget* dummypage = new DummyWidget(); return append_page( *dummypage , tab ); } int TabNotebook::insert_tab( Widget& tab, int page ) { #ifdef _DEBUG std::cout << "TabNotebook::insert_tab position = " << page << std::endl; #endif // ダミーWidgetを作成してtabにappend (表示はされない ) // remove_tab()でdeleteする DummyWidget* dummypage = new DummyWidget(); return insert_page( *dummypage, tab, page ); } void TabNotebook::remove_tab( const int page, const bool adjust_tab ) { #ifdef _DEBUG std::cout << "TabNotebook::remove_tab page = " << page << std::endl; #endif // ダミーWidgetをdelete Gtk::Widget* dummypage = get_nth_page( page ); remove_page( page ); if( dummypage ) delete dummypage; if( adjust_tab ) adjust_tabwidth(); } void TabNotebook::reorder_child( int page1, int page2 ) { Gtk::Notebook::reorder_child( *get_nth_page( page1 ), page2 ); } // タブ取得 SKELETON::TabLabel* TabNotebook::get_tablabel( int page ) { return dynamic_cast< SKELETON::TabLabel* >( get_tab_label( *get_nth_page( page ) ) ); } // // マウスの下にあるタブの番号を取得 // // タブ上では無いときは-1を返す // マウスがタブの右側にある場合はページ数( get_n_pages() )を返す // const int TabNotebook::get_page_under_mouse() { int x, y; Gdk::Rectangle rect = get_allocation(); get_pointer( x, y ); x += rect.get_x(); y += rect.get_y(); #ifdef _DEBUG std::cout << "TabNotebook::get_page_under_mouse x = " << x << " y = " << y << std::endl; #endif if( y < rect.get_y() || y > rect.get_y() + rect.get_height() ) return -1; calc_tabsize(); const int pages = get_n_pages(); int ret = pages; for( int i = 0; i < pages; ++i ){ SKELETON::TabLabel* tab = get_tablabel( i ); if( tab ){ int tab_x = tab->get_tab_x(); int tab_w = tab->get_tab_width(); if( tab_x < 0 ) continue; #ifdef _DEBUG std::cout << "page = " << i << " x = " << tab_x << " w = " << tab_w << std::endl; #endif if( x < tab_x ){ ret = -1; break; } if( x >= tab_x && x <= tab_x + tab_w ){ ret = i; break; } } } #ifdef _DEBUG std::cout << "ret = " << ret << std::endl; #endif return ret; } // // タブの文字列取得 // const std::string TabNotebook::get_tab_fulltext( int page ) { SKELETON::TabLabel* tablabel = get_tablabel( page ); if( ! tablabel ) return std::string(); return tablabel->get_fulltext(); } // // タブに文字列をセットとタブ幅調整 // void TabNotebook::set_tab_fulltext( const std::string& str, int page ) { #ifdef _DEBUG std::cout << "TabNotebook::set_tab_fulltext page = " << page << " " << str << std::endl; #endif SKELETON::TabLabel* tablabel = get_tablabel( page ); if( tablabel && str != tablabel->get_fulltext() ){ tablabel->set_fulltext( str ); if( m_fixtab ) tablabel->resize_tab( str.length() ); else adjust_tabwidth(); } } // // 各タブのサイズと座標を取得 // void TabNotebook::calc_tabsize() { #ifdef _DEBUG std::cout << "TabNotebook::calc_tabsize\n"; #endif GtkNotebook *notebook = gobj(); GList * children = notebook->children; for( int i = 0; children ; ++i, children = children->next ){ GtkNotebookPage* page = ( GtkNotebookPage* ) children->data; SKELETON::TabLabel* tab = get_tablabel( i ); if( tab ){ int tab_x = -1; int tab_y = -1; int tab_w = -1; int tab_h = -1; if( tab->is_mapped() && page ){ tab_x = page->allocation.x; tab_y = page->allocation.y; tab_w = page->allocation.width; tab_h = page->allocation.height; Gdk::Rectangle rect = tab->get_allocation(); m_tab_mrg = tab_w - rect.get_width(); } #ifdef _DEBUG std::cout << "page = " << i << " x = " << tab_x << " w = " << tab_w << " mrg = " << m_tab_mrg << std::endl; #endif tab->set_tab_x( tab_x ); tab->set_tab_y( tab_y ); tab->set_tab_width( tab_w ); tab->set_tab_height( tab_h ); } } } // // タブ幅調整 // #define LABEL_WIDTH ( ulabel.substr( 0, vec_width[ i ] ) + ( vec_width[ i ] < vec_width_org[ i ] ? "..." : "" ) ) bool TabNotebook::adjust_tabwidth() { // 起動中とシャットダウン中は処理しない if( SESSION::is_booting() ) return false; if( SESSION::is_quitting() ) return false; const int mrg_notebook = 30; const int pages = get_n_pages(); if( ! pages ) return false; // layoutにラベルのフォントをセットする SKELETON::TabLabel* tab = get_tablabel( 0 ); if( ! tab ) return false; m_layout_tab->set_font_description( tab->get_label_font_description() ); const int label_margin = tab->get_label_margin(); std::vector< int > vec_width_org; // 変更前のタブの文字数 std::vector< int > vec_width; // 変更後のタブの文字数 vec_width_org.resize( pages ); vec_width.resize( pages ); m_pre_width = get_width(); const int width_notebook = m_pre_width - mrg_notebook; const int avg_width_tab = (int)( (double)width_notebook / MAX( 3, pages ) ); // タブ幅の平均値 #ifdef _DEBUG_RESIZE_TAB std::cout << "TabNotebook::adjust_tabwidth\n" << "width_notebook = " << width_notebook << " page = " << pages << std::endl << "avg_width_tab = " << avg_width_tab << " tab_mrg = " << m_tab_mrg << " label_margin " << label_margin << std::endl; #endif // 一端、全てのタブの幅を平均値以下に縮める for( int i = 0; i < pages; ++i ){ tab = get_tablabel( i ); if( tab ){ Glib::ustring ulabel( tab->get_fulltext() ); vec_width_org[ i ] = vec_width[ i ] = ulabel.length(); while( vec_width[ i ] > CONFIG::get_tab_min_str() ){ m_layout_tab->set_text( LABEL_WIDTH ); int width = m_layout_tab->get_pixel_logical_extents().get_width() + label_margin + m_tab_mrg; #ifdef _DEBUG_RESIZE_TAB std::cout << "s " << i << " " << width << " / " << avg_width_tab << " lng = " << vec_width[ i ] << " : " << ulabel.substr( 0, vec_width[ i ] ) << std::endl; #endif if( width < avg_width_tab ) break; --vec_width[ i ]; if( vec_width[ i ] < 0 ) vec_width[ i ] = 0; } } } // 横をはみださないようにタブ幅を延ばしていく int width_total = 0; for( int i = 0; i < pages; ++i ){ SKELETON::TabLabel* tab = get_tablabel( i ); if( tab ){ Glib::ustring ulabel( tab->get_fulltext() ); for(;;){ if( vec_width[ i ] >= vec_width_org[ i ] ) break; ++vec_width[ i ]; m_layout_tab->set_text( LABEL_WIDTH ); int width = m_layout_tab->get_pixel_logical_extents().get_width() + label_margin + m_tab_mrg; #ifdef _DEBUG_RESIZE_TAB std::cout << "w " << i << " " << width << " / " << avg_width_tab << " total= " << width_total + width << " / " << avg_width_tab * ( i + 1 ) << " lng = " << vec_width[ i ] << " : " << ulabel.substr( 0, vec_width[ i ] ) << std::endl; #endif // 最大値を越えたらひとつ戻してbreak; if( width_total + width > avg_width_tab * ( i + 1 ) ){ --vec_width[ i ]; break; } } m_layout_tab->set_text( LABEL_WIDTH ); width_total += ( m_layout_tab->get_pixel_logical_extents().get_width() + label_margin + m_tab_mrg ); tab->resize_tab( vec_width[ i ] ); } } // 枠の再描画 m_parent->queue_draw(); return true; } // // タブの高さ、幅、位置を取得 ( 描画用 ) // void TabNotebook::get_alloc_tab( Alloc_NoteBook& alloc ) { alloc.x_tab = 0; alloc.width_tab = 0; alloc.height_tab = 0; GtkNotebook *notebook = gobj(); if( notebook && notebook->cur_page ){ const int bw = get_border_width(); const int yy = get_allocation().get_y() + bw; const int xx = get_allocation().get_x() + bw; alloc.y_tab = notebook->cur_page->allocation.y - yy; alloc.x_tab = notebook->cur_page->allocation.x - xx; alloc.width_tab = notebook->cur_page->allocation.width; alloc.height_tab = notebook->cur_page->allocation.height; } } // // 描画イベント // bool TabNotebook::on_expose_event( GdkEventExpose* event ) { return paint( event ); } // signal_button_press_event と signal_button_release_event は emit されない // ときがあるので自前でemitする bool TabNotebook::on_button_press_event( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "TabNotebook::on_button_press_event\n"; #endif if( m_sig_button_press.emit( event ) ) return true; #ifdef _DEBUG std::cout << "Gtk::Notebook::on_button_press_event\n"; #endif return Gtk::Notebook::on_button_press_event( event ); } bool TabNotebook::on_button_release_event( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "TabNotebook::on_button_release_event\n"; #endif if( m_sig_button_release.emit( event ) ) return true; #ifdef _DEBUG std::cout << "Gtk::Notebook::on_button_release_event\n"; #endif return Gtk::Notebook::on_button_release_event( event ); } // // マウスが動いた // bool TabNotebook::on_motion_notify_event( GdkEventMotion* event ) { #ifdef _DEBUG std::cout << "TabNotebook::on_motion_notify_event\n"; #endif m_sig_tab_motion_event.emit(); return Gtk::Notebook::on_motion_notify_event( event ); } // // マウスが出た // bool TabNotebook::on_leave_notify_event( GdkEventCrossing* event ) { #ifdef _DEBUG std::cout << "TabNotebook::leave\n"; #endif m_sig_tab_leave_event.emit(); return Gtk::Notebook::on_leave_notify_event( event ); } // // マウスホイールを回した // bool TabNotebook::on_scroll_event( GdkEventScroll* event ) { if( ! CONFIG::get_switchtab_wheel() ) return true; #ifdef _DEBUG std::cout << "TabNotebook::scroll\n"; #endif if( m_sig_scroll_event.emit( event ) ) return true; return Gtk::Notebook::on_scroll_event( event ); } // // ドラッグ中にマウスを動かした // bool TabNotebook::on_drag_motion( const Glib::RefPtr& context, int x, int y, guint time) { #ifdef _DEBUG std::cout << "Gtk::Notebook::on_drag_motion x = " << x << " y = " << y << std::endl; #endif int tab_x = -1; int tab_y = -1; int tab_w = -1; int page = get_page_under_mouse(); if( page >= 0 ){ if( page >= get_n_pages() ) page = get_n_pages() -1; SKELETON::TabLabel* tab = get_tablabel( page ); if( tab ){ tab_x = tab->get_tab_x(); tab_y = tab->get_tab_y(); tab_w = tab->get_tab_width(); #ifdef _DEBUG std::cout << "page = " << page << " tab_x = " << tab_x << " tab_y = " << tab_y << " tab_w " << tab_w << std::endl; #endif } } m_sig_tab_drag_motion( page, tab_x, tab_y, tab_w ); // on_drag_motion をキャンセルしないとDnD中にタブが勝手に切り替わる( gtknotebook.c をハック ) return true; } jd-2.8.7-140104/src/skeleton/tabnote.h0000644000076400010400000001117411570441710014014 0ustar // ライセンス: GPL2 // // DragableNoteBookを構成するタブ表示用の Notebook // #ifndef _TABNOTE_H #define _TABNOTE_H #include namespace SKELETON { class DragableNoteBook; class TabLabel; struct Alloc_NoteBook; // タブのクリック typedef sigc::signal< bool, GdkEventButton* > SIG_BUTTON_PRESS; typedef sigc::signal< bool, GdkEventButton* > SIG_BUTTON_RELEASE; // マウス移動 typedef sigc::signal< void > SIG_TAB_MOTION_EVENT; typedef sigc::signal< void > SIG_TAB_LEAVE_EVENT; // ホイール回転 typedef sigc::signal< bool, GdkEventScroll* > SIG_SCROLL_EVENT; // D&D typedef sigc::signal< void, const int, const int, const int, const int > SIG_TAB_DRAG_MOTION; // タブ用の Notebook class TabNotebook : public Gtk::Notebook { SIG_BUTTON_PRESS m_sig_button_press; SIG_BUTTON_RELEASE m_sig_button_release; SIG_TAB_MOTION_EVENT m_sig_tab_motion_event; SIG_TAB_LEAVE_EVENT m_sig_tab_leave_event; SIG_TAB_DRAG_MOTION m_sig_tab_drag_motion; SIG_SCROLL_EVENT m_sig_scroll_event; DragableNoteBook* m_parent; // タブ幅計算用layout Glib::RefPtr< Pango::Layout > m_layout_tab; int m_pre_width; bool m_fixtab; int m_tab_mrg; public: SIG_BUTTON_PRESS sig_button_press(){ return m_sig_button_press; } SIG_BUTTON_RELEASE sig_button_release(){ return m_sig_button_release; } SIG_TAB_MOTION_EVENT sig_tab_motion_event(){ return m_sig_tab_motion_event; } SIG_TAB_LEAVE_EVENT sig_tab_leave_event(){ return m_sig_tab_leave_event; } SIG_TAB_DRAG_MOTION sig_tab_drag_motion(){ return m_sig_tab_drag_motion; } SIG_SCROLL_EVENT sig_scroll_event(){ return m_sig_scroll_event; } TabNotebook( DragableNoteBook* parent ); void clock_in(); // タブの幅を固定するか(デフォルト false ); void set_fixtab( bool fix ){ m_fixtab = fix; } int append_tab( Widget& tab ); int insert_tab( Widget& tab, int page ); void remove_tab( const int page, const bool adjust_tab ); void reorder_child( int page1, int page2 ); // タブ取得 SKELETON::TabLabel* get_tablabel( int page ); // タブの文字列取得/セット const std::string get_tab_fulltext( int page ); void set_tab_fulltext( const std::string& str, int page ); // タブ幅調整 bool adjust_tabwidth(); // マウスの下にあるタブの番号を取得 // タブ上では無いときは-1を返す // マウスがタブの右側にある場合はページ数の値を返す const int get_page_under_mouse(); // タブの高さ、幅、位置を取得 ( 描画用 ) void get_alloc_tab( Alloc_NoteBook& alloc ); private: // gtknotebook.c ( Revision 19311, 2008-01-06 ) を参考にして作成した描画関係の関数 const bool paint( GdkEventExpose* event ); void draw_tab( const GtkNotebook *notebook, const GtkNotebookPage *page, GdkRectangle *area, const Gdk::Rectangle& rect, const Glib::RefPtr< Gdk::Window >& win ); void draw_arrow( GtkWidget *widget, const GtkNotebook *notebook, const Gdk::Rectangle& rect, const Glib::RefPtr< Gdk::Window >& win, const int nbarrow ); void get_arrow_rect( GtkWidget *widget, const GtkNotebook *notebook, GdkRectangle *rectangle, const gboolean before ); const gboolean get_event_window_position( const GtkWidget *widget, const GtkNotebook *notebook, GdkRectangle *rectangle ); // 各タブのサイズと座標を取得 void calc_tabsize(); protected: virtual bool on_expose_event( GdkEventExpose* event ); virtual void on_size_allocate( Gtk::Allocation& allocation ); // signal_button_press_event と signal_button_release_event は emit されない // ときがあるので自前でemitする virtual bool on_button_press_event( GdkEventButton* event ); virtual bool on_button_release_event( GdkEventButton* event ); virtual bool on_motion_notify_event( GdkEventMotion* event ); virtual bool on_leave_notify_event( GdkEventCrossing* event ); virtual bool on_scroll_event( GdkEventScroll* event ); virtual bool on_drag_motion( const Glib::RefPtr& context, int x, int y, guint time); }; } #endif jd-2.8.7-140104/src/skeleton/tabswitchbutton.cpp0000644000076400010400000000267311210756175016150 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "tabswitchbutton.h" #include "dragnote.h" using namespace SKELETON; TabSwitchButton::TabSwitchButton( DragableNoteBook* parent ) : Gtk::Notebook(), m_parent( parent ), m_arrow( Gtk::ARROW_DOWN, Gtk::SHADOW_NONE ), m_shown( false ) { set_border_width( 0 ); m_button.add( m_arrow ); m_button.show_all_children(); m_button.set_relief( Gtk::RELIEF_NONE ); m_button.set_focus_on_click( false ); // フォーカス時にボタンの枠がはみ出さないようにする Glib::RefPtr< Gtk::RcStyle > rcst = m_button.get_modifier_style(); rcst->set_ythickness( 0 ); m_button.modify_style( rcst ); m_vbox.pack_start( m_button, Gtk::PACK_SHRINK ); set_show_tabs( false ); } TabSwitchButton::~TabSwitchButton() {} void TabSwitchButton::show_button() { if( m_shown ) return; append_page( m_vbox ); show_all_children(); m_shown = true; } void TabSwitchButton::hide_button() { if( ! m_shown ) return; remove_page( m_vbox ); m_shown = false; } // // 描画イベント // // 自前でビュー領域の枠を描画する // bool TabSwitchButton::on_expose_event( GdkEventExpose* event ) { if( ! m_shown ) return Gtk::Notebook::on_expose_event( event ); // 枠描画 m_parent->draw_box( this, event ); // ボタン描画 propagate_expose( m_vbox, event ); return true; } jd-2.8.7-140104/src/skeleton/tabswitchbutton.h0000644000076400010400000000162511210756175015611 0ustar // ライセンス: GPL2 // // タブの切り替えボタン // // 枠の描画時に get_style()->paint_box_gap() で warning が出るので // 直接 Gtk::Button を継承するのではなくて Notebook の中にボタンを入れる // DragableNoteBook::draw_box() 参照 // #ifndef TABSWITCHBUTON_H #define TABSWITCHBUTON_H #include namespace SKELETON { class DragableNoteBook; class TabSwitchButton: public Gtk::Notebook { DragableNoteBook* m_parent; Gtk::VBox m_vbox; Gtk::Button m_button; Gtk::Arrow m_arrow; bool m_shown; public: TabSwitchButton( DragableNoteBook* parent ); virtual ~TabSwitchButton(); Gtk::Button& get_button(){ return m_button; } void show_button(); void hide_button(); protected: virtual bool on_expose_event( GdkEventExpose* event ); }; } #endif jd-2.8.7-140104/src/skeleton/tabswitchmenu.cpp0000644000076400010400000000575411242032217015571 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "tabswitchmenu.h" #include "dragnote.h" #include "admin.h" #include "jdlib/miscutil.h" #include "icons/iconmanager.h" enum { SPACING_MENU = 3, // アイコンと項目名の間のスペース }; using namespace SKELETON; TabSwitchMenu::TabSwitchMenu( DragableNoteBook* notebook, Admin* admin ) : Gtk::Menu(), m_parentadmin( admin ), m_parentnote( notebook ), m_deactivated( true ), m_size( 0 ) { #ifdef _DEBUG std::cout << "TabSwitchMenu::TabSwitchMenu\n"; #endif } TabSwitchMenu::~TabSwitchMenu() { #ifdef _DEBUG std::cout << "TabSwitchMenu::~TabSwitchMenu\n"; #endif } void TabSwitchMenu::remove_items() { #ifdef _DEBUG std::cout << "TabSwitchMenu::remove_items\n"; #endif for( int i = 0; i < m_size; ++i ) remove( *m_vec_items[ i ] ); } void TabSwitchMenu::append_items() { #ifdef _DEBUG std::cout << "TabSwitchMenu::append_items\n"; #endif m_size = m_parentnote->get_n_pages(); if( (int) m_vec_items.size() < m_size ){ for( int i = m_vec_items.size(); i < m_size ; ++ i ){ Gtk::Image* image = Gtk::manage( new Gtk::Image() ); m_vec_images.push_back( image ); Gtk::Label* label = Gtk::manage( new Gtk::Label() ); m_vec_labels.push_back( label ); Gtk::HBox* hbox = Gtk::manage( new Gtk::HBox() ); hbox->set_spacing( SPACING_MENU ); hbox->pack_start( *image, Gtk::PACK_SHRINK ); hbox->pack_start( *label, Gtk::PACK_SHRINK ); Gtk::MenuItem* item = Gtk::manage( new Gtk::MenuItem( *hbox ) ); item->signal_activate().connect( sigc::bind< int >( sigc::mem_fun( *m_parentadmin, &Admin::set_current_page_focus ), i ) ); m_vec_items.push_back( item ); } } for( int i = 0; i < m_size; ++i ) append( *m_vec_items[ i ] ); show_all_children(); m_deactivated = false; } void TabSwitchMenu::update_labels() { if( m_deactivated ) return; if( ! m_parentnote ) return; #ifdef _DEBUG std::cout << "TabSwitchMenu::update_labels\n"; #endif for( int i = 0; i < m_size; ++ i ){ std::string name = m_parentnote->get_tab_fulltext( i ); if( name.empty() ) name = "???"; const unsigned int maxsize = 50; m_vec_labels[ i ]->set_label( MISC::cut_str( name, maxsize ) ); } } void TabSwitchMenu::update_icons() { if( m_deactivated ) return; if( ! m_parentnote ) return; #ifdef _DEBUG std::cout << "TabSwitchMenu::update_icons\n"; #endif for( int i = 0; i < m_size; ++ i ){ const int icon = m_parentnote->get_tabicon( i ); if( icon != ICON::NONE && icon != ICON::NUM_ICONS ){ m_vec_images[ i ]->set( ICON::get_icon( icon ) ); } } } void TabSwitchMenu::deactivate() { #ifdef _DEBUG std::cout << "TabSwitchMenu::deactivate\n"; #endif m_deactivated = true; } void TabSwitchMenu::on_deactivate() { deactivate(); Gtk::Menu::on_deactivate(); } jd-2.8.7-140104/src/skeleton/tabswitchmenu.h0000644000076400010400000000146712074575077015257 0ustar // ライセンス: GPL2 // // タブの切り替えメニュー // #include #include namespace SKELETON { class DragableNoteBook; class Admin; class TabSwitchMenu : public Gtk::Menu { Admin* m_parentadmin; DragableNoteBook* m_parentnote; bool m_deactivated; int m_size; std::vector< Gtk::MenuItem* > m_vec_items; std::vector< Gtk::Label* > m_vec_labels; std::vector< Gtk::Image* > m_vec_images; public: TabSwitchMenu( DragableNoteBook* notebook, Admin* admin ); virtual ~TabSwitchMenu(); void remove_items(); void append_items(); void update_labels(); void update_icons(); void deactivate(); protected: virtual void on_deactivate(); }; } jd-2.8.7-140104/src/skeleton/textloader.cpp0000644000076400010400000000733311204541171015064 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "textloader.h" #include "jdlib/jdiconv.h" #include "jdlib/loaderdata.h" #include "jdlib/miscmsg.h" #include "httpcode.h" #include "session.h" #include "cache.h" #include enum { SIZE_OF_RAWDATA = 1024 * 1024 }; using namespace SKELETON; TextLoader::TextLoader() : SKELETON::Loadable(), m_loaded( false ), m_rawdata( NULL ), m_lng_rawdata( 0 ) { #ifdef _DEBUG std::cout << "TextLoader::TextLoader\n"; #endif } TextLoader::~TextLoader() { #ifdef _DEBUG std::cout << "TextLoader::~TextLoader\n"; #endif clear(); } void TextLoader::init() { clear(); m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA ); } void TextLoader::clear() { if( m_rawdata ) free( m_rawdata ); m_rawdata = NULL; m_lng_rawdata = 0; } void TextLoader::reset() { m_loaded = false; m_data = std::string(); clear(); } // // キャッシュからロード // void TextLoader::load_text() { if( get_path().empty() ) return; init(); set_code( HTTP_INIT ); receive_finish(); } // // ダウンロード開始 // void TextLoader::download_text() { #ifdef _DEBUG std::cout << "TextLoader::download_text url = " << get_url() << std::endl; #endif if( get_url().empty() ) return; if( is_loading() ) return; if( m_loaded ) return; // 読み込み済み if( ! SESSION::is_online() ){ load_text(); return; } #ifdef _DEBUG std::cout << "start loading...\n"; #endif JDLIB::LOADERDATA data; init(); create_loaderdata( data ); if( data.url.empty() ) return; if( ! start_load( data ) ) clear(); } // // ローダよりデータ受信 // void TextLoader::receive_data( const char* data, size_t size ) { if( m_lng_rawdata + size < SIZE_OF_RAWDATA ){ memcpy( m_rawdata + m_lng_rawdata , data, size ); m_lng_rawdata += size; } else{ MISC::ERRMSG( "TextLoader : received failed ( BOF )\n" ); } } // // ロード完了 // void TextLoader::receive_finish() { #ifdef _DEBUG std::cout << "TextLoader::receive_finish code = " << get_str_code() << std::endl << "lng = " << m_lng_rawdata << " modified = " << get_date_modified() << std::endl; #endif // 初期化時やnot modifiedの時はキャッシュから読み込み if( ! get_path().empty() && ( get_code() == HTTP_INIT || get_code() == HTTP_NOT_MODIFIED ) ){ m_lng_rawdata = CACHE::load_rawdata( get_path(), m_rawdata, SIZE_OF_RAWDATA ); #ifdef _DEBUG std::cout << "read from " << get_path() << std::endl; if( ! m_lng_rawdata ) std::cout << "no data in cache!\n"; #endif if( ! m_lng_rawdata && get_code() == HTTP_INIT ) set_date_modified( std::string() ); } // 読み込みエラー if( get_code() != HTTP_OK && get_code() != HTTP_INIT && get_code() != HTTP_NOT_MODIFIED ){ if( get_code() == HTTP_NOT_FOUND ) m_loaded = true; clear(); set_date_modified( std::string() ); parse_data(); return; } // キャッシュに保存 if( ! get_path().empty() && get_code() == HTTP_OK && m_lng_rawdata ){ CACHE::save_rawdata( get_path(), m_rawdata, m_lng_rawdata ); #ifdef _DEBUG std::cout << "save to " << get_path() << std::endl; #endif } if( get_code() != HTTP_INIT ) m_loaded = true; set_code( HTTP_OK ); set_str_code( std::string() ); // UTF-8に変換しておく JDLIB::Iconv* libiconv = new JDLIB::Iconv( get_charset(), "UTF-8" ); int byte_out; m_data = libiconv->convert( m_rawdata , m_lng_rawdata, byte_out ); delete libiconv; clear(); #ifdef _DEBUG // std::cout << m_data << std::endl; #endif parse_data(); } jd-2.8.7-140104/src/skeleton/textloader.h0000644000076400010400000000277710702052305014536 0ustar // ライセンス: GPL2 // // テキストファイルの簡易ローダ // // ロードしたファイルはget_path()で示されたパスに保存される // get_path() が empty() ならば保存しない // #ifndef _TEXTLODER_H #define _TEXTLODER_H #include "loadable.h" #include namespace JDLIB { class LOADERDATA; } namespace SKELETON { class TextLoader : public SKELETON::Loadable { bool m_loaded; // 読み込み済みか char* m_rawdata; int m_lng_rawdata; std::string m_data; public: TextLoader(); ~TextLoader(); const std::string& get_data() const { return m_data; } // 一度ロードしたらreset()を呼ばない限りリロードしない void reset(); // キャッシュからロード void load_text(); // ダウンロード開始 // not modifiedの時はキャッシュから読み込む void download_text(); protected: virtual const std::string get_url() = 0; virtual const std::string get_path() = 0; virtual const std::string get_charset() = 0; // ロード用データ作成 virtual void create_loaderdata( JDLIB::LOADERDATA& data ) = 0; // ロード後に呼び出される virtual void parse_data() = 0; private: void init(); void clear(); virtual void receive_data( const char* data, size_t size ); virtual void receive_finish(); }; } #endif jd-2.8.7-140104/src/skeleton/toolbar.cpp0000644000076400010400000006525412006761301014361 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "toolbar.h" #include "admin.h" #include "view.h" #include "imgtoolbutton.h" #include "imgtoggletoolbutton.h" #include "menubutton.h" #include "toolmenubutton.h" #include "backforwardbutton.h" #include "compentry.h" #include "dbtree/interface.h" #include "jdlib/miscutil.h" #include "icons/iconmanager.h" #include "config/globalconf.h" #include "control/controlutil.h" #include "control/controlid.h" #include "command.h" #include "prefdiagfactory.h" #include // gtk_separator_tool_item_set_draw #include #include using namespace SKELETON; ToolBar::ToolBar( Admin* admin ) : m_admin( admin ), m_enable_slot( true ), m_buttonbar_shown( false ), m_buttonbar_packed( false ), m_tool_label( NULL ), m_ebox_label( NULL ), m_label( NULL ), m_searchbar( NULL ), m_searchbar_shown( false ), m_searchbar_packed( false ), m_button_open_searchbar( NULL ), m_button_close_searchbar( NULL ), m_button_up_search( NULL ), m_button_down_search( NULL ), m_button_clear_highlight( NULL ), m_tool_search( NULL ), m_entry_search( NULL ), m_label_board( NULL ), m_button_board( NULL ), m_button_write( NULL ), m_button_reload( NULL ), m_button_stop( NULL ), m_button_close( NULL ), m_button_delete( NULL ), m_button_favorite( NULL ), m_button_undo( NULL ), m_button_redo( NULL ), m_button_lock( NULL ), m_button_back( NULL ), m_button_forward( NULL ) { m_buttonbar.set_border_width( 0 ); #if GTKMM_CHECK_VERSION(2,12,0) m_buttonbar.set_icon_size( Gtk::ICON_SIZE_MENU ); #endif m_buttonbar.set_toolbar_style( Gtk::TOOLBAR_ICONS ); } void ToolBar::set_url( const std::string& url ) { m_url = url; if( m_button_back ) m_button_back->get_backforward_button()->set_url( m_url ); if( m_button_forward ) m_button_forward->get_backforward_button()->set_url( m_url ); } const bool ToolBar::is_empty() { return ( ! m_buttonbar.get_children().size() ); } // // タブが切り替わった時にDragableNoteBook::set_current_toolbar()から呼び出される( Viewの情報を取得する ) // // virtual void ToolBar::set_view( SKELETON::View* view ) { if( ! view ) return; // slot関数を実行しない m_enable_slot = false; set_url( view->get_url() ); // ラベル表示更新 set_label( view->get_label() ); if( view->is_broken() || view->is_old() ) set_color( view->get_color() ); // 閉じるボタンの表示更新 if( m_button_close ){ if( view->is_locked() ) m_button_close->set_sensitive( false ); else m_button_close->set_sensitive( true ); if( m_button_lock ) m_button_lock->set_active( view->is_locked() ); } if( m_button_write ) m_button_write->set_sensitive( view->is_writeable() ); if( m_entry_search ) m_entry_search->set_text( view->get_search_query() ); if( m_label_board ) m_label_board->set_text( DBTREE::board_name( get_url() ) ); m_enable_slot = true; } // // タブが切り替わった時にDragableNoteBookから呼び出される( ツールバーを表示する ) // // gtk+-2.4 辺りの古い gtk では、スレビューなどツールバーの複数が複数ある場合に // 最初からボタンバーを pack するとボタンが押せなくなる症状があったので、実際に // ツールバーが表示されるまでpackしないようにした // void ToolBar::show_toolbar() { // ボタンバーのpack if( m_buttonbar_shown && ! m_buttonbar_packed ){ if( m_searchbar_packed ) remove( *m_searchbar ); pack_start( m_buttonbar, Gtk::PACK_SHRINK ); if( m_searchbar_packed ) pack_start( *m_searchbar, Gtk::PACK_SHRINK ); show_all_children(); set_relief(); m_buttonbar_packed = true; } // 検索バーのpack if( m_searchbar_shown && ! m_searchbar_packed ){ pack_start( *m_searchbar, Gtk::PACK_SHRINK ); show_all_children(); set_relief(); m_searchbar_packed = true; } } // ボタンバー表示 void ToolBar::open_buttonbar() { // フラグだけ立てて実際に pack するのは show_toolbar() の中 // 何故そんな面倒な事をしているかは show_toolbar() の説明を参照 m_buttonbar_shown = true; } // ボタンバーを隠す void ToolBar::close_buttonbar() { m_buttonbar_shown = false; if( m_buttonbar_packed ){ remove( m_buttonbar ); show_all_children(); m_buttonbar_packed = false; } } // ボタン表示更新 void ToolBar::update_button() { unpack_buttons(); pack_buttons(); if( ! m_buttonbar_shown ) close_buttonbar(); // 進む、戻るボタンのsensitive状態を更新する set_url( m_url ); } // ボタンのアンパック void ToolBar::unpack_buttons() { std::list< Gtk::Widget* > lists = m_buttonbar.get_children(); std::list< Gtk::Widget* >::iterator it = lists.begin(); for( ; it != lists.end(); ++it ){ m_buttonbar.remove( *(*it) ); if( dynamic_cast< Gtk::SeparatorToolItem* >( *it ) ) delete *it; } } // 検索ツールバー上のボタンのアンパック void ToolBar::unpack_search_buttons() { if( ! m_searchbar ) return; std::list< Gtk::Widget* > lists = m_searchbar->get_children(); std::list< Gtk::Widget* >::iterator it = lists.begin(); for( ; it != lists.end(); ++it ){ m_searchbar->remove( *(*it) ); if( dynamic_cast< Gtk::SeparatorToolItem* >( *it ) ) delete *it; } } // ボタンのrelief指定 void ToolBar::set_relief() { std::list< Gtk::Widget* > lists_toolbar = get_children(); std::list< Gtk::Widget* >::iterator it_toolbar = lists_toolbar.begin(); for( ; it_toolbar != lists_toolbar.end(); ++it_toolbar ){ Gtk::Toolbar* toolbar = dynamic_cast< Gtk::Toolbar* >( *it_toolbar ); if( ! toolbar ) continue; std::list< Gtk::Widget* > lists = toolbar->get_children(); std::list< Gtk::Widget* >::iterator it = lists.begin(); for( ; it != lists.end(); ++it ){ Gtk::Button* button = NULL; Gtk::ToolButton* toolbutton = dynamic_cast< Gtk::ToolButton* >( *it ); if( toolbutton ) button = dynamic_cast< Gtk::Button* >( toolbutton->get_child() ); if( ! button ){ Gtk::ToolItem* toolitem = dynamic_cast< Gtk::ToolItem* >( *it ); if( toolitem ) button = dynamic_cast< Gtk::Button* >( toolitem->get_child() ); } if( button ){ if( CONFIG::get_flat_button() ) button->set_relief( Gtk:: RELIEF_NONE ); else button->set_relief( Gtk:: RELIEF_NORMAL ); } } } } // 区切り追加 void ToolBar::pack_separator() { Gtk::SeparatorToolItem *sep = Gtk::manage( new Gtk::SeparatorToolItem() ); // delete は unpack_buttons() で行う m_buttonbar.append( *sep ); } // 透明区切り追加 void ToolBar::pack_transparent_separator() { Gtk::SeparatorToolItem *sep = Gtk::manage( new Gtk::SeparatorToolItem() ); // delete は unpack_buttons() で行う gtk_separator_tool_item_set_draw( sep->gobj(), false ); m_buttonbar.append( *sep ); } // // ツールチップ // void ToolBar::set_tooltip( Gtk::ToolItem& toolitem, const std::string& tip ) { #if GTKMM_CHECK_VERSION(2,12,0) toolitem.set_tooltip_text( tip ); #else toolitem.set_tooltip( m_tooltip, tip ); #endif } // // ラベル // Gtk::ToolItem* ToolBar::get_label() { if( ! m_tool_label ){ m_tool_label = Gtk::manage( new Gtk::ToolItem ); m_ebox_label = Gtk::manage( new Gtk::EventBox ); m_label = Gtk::manage( new Gtk::Label ); m_label->set_size_request( 0, 0 ); m_label->set_alignment( Gtk::ALIGN_LEFT ); m_label->set_selectable( true ); m_ebox_label->add( *m_label ); m_ebox_label->set_visible_window( false ); m_tool_label->add( *m_ebox_label ); m_tool_label->set_expand( true ); } return m_tool_label; } void ToolBar::set_label( const std::string& label ) { if( ! m_ebox_label ) return; m_label->set_text( label ); if( m_tool_label ) set_tooltip( *m_tool_label, label ); set_color( "" ); } void ToolBar::set_color( const std::string& color ) { if( ! m_ebox_label ) return; if( color.empty() ){ if( m_ebox_label->get_visible_window() ){ m_ebox_label->set_visible_window( false ); m_label->unset_fg( Gtk::STATE_NORMAL ); } } else{ m_ebox_label->set_visible_window( true ); m_label->modify_fg( Gtk::STATE_NORMAL, Gdk::Color( "white" ) ); m_ebox_label->modify_bg( Gtk::STATE_NORMAL, Gdk::Color( color ) ); m_ebox_label->modify_bg( Gtk::STATE_ACTIVE, Gdk::Color( color ) ); } } // 検索バー Gtk::Toolbar* ToolBar::get_searchbar() { if( ! m_searchbar ){ m_searchbar = Gtk::manage( new SKELETON::JDToolbar() ); #if GTKMM_CHECK_VERSION(2,12,0) m_searchbar->set_icon_size( Gtk::ICON_SIZE_MENU ); #endif m_searchbar->set_toolbar_style( Gtk::TOOLBAR_ICONS ); } return m_searchbar; } // 検索バー表示 void ToolBar::open_searchbar() { if( ! m_searchbar ) return; #ifdef _DEBUG std::cout << "ToolBar::open_searchbar\n"; #endif // フラグだけ立てて実際に pack するのは show_toolbar() の中 // 何故そんな面倒な事をしているかは show_toolbar() の説明を参照 m_searchbar_shown = true; } // 検索バー非表示 void ToolBar::close_searchbar() { if( ! m_searchbar ) return; #ifdef _DEBUG std::cout << "ToolBar::close_searchbar\n"; #endif m_searchbar_shown = false; if( m_searchbar_packed ){ remove( *m_searchbar ); show_all_children(); m_searchbar_packed = false; m_admin->set_command( "focus_current_view" ); } } // // 検索バーを開く/閉じるボタン // Gtk::ToolItem* ToolBar::get_button_open_searchbar() { if( ! m_button_open_searchbar ){ m_button_open_searchbar = Gtk::manage( new SKELETON::ImgToolButton( ICON::SEARCH ) ); std::string tooltip = "検索バーを開く " + CONTROL::get_str_motions( CONTROL::Search ); set_tooltip( *m_button_open_searchbar, tooltip ); m_button_open_searchbar->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_toggle_searchbar ) ); } return m_button_open_searchbar; } Gtk::ToolItem* ToolBar::get_button_close_searchbar() { if( ! m_button_close_searchbar ){ m_button_close_searchbar = Gtk::manage( new SKELETON::ImgToolButton( ICON::CLOSE_SEARCH ) ); set_tooltip( *m_button_close_searchbar, CONTROL::get_label_motions( CONTROL::CloseSearchBar ) ); m_button_close_searchbar->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_toggle_searchbar ) ); } return m_button_close_searchbar; } // 検索バー表示/非表示切り替え void ToolBar::slot_toggle_searchbar() { if( ! m_enable_slot ) return; if( ! m_searchbar ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_toggle_searchbar shown = " << m_searchbar_shown << std::endl; #endif if( ! m_searchbar_shown ) m_admin->set_command( "open_searchbar", m_url ); else m_admin->set_command( "close_searchbar", m_url ); } // // 検索 entry // Gtk::ToolItem* ToolBar::get_tool_search( const int mode ) { if( ! m_tool_search ){ m_tool_search = Gtk::manage( new Gtk::ToolItem ); m_entry_search = Gtk::manage( new CompletionEntry( mode ) ); m_entry_search->signal_changed().connect( sigc::mem_fun( *this, &ToolBar::slot_changed_search ) ); m_entry_search->signal_activate().connect( sigc::mem_fun( *this, &ToolBar::slot_active_search ) ); m_entry_search->signal_operate().connect( sigc::mem_fun( *this, &ToolBar::slot_operate_search ) ); m_tool_search->add( *m_entry_search ); m_tool_search->set_expand( true ); } return m_tool_search; } SKELETON::CompletionEntry* ToolBar::get_entry_search() { return m_entry_search; } void ToolBar::add_search_control_mode( const int mode ) { if( m_entry_search ) m_entry_search->add_control_mode( mode ); } const std::string ToolBar::get_search_text() { if( ! m_entry_search ) return std::string(); return m_entry_search->get_text(); } void ToolBar::slot_changed_search() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; std::string query = m_entry_search->get_text(); #ifdef _DEBUG std::cout << "ToolBar::slot_changed_search query = " << query << std::endl; #endif m_admin->set_command( "toolbar_set_search_query", m_url, query ); } void ToolBar::slot_active_search() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_active_search\n"; #endif m_admin->set_command( "toolbar_exec_search", m_url ); } void ToolBar::slot_operate_search( const int controlid ) { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_operate_search id = " << controlid << std::endl; #endif m_admin->set_command( "toolbar_operate_search", m_url, MISC::itostr( controlid ) ); } // 検索 entry をフォーカス void ToolBar::focus_entry_search() { if( m_entry_search ) m_entry_search->grab_focus(); } // // 上検索 // Gtk::ToolButton* ToolBar::get_button_up_search() { if( ! m_button_up_search ){ m_button_up_search = Gtk::manage( new ImgToolButton( ICON::SEARCH_PREV ) ); set_tooltip( *m_button_up_search, CONTROL::get_label_motions( CONTROL::SearchPrev ) ); m_button_up_search->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_up_search ) ); } return m_button_up_search; } void ToolBar::slot_clicked_up_search() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_up_search\n"; #endif m_admin->set_command( "toolbar_up_search", m_url ); } // // 下検索 // Gtk::ToolButton* ToolBar::get_button_down_search() { if( ! m_button_down_search ){ m_button_down_search = Gtk::manage( new ImgToolButton( ICON::SEARCH_NEXT ) ); set_tooltip( *m_button_down_search, CONTROL::get_label_motions( CONTROL::SearchNext ) ); m_button_down_search->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_down_search ) ); } return m_button_down_search; } void ToolBar::slot_clicked_down_search() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_down_search\n"; #endif m_admin->set_command( "toolbar_down_search", m_url ); } // // ハイライト解除 // Gtk::ToolButton* ToolBar::get_button_clear_highlight() { if( ! m_button_clear_highlight ){ m_button_clear_highlight = Gtk::manage( new ImgToolButton( ICON::CLEAR_SEARCH ) ); set_tooltip( *m_button_clear_highlight, CONTROL::get_label_motions( CONTROL::HiLightOff ) ); m_button_clear_highlight->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clear_highlight ) ); } return m_button_clear_highlight; } void ToolBar::slot_clear_highlight() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; m_admin->set_command( "clear_highlight", m_url ); } // 板を開くボタン Gtk::ToolItem* ToolBar::get_button_board() { if( ! m_button_board ){ m_label_board = Gtk::manage( new Gtk::Label ); m_label_board->set_alignment( Gtk::ALIGN_LEFT ); m_button_board = Gtk::manage( new SKELETON::ToolMenuButton( CONTROL::get_label( CONTROL::OpenParentBoard ), false, true, *m_label_board ) ); std::vector< std::string > menu; menu.push_back( "開く" ); menu.push_back( "再読み込みして開く" ); menu.push_back( "separator" ); menu.push_back( "ローカルルールを表示" ); menu.push_back( "板のプロパティを表示" ); m_button_board->get_button()->append_menu( menu ); m_button_board->get_button()->signal_selected().connect( sigc::mem_fun(*this, &ToolBar::slot_menu_board ) ); m_button_board->get_button()->signal_button_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_open_board ) ); set_tooltip( *m_button_board, CONTROL::get_label_motions( CONTROL::OpenParentBoard ) ); } return m_button_board; } void ToolBar::slot_open_board() { if( ! m_enable_slot ) return; CORE::core_set_command( "open_board", DBTREE::url_subject( get_url() ), "true", "auto" // オートモードで開く ); } void ToolBar::slot_menu_board( int i ) { if( ! m_enable_slot ) return; SKELETON::PrefDiag* pref = NULL; // ToolBar::get_button_board()で作成したメニューの順番に内容を合わせる if( i == 0 ) slot_open_board(); else if( i == 1 ) CORE::core_set_command( "open_board", DBTREE::url_subject( get_url() ), "true" ); else if( i == 3 ) pref = CORE::PrefDiagFactory( CORE::get_mainwindow(), CORE::PREFDIAG_BOARD, DBTREE::url_subject( get_url() ), "show_localrule" ); else if( i == 4 ) pref = CORE::PrefDiagFactory( CORE::get_mainwindow(), CORE::PREFDIAG_BOARD, DBTREE::url_subject( get_url() ) ); if( pref ){ pref->run(); delete pref; } } // // 書き込みボタン // Gtk::ToolItem* ToolBar::get_button_write() { if( ! m_button_write ){ m_button_write = Gtk::manage( new ImgToolButton( ICON::WRITE ) ); set_tooltip( *m_button_write, CONTROL::get_label_motions( CONTROL::WriteMessage ) ); m_button_write->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_write ) ); m_button_write->get_child()->signal_focus_out_event().connect( sigc::mem_fun(*this, &ToolBar::slot_focusout_write_button ) ); } return m_button_write; } void ToolBar::slot_clicked_write() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_write\n"; #endif m_admin->set_command( "toolbar_write", m_url ); } // 書き込みボタンをフォーカス void ToolBar::focus_button_write() { get_button_write()->get_child()->grab_focus(); drawframe_button_write( true ); } // 書き込みボタンの廻りに枠を描く void ToolBar::drawframe_button_write( const bool draw ) { if( CONFIG::get_flat_button() ){ // relief が Gtk:: RELIEF_NONE のときにボタンに枠を描画 // gtk+-2.12.9/gtk/gtkbutton.c の gtk_button_enter_notify() // とgtk_button_leave_notify() をハック Gtk::Button* button = dynamic_cast< Gtk::Button* >( get_button_write()->get_child() ); if( button ){ GtkButton* gtkbutton = button->gobj(); gtkbutton->in_button = draw; if( draw ) gtk_button_enter( gtkbutton ); else gtk_button_leave( gtkbutton ); } } } bool ToolBar::slot_focusout_write_button( GdkEventFocus* event ) { #ifdef _DEBUG std::cout << "ToolBar::slot_focusout_write_button\n"; #endif drawframe_button_write( false ); return true; } // // 再読み込みボタン // Gtk::ToolItem* ToolBar::get_button_reload() { if( ! m_button_reload ){ m_button_reload = Gtk::manage( new ImgToolButton( ICON::RELOAD ) ); set_tooltip( *m_button_reload, CONTROL::get_label_motions( CONTROL::Reload ) ); m_button_reload->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_reload ) ); } return m_button_reload; } void ToolBar::slot_clicked_reload() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_reload\n"; #endif m_admin->set_command( "toolbar_reload", m_url ); } // // 読み込み停止ボタン // Gtk::ToolItem* ToolBar::get_button_stop() { if( ! m_button_stop ){ m_button_stop = Gtk::manage( new ImgToolButton( ICON::STOPLOADING ) ); set_tooltip( *m_button_stop, CONTROL::get_label_motions( CONTROL::StopLoading ) ); m_button_stop->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_stop ) ); } return m_button_stop; } void ToolBar::slot_clicked_stop() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_stop\n"; #endif m_admin->set_command( "toolbar_stop", m_url ); } // // 閉じるボタン // Gtk::ToolButton* ToolBar::get_button_close() { if( ! m_button_close ){ m_button_close = Gtk::manage( new ImgToolButton( ICON::QUIT ) ); set_tooltip( *m_button_close, CONTROL::get_label_motions( CONTROL::Quit ) ); m_button_close->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_close ) ); } return m_button_close; } void ToolBar::slot_clicked_close() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_close\n"; #endif // relief が Gtk:: RELIEF_NONE のときにタブの最後のビューを閉じると、 // ボタンに leave_notify イベントが送られないため、次にビューを開いたときに // 枠が残ったままになる // // gtk+-2.12.9/gtk/gtkbutton.c の gtk_button_leave_notify() をハックして // gtkbutton->in_button = false にすると枠が消えることが分かった if( m_admin->get_tab_nums() == 1 ){ Gtk::Button* button = dynamic_cast< Gtk::Button* >( m_button_close->get_child() ); GtkButton* gtkbutton = button->gobj(); gtkbutton->in_button = false; } m_admin->set_command( "toolbar_close_view", m_url ); } // // 削除ボタン // Gtk::ToolItem* ToolBar::get_button_delete() { if( ! m_button_delete ){ m_button_delete = Gtk::manage( new ImgToolButton( ICON::DELETE ) ); set_tooltip( *m_button_delete, CONTROL::get_label_motions( CONTROL::Delete ) ); m_button_delete->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_delete ) ); } return m_button_delete; } void ToolBar::slot_clicked_delete() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_delete\n"; #endif m_admin->set_command( "toolbar_delete_view", m_url ); } // // お気に入りボタン // Gtk::ToolItem* ToolBar::get_button_favorite() { if( ! m_button_favorite ){ m_button_favorite = Gtk::manage( new ImgToolButton( ICON::APPENDFAVORITE ) ); set_tooltip( *m_button_favorite, CONTROL::get_label_motions( CONTROL::AppendFavorite ) ); m_button_favorite->signal_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_favorite ) ); } return m_button_favorite; } void ToolBar::slot_clicked_favorite() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_favorite\n"; #endif m_admin->set_command( "toolbar_set_favorite", m_url ); } // // UNDO ボタン // Gtk::ToolButton* ToolBar::get_button_undo() { if( ! m_button_undo ){ m_button_undo = Gtk::manage( new SKELETON::ImgToolButton( ICON::UNDO ) ); m_button_undo->set_sensitive( false ); set_tooltip( *m_button_undo, CONTROL::get_label_motions( CONTROL::Undo ) ); } return m_button_undo; } // // REDO ボタン // Gtk::ToolButton* ToolBar::get_button_redo() { if( ! m_button_redo ){ m_button_redo = Gtk::manage( new SKELETON::ImgToolButton( ICON::REDO ) ); m_button_redo->set_sensitive( false ); set_tooltip( *m_button_redo, CONTROL::get_label_motions( CONTROL::Redo ) ); } return m_button_redo; } // // 戻るボタン // Gtk::ToolItem* ToolBar::get_button_back() { if( ! m_button_back ){ m_button_back = Gtk::manage( new SKELETON::ToolBackForwardButton( "back", false, m_url, true ) ); m_button_back->get_button()->signal_button_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_back ) ); m_button_back->get_button()->signal_selected().connect( sigc::mem_fun(*this, &ToolBar::slot_selected_back ) ); set_tooltip( *m_button_back, CONTROL::get_label_motions( CONTROL::PrevView ) ); } return m_button_back; } void ToolBar::slot_clicked_back() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_back : " << m_url << std::endl; #endif m_admin->set_command( "back_viewhistory", m_url, "1" ); } void ToolBar::slot_selected_back( const int i ) { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_selected_back : " << i << " url = " << m_url << std::endl; #endif m_admin->set_command( "back_viewhistory", m_url, MISC::itostr( i+1 ) ); } // // 進むボタン // Gtk::ToolItem* ToolBar::get_button_forward() { if( ! m_button_forward ){ m_button_forward = Gtk::manage( new SKELETON::ToolBackForwardButton( "forward", false, m_url, false ) ); m_button_forward->get_button()->signal_button_clicked().connect( sigc::mem_fun(*this, &ToolBar::slot_clicked_forward ) ); m_button_forward->get_button()->signal_selected().connect( sigc::mem_fun(*this, &ToolBar::slot_selected_forward ) ); set_tooltip( *m_button_forward, CONTROL::get_label_motions( CONTROL::NextView ) ); } return m_button_forward; } void ToolBar::slot_clicked_forward() { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_clicked_forward : " << m_url << std::endl; #endif m_admin->set_command( "forward_viewhistory", m_url, "1" ); } void ToolBar::slot_selected_forward( const int i ) { if( ! m_enable_slot ) return; if( m_url.empty() || ! m_admin ) return; #ifdef _DEBUG std::cout << "ToolBar::slot_selected_forward : " << i << " url = " << m_url << std::endl; #endif m_admin->set_command( "forward_viewhistory", m_url, MISC::itostr( i+1 ) ); } // // ロックボタン // Gtk::ToolItem* ToolBar::get_button_lock() { if( ! m_button_lock ){ m_button_lock = Gtk::manage( new SKELETON::ImgToggleToolButton( ICON::LOCK ) ); set_tooltip( *m_button_lock, CONTROL::get_label_motions( CONTROL::Lock ) ); m_button_lock->set_label( CONTROL::get_label( CONTROL::Lock ) ); m_button_lock->signal_clicked().connect( sigc::mem_fun( *this, &ToolBar::slot_lock_clicked ) ); } return m_button_lock; } void ToolBar::slot_lock_clicked() { if( ! m_enable_slot ) return; m_admin->set_command( "toolbar_lock_view", get_url() ); } jd-2.8.7-140104/src/skeleton/toolbar.h0000644000076400010400000001404412006761301014015 0ustar // ライセンス: GPL2 // // ツールバーの基底クラス // #ifndef _TOOLBAR_H #define _TOOLBAR_H #include "jdtoolbar.h" #include #include "gtkmmversion.h" namespace SKELETON { class Admin; class View; class ImgToolButton; class ImgToggleToolButton; class ToolMenuButton; class ToolBackForwardButton; class BackForwardButton; class CompletionEntry; class ToolBar : public Gtk::VBox { SKELETON::Admin* m_admin; std::string m_url; bool m_enable_slot; #if !GTKMM_CHECK_VERSION(2,13,0) Gtk::Tooltips m_tooltip; #endif // ボタンバー SKELETON::JDToolbar m_buttonbar; bool m_buttonbar_shown; bool m_buttonbar_packed; // ラベル Gtk::ToolItem* m_tool_label; Gtk::EventBox* m_ebox_label; Gtk::Label* m_label; // 検索関係 Gtk::Toolbar* m_searchbar; // 検索バー bool m_searchbar_shown; bool m_searchbar_packed; SKELETON::ImgToolButton *m_button_open_searchbar; SKELETON::ImgToolButton *m_button_close_searchbar; SKELETON::ImgToolButton *m_button_up_search; SKELETON::ImgToolButton *m_button_down_search; SKELETON::ImgToolButton *m_button_clear_highlight; Gtk::ToolItem* m_tool_search; SKELETON::CompletionEntry* m_entry_search; // 板を開く Gtk::Label* m_label_board; SKELETON::ToolMenuButton* m_button_board; // その他ボタン SKELETON::ImgToolButton* m_button_write; SKELETON::ImgToolButton* m_button_reload; SKELETON::ImgToolButton* m_button_stop; SKELETON::ImgToolButton* m_button_close; SKELETON::ImgToolButton* m_button_delete; SKELETON::ImgToolButton* m_button_favorite; SKELETON::ImgToolButton* m_button_undo; SKELETON::ImgToolButton* m_button_redo; SKELETON::ImgToggleToolButton* m_button_lock; // 進む、戻るボタン SKELETON::ToolBackForwardButton* m_button_back; SKELETON::ToolBackForwardButton* m_button_forward; public: ToolBar( Admin* admin ); virtual ~ToolBar(){} void set_url( const std::string& url ); const std::string& get_url() { return m_url; } const bool is_empty(); // タブが切り替わった時にDragableNoteBookから呼び出される( Viewの情報を取得する ) virtual void set_view( SKELETON::View * view ); // タブが切り替わった時にDragableNoteBookから呼び出される( ツールバーを表示する ) void show_toolbar(); // ボタンバー表示/非表示 void open_buttonbar(); void close_buttonbar(); // 検索バー表示/非表示 void open_searchbar(); void close_searchbar(); // 検索entryをフォーカス void focus_entry_search(); // 書き込みボタンをフォーカス void focus_button_write(); // ボタン表示更新 void update_button(); protected: SKELETON::Admin* get_admin(){ return m_admin; } // ボタンのパッキング virtual void pack_buttons() = 0; void unpack_buttons(); void unpack_search_buttons(); // ボタンのrelief指定 void set_relief(); Gtk::Toolbar& get_buttonbar(){ return m_buttonbar; } // ラベル Gtk::ToolItem* get_label(); // 検索関係 Gtk::Toolbar* get_searchbar(); Gtk::ToolItem* get_button_open_searchbar(); Gtk::ToolItem* get_button_close_searchbar(); // mode は補完モード ( compmanager.h 参照 ) Gtk::ToolItem* get_tool_search( const int mode ); SKELETON::CompletionEntry* get_entry_search(); // CompletionEntry の入力コントローラのモード設定 void add_search_control_mode( const int mode ); const std::string get_search_text(); // 上検索 Gtk::ToolButton* get_button_up_search(); // 下検索 Gtk::ToolButton* get_button_down_search(); // ハイライト解除 Gtk::ToolButton* get_button_clear_highlight(); // 板を開く Gtk::ToolItem* get_button_board(); // その他ボタン Gtk::ToolItem* get_button_write(); Gtk::ToolItem* get_button_reload(); Gtk::ToolItem* get_button_stop(); Gtk::ToolButton* get_button_close(); Gtk::ToolItem* get_button_delete(); Gtk::ToolItem* get_button_favorite(); Gtk::ToolButton* get_button_undo(); Gtk::ToolButton* get_button_redo(); Gtk::ToolItem* get_button_lock(); Gtk::ToolItem* get_button_back(); Gtk::ToolItem* get_button_forward(); void pack_separator(); void pack_transparent_separator(); void set_tooltip( Gtk::ToolItem& toolitem, const std::string& tip ); private: // ラベル関係 void set_label( const std::string& label ); void set_color( const std::string& color ); // 書き込みボタン関係 void drawframe_button_write( const bool draw ); bool slot_focusout_write_button( GdkEventFocus* event ); // 検索関係 void slot_toggle_searchbar(); void slot_changed_search(); void slot_active_search(); void slot_operate_search( const int controlid ); void slot_clicked_up_search(); void slot_clicked_down_search(); void slot_clear_highlight(); // 板を開く void slot_open_board(); void slot_menu_board( int i ); // その他ボタン void slot_clicked_write(); void slot_clicked_reload(); void slot_clicked_stop(); void slot_clicked_close(); void slot_clicked_delete(); void slot_clicked_favorite(); void slot_lock_clicked(); void slot_clicked_back(); void slot_selected_back( const int i ); void slot_clicked_forward(); void slot_selected_forward( const int i ); }; } #endif jd-2.8.7-140104/src/skeleton/toolbarnote.cpp0000644000076400010400000000166411174074717015257 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "dragnote.h" #include "toolbarnote.h" #include using namespace SKELETON; ToolBarNotebook::ToolBarNotebook( DragableNoteBook* parent ) : Gtk::Notebook(), m_parent( parent ) { set_show_border( true ); set_show_tabs( false ); set_border_width( 0 ); Glib::RefPtr< Gtk::RcStyle > rcst = get_modifier_style(); rcst->set_ythickness( 1 ); modify_style( rcst ); } // // 描画イベント // // 自前でビュー領域の枠を描画する // bool ToolBarNotebook::on_expose_event( GdkEventExpose* event ) { // 枠描画 m_parent->draw_box( this, event ); // 枠は自前で書いたので gtk_notebook_expose では枠を描画させない GtkNotebook *notebook = gobj(); notebook->show_border = false; bool ret = Notebook::on_expose_event( event ); notebook->show_border = true; return ret; } jd-2.8.7-140104/src/skeleton/toolbarnote.h0000644000076400010400000000073711011547756014722 0ustar // ライセンス: GPL2 // // DragableNoteBookを構成するツールバー表示用の Notebook // #ifndef _TOOLBARNOTE_H #define _TOOLBARNOTE_H #include namespace SKELETON { class DragableNoteBook; class ToolBarNotebook : public Gtk::Notebook { DragableNoteBook* m_parent; public: ToolBarNotebook( DragableNoteBook* parent ); protected: virtual bool on_expose_event( GdkEventExpose* event ); }; } #endif jd-2.8.7-140104/src/skeleton/toolmenubutton.cpp0000644000076400010400000000416411506370702016013 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "toolmenubutton.h" #include "menubutton.h" #include "backforwardbutton.h" using namespace SKELETON; ToolMenuButton::ToolMenuButton( const std::string& label, const bool expand, const bool show_arrow, Gtk::Widget& widget ) { SKELETON::MenuButton *button = Gtk::manage( new SKELETON::MenuButton( show_arrow, widget ) ); setup( button, label, expand ); } ToolMenuButton::ToolMenuButton( const std::string& label, const bool expand, const bool show_arrow , const int id ) { SKELETON::MenuButton *button = Gtk::manage( new SKELETON::MenuButton( show_arrow, id ) ); setup( button, label, expand ); } void ToolMenuButton::setup( SKELETON::MenuButton* button, const std::string& label, const bool expand ) { m_button = button; assert( m_button != NULL ); assert( m_button->get_label_widget() != NULL ); Gtk::MenuItem* item = NULL; // アイコンの場合はアイコン表示 Gtk::Image* image = dynamic_cast< Gtk::Image* >( m_button->get_label_widget() ); if( image ){ Gtk::StockID id; Gtk::IconSize size; image->get_stock( id, size ); item = Gtk::manage( new Gtk::ImageMenuItem( *Gtk::manage( new Gtk::Image( id, size ) ), "" ) ); } else item = Gtk::manage( new Gtk::MenuItem( label ) ); if( item ){ item->signal_activate().connect( sigc::mem_fun( *m_button, &MenuButton::on_clicked ) ); set_proxy_menu_item( label, *item ); } set_expand( expand ); add( *m_button ); } /////////////////////////// ToolBackForwardButton::ToolBackForwardButton( const std::string& label, const bool expand, const std::string& url, const bool back ) { SKELETON::MenuButton *button = Gtk::manage( new SKELETON::BackForwardButton( url, back ) ); setup( button, label, expand ); } SKELETON::BackForwardButton* ToolBackForwardButton::get_backforward_button() { return dynamic_cast< SKELETON::BackForwardButton* >( get_button() ); } jd-2.8.7-140104/src/skeleton/toolmenubutton.h0000644000076400010400000000264611506370702015463 0ustar // ライセンス: GPL2 // ツールバーに表示する SKELETON::MenuButton、および SKELETON::BackForwardButton // メニューがオーバーフローしたときにアイコン、または label を表示して // 選択したら MenuButton::on_clicked() を呼び出す #ifndef _TOOLMENUBUTTON_H #define _TOOLMENUBUTTON_H #include namespace SKELETON { class MenuButton; class BackForwardButton; class ToolMenuButton : public Gtk::ToolItem { SKELETON::MenuButton* m_button; public: ToolMenuButton() : m_button( NULL ){} ToolMenuButton( const std::string& label, const bool expand, const bool show_arrow, Gtk::Widget& widget ); ToolMenuButton( const std::string& label, const bool expand, const bool show_arrow , const int id ); SKELETON::MenuButton* get_button(){ return m_button; } protected: void setup( SKELETON::MenuButton* button, const std::string& label, const bool expand ); }; ////////////////////////// class ToolBackForwardButton : public SKELETON::ToolMenuButton { public: ToolBackForwardButton( const std::string& label, const bool expand, const std::string& url, const bool back ); SKELETON::BackForwardButton* get_backforward_button(); }; } #endif jd-2.8.7-140104/src/skeleton/tooltip.cpp0000644000076400010400000000445711407663463014425 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "tooltip.h" #include "global.h" using namespace SKELETON; // ツールチップ Tooltip::Tooltip() : PopupWinBase( POPUPWIN_DRAWFRAME ), m_counter( 0 ), m_min_width( 0 ) { // 背景色をテーマに合わせる set_name( "gtk-tooltips" ); set_border_width( 4 ); add( m_label ); show_all_children(); } // フォント void Tooltip::modify_font_label( const std::string& fontname ) { Pango::FontDescription pfd( fontname ); pfd.set_weight( Pango::WEIGHT_NORMAL ); m_label.modify_font( pfd ); } // // クロック入力 // void Tooltip::clock_in() { const int popup_time = 500 // msec / TIMER_TIMEOUT ; // カウンターが一杯になったらツールチップ表示 ++m_counter; if( m_counter == popup_time ) show_tooltip(); } void Tooltip::set_text( const std::string& text ) { if( m_label.get_text() == text ) return; #ifdef _DEBUG std::cout << "Tooltip::set_text" << text << std::endl; #endif hide_tooltip(); resize( 1, 1 ); m_label.set_text( text ); m_counter = 0; } // // 表示 // void Tooltip::show_tooltip() { if( m_label.get_text().empty() ) return; #ifdef _DEBUG std::cout << "Tooltip::show_tooltip" << m_label.get_text() << std::endl; #endif int x_mouse, y_mouse; Gdk::ModifierType mod; Gdk::Display::get_default()->get_pointer( x_mouse, y_mouse, mod ); // 一度画面外にshow()して幅を確定してから、もし m_min_width よりも // 幅が大きければマウスの位置に移動する move( -100, -100 ); show(); const int width = get_width(); const int height = get_height(); #ifdef _DEBUG std::cout << "width / min_width = " << width << " / " << m_min_width << std::endl; #endif if( width >= m_min_width ){ // 画面外にはみださないように調整 const int mrg = 4; const int width_desktop = get_screen()->get_width(); if( x_mouse + width > width_desktop ) x_mouse = MAX( 0, width_desktop - width ); move( x_mouse, y_mouse - height - mrg ); } } void Tooltip::hide_tooltip() { #ifdef _DEBUG std::cout << "Tooltip::hide_tooltip\n"; #endif m_counter = 10000; hide(); m_label.set_text( std::string() ); } jd-2.8.7-140104/src/skeleton/tooltip.h0000644000076400010400000000131010650414542014042 0ustar // ライセンス: GPL2 // // 自前のツールチップクラス // #ifndef _TOOLTIP_H #define _TOOLTIP_H #include "popupwinbase.h" namespace SKELETON { class Tooltip : public PopupWinBase { Glib::RefPtr< Gdk::GC > m_gc; Gtk::Label m_label; int m_counter; // 横幅が m_min_width より大きければ表示 int m_min_width; public: Tooltip(); void clock_in(); void modify_font_label( const std::string& fontname ); void set_text( const std::string& text ); void set_min_width( const int& min_width ){ m_min_width = min_width; } void show_tooltip(); void hide_tooltip(); }; } #endif jd-2.8.7-140104/src/skeleton/treeviewbase.cpp0000644000076400010400000002465312177057552015421 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "treeviewbase.h" using namespace SKELETON; JDTreeViewBase::JDTreeViewBase() : m_column_for_height( 0 ) { add_events( Gdk::KEY_PRESS_MASK ); add_events( Gdk::KEY_RELEASE_MASK ); add_events( Gdk::SCROLL_MASK ); add_events( Gdk::BUTTON_PRESS_MASK ); add_events( Gdk::POINTER_MOTION_MASK ); } JDTreeViewBase::~JDTreeViewBase() {} // // 行数 // const int JDTreeViewBase::get_row_size() { if( ! get_model() ) return 0; return get_model()->children().size(); } // // 現在フォーカスしてる行の最初のパスを取得 // Gtk::TreeModel::Path JDTreeViewBase::get_current_path() { Gtk::TreeModel::Path path; std::list< Gtk::TreeModel::Path > paths = get_selection()->get_selected_rows(); if( paths.size() ){ std::list< Gtk::TreeModel::Path >::iterator it = paths.begin(); path = ( *it ); } return path; } // 現在フォーカスしてる行の最初のrowを取得 Gtk::TreeModel::Row JDTreeViewBase::get_current_row() { Gtk::TreePath path = get_current_path(); return get_row( path ); } // // x, y 座標の下のパスを取得 // Gtk::TreeModel::Path JDTreeViewBase::get_path_under_xy( int x, int y ) { Gtk::TreeModel::Path path; Gtk::TreeViewColumn* column; int cell_x, cell_y; if( !get_path_at_pos( x, y, path, column, cell_x, cell_y ) ) return Gtk::TreeModel::Path(); return path; } // // 現在のマウスポインタの下のパスを取得 // Gtk::TreeModel::Path JDTreeViewBase::get_path_under_mouse() { int x, y; get_pointer( x, y ); return get_path_under_xy( x, y ); } // // 現在のマウスポインタの下のセルの幅高さとセル内での座標を取得 // void JDTreeViewBase::get_cell_xy_wh( int& cell_x, int& cell_y, int& cell_w, int& cell_h ) { cell_x = cell_y = cell_w = cell_h = -1; Gtk::TreeModel::Path path; Gtk::TreeViewColumn* column; int x, y, o_x, o_y; Gdk::Rectangle rect; get_pointer( x, y ); get_path_at_pos( x, y, path, column, cell_x, cell_y ); if( column ) column->cell_get_size( rect, o_x, o_y, cell_w, cell_h ); } // // 選択中の Gtk::TreeModel::iterator のリストを取得 // // 削除などを実行してから get_model()->get_iter() するとパスが変わってエラーが出るので // 先に iterator だけ取得しておく // std::list< Gtk::TreeModel::iterator > JDTreeViewBase::get_selected_iterators() { std::list< Gtk::TreeModel::iterator > list_it; if( get_model() ){ std::list< Gtk::TreeModel::Path > paths = get_selection()->get_selected_rows(); std::list< Gtk::TreeModel::Path >::iterator it = paths.begin(); for( ; it != paths.end(); ++it ) list_it.push_back( get_model()->get_iter( ( *it ) ) ); } return list_it; } // // 選択行の削除 // void JDTreeViewBase::delete_selected_rows( const bool force ) { std::list< Gtk::TreeModel::Path > list_path = get_selection()->get_selected_rows(); if( ! list_path.size() ) return; Glib::RefPtr< Gtk::ListStore > liststore; Glib::RefPtr< Gtk::TreeStore > treestore = Glib::RefPtr< Gtk::TreeStore >::cast_dynamic( get_model() ); if( ! treestore ){ liststore = Glib::RefPtr< Gtk::ListStore >::cast_dynamic( get_model() ); if( ! liststore ) return; } // カーソルを選択範囲の最後の行の次の行に移動 const Gtk::TreePath next = next_path( list_path.back(), true ); const bool gotobottom = ( ! get_row( next ) ); if( ! gotobottom ) set_cursor( next ); std::list< Gtk::TreePath >::reverse_iterator it = list_path.rbegin(); for( ; it != list_path.rend(); ++it ){ Gtk::TreeRow row = get_row( *it ); if( treestore ) treestore->erase( row ); else liststore->erase( row ); } if( gotobottom ) goto_bottom(); } // // 先頭へ // void JDTreeViewBase::goto_top() { if( ! get_row_size() ) return; Gtk::TreePath path = get_model()->get_path( *( get_model()->children().begin() ) ); scroll_to_row( path, 0 ); set_cursor( path ); } // // 一番最後へ // void JDTreeViewBase::goto_bottom() { if( ! get_row_size() ) return; Gtk::TreePath path = get_model()->get_path( *( get_model()->children().rbegin() ) ); // ディレクトリを開いている時、一番下の行に移動 Gtk::TreePath path_prev = path; while( ! path.empty() ){ Gtk::TreePath path_tmp = next_path( path ); if( path_tmp == path ) break; // 変化が無くなったらbreak path_prev = path; path = path_tmp; } scroll_to_row( path_prev, 0 ); set_cursor( path_prev ); } // // 選択行を上へ移動 // const bool JDTreeViewBase::row_up() { Gtk::TreePath path = get_current_path(); if( !get_row( path ) ) return false; Gtk::TreePath new_path = prev_path( path ); if( path != new_path ) set_cursor( new_path ); else return false; return true; } // // 選択行を下へ移動 // const bool JDTreeViewBase::row_down() { Gtk::TreePath path = get_current_path(); if( !get_row( path ) ) return false; Gtk::TreePath new_path = next_path( path ); if( new_path.get_depth() && get_row( new_path ) ) set_cursor( new_path ); else return false; return true; } // // page up // void JDTreeViewBase::page_up() { bool set_top = false; // スクロール Gtk::Adjustment *adj = get_vadjustment(); double val = adj->get_value(); if( val > adj->get_page_size()/2 ) set_top = true; val = MAX( 0, val - adj->get_page_size() ); adj->set_value( val ); // 選択行移動 Gtk::TreePath path; if( set_top ) path = get_path_under_xy( 0, (int)adj->get_page_size() - 4 ); else path = get_path_under_xy( 0, 0 ); if( path.get_depth() && get_row( path ) )set_cursor( path ); } // // page down // void JDTreeViewBase::page_down() { bool set_bottom = false; // スクロール Gtk::Adjustment *adj = get_vadjustment(); double val = adj->get_value(); if( val < adj->get_upper() - adj->get_page_size() - adj->get_page_size()/2 ) set_bottom = true; val = MIN( adj->get_upper() - adj->get_page_size(), val + adj->get_page_size() ); adj->set_value( val ); // 選択行移動 Gtk::TreePath path; if( set_bottom ) path = get_path_under_xy( 0, 0 ); else path = get_path_under_xy( 0, (int)adj->get_page_size() - 4 ); if( path.get_depth() && get_row( path ) ) set_cursor( path ); } // // path の前の path を取得 // // check_expand = true なら行が開いてるかチェックして開いて無い時はdown()しない // Gtk::TreePath JDTreeViewBase::prev_path( const Gtk::TreePath& path, bool check_expand ) { Gtk::TreePath path_out( path ); // 前に移動 if( path_out.prev() && ( row_expanded( path_out ) || ! check_expand ) ){ Gtk::TreePath path_tmp = path_out; while( get_row( path_out ) && ( path_out = next_path( path_out, check_expand ) ) != path ) path_tmp = path_out; if( get_row( path_tmp ) ) return path_tmp; } // 一番上まで到達したらup path_out = path; if( ! path_out.prev() && path_out.get_depth() >= 2 ) path_out.up(); return path_out;; } // // path の次の path を取得 // // check_expand = true なら行が開いてるかチェックして開いて無い時はdown()しない // Gtk::TreePath JDTreeViewBase::next_path( const Gtk::TreePath& path, bool check_expand ) { if( !get_row( path ) ) return path; Gtk::TreePath path_out( path ); if( row_expanded( path_out ) || ! check_expand ){ path_out.down(); if( get_row( path_out ) ) return path_out; } // next()してレベルの一番下まで到達したら上のレベルに移動 path_out = path; while( path_out.next(), ( ! get_row( path_out ) && path_out.get_depth() >=2 ) ) path_out.up(); return path_out; } // // path->row 変換 // Gtk::TreeModel::Row JDTreeViewBase::get_row( const Gtk::TreePath& path ) { if( path.empty() || ! get_model() ) return Gtk::TreeModel::Row(); Gtk::TreeModel::Row row = *( get_model()->get_iter( path ) ); if( !row ) return Gtk::TreeModel::Row(); if( path != get_model()->get_path( row ) ) return Gtk::TreeModel::Row(); return row; } // // pathの親を再起的に開く // void JDTreeViewBase::expand_parents( const Gtk::TreePath& path ) { if( ! get_model() ) return; for( int level = 1; level < path.get_depth(); ++level ){ Gtk::TreeModel::Row row_tmp = get_row( path ); if( ! row_tmp ) return; for( int i = 0; i < path.get_depth() - level; ++i ){ if( row_tmp.parent() ) row_tmp = *( row_tmp.parent() ); } Gtk::TreePath path_tmp = get_model()->get_path( row_tmp ); expand_row( path_tmp, false ); } } // // pathが開かれているか // const bool JDTreeViewBase::is_expand( const Gtk::TreePath& path ) { Gtk::TreePath parent( path ); if( path.get_depth() < 2 ) return true; if( parent.up() && row_expanded( parent ) ) return true; return false; } // // 行のセルの高さ // int JDTreeViewBase::get_row_height() { Gtk::TreeViewColumn* column = get_column( m_column_for_height ); if( !column ) return 0; int x,y,w,h; Gdk::Rectangle rect; column->cell_get_size( rect, x, y, w, h ); return h; } // // キーボードのキーを押した // bool JDTreeViewBase::on_key_press_event( GdkEventKey* event ) { return m_sig_key_press.emit( event ); } // // キーボードのキーを離した // bool JDTreeViewBase::on_key_release_event( GdkEventKey* event ) { m_sig_key_release.emit( event ); return true; } // マウスのwheelを回した bool JDTreeViewBase::on_scroll_event( GdkEventScroll* event ) { m_sig_scroll_event.emit( event ); return Gtk::TreeView::on_scroll_event( event ); } // // マウスボタンを押した // bool JDTreeViewBase::on_button_press_event( GdkEventButton* event ) { m_sig_button_press.emit( event ); return Gtk::TreeView::on_button_press_event( event ); } // // マウスボタンを離した // bool JDTreeViewBase::on_button_release_event( GdkEventButton* event ) { m_sig_button_release.emit( event ); return Gtk::TreeView::on_button_release_event( event ); } // // マウスを動かした // bool JDTreeViewBase::on_motion_notify_event( GdkEventMotion* event ) { m_sig_motion_notify.emit( event ); return Gtk::TreeView::on_motion_notify_event( event ); } jd-2.8.7-140104/src/skeleton/treeviewbase.h0000644000076400010400000000751712177057552015066 0ustar // ライセンス: GPL2 // // treeviewクラスの基底クラス // #ifndef _TREEVIEWBASE_H #define _TREEVIEWBASE_H #include #include namespace SKELETON { class JDTreeViewBase : public Gtk::TreeView { typedef sigc::signal< bool, GdkEventKey* > SIG_KEY_PRESS; typedef sigc::signal< bool, GdkEventKey* > SIG_KEY_RELEASE; typedef sigc::signal< bool, GdkEventScroll* > SIG_SCROLL_EVENT; typedef sigc::signal< bool, GdkEventButton* > SIG_BUTTON_PRESS; typedef sigc::signal< bool, GdkEventButton* > SIG_BUTTON_RELEASE; typedef sigc::signal< bool, GdkEventMotion* > SIG_MOTION_NOTIFY; SIG_KEY_PRESS m_sig_key_press; SIG_KEY_RELEASE m_sig_key_release; SIG_SCROLL_EVENT m_sig_scroll_event; SIG_BUTTON_PRESS m_sig_button_press; SIG_BUTTON_RELEASE m_sig_button_release; SIG_MOTION_NOTIFY m_sig_motion_notify; // get_row_height() で高さを取得するためのcolumn番号 int m_column_for_height; public: SIG_KEY_PRESS& sig_key_press() { return m_sig_key_press; } SIG_KEY_RELEASE& sig_key_release() { return m_sig_key_release; } SIG_SCROLL_EVENT& sig_scroll_event(){ return m_sig_scroll_event; } SIG_BUTTON_PRESS& sig_button_press() { return m_sig_button_press; } SIG_BUTTON_RELEASE& sig_button_release() { return m_sig_button_release; } SIG_MOTION_NOTIFY& sig_motion_notify() { return m_sig_motion_notify; } JDTreeViewBase(); virtual ~JDTreeViewBase(); // 行数 const int get_row_size(); // カーソル解除 void unset_cursor(){ get_selection()->unselect_all(); } // 現在フォーカスしてる行の最初のパスを取得 Gtk::TreeModel::Path get_current_path(); // 現在フォーカスしてる行の最初のrowを取得 Gtk::TreeModel::Row get_current_row(); //x, y 座標の下のパスを取得 Gtk::TreeModel::Path get_path_under_xy( int x, int y ); // 現在のマウスポインタの下のパスを取得 Gtk::TreeModel::Path get_path_under_mouse(); // 現在のマウスポインタの下のセルの幅高さとセル内での座標を取得 void get_cell_xy_wh( int& cell_x, int& cell_y, int& cell_w, int& cell_h ); // 選択中の Gtk::TreeModel::iterator のリストを取得 std::list< Gtk::TreeModel::iterator > get_selected_iterators(); // 選択行の削除 virtual void delete_selected_rows( const bool force ); // 選択行の移動 void goto_top(); void goto_bottom(); const bool row_up(); const bool row_down(); void page_up(); void page_down(); // path の前後のpathを取得 Gtk::TreePath prev_path( const Gtk::TreePath& path, bool check_expand = true ); Gtk::TreePath next_path( const Gtk::TreePath& path, bool check_expand = true ); // path -> row 変換 Gtk::TreeModel::Row get_row( const Gtk::TreePath& path ); // pathの親を再起的にexpandする void expand_parents( const Gtk::TreePath& path ); // pathが開かれているか const bool is_expand( const Gtk::TreePath& path ); // 行のセルの高さ int get_row_height(); void set_column_for_height( int column ){ m_column_for_height = column; } protected: virtual bool on_key_press_event( GdkEventKey* event ); virtual bool on_key_release_event( GdkEventKey* event ); virtual bool on_scroll_event( GdkEventScroll* event ); virtual bool on_button_press_event( GdkEventButton* event ); virtual bool on_button_release_event( GdkEventButton* event ); virtual bool on_motion_notify_event( GdkEventMotion* event ); }; } #endif jd-2.8.7-140104/src/skeleton/undobuffer.cpp0000644000076400010400000000551111145022252015042 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "undobuffer.h" using namespace SKELETON; UNDO_BUFFER::UNDO_BUFFER() : m_pos( 0 ), m_max( 0 ), m_first( true ) { m_vec_undo.push_back( UNDO_DATA() ); } void UNDO_BUFFER::set_item( UNDO_ITEM& item ) { #ifdef _DEBUG std::cout << "UNDO_BUFFER::set_item\n"; #endif if( m_first ){ #ifdef _DEBUG std::cout << "reset_data\n"; #endif get_undo_data().clear(); m_first = false; } get_undo_data().push_back( item ); #ifdef _DEBUG std::cout << "size = " << get_undo_data().size() << std::endl; #endif } void UNDO_BUFFER::undo() { if( get_enable_undo() ){ #ifdef _DEBUG std::cout << "UNDO_BUFFER::undo pos = " << m_pos << " max = " << m_max << std::endl; #endif --m_pos; m_first = true; m_sig_undo.emit(); } } void UNDO_BUFFER::redo() { if( get_enable_redo() ){ #ifdef _DEBUG std::cout << "SKELETON::UNDO_BUFFER::redo pos = " << m_pos << " max = " << m_max << std::endl; #endif ++m_pos; m_first = true; m_sig_redo.emit(); } } // // 選択中の行 // void UNDO_BUFFER::set_list_info_selected( const CORE::DATA_INFO_LIST& list_info_selected ) { #ifdef _DEBUG std::cout << "UNDO_BUFFER::set_list_info_selected\n"; #endif UNDO_ITEM item; item.list_info_selected = list_info_selected; set_item( item ); } // // 削除や追加した行 // void UNDO_BUFFER::set_list_info( const CORE::DATA_INFO_LIST& list_info_append, const CORE::DATA_INFO_LIST& list_info_delete ) { #ifdef _DEBUG std::cout << "UNDO_BUFFER::set_list_info pos = " << m_pos << " max = " << m_max << std::endl; #endif UNDO_ITEM item; item.list_info_append = list_info_append; item.list_info_delete = list_info_delete; set_item( item ); } // // 名前を変更した行 // void UNDO_BUFFER::set_name( const Gtk::TreePath& path_renamed, const Glib::ustring& name_new, const Glib::ustring& name_before ) { #ifdef _DEBUG std::cout << "UNDO_BUFFER::set_name pos = " << m_pos << " max = " << m_max << std::endl << "path = " << path_renamed.to_string() << " new = " << name_new << " before = " << name_before << std::endl; #endif UNDO_ITEM item; item.path_renamed = path_renamed; item.name_new = name_new; item.name_before = name_before; set_item( item ); } // // set_* でデータをセットしたら最後にcommitする // void UNDO_BUFFER::commit() { if( m_first ) return; #ifdef _DEBUG std::cout << "UNDO_BUFFER::commit pos = " << m_pos << " max = " << m_pos << std::endl; #endif ++m_pos; m_max = m_pos; if( (int)m_vec_undo.size() == m_pos ) m_vec_undo.push_back( UNDO_DATA() ); m_first = true; m_sig_commit.emit(); #ifdef _DEBUG std::cout << "-> pos = max = " << m_pos << std::endl; #endif } jd-2.8.7-140104/src/skeleton/undobuffer.h0000644000076400010400000000420611125705250014513 0ustar // ライセンス: GPL2 // UNDO用バッファ #include "sharedbuffer.h" #include namespace SKELETON { class UNDO_ITEM { public: CORE::DATA_INFO_LIST list_info_selected; CORE::DATA_INFO_LIST list_info_append; CORE::DATA_INFO_LIST list_info_delete; Gtk::TreePath path_renamed; Glib::ustring name_new; Glib::ustring name_before; UNDO_ITEM() { list_info_selected.clear(); list_info_append.clear(); list_info_delete.clear(); path_renamed = Gtk::TreePath(); name_new = std::string(); name_before = std::string(); } }; typedef std::vector< UNDO_ITEM > UNDO_DATA; typedef sigc::signal< void > SIG_UNDO; typedef sigc::signal< void > SIG_REDO; typedef sigc::signal< void > SIG_COMMIT; class UNDO_BUFFER { std::vector< UNDO_DATA > m_vec_undo; int m_pos; int m_max; bool m_first; SIG_UNDO m_sig_undo; SIG_REDO m_sig_redo; SIG_COMMIT m_sig_commit; public: UNDO_BUFFER(); virtual ~UNDO_BUFFER(){} SIG_UNDO sig_undo(){ return m_sig_undo; } SIG_REDO sig_redo(){ return m_sig_redo; } SIG_COMMIT sig_commit(){ return m_sig_commit; } UNDO_DATA& get_undo_data(){ return m_vec_undo[ m_pos ]; } const bool get_enable_undo() const { return ( m_pos ); } const bool get_enable_redo() const { return ( m_pos < m_max ); } void undo(); void redo(); // 選択中の行 void set_list_info_selected( const CORE::DATA_INFO_LIST& list_info_selected ); // 削除や追加した行 void set_list_info( const CORE::DATA_INFO_LIST& list_info_append, const CORE::DATA_INFO_LIST& list_info_delete ); // 名前を変更した行 void set_name( const Gtk::TreePath& path_renamed, const Glib::ustring& name_new, const Glib::ustring& name_before ); // set_* でデータをセットしたら最後にcommitする void commit(); private: void set_item( UNDO_ITEM& item ); }; } jd-2.8.7-140104/src/skeleton/vbox.cpp0000644000076400010400000000115310561113756013672 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "vbox.h" using namespace SKELETON; JDVBox::JDVBox() : Gtk::VBox() {} JDVBox::~JDVBox() {} // unpack = true の時取り除く void JDVBox::pack_remove_start( bool unpack, Widget& child, Gtk::PackOptions options, guint padding ) { if( unpack ) remove( child ); else pack_start( child, options, padding ); } // unpack = true の時取り除く void JDVBox::pack_remove_end( bool unpack, Widget& child, Gtk::PackOptions options, guint padding ) { if( unpack ) remove( child ); else pack_end( child, options, padding ); } jd-2.8.7-140104/src/skeleton/vbox.h0000644000076400010400000000103710561113756013340 0ustar // ライセンス: GPL2 // // VBoxクラス // #ifndef _VBOX_H #define _VBOX_H #include namespace SKELETON { class JDVBox : public Gtk::VBox { public: JDVBox(); ~JDVBox(); // unpack = true の時取り除く void pack_remove_start( bool unpack, Widget& child, Gtk::PackOptions options = Gtk::PACK_EXPAND_WIDGET, guint padding = 0 ); void pack_remove_end( bool unpack, Widget& child, Gtk::PackOptions options = Gtk::PACK_EXPAND_WIDGET, guint padding = 0 ); }; } #endif jd-2.8.7-140104/src/skeleton/view.cpp0000644000076400010400000001533312125473727013700 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "admin.h" #include "view.h" #include "jdlib/miscutil.h" #include "history/historymanager.h" #include "config/globalconf.h" #include "global.h" #include "session.h" #include "command.h" using namespace SKELETON; View::View( const std::string& url, const std::string& arg1 ,const std::string& arg2 ) : m_url( url ), m_parent_win( NULL ), m_status( std::string() ), m_enable_mg( false ), m_enable_autoreload( false ), m_autoreload_mode( AUTORELOAD_NOT ), m_autoreload_sec( 0 ), m_autoreload_counter( 0 ), m_keyjump_counter( 0 ), m_keyjump_num( 0 ), m_lockable( true ), m_locked( false ), m_writeable( true ), m_id_toolbar( 0 ), m_popup_upside( false ), m_reget( false ) {} const std::string& View::get_url_admin() { return get_admin()->get_url(); } // // url_new に URL を変更 // void View::set_url( const std::string& url_new ) { if( ! m_url.empty() && ! url_new.empty() && m_url != url_new ){ // View履歴のURLを更新 HISTORY::get_history_manager()->replace_url_viewhistory( m_url, url_new ); // ツールバーのURLを更新 get_admin()->set_command( "update_toolbar_url", m_url, url_new ); m_url = url_new; } } // // url 更新 // // 移転があったときなどにadminから呼び出される // void View::update_url( const std::string& url_old, const std::string& url_new ) { if( m_url.find( url_old ) != 0 ) return; std::string url = url_new + m_url.substr( url_old.length() ); #ifdef _DEBUG std::cout << "View::update_url\n"; std::cout << m_url << " -> " << url << std::endl; #endif set_url( url ); } // クロック入力 // clock_in_always()はviewの種類に依らず常に呼び出されるので重い処理を含めてはいけない void View::clock_in_always() { // タブ単位でのオートリロードモード if( m_autoreload_mode == AUTORELOAD_ONCE && inc_autoreload_counter() ) reload(); // キーボード数字入力ジャンプ if( inc_keyjump_counter() ){ goto_num( m_keyjump_num, 0 ); reset_keyjump_counter(); } } // オートリロードのカウンタをインクリメント // 指定秒数を越えたら true を返す bool View::inc_autoreload_counter() { if( m_autoreload_mode == AUTORELOAD_NOT ) return false; ++m_autoreload_counter; if( m_autoreload_counter > m_autoreload_sec * 1000/TIMER_TIMEOUT ){ reset_autoreload_counter(); return true; } return false; } // オートリロードのモードを設定 void View::set_autoreload_mode( int mode, int sec ) { if( ! m_enable_autoreload ) return; if( m_autoreload_mode != AUTORELOAD_NOT && mode != AUTORELOAD_NOT ) return; m_autoreload_mode = mode; m_autoreload_sec = sec; m_autoreload_counter = 0; } // オートリロードのカウンタをリセット void View::reset_autoreload_counter() { m_autoreload_counter = 0; // オートリロードのモードがAUTORELOAD_ONCEの時はオートリロード停止 if( m_autoreload_mode == AUTORELOAD_ONCE ) m_autoreload_mode = AUTORELOAD_NOT; } // 数字入力ジャンプカウンタのインクリメント // 指定秒数を越えたら true を返す bool View::inc_keyjump_counter() { if( ! m_keyjump_counter ) return false; ++m_keyjump_counter; if( m_keyjump_counter > CONFIG::get_numberjmp_msec() / TIMER_TIMEOUT ) return true; return false; } // 数字入力ジャンプカウンタのリセット void View::reset_keyjump_counter() { m_keyjump_counter = 0; m_keyjump_num = 0; } // 数字入力ジャンプ用に sig_key_press() から呼び出す const bool View::release_keyjump_key( int key ) { // キーパッド対応 if( key >= GDK_KP_0 && key <= GDK_KP_9 ) key = key - GDK_KP_0 + GDK_0; if( key >= GDK_0 && key <= GDK_9 ){ m_keyjump_counter = 1; m_keyjump_num *= 10; m_keyjump_num += key - '0'; CORE::core_set_command( "set_info", "", MISC::itostr( m_keyjump_num ) ); return true; } return false; } // view 上にマウスポインタがあれば true const bool View::is_mouse_on_view() { bool ret = false; int x,y; get_pointer( x, y ); if( x < get_width() && x >= 0 && y < get_height() && y >= 0 ) ret = true; #ifdef _DEBUG std::cout << "View::is_mouse_on_view ret = " << ret << " x= " << x << " y= " << y << " w= " << get_width() << " h= " << get_height() << std::endl; #endif return ret; } // ポップアップメニュー表示 void View::show_popupmenu( const std::string& url, bool use_slot ) { // ポップアップメニューを表示する前にメニューのアクティブ状態を切り替える activate_act_before_popupmenu( url ); Gtk::Menu* popupmenu = get_popupmenu( url ); if( popupmenu ){ #ifdef _DEBUG std::cout << "View::show_popupmenu\n"; #endif if( m_url_popup.find( url ) == m_url_popup.end() ){ m_url_popup.insert( url ); popupmenu->signal_map().connect( sigc::mem_fun( *this, &View::slot_map_popupmenu ) ); popupmenu->signal_hide().connect( sigc::mem_fun( *this, &View::slot_hide_popupmenu ) ); } if( use_slot ) popupmenu->popup( sigc::mem_fun( *this, &View::slot_popup_menu_position ), 0, gtk_get_current_event_time() ); else popupmenu->popup( 0, gtk_get_current_event_time() ); } } // ポップアップメニュー表示時に表示位置を決めるスロット void View::slot_popup_menu_position( int& x, int& y, bool& push_in) { // viewの左上の座標をセットする int x2, y2; get_window()->get_position( x, y ); translate_coordinates( *dynamic_cast< Gtk::Widget* >( get_toplevel() ), 0, 0, x2, y2 ); x += x2; y += y2; push_in = false; } // // ポップアップメニューがmapしたときに呼ばれるslot // void View::slot_map_popupmenu() { #ifdef _DEBUG std::cout << "View::slot_map_popupmenu\n"; #endif SESSION::set_popupmenu_shown( true ); } // // ポップアップメニューがhideしたときに呼ばれるslot // void View::slot_hide_popupmenu() { #ifdef _DEBUG std::cout << "View::slot_hide_popupmenu\n"; #endif SESSION::set_popupmenu_shown( false ); // もしviewがポップアップウィンドウ上にあって、かつ // メニューを消したときにマウスポインタが領域外にあれば自分自身をhide if( ! is_mouse_on_view() ) sig_hide_popup().emit(); } // // ラベルやステータスバーの色 // const std::string View::get_color() { if( is_broken() ) return "red"; else if( is_old() ) return "blue"; return ""; } jd-2.8.7-140104/src/skeleton/view.h0000644000076400010400000002772211570441710013340 0ustar // ライセンス: GPL2 #ifndef _VIEW_H #define _VIEW_H #include #include #include #include "control/control.h" namespace SKELETON { class Admin; // 自分がポップアップviewの時に(ポップアップウィンドウ( SKELETON::PopupWin ) 経由で) // 親widgetにhideを依頼するシグナル。PopupWin::PopupWin()でPopupWin::slot_hide_popup()にコネクトされる。 typedef sigc::signal< void > SIG_HIDE_POPUP; // 自分がポップアップviewでリサイズしたときに、明示的にポップアップウィンドウ( SKELETON::PopupWin ) // にリサイズを依頼するシグナル。PopupWin::PopupWin()でPopupWin::slot_resize_popup()にコネクトされる。 typedef sigc::signal< void > SIG_RESIZE_POPUP; class View : public Gtk::VBox { SIG_HIDE_POPUP m_sig_hide_popup; SIG_RESIZE_POPUP m_sig_resize_popup; std::string m_url; Gtk::Window* m_parent_win; // クライアント領域の幅、高さ int m_width_client; int m_height_client; // 入力コントローラ CONTROL::Control m_control; // ポップアップメニュー Glib::RefPtr< Gtk::ActionGroup > m_action_group; Glib::RefPtr< Gtk::UIManager > m_ui_manager; std::set< std::string > m_url_popup; // ツールバーに表示する文字列 std::string m_label; // メインウィンドウのタイトルに表示する文字 std::string m_title; // メインウィンドウのステータスバーに表示する文字 std::string m_status; // true ならマウスジェスチャ使用 bool m_enable_mg; // オートリロード bool m_enable_autoreload; // true ならオートリロード可能(デフォルト:off) int m_autoreload_mode; // モード int m_autoreload_sec; // 何秒おきにリロードするか int m_autoreload_counter; // オートリロード用のカウンタ // キーボード数字入力ジャンプ用 int m_keyjump_counter; int m_keyjump_num; // ロック可能か bool m_lockable; // ロック状態 bool m_locked; // 書き込み可能か bool m_writeable; // ツールバーのID int m_id_toolbar; // 検索文字列 std::string m_search_query; // ポップアップ時に全ての領域を表示できないならカーソルの上に表示 bool m_popup_upside; // ロード時にキャッシュを削除してからviewを再読み込みする bool m_reget; protected: // url_new に URL を変更 void set_url( const std::string& url_new ); // Viewが所属するAdminクラス virtual Admin* get_admin() = 0; // UI Glib::RefPtr< Gtk::ActionGroup >& action_group(){ return m_action_group; } Glib::RefPtr< Gtk::UIManager >& ui_manager(){ return m_ui_manager; } // コントローラ CONTROL::Control& get_control(){ return m_control; } // ツールバーに表示するラベル void set_label( const std::string& label ){ m_label = label; } // メインウィンドウのタイトルに表示する文字列 void set_title( const std::string& title ){ m_title = title; } // メインウィンドウのステータスバーに表示する文字 void set_status( const std::string& status ){ m_status = status; } // マウスジェスチャ void set_enable_mg( bool mg ){ m_enable_mg = mg; } const bool enable_mg() const { return m_enable_mg; } // オートリロードのカウンタをインクリメント // 指定秒数を越えたら true を返す bool inc_autoreload_counter(); // オートリロード可能/不可能切替え void set_enable_autoreload( bool autoreload ){ m_enable_autoreload = autoreload; } // オートリロードのカウンタをリセット void reset_autoreload_counter(); // オートリロード間隔設定 const int get_autoreload_sec() const{ return m_autoreload_sec; } void set_autoreload_sec( const int sec ){ m_autoreload_sec = sec; } // オートリロード用のカウンタ const int get_autoreload_counter() const{ return m_autoreload_counter; } void set_autoreload_counter( const int counter ) { m_autoreload_counter = counter; } // 数字入力ジャンプカウンタのインクリメント // 指定秒数を越えたら true を返す bool inc_keyjump_counter(); // 数字入力ジャンプカウンタのリセット void reset_keyjump_counter(); // 数字入力ジャンプ用に sig_key_press() から呼び出す const bool release_keyjump_key( int key ); // ポップアップメニュー表示 void show_popupmenu( const std::string& url, bool use_slot = false ); // ポップアップメニュー表示時に表示位置を決めるスロット void slot_popup_menu_position( int& x, int& y, bool& push_in ); // ポップアップメニューがmapした時に呼び出されるスロット void slot_map_popupmenu(); // ポップアップメニューがhideした時に呼び出されるスロット void slot_hide_popupmenu(); // ポップアップメニューを表示する前にメニューのアクティブ状態を切り替える virtual void activate_act_before_popupmenu( const std::string& url ){} // ポップアップメニュー取得 virtual Gtk::Menu* get_popupmenu( const std::string& url ){ return NULL; } public: SIG_HIDE_POPUP sig_hide_popup(){ return m_sig_hide_popup; } SIG_RESIZE_POPUP sig_resize_popup(){ return m_sig_resize_popup; } View( const std::string& url, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() ); virtual ~View(){} virtual void save_session() = 0; virtual const std::string& get_url(){ return m_url; } const std::string& get_url_admin(); virtual void set_parent_win( Gtk::Window* parent_win ){ m_parent_win = parent_win; } virtual Gtk::Window* get_parent_win(){ return m_parent_win; } // 移転があったときなどにadminから呼び出される virtual void update_url( const std::string& url_old, const std::string& url_new ); // 検索文字列 const std::string& get_search_query(){ return m_search_query; } // ツールバーのID // タブの切り替えのときに Admin から参照される // コンストラクタであらかじめ指定しておくこと void set_id_toolbar( const int id ) { m_id_toolbar = id; } const int get_id_toolbar() const { return m_id_toolbar; } // ロック/アンロック const bool is_lockable() const { return m_lockable; } void set_lockable( const bool lockable ){ m_lockable = lockable; } const bool is_locked() const { return m_locked; } virtual void lock(){ m_locked = true; } virtual void unlock(){ m_locked = false; } // 書き込み可能/不可能 const bool is_writeable() const { return m_writeable; } void set_writeable( const bool writeable ){ m_writeable = writeable; } // ポップアップ時に全ての領域を表示できないならカーソルの上に表示 const bool get_popup_upside() const { return m_popup_upside; } void set_popup_upside( const bool upside ){ m_popup_upside = upside; } // view 上にマウスポインタがあれば true const bool is_mouse_on_view(); // 各view個別のコマンド virtual const bool set_command( const std::string& command, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() ){ return true; } // コピー用のURL virtual const std::string url_for_copy(){ return m_url; } // ツールバーのラベルに表示する文字列 const std::string& get_label(){ return m_label; } // メインウィンドウのタイトルバーに表示する文字列 virtual const std::string& get_title(){ return m_title; } // メインウィンドウのステータスバーに表示する文字列 virtual const std::string& get_status(){ return m_status; } // クライアント領域の幅、高さ virtual const int width_client(){ return m_width_client; } virtual const int height_client(){ return m_height_client; } void set_width_client( int val ){ m_width_client = val; } void set_height_client( int val ){ m_height_client = val; } // オートリロード可能か const bool get_enable_autoreload() const { return m_enable_autoreload; } // オートリロードのモード設定 void set_autoreload_mode( int mode, int sec ); // 現在のオートリロードのモード取得 const int get_autoreload_mode() const { return m_autoreload_mode; } // ロード時にキャッシュを削除してからviewを再読み込みする const bool get_reget() const{ return m_reget; } void set_reget( const bool reget ){ m_reget = reget; } // アイコンのID取得 virtual const int get_icon( const std::string& iconname ){ return -1; } // ロード中 virtual const bool is_loading(){ return false;} // 更新した virtual const bool is_updated(){ return false;} // 更新チェックして更新可能か virtual const bool is_check_update(){ return false;} // 古いデータか virtual const bool is_old(){ return false;} // 壊れているか virtual const bool is_broken(){ return false; } // ラベルやステータスバーの色 const std::string get_color(); // キーを押した virtual const bool slot_key_press( GdkEventKey* event ){ return false; } // クロック入力 // clock_in()はビューがアクティブのときに呼び出される // clock_in_always()はviewの種類に依らず常に呼び出されるので重い処理を含めてはいけない virtual void clock_in(){}; virtual void clock_in_always(); virtual void write(){} virtual void reload(){} virtual void stop(){} virtual void show_view(){} virtual void redraw_view(){} virtual void redraw_scrollbar(){} virtual void relayout(){} virtual void update_view(){} virtual void update_finish(){} virtual void focus_view(){} virtual void focus_out(){} virtual void close_view(){} virtual void delete_view(){} virtual void set_favorite(){} virtual void update_item( const std::string& url, const std::string& id ){} virtual const bool operate_view( const int ) = 0; virtual void goto_top(){} virtual void goto_bottom(){} virtual void goto_num( const int num_to, const int num_from ){} virtual void scroll_up(){} virtual void scroll_down(){} virtual void scroll_left(){} virtual void scroll_right(){} virtual void show_preference(){} virtual void update_boardname(){} // 進む、戻る virtual void back_viewhistory( const int count ){} virtual void forward_viewhistory( const int count ){} // 検索 virtual void exec_search(){} virtual void up_search(){} virtual void down_search(){} virtual void operate_search( const std::string& controlid ){} virtual void set_search_query( const std::string& query ){ m_search_query = query; } }; } #endif jd-2.8.7-140104/src/skeleton/viewnote.cpp0000644000076400010400000000256711175062541014563 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "dragnote.h" #include "viewnote.h" #include "view.h" #include "config/globalconf.h" #include using namespace SKELETON; ViewNotebook::ViewNotebook( DragableNoteBook* parent ) : Gtk::Notebook(), m_parent( parent ) { set_show_border( true ); set_show_tabs( false ); set_border_width( CONFIG::get_view_margin() ); } // // 描画イベント // // 自前で枠を描画する // bool ViewNotebook::on_expose_event( GdkEventExpose* event ) { if( ! get_n_pages() ) return Notebook::on_expose_event( event ); // 枠描画 m_parent->draw_box( this, event ); // 枠は自前で書いたので gtk_notebook_expose では枠を描画させない GtkNotebook *notebook = gobj(); notebook->show_border = false; bool ret = Notebook::on_expose_event( event ); notebook->show_border = true; return ret; } // // スクロールバー再描画 // // テーマによってはビューのスクロールバーが消えるときがあるので明示的に再描画する // DragableNoteBook::on_expose_event()を参照せよ // void ViewNotebook::redraw_scrollbar() { int page = get_current_page(); if( page == -1 ) return; SKELETON::View* view = dynamic_cast< View* >( get_nth_page( page ) ); if( ! view ) return; view->redraw_scrollbar(); } jd-2.8.7-140104/src/skeleton/viewnote.h0000644000076400010400000000075211045233203014211 0ustar // ライセンス: GPL2 // // DragableNoteBookを構成するview表示用の Notebook // #ifndef _VIEWNOTE_H #define _VIEWNOTE_H #include namespace SKELETON { class DragableNoteBook; class ViewNotebook : public Gtk::Notebook { DragableNoteBook* m_parent; public: ViewNotebook( DragableNoteBook* parent ); void redraw_scrollbar(); protected: virtual bool on_expose_event( GdkEventExpose* event ); }; } #endif jd-2.8.7-140104/src/skeleton/vpaned.cpp0000644000076400010400000000217211571212223014162 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "vpaned.h" using namespace SKELETON; JDVPaned::JDVPaned( const int fixmode ) : Gtk::VPaned(), m_pctrl( *this, fixmode ) {} void JDVPaned::on_realize() { Gtk::VPaned::on_realize(); m_pctrl.update_position(); } bool JDVPaned::on_button_press_event( GdkEventButton* event ) { m_pctrl.button_press_event( event ); return Gtk::VPaned::on_button_press_event( event ); } bool JDVPaned::on_button_release_event( GdkEventButton* event ) { m_pctrl.button_release_event( event ); return Gtk::VPaned::on_button_release_event( event ); } bool JDVPaned::on_motion_notify_event( GdkEventMotion* event ) { m_pctrl.motion_notify_event( event ); return Gtk::VPaned::on_motion_notify_event( event ); } bool JDVPaned::on_enter_notify_event( GdkEventCrossing* event ) { m_pctrl.enter_notify_event( event ); return Gtk::VPaned::on_enter_notify_event( event ); } bool JDVPaned::on_leave_notify_event( GdkEventCrossing* event ) { m_pctrl.leave_notify_event( event ); return Gtk::VPaned::on_leave_notify_event( event ); } jd-2.8.7-140104/src/skeleton/vpaned.h0000644000076400010400000000143011571212223013623 0ustar // ライセンス: GPL2 // // VPanedクラス // #ifndef _VPANED_H #define _VPANED_H #include #include "panecontrol.h" namespace SKELETON { class JDVPaned : public Gtk::VPaned { VPaneControl m_pctrl; public: JDVPaned( const int fixmode ); virtual ~JDVPaned(){} VPaneControl& get_ctrl(){ return m_pctrl; } protected: virtual void on_realize(); virtual bool on_button_press_event( GdkEventButton* event ); virtual bool on_button_release_event( GdkEventButton* event ); virtual bool on_motion_notify_event( GdkEventMotion* event ); virtual bool on_enter_notify_event( GdkEventCrossing* event ); virtual bool on_leave_notify_event( GdkEventCrossing* event ); }; } #endif jd-2.8.7-140104/src/skeleton/window.cpp0000644000076400010400000005337212006761301014224 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "window.h" #include "config/globalconf.h" #include "environment.h" #include "global.h" #include "session.h" #include "dndmanager.h" #include "command.h" #include enum { MGINFO_CHARS = MAX_MG_LNG * 2 + 16, // マウスジェスチャ表示欄の文字数 FOCUSOUT_TIMEOUT = 250, // GNOME環境でフォーカスを外すまでの時間 ( msec ) FOCUS_TIME = 100, // JDWindowにフォーカスを移してウィンドウサイズを復元するまでの時間 ( msec ) UNGRAB_TIME = 100, // ブート直後にフォーカスをメインウィンドウに戻すまでの時間 ( msec ) JDWIN_FOLDSIZE = 10 // 折りたたみ時に指定するウィンドウ高さ }; // ウィンドウ状態 enum { JDWIN_INIT = 0, JDWIN_NORMAL, // 開いている JDWIN_FOLD, // 折り畳んでいる JDWIN_EXPANDING, // 展開中( clock_in() 参照 ) JDWIN_UNMAX, // 最大化 -> 通常 JDWIN_UNMAX_FOLD, // 最大化 -> 折り畳み JDWIN_HIDE, // hide 中 JDWIN_UNGRAB // ブート直後にungrabする( clock_in() 参照 ) }; ////////////////////////////////////////////// using namespace SKELETON; // メッセージウィンドウでは m_mginfo が不要なので need_mginfo = false になる JDWindow::JDWindow( const bool fold_when_focusout, const bool need_mginfo ) : Gtk::Window( Gtk::WINDOW_TOPLEVEL ), m_gtkwidget( NULL ), m_gtkwindow( NULL ), m_grand_parent_class( NULL ), m_win_moved( false ), m_fold_when_focusout( fold_when_focusout ), m_boot( true ), m_enable_fold( m_fold_when_focusout ), m_transient( false ), m_mode( JDWIN_INIT ), m_count_focusout( 0 ), m_dummywin( NULL ), m_scrwin( NULL ), m_vbox_view( NULL ) { // ステータスバー #if GTKMM_CHECK_VERSION(2,5,0) m_label_stat.set_size_request( 0, -1 ); m_label_stat.set_alignment( Gtk::ALIGN_LEFT ); m_label_stat.set_selectable( true ); m_label_stat.set_single_line_mode( true ); m_label_stat_ebox.add( m_label_stat ); m_label_stat_ebox.set_visible_window( false ); m_statbar.pack_start( m_label_stat_ebox ); if( need_mginfo ){ m_mginfo_ebox.add( m_mginfo ); m_mginfo_ebox.set_visible_window( false ); m_statbar.pack_start( m_mginfo_ebox, Gtk::PACK_SHRINK ); } m_mginfo.set_width_chars( MGINFO_CHARS ); m_mginfo.set_alignment( Gtk::ALIGN_LEFT ); #else if( need_mginfo ) m_statbar.pack_start( m_mginfo ); #endif m_statbar.show_all_children(); add( m_vbox ); m_gtkwidget = GTK_WIDGET( gobj() ); m_gtkwindow = GTK_WINDOW( gobj() ); gpointer parent_class = g_type_class_peek_parent( G_OBJECT_GET_CLASS( gobj() ) ); m_grand_parent_class = g_type_class_peek_parent( parent_class ); } JDWindow::~JDWindow() { if( m_dummywin ) delete m_dummywin; if( m_vbox_view ) delete m_vbox_view; if( m_scrwin ) delete m_scrwin; } // windowの初期設定(サイズ変更や移動など) void JDWindow::init_win() { // フォーカスアウトで折り畳む場合 if( m_fold_when_focusout ){ m_scrwin = new Gtk::ScrolledWindow(); m_vbox_view = new SKELETON::JDVBox(); m_scrwin->set_size_request( 0, 0 ); m_scrwin->set_policy( Gtk::POLICY_NEVER, Gtk::POLICY_NEVER ); m_scrwin->add( *m_vbox_view ); m_vbox.pack_remove_end( false, *m_scrwin, Gtk::PACK_EXPAND_WIDGET ); m_dummywin = new Gtk::Window(); m_dummywin->resize( 1, 1 ); m_dummywin->move( -1, -1 ); m_dummywin->hide(); m_dummywin->set_skip_taskbar_hint( true ); set_skip_taskbar_hint( true ); resize( get_width_win(), 1 ); move_win( get_x_win(), get_y_win() ); focus_out(); property_window_position().set_value( Gtk::WIN_POS_NONE ); set_transient( true ); Glib::signal_idle().connect( sigc::mem_fun( *this, &JDWindow::slot_idle ) ); } // 通常のウィンドウ else{ resize( get_width_win(), get_height_win() ); move_win( get_x_win(), get_y_win() ); if( is_maximized_win() ) maximize_win(); property_window_position().set_value( Gtk::WIN_POS_NONE ); set_shown_win( true ); Glib::signal_idle().connect( sigc::mem_fun( *this, &JDWindow::slot_idle ) ); } } bool JDWindow::slot_idle() { // ブート完了 if( m_boot ){ #ifdef _DEBUG std::cout << "----------------\nJDWinow::slot_idle boot end mode = " << m_mode << std::endl; #endif m_boot = false; move_win( get_x_win(), get_y_win() ); if( m_fold_when_focusout ){ // 遅延させて clock_in()の中でフォーカスをメインウィンドウに戻す if( m_mode == JDWIN_FOLD ){ m_mode = JDWIN_UNGRAB; m_counter = 0; } } CORE::core_set_command( "window_boot_fin" ); } return false; } // クロック入力 void JDWindow::clock_in() { // 折りたたみ処理 if( m_fold_when_focusout ){ int waitcount = 0; // 遅延リサイズ( focus_in()にある説明を参照 ) if( m_mode == JDWIN_EXPANDING ){ waitcount = FOCUS_TIME / TIMER_TIMEOUT; ++m_counter; if( m_counter > waitcount && ! ( m_counter % waitcount ) ){ if( get_height() < get_height_win() ) resize( get_width_win(), get_height_win() ); else{ #ifdef _DEBUG std::cout << "JDWindow::clock_in resize\n"; #endif m_mode = JDWIN_NORMAL; set_shown_win( true ); present(); } } } // ブート直後にフォーカスをメインウィンドウに戻す else if( m_mode == JDWIN_UNGRAB ){ ++m_counter; if( m_counter > UNGRAB_TIME / TIMER_TIMEOUT ){ #ifdef _DEBUG std::cout << "JDWindow::clock_in ungrab\n"; #endif // WMによってはフォーカスが外れない時があるのでlower()して // 無理矢理フォーカスを外す set_transient( false ); get_window()->lower(); set_transient( true ); CORE::core_set_command( "restore_focus", "", "present" ); m_mode = JDWIN_FOLD; } } // GNOME環境ではタスクトレイなどで切り替えたときに画像windowがフォーカスされてしまうので // メインウィンドウと画像ウィンドウが同時にフォーカスアウトしたら // 一時的に transient 指定を外す。メインウィンドウがフォーカスインしたときに // Admin::focus_out() で transient 指定を戻す if( ENVIRONMENT::get_wm() == ENVIRONMENT::WM_GNOME && ! SESSION::is_iconified_win_main() // メインウィンドウが最小化しているときに transient を外すとウィンドウが表示されなくなる && ! SESSION::is_focus_win_main() && ! is_focus_win() ){ waitcount = FOCUSOUT_TIMEOUT / TIMER_TIMEOUT; if( m_count_focusout < waitcount ) ++m_count_focusout; if( m_count_focusout == waitcount ){ #ifdef _DEBUG std::cout << "JDWindow::clock_in focus timeout\n"; #endif set_transient( false ); ++m_count_focusout; } } else m_count_focusout = 0; } } void JDWindow::set_spacing( int space ) { m_vbox.set_spacing( space ); } void JDWindow::maximize_win() { set_maximized_win( true ); maximize(); } void JDWindow::unmaximize_win() { set_maximized_win( false ); unmaximize(); } void JDWindow::iconify_win() { set_iconified_win( true ); iconify(); } // // ウィンドウ移動 // void JDWindow::move_win( const int x, const int y ) { if( ! CONFIG::get_manage_winpos() ) return; #ifdef _DEBUG std::cout << "JDWindow::move_win " << "x = " << x << " y = " << y << std::endl; #endif move( x, y ); set_x_win( x ); set_y_win( y ); // compiz 環境などでは move() で指定した座標がズレるので補正する m_win_moved = true; } // // ウィンドウ座標取得 // void JDWindow::set_win_pos() { if( ! get_window() ) return; int x,y; get_window()->get_root_origin( x, y ); #ifdef _DEBUG std::cout << "JDWindow::set_win_pos " << "x = " << x << " / " << get_x_win() << ", y = " << y << " / " << get_y_win() << std::endl; #endif // compiz 環境などでは move() で指定した座標がズレるので補正する if( m_win_moved ){ if( x != get_x_win() || y != get_y_win() ){ // 補正量がmrgを越えたら補正を諦める const int mrg = 64; const int delta_x = x - get_x_win(); const int delta_y = y - get_y_win(); x = get_x_win(); y = get_y_win(); m_win_moved = false; if( abs( delta_x ) <= mrg && abs( delta_y ) <= mrg ){ move( get_x_win() - delta_x, get_y_win() - delta_y ); #ifdef _DEBUG std::cout << "!!! moved x = " << get_x_win() << " y = " << get_y_win() << " dx = " << delta_x << " dy = " << delta_y << std::endl; #endif } } } set_x_win( x ); set_y_win( y ); } // hide 中 const bool JDWindow::is_hide() { return ( m_mode == JDWIN_HIDE ); } void JDWindow::pack_remove_start( bool unpack, Widget& child, Gtk::PackOptions options, guint padding ) { if( m_fold_when_focusout ){ m_vbox_view->pack_remove_start( unpack, child, options, padding ); if( ! unpack ) m_vbox_view->show_all_children(); } else{ m_vbox.pack_remove_start( unpack, child, options, padding ); if( ! unpack ) m_vbox.show_all_children(); } } void JDWindow::pack_remove_end( bool unpack, Widget& child, Gtk::PackOptions options, guint padding ) { if( m_fold_when_focusout ){ m_vbox_view->pack_remove_end( unpack, child, options, padding ); if( ! unpack ) m_vbox_view->show_all_children(); } else{ m_vbox.pack_remove_end( unpack, child, options, padding ); if( ! unpack ) m_vbox.show_all_children(); } } // ステータスバー表示 void JDWindow::set_status( const std::string& stat ) { if( stat == m_status ) return; m_status = stat; #if GTKMM_CHECK_VERSION(2,5,0) m_label_stat.set_text( stat ); m_tooltip.set_tip( m_label_stat_ebox, stat ); #else m_statbar.push( stat ); #endif } // 一時的にステータスバーの表示を変える( マウスオーバーでのURL表示用 ) // // 恒久的に変えてしまうと、マウススオ-バー中に ArticleViewBase では // ないクラスから表示を変更された場合に本来の表示に戻せなくなる。 void JDWindow::set_status_temporary( const std::string& stat ) { if( stat == m_status ) return; #if GTKMM_CHECK_VERSION(2,5,0) m_label_stat.set_text( stat ); #else m_statbar.push( stat ); #endif } // 一時的に変えたステータスバーの表示を戻す void JDWindow::restore_status() { #if GTKMM_CHECK_VERSION(2,5,0) m_label_stat.set_text( m_status ); #else m_statbar.push( m_status ); #endif } // マウスジェスチャ表示 void JDWindow::set_mginfo( const std::string& mginfo ) { if( m_mginfo.is_realized() ) m_mginfo.set_text( mginfo ); } // ステータスの色を変える void JDWindow::set_status_color( const std::string& color ) { #if GTKMM_CHECK_VERSION(2,5,0) #ifdef _DEBUG std::cout << "JDWindow::set_status_color " << color << std::endl; #endif if( color.empty() ){ if( m_label_stat_ebox.get_visible_window() ){ m_label_stat.unset_fg( Gtk::STATE_NORMAL ); m_mginfo.unset_fg( Gtk::STATE_NORMAL ); m_label_stat_ebox.set_visible_window( false ); m_mginfo_ebox.set_visible_window( false ); } } else{ m_label_stat.modify_fg( Gtk::STATE_NORMAL, Gdk::Color( "white" ) ); m_mginfo.modify_fg( Gtk::STATE_NORMAL, Gdk::Color( "white" ) ); m_label_stat_ebox.set_visible_window( true ); m_label_stat_ebox.modify_bg( Gtk::STATE_NORMAL, Gdk::Color( color ) ); m_label_stat_ebox.modify_bg( Gtk::STATE_ACTIVE, Gdk::Color( color ) ); m_mginfo_ebox.set_visible_window( true ); m_mginfo_ebox.modify_bg( Gtk::STATE_NORMAL, Gdk::Color( color ) ); m_mginfo_ebox.modify_bg( Gtk::STATE_ACTIVE, Gdk::Color( color ) ); } #endif } // メインウィンドウに対して transient 設定 void JDWindow::set_transient( bool set ) { if( m_fold_when_focusout ){ #ifdef _DEBUG std::cout << "JDWindow::set_transient set = " << set << " " << m_transient << std::endl; #endif if( set && ! m_transient && CORE::get_mainwindow() ){ set_transient_for( *CORE::get_mainwindow() ); m_transient = true; } // ダミーwindowを使ってtransientを外す else if( ! set && m_transient ){ set_transient_for( *m_dummywin ); m_transient = false; } } } // // ダイアログ表示などでフォーカスが外れてもウインドウを畳まないようにする // void JDWindow::set_enable_fold( bool enable ) { if( m_fold_when_focusout && m_enable_fold != enable ){ #ifdef _DEBUG std::cout << "JDWindow::set_enable_fold " << enable << std::endl; #endif m_enable_fold = enable; // XFCE 環境の場合はここでpresent()しておかないとフォーカスが外れる if( m_mode == JDWIN_NORMAL && m_enable_fold ){ if( ENVIRONMENT::get_wm() == ENVIRONMENT::WM_KDE ) switch_admin(); else present(); } } } // フォーカスイン void JDWindow::focus_in() { // 折りたたみ処理 if( m_fold_when_focusout ){ // メインウィンドウが最小化しているときはメインウィンドウを開く if( SESSION::is_iconified_win_main() ){ m_mode = JDWIN_UNGRAB; m_counter = 0; return; } if( ! m_enable_fold ) return; show(); if( is_iconified_win() ) deiconify(); if( ! is_maximized_win() && get_window() ){ int x, y; get_window()->get_root_origin( x, y ); if( x != get_x_win() || y != get_y_win() ) move_win( get_x_win(), get_y_win() ); } // 開く // // GNOME環境では focus in 動作中に resize() が失敗する時が // あるので、遅延させて clock_in() の中でリサイズとpresentする if( ! is_maximized_win() && m_mode != JDWIN_EXPANDING ){ m_mode = JDWIN_EXPANDING; m_counter = 0; } #ifdef _DEBUG std::cout << "JDWindow::focus_in mode = " << m_mode << " maximized = " << is_maximized_win() << " iconified = " << is_iconified_win() << std::endl; #endif } else{ show(); if( is_iconified_win() ) deiconify(); present(); } } // フォーカスアウト void JDWindow::focus_out() { // 折りたたみ処理 if( m_fold_when_focusout && m_enable_fold ){ // ポップアップメニューを表示しているかD&D中はfocus_outしない if( SESSION::is_popupmenu_shown() ) return; if( CORE::DND_Now_dnd() ) return; // 最大化している時は通常状態に戻しておかないと表示されなくなる if( is_maximized_win() ) unmaximize(); // 折り畳み if( m_mode != JDWIN_FOLD ){ resize( get_width_win(), JDWIN_FOLDSIZE ); m_mode = JDWIN_FOLD; set_shown_win( false ); CORE::core_set_command( "restore_focus" ); } #ifdef _DEBUG std::cout << "JDWindow::focus_out mode = " << m_mode << " maximized = " << is_maximized_win() << " iconified = " << is_iconified_win() << std::endl; #endif } } // フォーカスインイベント bool JDWindow::on_focus_in_event( GdkEventFocus* event ) { set_focus_win( true ); if( ! m_boot ){ // 折りたたみ処理 if( m_fold_when_focusout ){ #ifdef _DEBUG std::cout << "JDWindow::on_focus_in_event\n"; #endif if( m_mode != JDWIN_UNGRAB ) switch_admin(); } } return Gtk::Window::on_focus_in_event( event ); } // フォーカスアウトイベント bool JDWindow::on_focus_out_event( GdkEventFocus* event ) { set_focus_win( false ); if( ! m_boot ){ // 折りたたみ処理 if( m_fold_when_focusout ){ #ifdef _DEBUG std::cout << "JDWindow::on_focus_out_event\n"; #endif focus_out(); } } return Gtk::Window::on_focus_out_event( event ); } // Xボタンを押した bool JDWindow::on_delete_event( GdkEventAny* event ) { #ifdef _DEBUG std::cout << "JDWindow::on_delete_event\n"; #endif // 折りたたみ処理 if( m_fold_when_focusout ){ if( is_maximized_win() ) unmaximize(); else{ // hideする前に座標保存 if( ! is_maximized_win() && ! is_iconified_win() && get_window() ) set_win_pos(); hide(); m_mode = JDWIN_HIDE; set_shown_win( false ); } return true; } return Gtk::Window::on_delete_event( event ); } // 最大、最小化 bool JDWindow::on_window_state_event( GdkEventWindowState* event ) { const bool maximized = event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED; const bool iconified = event->new_window_state & GDK_WINDOW_STATE_ICONIFIED; const bool fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN; #ifdef _DEBUG std::cout << "JDWindow::on_window_state_event : " << "maximized = " << is_maximized_win() << " -> " << maximized << " / iconified = " << is_iconified_win() << " -> " << iconified << " / full = " << is_full_win() << " -> " << fullscreen << std::endl; #endif if( ! m_boot ){ // 通常 -> アイコン化 if( ! is_iconified_win() && iconified ) set_shown_win( false ); // アイコン -> 通常 else if( is_iconified_win() && ! iconified && m_mode != JDWIN_FOLD ) set_shown_win( true ); // 通常 -> 最大化 if( ! is_maximized_win() && maximized ){ m_mode = JDWIN_NORMAL; set_shown_win( true ); } // 最大 -> 折り畳み or 通常 else if( is_maximized_win() && ! maximized ){ // 最大 -> 折り畳み if( m_fold_when_focusout && m_mode == JDWIN_FOLD ) m_mode = JDWIN_UNMAX_FOLD; // 最大 -> 通常 else m_mode = JDWIN_UNMAX; } // 通常 -> 全画面 else if( ! is_full_win() && fullscreen ) set_full_win( true ); // 全画面 -> 通常 else if( is_full_win() && ! fullscreen ) set_full_win( false ); #ifdef _DEBUG std::cout << " mode = " << m_mode << std::endl; #endif } set_maximized_win( maximized ); set_iconified_win( iconified ); return Gtk::Window::on_window_state_event( event ); } // 移動、サイズ変更イベント bool JDWindow::on_configure_event( GdkEventConfigure* event ) { const int mrg = 16; const int width_new = event->width; const int height_new = event->height; int min_height = 0; if( m_scrwin ) min_height = m_vbox.get_height() - m_scrwin->get_height() + mrg; if( ! m_boot ){ #ifdef _DEBUG std::cout << "JDWindow::on_configure_event" << " boot = " << m_boot << " mode = " << m_mode << " x = " << event->x << " y = " << event->y << " w = " << width_new << " h = " << height_new << " min_height = " << min_height << std::endl; #endif // 最大 -> 通常に戻る時はリサイズをキャンセル if( m_mode == JDWIN_UNMAX ) m_mode = JDWIN_NORMAL; else if( m_mode == JDWIN_UNMAX_FOLD ) m_mode = JDWIN_FOLD; // 最大、最小化しているときは除く else if( ! is_maximized_win() && ! is_iconified_win() && ! is_full_win() ){ set_win_pos(); // サイズ変更 if( ( ! m_fold_when_focusout || m_mode == JDWIN_NORMAL || m_mode == JDWIN_FOLD ) && height_new > min_height ) { set_width_win( width_new ); set_height_win( height_new ); } } #ifdef _DEBUG std::cout << "configure fin --> mode = " << m_mode << " show = " << is_shown_win() << " maximized = " << is_maximized_win() << " iconified = " << is_iconified_win() << " x = " << get_x_win() << " y = " << get_y_win() << " w = " << get_width_win() << " height = " << get_height_win() << std::endl; #endif } return Gtk::Window::on_configure_event( event ); } // uimなど、漢字変換モードの途中でctrl+qを押すとキーアクセレータが // 優先されてJDが終了する問題があった。 // // gedit-window.c の gedit_window_key_press_event を見ると // gtk_window_propagate_key_event() を実行した後でキーアクセレータ // の処理をするようにしていたのでJDもそうした。 bool JDWindow::on_key_press_event( GdkEventKey* event ) { if( gtk_window_propagate_key_event( m_gtkwindow, event ) ) return true; if( gtk_window_activate_key( m_gtkwindow, event ) ) return true; #ifdef _DEBUG std::cout << "JDWindow::on_key_press_event key = " << event->keyval << std::endl; std::cout << m_grand_parent_class << " - " << m_gtkwidget << std::endl; #endif return GTK_WIDGET_CLASS( m_grand_parent_class )->key_press_event( m_gtkwidget, event ); } jd-2.8.7-140104/src/skeleton/window.h0000644000076400010400000001062212074575077013702 0ustar // ライセンス: GPL2 // // Window クラス // #ifndef _JDWINDOW_H #define _JDWINDOW_H #include #include "gtkmmversion.h" #include "vbox.h" namespace SKELETON { class JDWindow : public Gtk::Window { GtkWidget* m_gtkwidget; GtkWindow *m_gtkwindow; gpointer m_grand_parent_class; bool m_win_moved; // フォーカスアウト時の折りたたみ処理で用いるメンバ変数 bool m_fold_when_focusout; // フォーカスアウトしたときにウィンドウを畳むか bool m_boot; bool m_enable_fold; // 「一時的に」折りたたみ可能かどうか切り替える bool m_transient; int m_mode; int m_counter; int m_count_focusout; // フォーカス制御用カウンタ Gtk::Window* m_dummywin; // set_transient()で使うダミーwindow SKELETON::JDVBox m_vbox; Gtk::ScrolledWindow* m_scrwin; SKELETON::JDVBox* m_vbox_view; // ステータスバー std::string m_status; #if GTKMM_CHECK_VERSION(2,5,0) Gtk::HBox m_statbar; Gtk::Label m_label_stat; Gtk::EventBox m_label_stat_ebox; Gtk::EventBox m_mginfo_ebox; Gtk::Tooltips m_tooltip; #else Gtk::Statusbar m_statbar; #endif Gtk::Label m_mginfo; public: JDWindow( const bool fold_when_focusout, const bool need_mginfo = true ); virtual ~JDWindow(); Gtk::HBox& get_statbar(){ return m_statbar; } virtual void clock_in(); // 最大、最小化 void maximize_win(); void unmaximize_win(); void iconify_win(); void set_spacing( int space ); // hide 中 const bool is_hide(); // 起動中 const bool is_booting() const { return m_boot; } void pack_remove_start( bool unpack, Widget& child, Gtk::PackOptions options = Gtk::PACK_EXPAND_WIDGET, guint padding = 0 ); void pack_remove_end( bool unpack, Widget& child, Gtk::PackOptions options = Gtk::PACK_EXPAND_WIDGET, guint padding = 0 ); void set_status( const std::string& stat ); void set_status_temporary( const std::string& stat ); void restore_status(); std::string get_status(){ return m_status; } void set_mginfo( const std::string& mginfo ); // ステータスの色を変える void set_status_color( const std::string& color ); // メインウィンドウに対して transient 設定 void set_transient( bool set ); // ダイアログ表示などでフォーカスが外れてもウインドウを畳まないようにする void set_enable_fold( bool enable ); virtual void focus_in(); virtual void focus_out(); protected: SKELETON::JDVBox& get_vbox(){ return m_vbox;} // windowの初期設定(サイズ変更や移動など) void init_win(); virtual void switch_admin(){} virtual const int get_x_win() = 0; virtual const int get_y_win() = 0; virtual void set_x_win( const int x ) = 0; virtual void set_y_win( const int y ) = 0; virtual const int get_width_win() = 0; virtual const int get_height_win() = 0; virtual void set_width_win( const int width ) = 0; virtual void set_height_win( const int height ) = 0; virtual const bool is_focus_win() = 0; virtual void set_focus_win( const bool set ) = 0; virtual const bool is_maximized_win() = 0; virtual void set_maximized_win( const bool set ) = 0; virtual const bool is_iconified_win() = 0; virtual void set_iconified_win( const bool set ) = 0; virtual const bool is_full_win() = 0; virtual void set_full_win( const bool set ) = 0; virtual const bool is_shown_win() = 0; virtual void set_shown_win( const bool set ) = 0; virtual bool on_focus_in_event( GdkEventFocus* event ); virtual bool on_focus_out_event( GdkEventFocus* event ); virtual bool on_delete_event( GdkEventAny* event ); virtual bool on_window_state_event( GdkEventWindowState* event ); virtual bool on_configure_event( GdkEventConfigure* event ); virtual bool on_key_press_event( GdkEventKey* event ); private: bool slot_idle(); void move_win( const int x, const int y ); void set_win_pos(); }; } #endif jd-2.8.7-140104/src/sound/0000755000076400010400000000000012261751612011512 5ustar jd-2.8.7-140104/src/sound/Makefile.am0000644000076400010400000000033212072045132013535 0ustar noinst_LIBRARIES = libsound.a libsound_a_SOURCES = \ playsound.cpp \ soundmanager.cpp noinst_HEADERS = \ playsound.h \ soundmanager.h AM_CXXFLAGS = @GTKMM_CFLAGS@ @ALSA_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/sound/playsound.cpp0000644000076400010400000001241511125640231014227 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "playsound.h" #ifdef USE_ALSA #include "jdlib/miscmsg.h" #include #include using namespace SOUND; Play_Sound::Play_Sound() : m_playing( false ) { #ifdef _DEBUG std::cout << "Play_Sound::Play_Sound\n"; #endif } Play_Sound::~Play_Sound() { #ifdef _DEBUG std::cout << "Play_Sound::~Play_Sound\n"; #endif // デストラクタの中からdispatchを呼ぶと落ちるので dispatch不可にする set_dispatchable( false ); stop(); wait(); } void Play_Sound::stop() { if( ! is_playing() ) return; #ifdef _DEBUG std::cout << "Play_Sound::stop\n"; #endif m_stop = true; wait(); } void Play_Sound::wait() { m_thread.join(); } // // wav 再生スレッド起動 // void Play_Sound::play( const std::string& wavfile ) { if( wavfile.empty() ) return; if( m_thread.is_running() ){ MISC::ERRMSG( "Play_Sound::play : thread has been running" ); return; } m_wavfile = wavfile; m_stop = false; if( ! m_thread.create( ( STARTFUNC ) launcher, ( void * ) this, JDLIB::NODETACH ) ){ MISC::ERRMSG( "Play_Sound::play : could not start thread" ); } else{ m_playing = true; } } // // スレッドのランチャ (static) // void* Play_Sound::launcher( void* dat ) { Play_Sound* ps = ( Play_Sound * ) dat; ps->play_wavfile(); return 0; } // // wav 再生 スレッド // void Play_Sound::play_wavfile() { if( m_wavfile.empty() ) return; #ifdef _DEBUG std::cout << "Play_Sound::play_wavfile file = " << m_wavfile << std::endl; #endif char *buffer = NULL; FILE* fin = NULL; snd_pcm_t *handle = NULL; try{ fin = fopen( m_wavfile.c_str(), "rb" ); if( ! fin ) throw "cannot open " + m_wavfile; // フォーマット取得 size_t filepos = 0; RIFFCHK riffchk; size_t chksize = 8; filepos += fread( &riffchk, 1, chksize, fin ); if( strncmp( riffchk.id, "RIFF", 4 ) != 0 ) throw m_wavfile + " is not a wave file"; WAVEFMTCHK wavefmt; chksize = 28; filepos += fread( &wavefmt, 1, chksize, fin ); if( strncmp( wavefmt.id, "WAVEfmt ", 8 ) != 0 ) throw m_wavfile + " is broken"; if( wavefmt.fmt != 1 ) throw m_wavfile + " is not a PCM format"; // データチャンクまでseek DATACHK datachk; chksize = 8; for(;;){ fseek( fin, filepos, SEEK_SET ); if( ! fread( &datachk, 1, chksize, fin ) ) throw m_wavfile + " is broken"; if( strncmp( datachk.id, "data", 4 ) == 0 ) break; ++filepos; } #ifdef _DEBUG std::cout << "rate = " << wavefmt.rate << std::endl << "chn = " << wavefmt.chn << std::endl << "bit = " << wavefmt.bit << std::endl << "sec = " << (double)datachk.size/wavefmt.average << std::endl; #endif // デバイスオープン const char *device = "default"; int err = snd_pcm_open( &handle, device, SND_PCM_STREAM_PLAYBACK, 0 ); if( err < 0 || ! handle ) throw std::string( "cannot open sound device : " ) + snd_strerror( err ); // パラメータ設定 const int msec = 100; snd_pcm_format_t pcmfm = ( wavefmt.bit == 8 ? SND_PCM_FORMAT_U8 : SND_PCM_FORMAT_S16_LE ); err = snd_pcm_set_params( handle, pcmfm, SND_PCM_ACCESS_RW_INTERLEAVED, wavefmt.chn, wavefmt.rate, 1, // リサンプリングする msec * 1000 // period の秒数( msec * 1000 ) ); if( err < 0 ) throw std::string( "failed to set parameter : " ) + snd_strerror( err ); // バッファのメモリ確保 snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; snd_pcm_get_params( handle, &buffer_size, &period_size ); size_t bufsize = period_size * wavefmt.block; buffer = new char[ bufsize + 64 ]; #ifdef _DEBUG std::cout << "period = " << period_size << ", bufsize = " << bufsize << std::endl; size_t totalsize = 0; #endif while( ! m_stop ){ memset( buffer, 0, bufsize ); size_t readsize = fread( buffer, 1, bufsize , fin ); if( ! readsize ) break; #ifdef _DEBUG totalsize += readsize; std::cout << totalsize << " / " << datachk.size << std::endl; #endif snd_pcm_sframes_t frames = snd_pcm_writei( handle, buffer, readsize / wavefmt.block ); if( frames < 0 ) frames = snd_pcm_recover( handle, frames, 0 ); // レジューム if( frames < 0 || frames < ( snd_pcm_sframes_t ) ( readsize / wavefmt.block ) ) throw std::string( "failed to snd_pcm_write : " ) + snd_strerror( err ); } } catch( const std::string& err ){ MISC::ERRMSG( err ); } if( handle ) snd_pcm_close( handle ); if( fin ) fclose( fin ); if( buffer ) delete[] buffer; #ifdef _DEBUG std::cout << "fin\n"; #endif dispatch(); } // // ディスパッチャのコールバック関数 // void Play_Sound::callback_dispatch() { #ifdef _DEBUG std::cout << "Play_Sound::callback_dispatch\n"; #endif wait(); m_playing = false; } #endif jd-2.8.7-140104/src/sound/playsound.h0000644000076400010400000000301311016050432013663 0ustar // ライセンス: GPL2 // サウンド再生クラス #ifndef _PLAYSOUND_H #define _PLAYSOUND_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef USE_ALSA #include #include "skeleton/dispatchable.h" #include "jdlib/jdthread.h" namespace SOUND { // RIFF ( 8 byte ) struct RIFFCHK { char id[ 4 ]; // = "RIFF" unsigned int size; // 全体サイズ }; // WAVEfmt ( 28 byte ) struct WAVEFMTCHK { char id[ 8 ]; // "WAVEfmt " unsigned int size; // チャンクサイズ unsigned short fmt; // 種類( PCMは1 ) unsigned short chn; unsigned int rate; unsigned int average; // = rate * block ( byte ) unsigned short block; // = chn * bit / 8 ( byte ) unsigned short bit; }; // data ( 8 byte ) struct DATACHK { char id[ 4 ]; // = "data" unsigned int size; // チャンクサイズ = PCMデータサイズ }; class Play_Sound : public SKELETON::Dispatchable { JDLIB::Thread m_thread; std::string m_wavfile; bool m_stop; bool m_playing; public: Play_Sound(); virtual ~Play_Sound(); const bool is_playing() const { return m_playing; } void play( const std::string& wavfile ); void stop(); private: void wait(); static void* launcher( void* ); void play_wavfile(); virtual void callback_dispatch(); }; } #endif #endif jd-2.8.7-140104/src/sound/soundmanager.cpp0000644000076400010400000000405511020521271014671 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "soundmanager.h" #include "cache.h" SOUND::SOUND_Manager* instance_sound_manager = NULL; SOUND::SOUND_Manager* SOUND::get_sound_manager() { #ifdef USE_ALSA if( ! instance_sound_manager ) instance_sound_manager = new SOUND::SOUND_Manager(); assert( instance_sound_manager ); #endif return instance_sound_manager; } void SOUND::delete_sound_manager() { #ifdef USE_ALSA if( instance_sound_manager ) delete instance_sound_manager; instance_sound_manager = NULL; #endif } void SOUND::play( const int sound ) { #ifdef USE_ALSA SOUND::get_sound_manager()->play( sound ); #endif } /////////////////////////////////////////////// #ifdef USE_ALSA using namespace SOUND; SOUND_Manager::SOUND_Manager() { #ifdef _DEBUG std::cout << "SOUND_Manager::SOUND_Manager\n"; #endif for( int i = 0; i < NUM_SOUNDS; ++i ){ std::string path_sound = get_file( i ); bool exist = false; if( CACHE::file_exists( path_sound ) == CACHE::EXIST_FILE ) exist = true; #ifdef _DEBUG std::cout << path_sound << " " << exist << std::endl; #endif m_playable.push_back( exist ); } } SOUND_Manager::~SOUND_Manager() { #ifdef _DEBUG std::cout << "SOUND_Manager::~SOUND_Manager\n"; #endif m_playsound.stop(); } void SOUND_Manager::play( const int sound ) { if( ! m_playable[ sound ] ) return; #ifdef _DEBUG std::cout << "SOUND_Manager::play sound = " << sound << std::endl; #endif std::string path_sound = get_file( sound ); if( ! path_sound.empty() ) m_playsound.play( path_sound ); } std::string SOUND_Manager::get_file( const int sound ) { std::string path_sound = CACHE::path_sound_root(); switch( sound ){ case SOUND_RES: path_sound += "res.wav"; break; case SOUND_NO: path_sound += "no.wav"; break; case SOUND_NEW: path_sound += "new.wav"; break; case SOUND_ERR: path_sound += "err.wav"; break; default: return std::string(); } return path_sound; } #endif jd-2.8.7-140104/src/sound/soundmanager.h0000644000076400010400000000170711016273562014353 0ustar // ライセンス: GPL2 // サウンド管理クラス #ifndef _SOUNDMANAGER_H #define _SOUNDMANAGER_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "playsound.h" #include namespace SOUND { enum{ SOUND_RES = 0, SOUND_NO, SOUND_NEW, SOUND_ERR, NUM_SOUNDS }; #ifdef USE_ALSA class SOUND_Manager { std::vector< bool > m_playable; Play_Sound m_playsound; public: SOUND_Manager(); virtual ~SOUND_Manager(); void play( const int sound ); private: std::string get_file( const int sound ); }; #else class SOUND_Manager { public: SOUND_Manager(){} virtual ~SOUND_Manager(){} }; #endif /////////////////////////////////////// // インターフェース SOUND_Manager* get_sound_manager(); void delete_sound_manager(); void play( const int sound ); } #endif jd-2.8.7-140104/src/type.h0000644000076400010400000000145211350440352011510 0ustar // タイプ #ifndef _TYPE_H #define _TYPE_H enum { // 板のタイプ TYPE_BOARD_2CH = 0, TYPE_BOARD_2CH_COMPATI, // 2ch 互換 TYPE_BOARD_LOCAL, // ローカルファイル TYPE_BOARD_JBBS, // したらば TYPE_BOARD_MACHI, // まち TYPE_BOARD_UNKNOWN, // その他一般的なデータタイプ TYPE_BOARD, TYPE_BOARD_UPDATE, TYPE_THREAD, TYPE_THREAD_UPDATE, TYPE_THREAD_OLD, TYPE_IMAGE, TYPE_DIR, TYPE_DIR_END, // お気に入りの追加の時にサブディレクトリの終了の意味で使う TYPE_COMMENT, TYPE_LINK, TYPE_VBOARD, // お気に入りの仮想板 TYPE_AA, TYPE_HISTITEM, TYPE_USRCMD, TYPE_LINKFILTER, TYPE_SEPARATOR, TYPE_FILE, TYPE_UNKNOWN }; #endif jd-2.8.7-140104/src/updatemanager.cpp0000644000076400010400000001576711350440352013715 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "updatemanager.h" #include "dbtree/interface.h" #include "jdlib/miscutil.h" #include "command.h" #include "global.h" #include CORE::CheckUpdate_Manager* instance_checkupdate_manager = NULL; CORE::CheckUpdate_Manager* CORE::get_checkupdate_manager() { if( ! instance_checkupdate_manager ) instance_checkupdate_manager = new CheckUpdate_Manager(); assert( instance_checkupdate_manager ); return instance_checkupdate_manager; } void CORE::delete_checkupdate_manager() { if( instance_checkupdate_manager ) delete instance_checkupdate_manager; instance_checkupdate_manager = NULL; } /////////////////////////////////////////////// using namespace CORE; CheckUpdate_Manager::CheckUpdate_Manager() : m_running( false ) { m_list_open.clear(); } CheckUpdate_Manager::~CheckUpdate_Manager() { assert( ! m_list_item.size() ); } void CheckUpdate_Manager::run() { if( m_running ){ #ifdef _DEBUG std::cout << "CheckUpdate_Manager::run failed items = " << m_list_item.size() << std::endl; #endif return; } m_total = m_list_item.size(); if( ! m_total ) return; #ifdef _DEBUG std::cout << "CheckUpdate_Manager::run total = " << m_total << std::endl; #endif m_running = true; m_url_checking = std::string(); pop_front(); } void CheckUpdate_Manager::stop() { if( ! m_running ) return; m_list_item.clear(); #ifdef _DEBUG std::cout << "CheckUpdate_Manager::stop running = " << m_url_checking << std::endl; #endif // ArticleBase::slot_load_finished()経由でpop_front()が呼び出されて m_running が false になる DBTREE::article_stop_load( m_url_checking ); } // // 更新チェックする板やスレをセットする // // open == true なら更新チェック終了時に url を開く( url が更新可能状態なら ) // void CheckUpdate_Manager::push_back( const std::string& url, const bool open ) { if( m_running ) return; #ifdef _DEBUG std::cout << "CheckUpdate_Manager::push_back " << " open = " << open << " url = " << url << std::endl; #endif std::list< std::string > urllist; // urlが板のアドレスかスレのアドレスか判断する int num_from, num_to; std::string num_str; const std::string url_dat = DBTREE::url_dat( url, num_from, num_to, num_str ); const std::string url_subject = DBTREE::url_subject( url ); // スレ if( ! url_dat.empty() ){ #ifdef _DEBUG std::cout << "type = dat\n" << DBTREE::article_subject( url ) << std::endl; #endif urllist.push_back( url ); } // 板 else if( ! url_subject.empty() ){ #ifdef _DEBUG std::cout << "type = board\n" << url_subject << std::endl; #endif urllist = DBTREE::board_get_check_update_articles( url ); } else return; if( open ) m_list_open.push_back( url ); if( ! urllist.size() ) return; // リストの先頭にあるスレから更新チェックをしていき、もし更新されていたらグループに属する // 残りのスレの更新チェックをキャンセルする CheckItem item; item.urllist = urllist; m_list_item.push_back( item ); #ifdef _DEBUG std::cout << "size = " << m_list_item.size() << std::endl; std::list< std::string >::const_iterator it = urllist.begin(); for( ; it != urllist.end(); ++it ) std::cout << ( *it ) << std::endl; #endif } // 次のスレをチェック void CheckUpdate_Manager::pop_front() { if( ! m_running ) return; // チェック完了 if( ! m_list_item.size() ){ m_running = false; #ifdef _DEBUG std::cout << "CheckUpdate_Manager::pop_front end size = " << m_list_item.size() << std::endl; #endif // 更新したスレを開く if( m_list_open.size() ){ std::string urls_article = std::string(); std::string urls_board = std::string(); std::list< std::string >::const_iterator it = m_list_open.begin(); for( ; it != m_list_open.end(); ++it ){ const std::string& url = ( *it ); // urlが板のアドレスかスレのアドレスか判断する int num_from, num_to; std::string num_str; const std::string url_dat = DBTREE::url_dat( url, num_from, num_to, num_str ); const std::string url_subject = DBTREE::url_subject( url ); // スレ if( ! url_dat.empty() ){ if( DBTREE::article_status( url ) & STATUS_UPDATE ) urls_article += url + " "; } // 板 else if( ! url_subject.empty() ){ if( DBTREE::board_status( url ) & STATUS_UPDATE ) urls_board += url + " "; } } #ifdef _DEBUG std::cout << "open urls_article = " << urls_article << std::endl; std::cout << "open urls_board = " << urls_board << std::endl; #endif if( ! urls_article.empty() ) CORE::core_set_command( "open_article_list", std::string(), urls_article ); if( ! urls_board.empty() ) CORE::core_set_command( "open_board_list", std::string(), urls_board ); m_list_open.clear(); } CORE::core_set_command( "set_info", "", "更新チェック完了"); } // チェック実行 else{ CORE::core_set_command( "set_info", "", "更新チェック中 (" + MISC::itostr( m_total - m_list_item.size() ) + "/" + MISC::itostr( m_total ) +")" ); // チェックした結果、更新されていたら // グループの残りのスレのチェックをキャンセルして次のグループへ if( ! m_url_checking.empty() && ( DBTREE::article_status( m_url_checking ) & STATUS_UPDATE ) ){ m_list_item.pop_front(); m_url_checking = std::string(); pop_front(); return; } CheckItem& item = m_list_item.front(); if( ! item.urllist.size() ){ // 次のグループへ m_list_item.pop_front(); m_url_checking = std::string(); pop_front(); return; } m_url_checking = item.urllist.front(); item.urllist.pop_front(); #ifdef _DEBUG std::cout << "CheckUpdate_Manager::pop_front download url = " << m_url_checking << " size = " << m_list_item.size() << std::endl; #endif // 更新チェックが終わったらローダからpop_front()がコールバックされる const bool check_update = true; DBTREE::article_download_dat( m_url_checking, check_update ); if( ! DBTREE::article_is_checking_update( m_url_checking ) ){ #ifdef _DEBUG std::cout << "skipped\n"; #endif m_url_checking = std::string(); pop_front(); return; } #ifdef _DEBUG std::cout << "started\n"; #endif } } jd-2.8.7-140104/src/updatemanager.h0000644000076400010400000000252611334022056013346 0ustar // ライセンス: GPL2 // // 更新チェッククラス // // push_back() 更新チェックするスレのグループを指定してからrun()を呼び出すと更新チェックを開始する。 // stop()で停止する。 // #ifndef _UPDATEMANAGER_H #define _UPDATEMANAGER_H #include #include namespace CORE { class CheckItem { public: std::list< std::string > urllist; // 更新チェックするスレのアドレスのリスト CheckItem(){ urllist.clear(); } }; class CheckUpdate_Manager { std::list< CheckItem > m_list_item; std::list< std::string > m_list_open; bool m_running; int m_total; std::string m_url_checking; public: CheckUpdate_Manager(); virtual ~CheckUpdate_Manager(); void run(); void stop(); // 更新チェックする板やスレをセットする // open == true なら更新チェック終了時に url を開く( url が更新可能状態なら ) void push_back( const std::string& url, const bool open ); // 次のスレをチェック void pop_front(); }; /////////////////////////////////////// // インターフェース CheckUpdate_Manager* get_checkupdate_manager(); void delete_checkupdate_manager(); } #endif jd-2.8.7-140104/src/urlreplacemanager.cpp0000644000076400010400000002022412125473343014560 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "urlreplacemanager.h" #include "cache.h" #include "type.h" #include "jdlib/miscutil.h" #include "jdlib/miscmsg.h" CORE::Urlreplace_Manager* instance_urlreplace_manager = NULL; CORE::Urlreplace_Manager* CORE::get_urlreplace_manager() { if( ! instance_urlreplace_manager ) instance_urlreplace_manager = new Urlreplace_Manager(); assert( instance_urlreplace_manager ); return instance_urlreplace_manager; } void CORE::delete_urlreplace_manager() { if( instance_urlreplace_manager ) delete instance_urlreplace_manager; instance_urlreplace_manager = NULL; } /////////////////////////////////////////////// using namespace CORE; #define DEFALUT_CONFIG \ "#\n" \ "# UrlReplace設定ファイル (urlreplace.conf)\n" \ "#\n" \ "# 設定ファイルの書式:\n" \ "# 正規表現<タブ>変換後URL<タブ>リファラURL<タブ>制御文字\n" \ "#\n" \ "# 設定例:\n" \ "# http://www\\.foobar\\.com/(view/|img\\.php\\?id=)([0-9]+) http://www.foobar.com/view/$2 $0 $IMAGE\n" \ "#\n" \ "# 詳細な書式はマニュアルを参照してください。\n" \ "# この機能を無効にする場合は、このファイルの内容を空にして保存してください。\n" \ "#\n" \ "http://www\\.youtube\\.com/watch\\?(|[^#]+&)v=([^&#/]+) http://img.youtube.com/vi/$2/0.jpg\n" \ "http://youtu\\.be/([^#&=/]+) http://img.youtube.com/vi/$1/0.jpg\n" \ "http://img\\.youtube\\.com/vi/[^/]+/0.jpg $0 $THUMBNAIL\n" \ "\n" Urlreplace_Manager::Urlreplace_Manager() { std::string conf; const std::string path = CACHE::path_urlreplace(); if( CACHE::load_rawdata( path, conf ) ){ conf2list( conf ); } else { // 読み込みエラー、または空ファイル if( CACHE::file_exists( path ) == CACHE::EXIST_ERROR ){ // ファイルが存在しないとき、デフォルト設定ファイルを作成する conf = DEFALUT_CONFIG; if( CACHE::save_rawdata( path, conf ) ){ conf2list( conf ); } } } } // // conf -> リスト // void Urlreplace_Manager::conf2list( const std::string& conf ) { m_list_cmd.clear(); if( conf.empty() ) return; std::list< std::string > lines = MISC::get_lines( conf ); if( lines.size() == 0 ) return; std::list < std::string >::iterator it = lines.begin(); for( ; it != lines.end(); ++it ){ if( (*it).length() <= 0 ) continue; if( (*it)[0] == '#' ) continue; // コメント行 std::list< std::string > line = MISC::StringTokenizer( *it, '\t' ); if( line.size() < 2 ) continue; UrlreplaceItem item; std::string ctrl; std::list < std::string >::iterator str = line.begin(); // 1: 検索URL item.match = *str; // 2: 置換URL item.replace = *(++str); // 3: リファラURL item.referer.clear(); if( (++str) != line.end() ) item.referer = *str; // 4: コントロール item.imgctrl = IMGCTRL_NONE; item.match_break = false; if( (++str) != line.end() ){ ctrl = *str; int imgctrl = IMGCTRL_INIT; // 拡張子がない場合でも画像として扱う if( ctrl.find( "$IMAGE" ) != std::string::npos ){ imgctrl += IMGCTRL_FORCEIMAGE; } // 拡張子があっても画像として扱わない else if( ctrl.find( "$BROWSER" ) != std::string::npos ){ imgctrl += IMGCTRL_FORCEBROWSER; // $IMAGEを優先 } // 拡張子の偽装をチェックしない if( ctrl.find( "$GENUINE" ) != std::string::npos ){ imgctrl += IMGCTRL_GENUINE; } // サムネイル画像 if( ctrl.find( "$THUMBNAIL" ) != std::string::npos ){ imgctrl += IMGCTRL_THUMBNAIL; } if( imgctrl != IMGCTRL_INIT ) item.imgctrl = imgctrl; // 正規表現に一致したら以降の判定を行わない item.match_break = ( ctrl.find( "$BREAK" ) != std::string::npos ); } if( ! item.match.empty() && ! item.replace.empty() ) m_list_cmd.push_back( item ); } } // // URLを任意の正規表現で変換する // const bool Urlreplace_Manager::exec( std::string &url ) { if( m_list_cmd.empty() ) return false; JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; // いずれかの正規表現に一致するか bool matched = false; std::list< UrlreplaceItem >::iterator it = m_list_cmd.begin(); for( ; it != m_list_cmd.end(); ++it ){ if( regex.exec( (*it).match, url, offset, icase, newline, usemigemo, wchar ) ){ matched = true; // 置換URLの変換 url = (*it).replace; replace( regex, url ); // URLが空になったか、以降の判定を行わない if( url.empty() || (*it).match_break ) break; } } return matched; } // // URLからリファラを求める // const bool Urlreplace_Manager::referer( const std::string &url, std::string &referer ) { if( m_list_cmd.empty() ) return false; referer = url; JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; // いずれかの正規表現に一致するか bool matched = false; std::list< UrlreplaceItem >::iterator it = m_list_cmd.begin(); for( ; it != m_list_cmd.end(); ++it ){ if( regex.exec( (*it).match, referer, offset, icase, newline, usemigemo, wchar ) ){ matched = true; // リファラURLの変換 referer = (*it).referer; replace( regex, referer ); // URLが空になったか、以降の判定を行わない if( referer.empty() || (*it).match_break ) break; } } return matched; } // // URLの画像コントロールを取得する (URLキャッシュ) // const int Urlreplace_Manager::get_imgctrl( const std::string &url ) { if( m_list_cmd.empty() ) return IMGCTRL_NONE; // 取得済みのURLか std::map< std::string, int >::iterator it = m_map_imgctrl.find( url ); if( it != m_map_imgctrl.end() ) return ( *it ).second; // 新たに取得してキャッシュする int imgctrl = get_imgctrl_impl( url ); m_map_imgctrl.insert( make_pair( url, imgctrl ) ); return imgctrl; } // // URLの画像コントロールを取得する // const int Urlreplace_Manager::get_imgctrl_impl( const std::string &url ) { int imgctrl = IMGCTRL_NONE; JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; // いずれかの正規表現に一致するか std::list< UrlreplaceItem >::iterator it = m_list_cmd.begin(); for( ; it != m_list_cmd.end(); ++it ){ if( regex.exec( (*it).match, url, offset, icase, newline, usemigemo, wchar ) ){ // 画像コントロールを取得 imgctrl = (*it).imgctrl; // 以降の判定を行わない if( (*it).match_break ) break; } } return imgctrl; } // // 置換文字列を変換 // \0 ... \9 ( $0 ... $9 ) : 正規表現の部分一致 // void Urlreplace_Manager::replace( JDLIB::Regex ®ex, std::string &str ) { if( str.empty() ) return; char rep1[] = "\\0"; char rep2[] = "$0"; for( int i = 0; i < 9; i++ ){ if( regex.pos( i ) == -1 ){ break; } rep1[ 1 ] = '0' + i; if( str.find( rep1 ) != std::string::npos ){ str = MISC::replace_str( str, rep1, regex.str( i ) ); } rep2[ 1 ] = '0' + i; if( str.find( rep2 ) != std::string::npos ){ str = MISC::replace_str( str, rep2, regex.str( i ) ); } } } jd-2.8.7-140104/src/urlreplacemanager.h0000644000076400010400000000304512125473343014227 0ustar // ライセンス: GPL2 #ifndef _URLREPLACEMANAGER_H #define _URLREPLACEMANAGER_H #include #include #include #include "jdlib/jdregex.h" namespace CORE { enum { IMGCTRL_INIT = 0, IMGCTRL_NONE = 1, IMGCTRL_FORCEIMAGE = 2, IMGCTRL_FORCEBROWSER = 4, IMGCTRL_GENUINE = 8, IMGCTRL_THUMBNAIL = 16, }; struct UrlreplaceItem { std::string match; std::string replace; std::string referer; int imgctrl; bool match_break; }; class Urlreplace_Manager { std::list< UrlreplaceItem > m_list_cmd; std::map< std::string, int > m_map_imgctrl; // 画像コントロールのキャッシュ public: Urlreplace_Manager(); virtual ~Urlreplace_Manager(){} // URLを任意の正規表現で変換する const bool exec( std::string &url ); // URLからリファラを求める const bool referer( const std::string &url, std::string &referer ); // URLの画像コントロールを取得する const int get_imgctrl( const std::string &url ); private: void conf2list( const std::string& conf ); const int get_imgctrl_impl( const std::string &url ); // 置換文字列を変換 void replace( JDLIB::Regex ®ex, std::string &str ); }; /////////////////////////////////////// // インターフェース Urlreplace_Manager* get_urlreplace_manager(); void delete_urlreplace_manager(); } #endif jd-2.8.7-140104/src/usrcmdmanager.cpp0000644000076400010400000004570612006761301013723 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "gtkmmversion.h" #include "usrcmdmanager.h" #include "command.h" #include "cache.h" #include "type.h" #include "skeleton/msgdiag.h" #include "skeleton/prefdiag.h" #include "xml/tools.h" #include "jdlib/miscutil.h" #include "jdlib/jdregex.h" #include "dbtree/interface.h" #include "dbimg/imginterface.h" #include "config/globalconf.h" CORE::Usrcmd_Manager* instance_usrcmd_manager = NULL; CORE::Usrcmd_Manager* CORE::get_usrcmd_manager() { if( ! instance_usrcmd_manager ) instance_usrcmd_manager = new Usrcmd_Manager(); assert( instance_usrcmd_manager ); return instance_usrcmd_manager; } void CORE::delete_usrcmd_manager() { if( instance_usrcmd_manager ) delete instance_usrcmd_manager; instance_usrcmd_manager = NULL; } /////////////////////////////////////////////// class ReplaceTextDiag : public SKELETON::PrefDiag { Gtk::VBox m_vbox; Gtk::Entry m_entry; Gtk::Label m_label; public: ReplaceTextDiag( Gtk::Window* parent, const std::string& title ) : SKELETON::PrefDiag( parent, "" ), m_label( title + "を置き換えるテキストを入力してください。" ) { resize( 640, 1 ); m_vbox.pack_start( m_label, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_entry, Gtk::PACK_SHRINK ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_vbox ); set_title( "テキスト入力" ); show_all_children(); } const Glib::ustring get_text() { return m_entry.get_text(); } }; /////////////////////////////////////////////// using namespace CORE; Usrcmd_Manager::Usrcmd_Manager() { std::string xml; if( CACHE::load_rawdata( CACHE::path_usrcmd(), xml ) ) m_document.init( xml ); else txt2xml(); analyze_xml(); } // // 旧式の設定ファイル(テキスト形式)をxmlに変換する // void Usrcmd_Manager::txt2xml() { m_document.clear(); // 旧設定ファイルからユーザーコマンドを読み込み const std::string file_usrcmd = CACHE::path_usrcmd_old(); std::string usrcmd; if( CACHE::load_rawdata( file_usrcmd, usrcmd ) ){ XML::Dom* root = m_document.appendChild( XML::NODE_TYPE_ELEMENT, std::string( ROOT_NODE_NAME_USRCMD ) ); XML::Dom* subdir = root; std::list< std::string > list_usrcmd = MISC::get_lines( usrcmd ); list_usrcmd = MISC::remove_commentline_from_list( list_usrcmd ); list_usrcmd = MISC::remove_space_from_list( list_usrcmd ); list_usrcmd = MISC::remove_nullline_from_list( list_usrcmd ); // ユーザコマンドが 3つ以上 (廃止した max_show_usrcmd 設定の初期値 )より // 大きい場合はサブディレクトリ化する if( list_usrcmd.size() >= 3 * 2 ){ subdir = root->appendChild( XML::NODE_TYPE_ELEMENT, XML::get_name( TYPE_DIR ) ); subdir->setAttribute( "name", "ユーザコマンド" ); subdir->setAttribute( "open", "y" ); } std::list< std::string >::iterator it; for( it = list_usrcmd.begin(); it != list_usrcmd.end(); ++it ){ const std::string name = *( it++ ); if( it == list_usrcmd.end() ) break; const std::string cmd = *it; XML::Dom* usrcmd = subdir->appendChild( XML::NODE_TYPE_ELEMENT, XML::get_name( TYPE_USRCMD ) ); usrcmd->setAttribute( "name", name ); usrcmd->setAttribute( "data", cmd ); } #ifdef _DEBUG std::cout << "Usrcmd_Manager::txt2xml\n"; std::cout << "nodes = " << m_document.childNodes().size() << std::endl; std::cout << m_document.get_xml() << std::endl; #endif save_xml(); } } // // XML に含まれるコマンド情報を取り出してデータベースを更新 // void Usrcmd_Manager::analyze_xml() { #ifdef _DEBUG std::cout << "Usrcmd_Manager::analyze_xml\n"; #endif m_list_cmd.clear(); XML::DomList usrcmds = m_document.getElementsByTagName( XML::get_name( TYPE_USRCMD ) ); std::list< XML::Dom* >::iterator it = usrcmds.begin(); while( it != usrcmds.end() ) { const std::string cmd = (*it)->getAttribute( "data" ); #ifdef _DEBUG const std::string name = (*it)->getAttribute( "name" ); std::cout << (*it)->nodeName() << " " << name << " " << cmd << std::endl; #endif set_cmd( cmd ); ++it; } m_size = m_list_cmd.size(); } void Usrcmd_Manager::set_cmd( const std::string& cmd ) { std::string cmd2 = MISC::remove_space( cmd ); m_list_cmd.push_back( cmd2 ); #ifdef _DEBUG std::cout << "Usrcmd_Manager::set_cmd "; std::cout << "[" << m_list_cmd.size()-1 << "] " << cmd2 << std::endl; #endif } // // XML 保存 // void Usrcmd_Manager::save_xml() { #ifdef _DEBUG std::cout << "Usrcmd_Manager::save_xml\n"; std::cout << m_document.get_xml() << std::endl; #endif CACHE::save_rawdata( CACHE::path_usrcmd(), m_document.get_xml() ); } // // 実行 // void Usrcmd_Manager::exec( const int comnum, // コマンド番号 const std::string& url, const std::string& link, const std::string& selection, // 選択文字 const int number // レス番号 ) { if( comnum >= m_size ) return; exec( m_list_cmd[ comnum ], url, link, selection, number ); } void Usrcmd_Manager::exec( const std::string command, // コマンド const std::string& url, const std::string& link, const std::string& selection, // 選択文字 const int number // レス番号 ) { std::string cmd = command; if( cmd.find( "$ONLY" ) != std::string::npos ){ std::list< std::string > lines = MISC::split_line( cmd ); if( lines.size() >= 2 ){ std::list< std::string >::iterator it = lines.begin(); ++it; ++it; cmd = *it; ++it; for( ; it != lines.end(); ++it ) cmd += " " + ( *it ); } } #ifdef _DEBUG std::cout << "Usrcmd_Manager::exec\n" << "command = " << cmd << std::endl << "url = " << url << std::endl << "link = " << link << std::endl << "selection = " << selection << std::endl << "number = " << number << std::endl; #endif bool use_browser = false; if( cmd.find( "$VIEW" ) == 0 ){ use_browser = true; cmd = cmd.substr( 5 ); cmd = MISC::remove_space( cmd ); } bool show_dialog = false; if( cmd.find( "$DIALOG" ) == 0 ){ show_dialog = true; cmd = cmd.substr( 7 ); cmd = MISC::remove_space( cmd ); } cmd = replace_cmd( cmd, url, link, selection, number ); #ifdef _DEBUG std::cout << "exec " << cmd << std::endl; #endif if( cmd.empty() ) return; if( use_browser ) CORE::core_set_command( "open_url_browser", cmd ); else if( show_dialog ){ SKELETON::MsgDiag mdiag( NULL, cmd ); mdiag.run(); } else Glib::spawn_command_line_async( cmd ); } // // 文字列置換用テキストダイアログ表示 // const bool Usrcmd_Manager::show_replacetextdiag( std::string& texti, const std::string& title ) { if( ! texti.empty() ) return true; ReplaceTextDiag textdiag( NULL, title ); if( textdiag.run() != Gtk::RESPONSE_OK ) return false; texti = textdiag.get_text(); return true; } // コマンド置換 // cmdの$URLをurl, $LINKをlink, $TEXT*をtext, $NUMBERをnumberで置き換えて出力 // text は UTF-8 であること const std::string Usrcmd_Manager::replace_cmd( const std::string& cmd, const std::string& url, const std::string& link, const std::string& text, const int number ) { std::string cmd_out = cmd; const std::string oldhostl = DBTREE::article_org_host( link ); const std::string oldhost = DBTREE::article_org_host( url ); cmd_out = MISC::replace_str( cmd_out, "$URL", DBTREE::url_readcgi( url, 0, 0 ) ); cmd_out = MISC::replace_str( cmd_out, "$DATURL", DBTREE::url_dat( url ) ); cmd_out = MISC::replace_str( cmd_out, "$LOGPATH", CACHE::path_root() ); cmd_out = MISC::replace_str( cmd_out, "$LOCALDATL", CACHE::path_dat( link ) ); cmd_out = MISC::replace_str( cmd_out, "$LOCALDAT", CACHE::path_dat( url ) ); cmd_out = MISC::replace_str( cmd_out, "$LINK", link ); cmd_out = MISC::replace_str( cmd_out, "$NUMBER", MISC::itostr( number ) ); if( cmd_out.find( "$CACHEDIMG" ) != std::string::npos ){ cmd_out = MISC::replace_str( cmd_out, "$CACHEDIMG", DBIMG::get_cache_path( link ) ); } // ホスト名(http://含む) cmd_out = MISC::replace_str( cmd_out, "$SERVERL", MISC::get_hostname( link ) ); cmd_out = MISC::replace_str( cmd_out, "$SERVER", MISC::get_hostname( url ) ); // ホスト名(http://含まない) cmd_out = MISC::replace_str( cmd_out, "$OLDHOSTNAMEL", MISC::get_hostname( oldhostl, false ) ); cmd_out = MISC::replace_str( cmd_out, "$OLDHOSTNAME", MISC::get_hostname( oldhost, false ) ); cmd_out = MISC::replace_str( cmd_out, "$OLDHOSTL", MISC::get_hostname( oldhostl, false ) ); cmd_out = MISC::replace_str( cmd_out, "$OLDHOST", MISC::get_hostname( oldhost, false ) ); cmd_out = MISC::replace_str( cmd_out, "$HOSTNAMEL", MISC::get_hostname( link, false ) ); cmd_out = MISC::replace_str( cmd_out, "$HOSTNAME", MISC::get_hostname( url, false ) ); cmd_out = MISC::replace_str( cmd_out, "$HOSTL", MISC::get_hostname( link, false ) ); cmd_out = MISC::replace_str( cmd_out, "$HOST", MISC::get_hostname( url, false ) ); // スレが属する板のID cmd_out = MISC::replace_str( cmd_out, "$BBSNAMEL", DBTREE::board_id( link ) ); cmd_out = MISC::replace_str( cmd_out, "$BBSNAME", DBTREE::board_id( url ) ); // スレのID cmd_out = MISC::replace_str( cmd_out, "$DATNAMEL", DBTREE::article_key( link ) ); cmd_out = MISC::replace_str( cmd_out, "$DATNAME", DBTREE::article_key( url ) ); cmd_out = MISC::replace_str( cmd_out, "$TITLE", DBTREE::article_subject( url ) ); cmd_out = MISC::replace_str( cmd_out, "$BOARDNAME", DBTREE::board_name( url ) ); std::string texti = text; if( cmd_out.find( "$TEXTIU" ) != std::string::npos ){ if( ! show_replacetextdiag( texti, "$TEXTIU" ) ) return std::string(); cmd_out = MISC::replace_str( cmd_out, "$TEXTIU", MISC::charset_url_encode_split( texti, "UTF-8" ) ); } if( cmd_out.find( "$TEXTU" ) != std::string::npos ){ cmd_out = MISC::replace_str( cmd_out, "$TEXTU", MISC::charset_url_encode_split( texti, "UTF-8" ) ); } if( cmd_out.find( "$TEXTIX" ) != std::string::npos ){ if( ! show_replacetextdiag( texti, "$TEXTIX" ) ) return std::string(); cmd_out = MISC::replace_str( cmd_out, "$TEXTIX", MISC::charset_url_encode_split( texti, "EUC-JP" ) ); } if( cmd_out.find( "$TEXTX" ) != std::string::npos ){ cmd_out = MISC::replace_str( cmd_out, "$TEXTX", MISC::charset_url_encode_split( texti, "EUC-JP" ) ); } if( cmd_out.find( "$TEXTIE" ) != std::string::npos ){ if( ! show_replacetextdiag( texti, "$TEXTIE" ) ) return std::string(); cmd_out = MISC::replace_str( cmd_out, "$TEXTIE", MISC::charset_url_encode_split( texti, "MS932" ) ); } if( cmd_out.find( "$TEXTE" ) != std::string::npos ){ cmd_out = MISC::replace_str( cmd_out, "$TEXTE", MISC::charset_url_encode_split( texti, "MS932" ) ); } if( cmd_out.find( "$TEXTI" ) != std::string::npos ){ if( ! show_replacetextdiag( texti, "$TEXTI" ) ) return std::string(); cmd_out = MISC::replace_str( cmd_out, "$TEXTI", texti ); } if( cmd_out.find( "$TEXT" ) != std::string::npos ){ cmd_out = MISC::replace_str( cmd_out, "$TEXT", texti ); } std::string input; if( cmd_out.find( "$INPUTU" ) != std::string::npos ){ if( ! show_replacetextdiag( input, "$INPUTU" ) ) return std::string(); cmd_out = MISC::replace_str( cmd_out, "$INPUTU", MISC::charset_url_encode_split( input, "UTF-8" ) ); } if( cmd_out.find( "$INPUTX" ) != std::string::npos ){ if( ! show_replacetextdiag( input, "$INPUTX" ) ) return std::string(); cmd_out = MISC::replace_str( cmd_out, "$INPUTX", MISC::charset_url_encode_split( input, "EUC-JP" ) ); } if( cmd_out.find( "$INPUTE" ) != std::string::npos ){ if( ! show_replacetextdiag( input, "$INPUTE" ) ) return std::string(); cmd_out = MISC::replace_str( cmd_out, "$INPUTE", MISC::charset_url_encode_split( input, "MS932" ) ); } if( cmd_out.find( "$INPUT" ) != std::string::npos ){ if( ! show_replacetextdiag( input, "$INPUT" ) ) return std::string(); cmd_out = MISC::replace_str( cmd_out, "$INPUT", input ); } #ifdef _DEBUG std::cout << "Usrcmd_Manager::replace_cmd\n"; std::cout << "cmd = " << cmd << std::endl; std::cout << "out = " << cmd_out << std::endl; #endif return cmd_out; } // // メニューをアクティブにするか // const bool Usrcmd_Manager::is_sensitive( int num, const std::string& link, const std::string& selection ) { const unsigned int max_selection_str = 1024; if( num >= m_size ) return false; const std::string cmd = m_list_cmd[ num ]; if( cmd.find( "$LINK" ) != std::string::npos || cmd.find( "$SERVERL" ) != std::string::npos || cmd.find( "$HOSTNAMEL" ) != std::string::npos || cmd.find( "$HOSTL" ) != std::string::npos || cmd.find( "$OLDHOSTNAMEL" ) != std::string::npos || cmd.find( "$OLDHOSTL" ) != std::string::npos || cmd.find( "$BBSNAMEL" ) != std::string::npos || cmd.find( "$DATNAMEL" ) != std::string::npos || cmd.find( "$LOCALDATL" ) != std::string::npos ){ if( link.empty() ) return false; } if( cmd.find( "$TEXT" ) != std::string::npos && cmd.find( "$TEXTI" ) == std::string::npos ){ if( selection.empty() || selection.length() > max_selection_str ) return false; } if( cmd.find( "$CACHEDIMG" ) != std::string::npos ){ if( link.empty() ) return false; if( DBIMG::get_type_ext( link ) == DBIMG::T_UNKNOWN ) return false; if( ! DBIMG::is_cached( link ) ) return false; } return true; } // // メニューを隠すか // const bool Usrcmd_Manager::is_hide( int num, const std::string& url ) { if( num >= m_size ) return false; const std::string cmd = m_list_cmd[ num ]; #ifdef _DEBUG std::cout << "Usrcmd_manager::is_hide cmd = " << cmd << std::endl << "url = " << url << std::endl; #endif if( cmd.find( "$ONLY" ) != std::string::npos ){ std::list< std::string > lines = MISC::split_line( cmd ); if( lines.size() >= 2 ){ JDLIB::Regex regex; const size_t offset = 0; const bool icase = false; const bool newline = true; const bool usemigemo = false; const bool wchar = false; std::list< std::string >::iterator it = lines.begin(); ++it; const std::string query = *it; #ifdef _DEBUG std::cout << "query = " << query << std::endl; #endif if( ! regex.exec( query, url, offset, icase, newline, usemigemo, wchar ) ) return true; } } return false; } // // ユーザコマンドの登録とメニュー作成 // const std::string Usrcmd_Manager::create_usrcmd_menu( Glib::RefPtr< Gtk::ActionGroup >& action_group ) { int dirno = 0; int cmdno = 0; return create_usrcmd_menu( action_group, &m_document, dirno, cmdno ); } // ユーザコマンドの登録とメニュー作成(再帰用) const std::string Usrcmd_Manager::create_usrcmd_menu( Glib::RefPtr< Gtk::ActionGroup >& action_group, XML::Dom* dom, int& dirno, int& cmdno ) { std::string menu; if( ! dom ) return menu; XML::DomList domlist = dom->childNodes(); std::list< XML::Dom* >::iterator it = domlist.begin(); while( it != domlist.end() ) { if( (*it)->nodeType() == XML::NODE_TYPE_ELEMENT ) { #ifdef _DEBUG std::cout << "name = " << (*it)->nodeName() << std::endl; #endif const int type = XML::get_type( (*it)->nodeName() ); if( type == TYPE_DIR ){ const std::string name = (*it)->getAttribute( "name" ); #ifdef _DEBUG std::cout << "[" << dirno << "] " << name << std::endl; #endif const std::string dirname = "usrcmd_dir" + MISC::itostr( dirno ); action_group->add( Gtk::Action::create( dirname, name ) ); ++dirno; menu += ""; menu += create_usrcmd_menu( action_group, *it, dirno, cmdno ); menu += ""; } else if( type == TYPE_SEPARATOR ){ menu += ""; } else if( type == TYPE_USRCMD ){ const std::string name = (*it)->getAttribute( "name" ); #ifdef _DEBUG std::cout << "[" << cmdno << "] " << name << std::endl; #endif const std::string cmdname = "usrcmd" + MISC::itostr( cmdno ); action_group->add( Gtk::Action::create( cmdname, name ) ); ++cmdno; menu += ""; } else if( (*it)->hasChildNodes() ) menu += create_usrcmd_menu( action_group, *it, dirno, cmdno ); } ++it; } return menu; } Glib::RefPtr< Gtk::Action > Usrcmd_Manager::get_action( Glib::RefPtr< Gtk::ActionGroup >& action_group, const int num ) { const std::string str_cmd = "usrcmd" + MISC::itostr( num ); return action_group->get_action( str_cmd ); } // // 選択不可かどうか判断して visible や sensitive を切り替える // void Usrcmd_Manager::toggle_sensitive( Glib::RefPtr< Gtk::ActionGroup >& action_group, const std::string& url_article, const std::string& url_link, const std::string& str_select ) { for( int i = 0; i < m_size; ++i ){ Glib::RefPtr< Gtk::Action > act = get_action( action_group, i ); if( act ){ #if GTKMM_CHECK_VERSION(2,6,0) if( is_hide( i, url_article ) ) act->set_visible( false ); else{ act->set_visible( true ); if( is_sensitive( i, url_link, str_select ) ) act->set_sensitive( true ); else{ act->set_sensitive( false ); if( CONFIG::get_hide_usrcmd() ) act->set_visible( false ); } } #else if( is_sensitive( i, url_link, str_select ) ) act->set_sensitive( true ); else act->set_sensitive( false ); #endif } } } jd-2.8.7-140104/src/usrcmdmanager.h0000644000076400010400000000572311451767556013410 0ustar // ライセンス: GPL2 // // ユーザーコマンドの管理クラス // #ifndef _USRCMDMANAGER_H #define _USRCMDMANAGER_H #include "xml/document.h" #include #include #define ROOT_NODE_NAME_USRCMD "usrcmdlist" namespace CORE { class Usrcmd_Manager { XML::Document m_document; int m_size; std::vector< std::string > m_list_cmd; public: Usrcmd_Manager(); virtual ~Usrcmd_Manager(){} XML::Document& xml_document() { return m_document; } void analyze_xml(); void save_xml(); const int get_size() const { return m_size; } // 実行 void exec( const int comnum, // コマンド番号 const std::string& url, const std::string& link, const std::string& selection, // 選択文字 const int number // レス番号 ); void exec( const std::string command, // コマンド const std::string& url, const std::string& link, const std::string& selection, // 選択文字 const int number // レス番号 ); // コマンド置換 // cmdの$URLをurl, $LINKをlink, $TEXT*をtext, $NUMBERをnumberで置き換えて出力 // text は UTF-8 であること const std::string replace_cmd( const std::string& cmd, const std::string& url, const std::string& link, const std::string& text, const int number ); // ユーザコマンドメニューの作成 const std::string create_usrcmd_menu( Glib::RefPtr< Gtk::ActionGroup >& action_group ); const std::string create_usrcmd_menu( Glib::RefPtr< Gtk::ActionGroup >& action_group, XML::Dom* dom, int& dirno, int& cmdno ); Glib::RefPtr< Gtk::Action > get_action( Glib::RefPtr< Gtk::ActionGroup >& action_group, const int num ); // 選択不可かどうか判断して visible や sensitive を切り替える void toggle_sensitive( Glib::RefPtr< Gtk::ActionGroup >& action_group, const std::string& url_article, const std::string& url_link, const std::string& str_select ); private: void txt2xml(); const bool show_replacetextdiag( std::string& texti, const std::string& title ); void set_cmd( const std::string& cmd ); const bool is_sensitive( int num, const std::string& link, const std::string& selection ); const bool is_hide( int num, const std::string& url ); }; /////////////////////////////////////// // インターフェース Usrcmd_Manager* get_usrcmd_manager(); void delete_usrcmd_manager(); } #endif jd-2.8.7-140104/src/usrcmdpref.cpp0000644000076400010400000002711412006761301013236 0ustar // ライセンス: GPL2 //#define _DEBUG #include "jddebug.h" #include "gtkmmversion.h" #include "usrcmdpref.h" #include "usrcmdmanager.h" #include "command.h" #include "type.h" #include "jdversion.h" #include "dndmanager.h" #include "control/controlid.h" #include "control/controlutil.h" #include "skeleton/msgdiag.h" #include "config/globalconf.h" #include "jdlib/miscutil.h" using namespace CORE; UsrCmdDiag::UsrCmdDiag( Gtk::Window* parent, const Glib::ustring& name, const Glib::ustring& cmd ) : SKELETON::PrefDiag( parent, "" ), m_label_name( "コマンド名", Gtk::ALIGN_LEFT ), m_label_cmd( "実行するコマンド", Gtk::ALIGN_LEFT ), m_button_manual( "オンラインマニュアルの置換文字一覧を表示" ) { resize( 640, 1 ); m_entry_name.set_text( name ); m_entry_cmd.set_text( cmd ); m_button_manual.signal_clicked().connect( sigc::mem_fun( *this, &UsrCmdDiag::slot_show_manual ) ); m_vbox.set_spacing( 8 ); m_vbox.pack_start( m_label_name, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_entry_name, Gtk::PACK_SHRINK ); m_hbox_cmd.pack_start( m_label_cmd, Gtk::PACK_SHRINK ); m_hbox_cmd.pack_end( m_button_manual, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_hbox_cmd, Gtk::PACK_SHRINK ); m_vbox.pack_start( m_entry_cmd, Gtk::PACK_SHRINK ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_vbox ); set_activate_entry( m_entry_name ); set_activate_entry( m_entry_cmd ); set_title( "ユーザコマンド設定" ); show_all_children(); } void UsrCmdDiag::slot_show_manual() { CORE::core_set_command( "open_url_browser", JDHELPCMD ); } /////////////////////////////////////////// UsrCmdPref::UsrCmdPref( Gtk::Window* parent, const std::string& url ) : SKELETON::PrefDiag( parent, url ), m_label( "右クリックしてコンテキストメニューからコマンドの追加と削除が出来ます。編集するにはダブルクリックします。" ), m_treeview( url, DNDTARGET_USRCMD, m_columns ), m_ckbt_hide_usrcmd( "選択不可のユーザコマンドを非表示にする", true ) { m_treestore = Gtk::TreeStore::create( m_columns ); #if !GTKMM_CHECK_VERSION(2,7,0) // gtkmm26以下にはunset_model()が無いのでここでset_model()しておく // それ以上は m_treeview.xml2tree() でセットする m_treeview.set_treestore( m_treestore ); #endif m_treeview.create_column( 0 ); m_treeview.set_editable_view( true ); m_treeview.set_size_request( 640, 400 ); m_treeview.signal_row_activated().connect( sigc::mem_fun( *this, &UsrCmdPref::slot_row_activated ) ); m_treeview.sig_button_press().connect( sigc::mem_fun(*this, &UsrCmdPref::slot_button_press ) ); m_treeview.sig_button_release().connect( sigc::mem_fun(*this, &UsrCmdPref::slot_button_release ) ); m_treeview.sig_key_press().connect( sigc::mem_fun(*this, &UsrCmdPref::slot_key_press ) ); m_treeview.sig_key_release().connect( sigc::mem_fun(*this, &UsrCmdPref::slot_key_release ) ); m_scrollwin.add( m_treeview ); m_scrollwin.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS ); get_vbox()->set_spacing( 8 ); get_vbox()->pack_start( m_label ); get_vbox()->pack_start( m_scrollwin ); #if !GTKMM_CHECK_VERSION(2,7,0) m_ckbt_hide_usrcmd.set_active( CONFIG::get_hide_usrcmd() ); get_vbox()->pack_start( m_ckbt_hide_usrcmd, Gtk::PACK_SHRINK ); #endif // ポップアップメニュー m_action_group = Gtk::ActionGroup::create(); m_action_group->add( Gtk::Action::create( "NewCmd", "新規コマンド(_C)"), sigc::mem_fun( *this, &UsrCmdPref::slot_newcmd ) ); m_action_group->add( Gtk::Action::create( "NewDir", "新規ディレクトリ(_N)"), sigc::mem_fun( *this, &UsrCmdPref::slot_newdir ) ); m_action_group->add( Gtk::Action::create( "NewSepa", "区切り(_S)"), sigc::mem_fun( *this, &UsrCmdPref::slot_newsepa ) ); m_action_group->add( Gtk::Action::create( "Rename", "名前変更(_R)"), sigc::mem_fun( *this, &UsrCmdPref::slot_rename ) ); m_action_group->add( Gtk::Action::create( "Delete_Menu", "Delete" ) ); m_action_group->add( Gtk::Action::create( "Delete", "削除する(_D)"), sigc::mem_fun( *this, &UsrCmdPref::slot_delete ) ); Glib::ustring str_ui = "" "" "" "" "" "" "" "" "" "" "" "" // 複数選択 "" "" "" "" "" ""; m_ui_manager = Gtk::UIManager::create(); m_ui_manager->insert_action_group( m_action_group ); m_ui_manager->add_ui_from_string( str_ui ); // ポップアップメニューにキーアクセレータを表示 Gtk::Menu* menu = dynamic_cast< Gtk::Menu* >( m_ui_manager->get_widget( "/popup_menu" ) ); CONTROL::set_menu_motion( menu ); menu = dynamic_cast< Gtk::Menu* >( m_ui_manager->get_widget( "/popup_menu_mul" ) ); CONTROL::set_menu_motion( menu ); m_treeview.xml2tree( CORE::get_usrcmd_manager()->xml_document(), m_treestore, ROOT_NODE_NAME_USRCMD ); show_all_children(); set_title( "ユーザコマンド設定" ); } void UsrCmdPref::timeout() { m_treeview.clock_in(); } void UsrCmdPref::slot_ok_clicked() { CONFIG::set_hide_usrcmd( m_ckbt_hide_usrcmd.get_active() ); m_treeview.tree2xml( CORE::get_usrcmd_manager()->xml_document(), ROOT_NODE_NAME_USRCMD ); CORE::get_usrcmd_manager()->analyze_xml(); CORE::get_usrcmd_manager()->save_xml(); CORE::core_set_command( "reset_article_popupmenu" ); } // // マウスボタン押した // bool UsrCmdPref::slot_button_press( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "UsrCmdPref::slot_button_press\n"; #endif return true; } // // マウスボタン離した // bool UsrCmdPref::slot_button_release( GdkEventButton* event ) { m_path_selected = m_treeview.get_path_under_xy( (int)event->x, (int)event->y ); #ifdef _DEBUG std::cout << "UsrCmdPref::slot_button_release path = " << m_path_selected.to_string() << std::endl;; #endif if( m_control.button_alloted( event, CONTROL::PopupmenuButton ) ) show_popupmenu(); // ディレクトリの開閉 else if( ! m_path_selected.empty() && m_control.button_alloted( event, CONTROL::ClickButton ) ){ Gtk::TreeModel::Row row = *( m_treestore->get_iter( m_path_selected ) ); if( row && row[ m_columns.m_type ] == TYPE_DIR ){ if( ! m_treeview.row_expanded( m_path_selected ) ) m_treeview.expand_row( m_path_selected, false ); else m_treeview.collapse_row( m_path_selected ); } } return true; } // // キーを押した // bool UsrCmdPref::slot_key_press( GdkEventKey* event ) { // 行の名前を編集中なら何もしない if( m_treeview.is_renaming_row() ) return false; const int control = m_control.key_press( event ); #ifdef _DEBUG std::cout << "UsrCmdPref::slot_key_press key = " << control << std::endl; #endif if( control == CONTROL::Delete ) delete_row(); return true; } // // キー上げた // bool UsrCmdPref::slot_key_release( GdkEventKey* event ) { // 行の名前を編集中なら何もしない if( m_treeview.is_renaming_row() ) return false; #ifdef _DEBUG std::cout << "UsrCmdPref::slot_key_release\n"; #endif return true; } // ポップアップメニュー表示 void UsrCmdPref::show_popupmenu() { Gtk::Menu* menu = NULL; std::list< Gtk::TreeModel::iterator > list_it = m_treeview.get_selected_iterators(); if( list_it.size() <= 1 ) menu = dynamic_cast< Gtk::Menu* >( m_ui_manager->get_widget( "/popup_menu" ) ); else menu = dynamic_cast< Gtk::Menu* >( m_ui_manager->get_widget( "/popup_menu_mul" ) ); if( ! menu ) return; Glib::RefPtr< Gtk::Action > act_del, act_rename; act_rename = m_action_group->get_action( "Rename" ); act_del = m_action_group->get_action( "Delete_Menu" ); if( m_path_selected.empty() ){ if( act_rename ) act_rename->set_sensitive( false ); if( act_del ) act_del->set_sensitive( false ); } else{ Gtk::TreeModel::Row row = *( m_treestore->get_iter( m_path_selected ) ); int type = row[ m_columns.m_type ]; if( act_rename ){ if( type != TYPE_SEPARATOR ) act_rename->set_sensitive( true ); else act_rename->set_sensitive( false ); } if( act_del ) act_del->set_sensitive( true ); } menu->popup( 0, gtk_get_current_event_time() ); } // コマンド作成 void UsrCmdPref::slot_newcmd() { UsrCmdDiag diag( this, "", "" ); if( diag.run() == Gtk::RESPONSE_OK ){ if( diag.get_name().empty() || diag.get_cmd().empty() ) return; CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; info.type = TYPE_USRCMD; info.parent = NULL; info.url = std::string(); info.name = diag.get_name(); info.data = diag.get_cmd(); if( m_path_selected.empty() ) info.path = Gtk::TreePath( "0" ).to_string(); else info.path = m_path_selected.to_string(); list_info.push_back( info ); const bool subdir = true; const bool scroll = false; const bool force = false; const bool cancel_undo_commit = false; const int check_dup = 0; // 項目の重複チェックをしない m_treeview.append_info( list_info, m_path_selected, subdir, scroll, force, cancel_undo_commit, check_dup ); m_path_selected = m_treeview.get_current_path(); } } // ディレクトリ作成 void UsrCmdPref::slot_newdir() { m_path_selected = m_treeview.create_newdir( m_path_selected ); } // 区切り作成 void UsrCmdPref::slot_newsepa() { CORE::DATA_INFO_LIST list_info; CORE::DATA_INFO info; info.type = TYPE_SEPARATOR; info.parent = NULL; info.url = std::string(); info.name = "--- 区切り ---"; info.data = std::string(); if( m_path_selected.empty() ) info.path = Gtk::TreePath( "0" ).to_string(); else info.path = m_path_selected.to_string(); list_info.push_back( info ); const bool subdir = true; const bool scroll = false; const bool force = false; const bool cancel_undo_commit = false; const int check_dup = 0; // 項目の重複チェックをしない m_treeview.append_info( list_info, m_path_selected, subdir, scroll, force, cancel_undo_commit, check_dup ); m_path_selected = m_treeview.get_current_path(); } // // 削除 // void UsrCmdPref::delete_row() { SKELETON::MsgDiag mdiag( NULL, "削除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO ); if( mdiag.run() != Gtk::RESPONSE_YES ) return; slot_delete(); } void UsrCmdPref::slot_delete() { const bool force = false; m_treeview.delete_selected_rows( force ); } // 名前変更 void UsrCmdPref::slot_rename() { m_treeview.rename_row( m_path_selected ); } void UsrCmdPref::slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ) { #ifdef _DEBUG std::cout << "UsrCmdPref::slot_row_activated path = " << path.to_string() << std::endl; #endif Gtk::TreeModel::Row row = *( m_treestore->get_iter( path ) ); if( ! row ) return; if( row[ m_columns.m_type ] != TYPE_USRCMD ) return; UsrCmdDiag diag( this, row[ m_columns.m_name ], row[ m_columns.m_data ] ); if( diag.run() == Gtk::RESPONSE_OK ){ row[ m_columns.m_name ] = diag.get_name(); row[ m_columns.m_data ] = diag.get_cmd(); } } jd-2.8.7-140104/src/usrcmdpref.h0000644000076400010400000000413511117762115012707 0ustar // ライセンス: GPL2 // ユーザコマンド設定ダイアログ #ifndef _USRCMDPREF_H #define _USRCMDPREF_H #include "skeleton/prefdiag.h" #include "skeleton/edittreeview.h" #include "skeleton/editcolumns.h" #include "control/control.h" namespace CORE { class UsrCmdDiag : public SKELETON::PrefDiag { Gtk::VBox m_vbox; Gtk::Entry m_entry_name; Gtk::Entry m_entry_cmd; Gtk::Label m_label_name; Gtk::HBox m_hbox_cmd; Gtk::Label m_label_cmd; Gtk::Button m_button_manual; public: UsrCmdDiag( Gtk::Window* parent, const Glib::ustring& name, const Glib::ustring& cmd ); const Glib::ustring get_name() { return m_entry_name.get_text(); } const Glib::ustring get_cmd() { return m_entry_cmd.get_text(); } private: void slot_show_manual(); }; class UsrCmdPref : public SKELETON::PrefDiag { Gtk::Label m_label; SKELETON::EditTreeView m_treeview; SKELETON::EditColumns m_columns; Glib::RefPtr< Gtk::TreeStore > m_treestore; Gtk::ScrolledWindow m_scrollwin; Gtk::CheckButton m_ckbt_hide_usrcmd; Gtk::TreeModel::Path m_path_selected; // ポップアップメニュー Glib::RefPtr< Gtk::ActionGroup > m_action_group; Glib::RefPtr< Gtk::UIManager > m_ui_manager; CONTROL::Control m_control; public: UsrCmdPref( Gtk::Window* parent, const std::string& url ); private: virtual void timeout(); // OK押した virtual void slot_ok_clicked(); bool slot_button_press( GdkEventButton* event ); bool slot_button_release( GdkEventButton* event ); bool slot_key_press( GdkEventKey* event ); bool slot_key_release( GdkEventKey* event ); void show_popupmenu(); void delete_row(); void slot_newcmd(); void slot_newdir(); void slot_newsepa(); void slot_delete(); void slot_rename(); void slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column ); }; } #endif jd-2.8.7-140104/src/viewfactory.cpp0000644000076400010400000001203511577662613013444 0ustar // ライセンス: GPL2 #include "viewfactory.h" #include "searchmanager.h" #include "bbslist/bbslistview.h" #include "bbslist/favoriteview.h" #include "bbslist/selectlistview.h" #include "bbslist/historyview.h" #include "board/boardview.h" #include "board/boardviewnext.h" #include "board/boardviewlog.h" #include "board/boardviewsidebar.h" #include "article/articleview.h" #include "article/articleviewsearch.h" #include "article/articleviewpreview.h" #include "article/articleviewinfo.h" #include "article/articleviewpopup.h" #include "article/articleviewetc.h" #include "image/imageview.h" #include "image/imageviewicon.h" #include "image/imageviewpopup.h" #include "message/messageview.h" SKELETON::View* CORE::ViewFactory( int type, const std::string& url, VIEWFACTORY_ARGS view_args ) { switch( type ) { case VIEW_BBSLISTVIEW: return new BBSLIST::BBSListViewMain( url, view_args.arg1, view_args.arg2 ); case VIEW_FAVORITELIST: return new BBSLIST::FavoriteListView( url, view_args.arg1, view_args.arg2 ); case VIEW_SELECTLIST: return new BBSLIST::SelectListView( url, view_args.arg1, view_args.arg2 ); case VIEW_HISTTHREAD: return new BBSLIST::HistoryThreadView( url, view_args.arg1, view_args.arg2 ); case VIEW_HISTCLOSE: return new BBSLIST::HistoryCloseView( url, view_args.arg1, view_args.arg2 ); case VIEW_HISTBOARD: return new BBSLIST::HistoryBoardView( url, view_args.arg1, view_args.arg2 ); case VIEW_HISTCLOSEBOARD: return new BBSLIST::HistoryCloseBoardView( url, view_args.arg1, view_args.arg2 ); case VIEW_HISTCLOSEIMG: return new BBSLIST::HistoryCloseImgView( url, view_args.arg1, view_args.arg2 ); ////////////////// case VIEW_BOARDVIEW: return new BOARD::BoardView( url ); case VIEW_BOARDNEXT: return new BOARD::BoardViewNext( url, view_args.arg1 ); case VIEW_BOARDLOG: return new BOARD::BoardViewLog( url ); case VIEW_BOARDSIDEBAR: return new BOARD::BoardViewSidebar( url, ( view_args.arg1 == "set_history" ) ); ///////////////// case VIEW_ARTICLEVIEW: return new ARTICLE::ArticleViewMain( url ); case VIEW_ARTICLERES: return new ARTICLE::ArticleViewRes( url ); case VIEW_ARTICLENAME: return new ARTICLE::ArticleViewName( url ); case VIEW_ARTICLEID: return new ARTICLE::ArticleViewID( url ); case VIEW_ARTICLEBM: return new ARTICLE::ArticleViewBM( url ); case VIEW_ARTICLEPOST: return new ARTICLE::ArticleViewPost( url ); case VIEW_ARTICLEURL: return new ARTICLE::ArticleViewURL( url ); case VIEW_ARTICLEREFER: return new ARTICLE::ArticleViewRefer( url ); case VIEW_ARTICLEDRAWOUT: return new ARTICLE::ArticleViewDrawout( url ); case VIEW_ARTICLEPOSTLOG: return new ARTICLE::ArticleViewPostlog( url ); case VIEW_ARTICLESEARCHLOG: return new ARTICLE::ArticleViewSearch( url, ( view_args.arg1 == "exec" ) ); case VIEW_ARTICLESEARCHALLLOG: return new ARTICLE::ArticleViewSearch( url, ( view_args.arg1 == "exec" ) ); case VIEW_ARTICLESEARCHTITLE: return new ARTICLE::ArticleViewSearch( url, ( view_args.arg1 == "exec" ) ); case VIEW_ARTICLEPREVIEW: return new ARTICLE::ArticleViewPreview( url ); case VIEW_ARTICLEINFO: return new ARTICLE::ArticleViewInfo( url ); ///////////////// case VIEW_ARTICLEPOPUPHTML: return new ARTICLE::ArticleViewPopupHTML( url, view_args.arg1 ); case VIEW_ARTICLEPOPUPRES: return new ARTICLE::ArticleViewPopupRes( url, view_args.arg1, ( view_args.arg2 == "true" ), ( view_args.arg3 == "true" ) ); case VIEW_ARTICLEPOPUPNAME: return new ARTICLE::ArticleViewPopupName( url, view_args.arg1 ); case VIEW_ARTICLEPOPUPID: return new ARTICLE::ArticleViewPopupID( url, view_args.arg1 ); case VIEW_ARTICLEPOPUPREFER: return new ARTICLE::ArticleViewPopupRefer( url, view_args.arg1 ); case VIEW_ARTICLEPOPUPDRAWOUT: return new ARTICLE::ArticleViewPopupDrawout( url, view_args.arg1, ( view_args.arg2 == "OR" ) ); case VIEW_ARTICLEPOPUPBM: return new ARTICLE::ArticleViewPopupBM( url ); ///////////////// case VIEW_IMAGEVIEW: return new IMAGE::ImageViewMain( url ); case VIEW_IMAGEICON: return new IMAGE::ImageViewIcon( url ); case VIEW_IMAGEPOPUP: return new IMAGE::ImageViewPopup( url ); ///////////////// case VIEW_MESSAGE: return new MESSAGE::MessageViewMain( url, view_args.arg1 ); case VIEW_NEWTHREAD: return new MESSAGE::MessageViewNew( url, view_args.arg1 ); default: return NULL; } } jd-2.8.7-140104/src/viewfactory.h0000644000076400010400000000307111577662613013111 0ustar // ライセンス: GPL2 // // SKELETON::VIEWのファクトリー // #ifndef _VIEWFACTORY_H #define _VIEWFACTORY_H #include #include namespace SKELETON { class View; } namespace CORE { enum { VIEW_BBSLISTVIEW, VIEW_FAVORITELIST, VIEW_SELECTLIST, VIEW_HISTTHREAD, VIEW_HISTCLOSE, VIEW_HISTBOARD, VIEW_HISTCLOSEBOARD, VIEW_HISTCLOSEIMG, VIEW_BOARDVIEW, VIEW_BOARDNEXT, VIEW_BOARDLOG, VIEW_BOARDSIDEBAR, VIEW_ARTICLEVIEW, VIEW_ARTICLERES, VIEW_ARTICLENAME, VIEW_ARTICLEID, VIEW_ARTICLEBM, VIEW_ARTICLEPOST, VIEW_ARTICLEURL, VIEW_ARTICLEREFER, VIEW_ARTICLEDRAWOUT, VIEW_ARTICLEPREVIEW, VIEW_ARTICLEINFO, VIEW_ARTICLESEARCHLOG, VIEW_ARTICLESEARCHALLLOG, VIEW_ARTICLESEARCHTITLE, VIEW_ARTICLEPOSTLOG, VIEW_ARTICLEPOPUPHTML, VIEW_ARTICLEPOPUPRES, VIEW_ARTICLEPOPUPNAME, VIEW_ARTICLEPOPUPID, VIEW_ARTICLEPOPUPREFER, VIEW_ARTICLEPOPUPDRAWOUT, VIEW_ARTICLEPOPUPBM, VIEW_IMAGEVIEW, VIEW_IMAGEICON, VIEW_IMAGEPOPUP, VIEW_MESSAGE, VIEW_NEWTHREAD, VIEW_NONE }; struct VIEWFACTORY_ARGS { std::string arg1; std::string arg2; std::string arg3; std::string arg4; }; SKELETON::View* ViewFactory( int type, const std::string& url, VIEWFACTORY_ARGS view_args = VIEWFACTORY_ARGS() ); } #endif jd-2.8.7-140104/src/winmain.cpp0000644000076400010400000001711011570211747012532 0ustar // ライセンス: GPL2 #ifdef HAVE_CONFIG_H #include "config.h" #endif //#define _DEBUG #include "jddebug.h" #include "winmain.h" #include "command.h" #include "core.h" #include "session.h" #include "icons/iconmanager.h" #include "jdlib/loader.h" #include "control/controlutil.h" #include "control/controlid.h" #ifdef HAVE_MIGEMO_H #include "jdlib/jdmigemo.h" #include "config/globalconf.h" #endif JDWinMain::JDWinMain( const bool init, const bool skip_setupdiag, const int init_w, const int init_h, const int init_x, const int init_y ) : SKELETON::JDWindow( false ), m_core( NULL ), m_cancel_state_event( false ) { #ifdef _DEBUG std::cout << "JDWinMain::JDWinMain init = " << init << std::endl << "x y w h = " << get_x_win() << " " << get_y_win() << " " << get_width_win() << " " << get_height_win() << std::endl; #endif setlocale( LC_ALL, "ja_JP.UTF-8" ); // GLIBのスレッドシステム初期化 if( !Glib::thread_supported() ) Glib::thread_init(); assert( Glib::thread_supported() ); #ifndef _WIN32 // アイコンをセット // WindowsはwindresのデフォルトICONが初期適用されるので不要 std::list< Glib::RefPtr< Gdk::Pixbuf > > list_icons; list_icons.push_back( ICON::get_icon( ICON::JD16 ) ); list_icons.push_back( ICON::get_icon( ICON::JD32 ) ); list_icons.push_back( ICON::get_icon( ICON::JD48 ) ); list_icons.push_back( ICON::get_icon( ICON::JD96 ) ); Gtk::Window::set_default_icon_list( list_icons ); #endif // セッション回復 SESSION::init_session(); bool cancel_maximize = false; if( init_w >= 0 ){ cancel_maximize = true; set_width_win( init_w ); } if( init_h >= 0 ){ cancel_maximize = true; set_height_win( init_h ); } if( init_x >= 0 ){ cancel_maximize = true; set_x_win( init_x ); } if( init_y >= 0 ){ cancel_maximize = true; set_y_win( init_y ); } if( cancel_maximize ){ set_maximized_win( false ); set_full_win( false ); } // サイズ変更 init_win(); if( SESSION::is_full_win_main() ) fullscreen(); set_spacing( 4 ); set_modal( false ); property_window_position().set_value( Gtk::WIN_POS_NONE ); set_resizable( true ); property_destroy_with_parent().set_value( false ); add_events( Gdk::BUTTON_PRESS_MASK ); add_events( Gdk::BUTTON_RELEASE_MASK ); add_events( Gdk::POINTER_MOTION_MASK ); // migemo 初期化 #ifdef HAVE_MIGEMO_H jd_migemo_init( CONFIG::get_migemodict_path().c_str() ); #endif // 後はcoreを作って任せる m_core = new class CORE::Core( *this ); m_core->run( init, skip_setupdiag ); } JDWinMain::~JDWinMain() { #ifdef _DEBUG std::cout << "JDWinMain::~JDWinMain window size : x = " << get_x_win() << " y = " << get_y_win() << " w = " << get_width_win() << " h = " << get_height_win() << " max = " << is_maximized_win() << std::endl; #endif if( m_core ){ delete m_core; m_core = NULL; JDLIB::check_loader_alive(); } // migemo のクローズ #ifdef HAVE_MIGEMO_H jd_migemo_close(); #endif // アイコンマネージャ削除 ICON::delete_icon_manager(); } // 通常のセッション保存 void JDWinMain::save_session() { #ifdef _DEBUG std::cout << "JDWinMain::save_session\n"; #endif if( m_core ) m_core->save_session(); } void JDWinMain::hide() { #ifdef _DEBUG std::cout << "JDWinMain::hide\n"; #endif // GNOME環境の時に閉じるとウィンドウが最小化する時があるので // state_eventをキャンセルする m_cancel_state_event = true; Gtk::Widget::hide(); } const int JDWinMain::get_x_win() { return SESSION::get_x_win_main(); } const int JDWinMain::get_y_win() { return SESSION::get_y_win_main(); } void JDWinMain::set_x_win( const int x ) { SESSION::set_x_win_main( x ); } void JDWinMain::set_y_win( const int y ) { SESSION::set_y_win_main( y ); } const int JDWinMain::get_width_win() { return SESSION::get_width_win_main(); } const int JDWinMain::get_height_win() { return SESSION::get_height_win_main(); } void JDWinMain::set_width_win( const int width ) { SESSION::set_width_win_main( width ); } void JDWinMain::set_height_win( const int height ) { SESSION::set_height_win_main( height ); } const bool JDWinMain::is_focus_win() { return SESSION::is_focus_win_main(); } void JDWinMain::set_focus_win( const bool set ) { SESSION::set_focus_win_main( set ); } const bool JDWinMain::is_maximized_win() { return SESSION::is_maximized_win_main(); } void JDWinMain::set_maximized_win( const bool set ) { SESSION::set_maximized_win_main( set ); } const bool JDWinMain::is_iconified_win() { return SESSION::is_iconified_win_main(); } void JDWinMain::set_iconified_win( const bool set ) { SESSION::set_iconified_win_main( set ); } const bool JDWinMain::is_full_win() { return SESSION::is_full_win_main(); } void JDWinMain::set_full_win( const bool set ) { SESSION::set_full_win_main( set ); } const bool JDWinMain::is_shown_win() { return SESSION::is_shown_win_main(); } void JDWinMain::set_shown_win( const bool set ) { SESSION::set_shown_win_main( set ); } bool JDWinMain::on_delete_event( GdkEventAny* event ) { #ifdef _DEBUG std::cout << "JDWinMain::on_delete_event\n"; #endif // GNOME環境の時に閉じるとウィンドウが最小化する時があるので // state_eventをキャンセルする m_cancel_state_event = true; return SKELETON::JDWindow::on_delete_event( event ); } // 最大、最小化 bool JDWinMain::on_window_state_event( GdkEventWindowState* event ) { #ifdef _DEBUG std::cout << "JDWinMain::on_window_state_event\n"; if( m_cancel_state_event ) std::cout << "cancel\n"; #endif // キャンセル ( JDWinMain::on_delete_even() の説明を参照せよ ) if( m_cancel_state_event ) return Gtk::Window::on_window_state_event( event ); return SKELETON::JDWindow::on_window_state_event( event ); } bool JDWinMain::on_configure_event( GdkEventConfigure* event ) { #ifdef _DEBUG std::cout << "JDWinMain::on_configure_event\n"; if( m_cancel_state_event ) std::cout << "cancel\n"; #endif // キャンセル ( JDWinMain::on_delete_event() の説明を参照せよ ) if( m_cancel_state_event ) return Gtk::Window::on_configure_event( event ); return SKELETON::JDWindow::on_configure_event( event ); } bool JDWinMain::on_button_press_event( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "JDWinMain::on_button_press_event\n"; #endif // マウスジェスチャ m_control.MG_start( event ); return SKELETON::JDWindow::on_button_press_event( event ); } bool JDWinMain::on_button_release_event( GdkEventButton* event ) { #ifdef _DEBUG std::cout << "JDWinMain::on_button_release_event\n"; #endif const bool ret = SKELETON::JDWindow::on_button_release_event( event ); /// マウスジェスチャ const int mg = m_control.MG_end( event ); // マウスジェスチャ if( mg != CONTROL::None ) operate_win( mg ); return ret; } // // マウスが動いた // bool JDWinMain::on_motion_notify_event( GdkEventMotion* event ) { #ifdef _DEBUG std::cout << "JDWinMain::on_motion_notify_event\n"; #endif /// マウスジェスチャ m_control.MG_motion( event ); return SKELETON::JDWindow::on_motion_notify_event( event ); } const bool JDWinMain::operate_win( const int control ) { return CONTROL::operate_common( control, std::string(), NULL ); } jd-2.8.7-140104/src/winmain.h0000644000076400010400000000357111570211747012205 0ustar // ライセンス: GPL2 // // メインウィンドウとmain関数 // #ifndef _MAINWIN_H #define _MAINWIN_H #include "skeleton/window.h" #include "control/control.h" namespace CORE { class Core; } class JDWinMain : public SKELETON::JDWindow { CORE::Core* m_core; bool m_cancel_state_event; // 入力コントローラ CONTROL::Control m_control; public: JDWinMain( const bool init, const bool skip_setupdiag, const int init_w, const int init_h, const int init_x, const int init_y ); virtual ~JDWinMain(); // 通常のセッション保存 void save_session(); void hide(); protected: virtual const int get_x_win(); virtual const int get_y_win(); virtual void set_x_win( const int x ); virtual void set_y_win( const int y ); virtual const int get_width_win(); virtual const int get_height_win(); virtual void set_width_win( const int width ); virtual void set_height_win( const int height ); virtual const bool is_focus_win(); virtual void set_focus_win( const bool set ); virtual const bool is_maximized_win(); virtual void set_maximized_win( const bool set ); virtual const bool is_iconified_win(); virtual void set_iconified_win( const bool set ); virtual const bool is_full_win(); virtual void set_full_win( const bool set ); virtual const bool is_shown_win(); virtual void set_shown_win( const bool set ); virtual bool on_delete_event( GdkEventAny* event ); virtual bool on_window_state_event( GdkEventWindowState* event ); virtual bool on_configure_event( GdkEventConfigure* event ); virtual bool on_button_press_event( GdkEventButton* event ); virtual bool on_button_release_event( GdkEventButton* event ); virtual bool on_motion_notify_event( GdkEventMotion* event ); private: const bool operate_win( const int control ); }; #endif jd-2.8.7-140104/src/xml/0000755000076400010400000000000012261751613011163 5ustar jd-2.8.7-140104/src/xml/document.cpp0000644000076400010400000000666311043627612013516 0ustar // License GPL2 //#define _DEBUG #include "jddebug.h" #include "document.h" #include "jdlib/miscutil.h" enum { SIZE_OF_RAWDATA = 2 * 1024 * 1024 }; using namespace XML; // 文字列を元にノードツリーを作る場合( htmlはHTMLモード。デフォルト = false ) Document::Document( const std::string& str, const bool html ) : Dom( NODE_TYPE_DOCUMENT, "#document", html ) { init( str ); } // Gtk::TreeStore を元にノードツリーを作る場合 Document::Document( Glib::RefPtr< Gtk::TreeStore > treestore, SKELETON::EditColumns& columns, const std::string& root_name ) : Dom( NODE_TYPE_DOCUMENT, "#document" ) { init( treestore, columns, root_name ); } // 何も無い状態からノードツリーを作る場合 Document::Document() : Dom( NODE_TYPE_DOCUMENT, "#document" ) {} // // このクラスは代入可能 // Document& Document::operator=( const Document& document ) { if( this == &document ) return *this; copy_childNodes( document ); return *this; } // // 初期化 // void Document::init( const std::string& str ) { clear(); if( ! str.empty() ) parse( remove_comments( str ) ); } void Document::init( Glib::RefPtr< Gtk::TreeStore > treestore, SKELETON::EditColumns& columns, const std::string& root_name ) { clear(); // XMLとして必要なのでルート要素を作成 Dom* root = appendChild( NODE_TYPE_ELEMENT, root_name ); // ルート以下に追加 root->parse( treestore->children(), columns ); } // // 予めコメントやXML宣言などを取り除いておく( 順番に注意 ) // std::string Document::remove_comments( const std::string& str ) { if( str.size() > SIZE_OF_RAWDATA ) return std::string(); std::string out_str = str; out_str = MISC::remove_str( out_str, "" ); // out_str = MISC::remove_str( out_str, "" ); // out_str = MISC::remove_str( out_str, "" ); // * ]]> out_str = MISC::remove_str( out_str, "" ); // return out_str; } // // Gtk::TreeStore をセット // // list_path_expand = 後で Gtk::TreeView::expand_row() をするためのリスト // void Document::set_treestore( Glib::RefPtr< Gtk::TreeStore >& treestore, SKELETON::EditColumns& columns, const std::string& root_name, std::list< Gtk::TreePath >& list_path_expand ) { treestore->clear(); if( childNodes().size() ) { // ルートの子要素以下が対象 Dom* root = get_root_element( root_name ); // ルート要素の有無で処理を分ける( 旧様式=無, 新様式=有 ) if( root ) root->append_treestore( treestore, columns, list_path_expand ); else append_treestore( treestore, columns, list_path_expand ); } } // // ルート要素を取得 // Dom* Document::get_root_element( const std::string& node_name ) { Dom* node = 0; if( ! this ) return node; DomList children = childNodes(); std::list< Dom* >::iterator it = children.begin(); while( it != children.end() ) { if( (*it)->nodeType() == NODE_TYPE_ELEMENT ) { // 要素名問わず if( node_name.empty() ) node = *it; // 要素名限定 else if( (*it)->nodeName() == node_name ) node = *it; break; } ++it; } return node; } jd-2.8.7-140104/src/xml/document.h0000644000076400010400000000333211043627612013151 0ustar // License GPL2 // Document( Dom派生 )クラス #ifndef _DOCUMENT_H #define _DOCUMENT_H #include "dom.h" namespace XML { class Document : public Dom { // コメントなどを取り除く std::string remove_comments( const std::string& str ); // コピーコンストラクタは使わない Document( const Document& ); public: // 文字列を元にノードツリーを作る場合( html = HTMLモード ) Document( const std::string& str, const bool html = false ); // Gtk::TreeStore を元にノードツリーを作る場合 // ただし列は SKELETON::EditColumns を継承したものであること Document( Glib::RefPtr< Gtk::TreeStore > treestore, SKELETON::EditColumns& columns, const std::string& root_name ); // 何も無い状態からノードツリーを作る場合 Document(); virtual ~Document(){}; // このクラスは代入可能 Document& operator=( const Document& document ); // 初期化 void init( const std::string& str ); void init( Glib::RefPtr< Gtk::TreeStore > treestore, SKELETON::EditColumns& columns, const std::string& root_name ); // Gtk::TreeStore をセットする // ただし列は SKELETON::EditColumns を継承したものであること void set_treestore( Glib::RefPtr< Gtk::TreeStore >& treestore, SKELETON::EditColumns& columns, const std::string& root_name, std::list< Gtk::TreePath >& list_path_expand ); // ルート要素を取得する Dom* get_root_element( const std::string& node_name = std::string() ); }; } #endif jd-2.8.7-140104/src/xml/dom.cpp0000644000076400010400000006024711350440352012450 0ustar // License: GPL2 //#define _DEBUG #include "jddebug.h" #include "dom.h" #include "jdlib/miscutil.h" #include "type.h" #include "tools.h" #include "skeleton/editcolumns.h" #include enum { SIZE_OF_RAWDATA = 2 * 1024 * 1024 }; using namespace XML; // staticなHTMLの要素名リストを再定義 std::set< std::string > Dom::m_static_html_elements; // コンストラクタ Dom::Dom( const int& type, const std::string& name, const bool html ) : m_html( html ), m_nodeType( type ), m_nodeName( name ), m_parentNode( 0 ) { // HTMLの場合に空要素として扱う物の内で、使われていそうな物( 小文字で統一 ) if( html && m_static_html_elements.empty() ) { m_static_html_elements.insert( "base" ); m_static_html_elements.insert( "br" ); m_static_html_elements.insert( "hr" ); m_static_html_elements.insert( "img" ); m_static_html_elements.insert( "link" ); m_static_html_elements.insert( "meta" ); } } // デストラクタ Dom::~Dom() { #ifdef _DEBUG std::cout << "~Dom() : " << m_nodeName << ", " << m_childNodes.size() << std::endl; #endif clear(); } // コピーコンストラクタ Dom::Dom( const Dom& dom ) : m_html( dom.m_html ), m_nodeType( dom.m_nodeType ), m_nodeName( dom.m_nodeName ), m_nodeValue( dom.m_nodeValue ), m_parentNode( 0 ), m_attributes( dom.m_attributes ) { copy_childNodes( dom ); } // // 子ノードのクリア // void Dom::clear() { std::list< Dom* >::iterator it = m_childNodes.begin(); while( it != m_childNodes.end() ) { if( *it ) delete *it; ++it; } m_childNodes.clear(); } // // XMLの文字列をパースして子ノードを追加する // void Dom::parse( const std::string& str ) { if( str.empty() || str.size() > SIZE_OF_RAWDATA ) return; size_t current_pos = 0, tag_lt_pos = 0, tag_gt_pos = 0; const size_t str_length = str.length(); while( current_pos < str_length ) { //プロパティなどに使う変数 int type = NODE_TYPE_UNKNOWN; std::string name; std::string value; std::map< std::string, std::string > attributes_pair; std::string next_source; // "<"を探す tag_lt_pos = str.find( "<", current_pos ); // タグの前のテキストノード if( current_pos < tag_lt_pos ) { type = NODE_TYPE_TEXT; name = "#text"; value = str.substr( current_pos, tag_lt_pos - current_pos ); current_pos = tag_lt_pos; } // 全てがテキストノード else if( tag_lt_pos == std::string::npos ) { type = NODE_TYPE_TEXT; name = "#text"; value = str; current_pos = str.length(); } // 要素ノード else if( current_pos == tag_lt_pos ) { tag_gt_pos = str.find( ">", tag_lt_pos + 1 ); current_pos = tag_gt_pos + 1; // 開始タグの中身( )を取り出す std::string open_tag = str.substr( tag_lt_pos + 1, tag_gt_pos - tag_lt_pos - 1 ); // タグの中身がアルファベットで始まっているか bool is_alpha = ( ( open_tag[0] >= 'A' && open_tag[0] <= 'Z' ) || ( open_tag[0] >= 'a' && open_tag[0] <= 'z' ) ); // タグ構造が壊れてる場合 size_t broken_pos = 0; if( open_tag.empty() || ! is_alpha ) continue; else if( ( broken_pos = open_tag.find( "<" ) ) != std::string::npos ) { current_pos += broken_pos; continue; } // XMLの場合に空要素として扱う要素( )かどうか bool empty_element = false; if( ! m_html && open_tag.compare( open_tag.length() - 1, 1, "/" ) == 0 ) { empty_element = true; open_tag.erase( open_tag.length() - 1 ); } // 要素名を取り出す std::string element_name; size_t i = 0; const size_t open_tag_length = open_tag.length(); while( i < open_tag_length && open_tag[i] != '\n' && open_tag[i] != '\t' && open_tag[i] != ' ' ) { element_name += open_tag[i]; ++i; } if( element_name.empty() ) continue; // 要素ノードのタイプを設定 type = NODE_TYPE_ELEMENT; // 要素名は小文字に統一 name = MISC::tolower_str( element_name ); // 属性ペアのリストを作成 attributes_pair = create_attribute( open_tag.substr( i ) ); // HTMLの場合に空要素として扱う要素かどうか if( m_html && m_static_html_elements.find( name ) != m_static_html_elements.end() ) empty_element = true; // 終了タグがある要素からの中身の取り出し( 中身 ) if( ! empty_element ) { // count は見つける必要がある終了タグの数 size_t close_tag_lt_pos = 0, close_tag_gt_pos = 0, count = 1; while( ( close_tag_lt_pos = str.find( "<", current_pos ) ) != std::string::npos && ( close_tag_gt_pos = str.find( ">", close_tag_lt_pos + 1 ) ) != std::string::npos ) { current_pos = close_tag_gt_pos + 1; // タグの中身を取り出す const std::string close_tag = str.substr( close_tag_lt_pos + 1, close_tag_gt_pos - close_tag_lt_pos - 1 ); // タグ構造が壊れてる場合 if( close_tag.empty() ) continue; else if( ( broken_pos = close_tag.find( "<" ) ) != std::string::npos ) { current_pos += broken_pos; continue; } // 空要素でない同名の開始タグを見つけたらカウントを増やす if( close_tag.compare( 0, element_name.length(), element_name ) == 0 && close_tag.compare( close_tag.length() - 1, 1, "/" ) != 0 ) ++count; // 終了タグを見つけたらカウントを減らす else if( close_tag.compare( 0, element_name.length() + 1, "/" + element_name ) == 0 ) --count; // 終了タグを見つける必要数が 0 になったらループを抜ける if( count <= 0 ) break; } // 必要な終了タグが見付からないまま上記のループを抜けた場合は、全体のループを抜ける if( count > 0 ) break; // 次の再帰で使う"子ノード"の素材になる文字列 next_source = str.substr( tag_gt_pos + 1, close_tag_lt_pos - tag_gt_pos - 1 ); } } #ifdef _DEBUG std::cout << "Dom:parse():---------------------------------------\n"; std::cout << "nodeName : " << name << "\n"; std::cout << "nodeType : " << type << "\n"; std::map< std::string, std::string >::iterator it = attributes_pair.begin(); while( it != attributes_pair.end() ) { std::cout << "Attribute: " << "name=" << (*it).first << ", value=" << (*it).second << std::endl; ++it; } std::cout << "nodeValue: " << value << std::endl; #endif // ノードを追加 Dom* node = appendChild( type, name ); node->attributes( attributes_pair ); node->nodeValue( value ); // 再帰 if( ! next_source.empty() ) node->parse( next_source ); } } // // 属性ペアのリストを作成 // std::map< std::string, std::string > Dom::create_attribute( const std::string& str ) { std::map< std::string, std::string > attributes_pair; if( str.empty() ) return attributes_pair; size_t i = 0, str_length = str.length(); while( i < str_length ) { std::string attr_key; std::string attr_value; // 余分なスペース等を詰める while( i < str_length && ( str[i] == '\n' || str[i] == '\t' || str[i] == ' ' ) ) ++i; // "="かスペース等でなければ属性名とする while( i < str_length && str[i] != '\n' && str[i] != '\t' && str[i] != ' ' && str[i] != '=' ) { attr_key += str[i]; ++i; } // 余分なスペース等を詰める while( i < str_length && ( str[i] == '\n' || str[i] == '\t' || str[i] == ' ' ) ) ++i; // "="の区切りがある場合のみ属性の値をセットする if( str[i] == '=' ) { // "="の分進める ++i; // 余分なスペース等を詰める while( i < str_length && ( str[i] == '\n' || str[i] == '\t' || str[i] == ' ' ) ) ++i; // 属性の値 "〜" if( str[i] == '"' ) { ++i; while( i < str_length && str[i] != '"' ) { attr_value += str[i]; ++i; } if( str[i] == '"' ) ++i; } // 属性の値 '〜' else if( str[i] == '\'' ) { ++i; while( i < str_length && str[i] != '\'' ) { attr_value += str[i]; ++i; } if( str[i] == '\'' ) ++i; } // 属性の値 その他( 本来ならXMLとしてエラー ) else { while( i < str_length && str[i] != '\n' && str[i] != '\t' && str[i] != ' ' ) { attr_value += str[i]; ++i; } } } // 属性を追加 if( ! attr_key.empty() && ! attr_value.empty() ) { // 属性名は小文字に統一する attributes_pair.insert( make_pair( MISC::tolower_str( attr_key ), attr_value ) ); } } return attributes_pair; } // // XMLタグ構造の文字列を生成 // std::string Dom::get_xml( const int n ) { if( ! this ) return std::string(); std::stringstream xml; // インデント std::string indent; // テキストノードの文字列 std::string text; // 属性 std::map< std::string, std::string >::iterator attr_it = m_attributes.begin(); // 子要素 std::list< Dom* >::iterator child_it = m_childNodes.begin(); // ノードの種類別に処理 switch( m_nodeType ) { // 要素 case NODE_TYPE_ELEMENT: // インデントを追加 for( int i = 0; i < n; ++i ) indent += " "; // タグの始まり xml << indent << "<" << m_nodeName; // 属性を追加 while( attr_it != m_attributes.end() ) { xml << " " << (*attr_it).first << "=\"" << (*attr_it).second << "\""; ++attr_it; } // 子要素がある場合 if( ! m_childNodes.empty() ) { xml << ">\n"; while( child_it != m_childNodes.end() ) { // 子要素をたどる xml << (*child_it)->get_xml( n + 2 ); ++child_it; } xml << indent << "\n"; } // 空要素の場合 else xml << " />\n"; break; // テキストノード case NODE_TYPE_TEXT: text = MISC::remove_spaces( m_nodeValue ); if( ! text.empty() ) { // インデントを追加 for( int i = 0; i < n; ++i ) indent += " "; xml << indent << text << "\n"; } break; // ドキュメントノード case NODE_TYPE_DOCUMENT: if( ! m_childNodes.empty() ) xml << "\n"; while( child_it != m_childNodes.end() ) { // 子要素をたどる xml << (*child_it)->get_xml(); ++child_it; } break; } return xml.str(); } // // Gtk::TreeModel::Children からノードツリーを生成 // // ただし列は SKELETON::EditColumns を継承したものであること // void Dom::parse( const Gtk::TreeModel::Children& children, SKELETON::EditColumns& columns ) { if( ! this || children.empty() ) return; // Gtk::TreeModel::Children を走査 Gtk::TreeModel::iterator it = children.begin(); while( it != children.end() ) { Gtk::TreeModel::Row row = *it; // 各値を取得( skeleton/editcolumns.h を参照 ) const int type = row[ columns.m_type ]; const Glib::ustring url = row[ columns.m_url ]; const Glib::ustring data = row[ columns.m_data ]; const Glib::ustring name = row[ columns.m_name ]; const size_t dirid = row[ columns.m_dirid ]; const bool expand = row[ columns.m_expand ]; if( type != TYPE_UNKNOWN ) { // タイプにより要素名を決定( board や link など) const std::string node_name = XML::get_name( type ); if( ! node_name.empty() ) { Dom* node = appendChild( NODE_TYPE_ELEMENT, node_name ); if( type == TYPE_DIR && expand ) node->setAttribute( "open", "y" ); if( ! name.empty() ) node->setAttribute( "name", name ); if( ! url.empty() ) node->setAttribute( "url", url ); if( ! data.empty() ) node->setAttribute( "data", data ); if( dirid ) node->setAttribute( "dirid", dirid ); // 再帰 if( ! row.children().empty() ) node->parse( row.children(), columns ); } } ++it; } } // // ノードを分解して Gtk::TreeStore へ Gtk::TreeModel::Row を追加 // // ただし列は SKELETON::EditColumns を継承したものであること // // list_path_expand は開いてるツリーを格納するための参照渡し // void Dom::append_treestore( Glib::RefPtr< Gtk::TreeStore >& treestore, SKELETON::EditColumns& columns, std::list< Gtk::TreePath >& list_path_expand, const Gtk::TreeModel::Row& parent ) { if( ! this ) return; // ノードの子要素を走査 std::list< Dom* >::iterator it = m_childNodes.begin(); while( it != m_childNodes.end() ) { const int node_type = (*it)->nodeType(); if( node_type == NODE_TYPE_ELEMENT ) { const int type = XML::get_type( (*it)->nodeName() ); if( type != TYPE_UNKNOWN ) { Gtk::TreeModel::Row row; // Gtk::TreeStore::append() の追加ポイント if( parent ) row = *( treestore->append( parent.children() ) ); else row = *( treestore->append() ); // 各値をセット columns.setup_row( row, (*it)->getAttribute( "url" ), (*it)->getAttribute( "name" ), (*it)->getAttribute( "data" ), type, 0 ); if( type == TYPE_DIR ){ row[ columns.m_dirid ] = atoi( (*it)->getAttribute( "dirid" ).c_str() ); // 開いているツリーを追加 if( (*it)->getAttribute( "open" ) == "y" ) list_path_expand.push_back( treestore->get_path( row ) ); } // 再帰 if( (*it)->hasChildNodes() ) (*it)->append_treestore( treestore, columns, list_path_expand, row ); } } ++it; } } // // プロパティを扱うアクセッサ // const int Dom::nodeType() { if( ! this ) return NODE_TYPE_UNKNOWN; return m_nodeType; } const std::string Dom::nodeName() { if( ! this ) return std::string(); return m_nodeName; } std::string Dom::nodeValue() { if( ! this ) return std::string(); return m_nodeValue; } void Dom::nodeValue( const std::string& value ) { if( this ) m_nodeValue = value; } // // getElementById() // Dom* Dom::getElementById( const std::string& id ) { Dom* node = 0; if( ! this ) return node; std::list< Dom* >::iterator it = m_childNodes.begin(); while( it != m_childNodes.end() ) { if( (*it)->nodeType() == NODE_TYPE_ELEMENT ) { if( (*it)->getAttribute( "id" ) == id ) node = *it; // 再帰 else if( (*it)->hasChildNodes() ) node = (*it)->getElementById( id ); if( node ) break; } ++it; } return node; } // // getElementsByTagName() // DomList Dom::getElementsByTagName( const std::string& name ) { DomList domlist; if( ! this ) return domlist; std::list< Dom* >::iterator it = m_childNodes.begin(); while( it != m_childNodes.end() ) { if( (*it)->nodeType() == NODE_TYPE_ELEMENT ) { if( (*it)->nodeName() == name ) domlist.push_back( *it ); // 再帰 DomList sub_nodes = (*it)->getElementsByTagName( name ); domlist.splice( domlist.end(), sub_nodes ); } ++it; } return domlist; } // // ノード:ownerDocument // Dom* Dom::ownerDocument() { if( ! this ) return 0; Dom* parent = m_parentNode; while( parent ) { if( parent->nodeType() == NODE_TYPE_DOCUMENT ) break; else parent = parent->parentNode(); } return parent; } // // ノード:parentNode // Dom* Dom::parentNode() { if( ! this ) return 0; return m_parentNode; } void Dom::parentNode( Dom* parent ) { if( this ) m_parentNode = parent; } // // ノード:hasChildNodes // const bool Dom::hasChildNodes() { if( this ) return ! m_childNodes.empty(); return false; } // // ノード:childNodes // DomList Dom::childNodes() { DomList result; // DomList に std::list< Dom* > を代入している if( this ) result = m_childNodes; return result; } // // dom の子ノードをコピーする // void Dom::copy_childNodes( const Dom& dom ) { clear(); DomList children; children = dom.m_childNodes; if( this && children.size() ){ std::list< Dom* >::iterator it = children.begin(); while( it != children.end() ) { Dom* node = new Dom( (*it)->nodeType(), (*it)->nodeName() ); node->nodeValue( (*it)->nodeValue() ); node->parentNode( this ); node->attributes( (*it)->attributes() ); node->copy_childNodes( *(*it) ); m_childNodes.push_back( node ); ++it; } } } // // ノード:firstChild // Dom* Dom::firstChild() { if( ! this || m_childNodes.empty() ) return 0; return m_childNodes.front(); } // // ノード:lastChild // Dom* Dom::lastChild() { if( ! this || m_childNodes.empty() ) return 0; return m_childNodes.back(); } // // ノード:appendChild() // Dom* Dom::appendChild( const int node_type, const std::string& node_name ) { Dom* node = 0; if( this ) { node = new Dom( node_type, node_name, m_html ); node->parentNode( this ); m_childNodes.push_back( node ); } return node; } // // ノード:removeChild() // bool Dom::removeChild( Dom* node ) { if( ! this || ! node ) return false; m_childNodes.remove( node ); if( node ) delete node; return true; } // // ノード:replaceChild() // Dom* Dom::replaceChild( const int node_type, const std::string& node_name, Dom* oldNode ) { Dom* newNode = 0; if( ! this && ! oldNode ) return newNode; newNode = new Dom( node_type, node_name ); std::list< Dom* >::iterator it = m_childNodes.begin(); while( it != m_childNodes.end() ) { if( *it == oldNode ) { newNode->parentNode( oldNode->parentNode() ); m_childNodes.erase( it ); m_childNodes.insert( it, newNode ); break; } ++it; } if( oldNode ) delete oldNode; return newNode; } // // ノード:insertBefore() // Dom* Dom::insertBefore( const int node_type, const std::string& node_name, Dom* insNode ) { Dom* newNode = 0; if( ! this && ! insNode ) return newNode; newNode = new Dom( node_type, node_name ); std::list< Dom* >::iterator it = m_childNodes.begin(); while( it != m_childNodes.end() ) { if( *it == insNode ) { newNode->parentNode( insNode->parentNode() ); m_childNodes.insert( it, newNode ); break; } ++it; } return newNode; } // // ノード:previousSibling // Dom* Dom::previousSibling() { Dom* previous = 0; if( ! this ) return previous; DomList brothers = m_parentNode->childNodes(); std::list< Dom* >::iterator it = brothers.begin(); while( it != brothers.end() ) { if( it != brothers.begin() && *it == this ) { previous = *( --it ); break; } ++it; } return previous; } // // ノード:nextSibling // Dom* Dom::nextSibling() { Dom* next = 0; if( ! this ) return next; DomList brothers = m_parentNode->childNodes(); std::list< Dom* >::iterator it = brothers.begin(); while( it != brothers.end() ) { if( *it == this ) { ++it; if( it != brothers.end() ) next = *it; break; } ++it; } return next; } // // 属性:attributes // std::map< std::string, std::string > Dom::attributes() { std::map< std::string, std::string > result; if( this ) result = m_attributes; return result; } void Dom::attributes( const std::map< std::string, std::string > attributes ) { if( this && ! attributes.empty() ) m_attributes = attributes; } // // 属性:hasAttributes() // const bool Dom::hasAttributes() { if( this ) return ! m_attributes.empty(); return false; } // // 属性:hasAttribute() // const bool Dom::hasAttribute( const std::string& name ) { if( ! this || name.empty() ) return false; return m_attributes.find( name ) != m_attributes.end(); } // // 属性:getAttribute() // std::string Dom::getAttribute( const std::string& name ) { std::string value; if( ! this || name.empty() ) return value; std::map< std::string, std::string >::iterator it = m_attributes.find( name ); if( it != m_attributes.end() ) value = MISC::html_unescape( (*it).second ); return value; } // // 属性:setAttribute( std::string ) // bool Dom::setAttribute( const std::string& name, const std::string& value ) { if( ! this || name.empty() || value.empty() || m_nodeType != NODE_TYPE_ELEMENT ) return false; // 属性名は小文字に統一 const std::string attr_name = MISC::tolower_str( name ); m_attributes.insert( make_pair( attr_name, MISC::html_escape( value ) ) ); return true; } // // 属性:setAttribute( int ) // bool Dom::setAttribute( const std::string& name, const int& value ) { if( ! this || name.empty() || m_nodeType != NODE_TYPE_ELEMENT ) return false; // 属性名は小文字に統一 const std::string attr_name = MISC::tolower_str( name ); m_attributes.insert( make_pair( attr_name, MISC::itostr( value ) ) ); return true; } // // 属性:removeAttribute() // bool Dom::removeAttribute( const std::string& name ) { bool result = false; if( ! this || name.empty() ) return result; std::map< std::string, std::string >::iterator it = m_attributes.find( name ); if( it != m_attributes.end() ) { m_attributes.erase( it ); result = true; } return result; } jd-2.8.7-140104/src/xml/dom.h0000644000076400010400000001057111043627612012115 0ustar // License: GPL2 // DOM基本クラス #ifndef _DOM_H #define _DOM_H #include #include #include #include #include #include "domlist.h" namespace SKELETON { class EditColumns; } namespace XML { // ノードタイプ( m_nodeType ) enum { NODE_TYPE_UNKNOWN = 0, NODE_TYPE_ELEMENT, NODE_TYPE_TEXT, NODE_TYPE_DOCUMENT }; class DomList; class Dom { // HTMLの時に空要素として扱う要素を格納する static std::set< std::string > m_static_html_elements; // HTMLモード有/無 bool m_html; // プロパティ int m_nodeType; std::string m_nodeName; std::string m_nodeValue; Dom* m_parentNode; // 属性ペアのリスト std::map< std::string, std::string > m_attributes; // 子要素リスト std::list< Dom* > m_childNodes; private: // このクラスの代入演算子は使わない Dom& operator=( const Dom& ); // 属性ペアのリストを作成 std::map< std::string, std::string > create_attribute( const std::string& str ); protected: // Document をフレンドクラスとする( append_treestore() を public にしたくない ) friend class Document; // コピーコンストラクタ Dom( const Dom& dom ); // パースして子ノードを追加 void parse( const std::string& str ); void parse( const Gtk::TreeModel::Children& children, SKELETON::EditColumns& columns ); // プロパティをセットするアクセッサ void parentNode( Dom* parent ); void copy_childNodes( const Dom& dom ); // dom の子ノードをコピーする // ノードを分解して Gtk::TreeStore へ Gtk::TreeModel::Row を追加 // ただし列は SKELETON::EditColumns を継承したものであること void append_treestore( Glib::RefPtr< Gtk::TreeStore >& treestore, SKELETON::EditColumns& columns, std::list< Gtk::TreePath >& list_path_expand, const Gtk::TreeModel::Row& parnet = Gtk::TreeModel::Row() ); public: // コンストラクタ、デストラクタ Dom( const int& type, const std::string& name, const bool html = false ); virtual ~Dom(); // クリア void clear(); // XMLタグ構造の文字列を生成 std::string get_xml( const int n = 0 ); // getElement(s)By*() Dom* getElementById( const std::string& id ); DomList getElementsByTagName( const std::string& name ); // プロパティを扱うアクセッサ const int nodeType(); const std::string nodeName(); std::string nodeValue(); void nodeValue( const std::string& value ); // ノード // 注意:appendChild(), replaceChild(), insertBefore() は // 戻り値と引数がJavascriptなどのDOMとは異なります。 // // delete忘れを防ぐために外部でnewしない方が良いだろうという // 事で、メンバ関数の内部でnewして追加されたノードのポインタ // を返すようにしてあります。 Dom* ownerDocument(); Dom* parentNode(); const bool hasChildNodes(); DomList childNodes(); Dom* firstChild(); Dom* lastChild(); Dom* appendChild( const int node_type, const std::string& node_name ); bool removeChild( Dom* node ); Dom* replaceChild( const int node_type, const std::string& node_name, Dom* oldNode ); Dom* insertBefore( const int node_type, const std::string& node_name, Dom* insNode ); Dom* previousSibling(); Dom* nextSibling(); // 属性 const bool hasAttributes(); std::map< std::string, std::string > attributes(); void attributes( const std::map< std::string, std::string > attributes ); const bool hasAttribute( const std::string& name ); std::string getAttribute( const std::string& name ); bool setAttribute( const std::string& name, const std::string& value ); bool setAttribute( const std::string& name, const int& value ); bool removeAttribute( const std::string& name ); }; } #endif jd-2.8.7-140104/src/xml/domlist.cpp0000644000076400010400000000470610650414542013346 0ustar // License GPL2 //#define _DEBUG #include "jddebug.h" #include "domlist.h" using namespace XML; DomList::DomList() { } DomList::~DomList() { } // std::list< Dom* > が代入された場合 DomList& DomList::operator =( const std::list< Dom* >& list ) { m_list = list; return *this; } // 添字によるアクセス Dom* DomList::operator []( const unsigned int n ) { if( ! this || m_list.empty() || n > m_list.size() ) return 0; size_t count = 0; std::list< Dom* >::iterator it = m_list.begin(); while( it != m_list.end() ) { if( count == n ) return *it; ++count; ++it; } return 0; } // 以下 std::list の主なメンバ関数 std::list< Dom* >::iterator DomList::begin() { return m_list.begin(); } std::list< Dom* >::reverse_iterator DomList::rbegin() { return m_list.rbegin(); } std::list< Dom* >::iterator DomList::end() { return m_list.end(); } std::list< Dom* >::reverse_iterator DomList::rend() { return m_list.rend(); } size_t DomList::size() const { return m_list.size(); } size_t DomList::max_size() const { return m_list.max_size(); } bool DomList::empty() const { return m_list.empty(); } // 参照ではなくポインタを返す Dom* DomList::front() { if( m_list.empty() ) return 0; return *m_list.begin(); } // 参照ではなくポインタを返す Dom* DomList::back() { if( m_list.empty() ) return 0; return *m_list.end(); } void DomList::push_front( Dom* dom ) { m_list.push_front( dom ); } void DomList::push_back( Dom* dom ) { m_list.push_back( dom ); } void DomList::pop_front() { m_list.pop_front(); } void DomList::pop_back() { m_list.pop_back(); } std::list< Dom* >::iterator DomList::insert( std::list< Dom* >::iterator it, Dom* dom ) { return m_list.insert( it, dom ); } std::list< Dom* >::iterator DomList::erase( std::list< Dom* >::iterator it ) { return erase( it ); } void DomList::clear() { m_list.clear(); } void DomList::splice( std::list< Dom* >::iterator it, DomList& domlist ) { m_list.splice( it, domlist.m_list ); } void DomList::remove( Dom* dom ) { m_list.remove( dom ); } void DomList::unique() { m_list.unique(); } void DomList::merge( DomList& domlist ) { m_list.merge( domlist.m_list ); } void DomList::sort() { m_list.sort(); } void DomList::reverce() { m_list.reverse(); } void DomList::swap( DomList& domlist ) { m_list.swap( domlist.m_list ); } jd-2.8.7-140104/src/xml/domlist.h0000644000076400010400000000353511517034552013014 0ustar // License GPL2 // std::list< Dom* > の代わりのクラス // // Domクラスで std::list のメンバ関数の front() と back() の戻り値が // 存在しないインスタンスへの参照になっていると都合が悪いので、その対策 // のためだけに作られたアホみたいなクラスです。ついでに添字を使えるよう // にしてあります。 #ifndef _DOMLIST_H #define _DOMLIST_H #include #include namespace XML { class Dom; class DomList { std::list< Dom* > m_list; //DomList( const DomList& ); public: DomList(); ~DomList(); // std::list< Dom* > が代入された場合 DomList& operator =( const std::list< Dom* >& list ); // 添字によるアクセス Dom* operator []( const unsigned int n ); std::list< Dom* > get_list() { return m_list; } std::list< Dom* >::iterator begin(); std::list< Dom* >::reverse_iterator rbegin(); std::list< Dom* >::iterator end(); std::list< Dom* >::reverse_iterator rend(); size_t size() const; size_t max_size() const; bool empty() const; Dom* front(); // front() と back()は参照ではなくポインタを返す Dom* back(); void push_front( Dom* dom ); void push_back( Dom* dom ); void pop_front(); void pop_back(); std::list< Dom* >::iterator insert( std::list< Dom* >::iterator it, Dom* dom ); std::list< Dom* >::iterator erase( std::list< Dom* >::iterator it ); void clear(); void splice( std::list< Dom* >::iterator it, DomList& domlist ); void remove( Dom* dom ); void unique(); void merge( DomList& domlist ); void sort(); void reverce(); void swap( DomList& domlist ); }; } #endif jd-2.8.7-140104/src/xml/Makefile.am0000644000076400010400000000035012072045132013205 0ustar noinst_LIBRARIES = libxml.a libxml_a_SOURCES = \ document.cpp \ dom.cpp \ domlist.cpp \ tools.cpp noinst_HEADERS = \ document.h \ dom.h \ domlist.h \ tools.h AM_CXXFLAGS = @GTKMM_CFLAGS@ AM_CPPFLAGS = -I$(top_srcdir)/src jd-2.8.7-140104/src/xml/tools.cpp0000644000076400010400000001024711350440352013024 0ustar // License: GPL2 #include "tools.h" #include "icons/iconmanager.h" #include "type.h" // // TYPE_ID から要素名を取得( TYPE_ID は global.h を参照 ) // std::string XML::get_name( const int type_id ) { std::string name; switch( type_id ) { case TYPE_DIR: // サブディレクトリ name = "subdir"; break; case TYPE_BOARD: // 板 name = "board"; break; case TYPE_BOARD_UPDATE: // 更新可能板 name = "board_update"; break; case TYPE_THREAD: // スレ name = "thread"; break; case TYPE_THREAD_UPDATE: // 更新可能スレ name = "thread_update"; break; case TYPE_THREAD_OLD: // dat落ちスレ name = "thread_old"; break; case TYPE_IMAGE: // 画像 name = "image"; break; case TYPE_COMMENT: // コメント name = "comment"; break; case TYPE_LINK: // リンク name = "link"; break; case TYPE_VBOARD: // 仮想板 name = "vboard"; break; case TYPE_AA: // AA name = "aa"; break; case TYPE_HISTITEM: // HISTORY::ViewHistoryItem name = "histitem"; break; case TYPE_USRCMD: name = "usrcmd"; break; case TYPE_LINKFILTER: name = "linkfilter"; break; case TYPE_SEPARATOR: name = "separator"; break; } return name; } // // 要素名から TYPE_ID を取得 // int XML::get_type( const std::string& node_name ) { int type = TYPE_UNKNOWN; if( node_name == "board" ) { type = TYPE_BOARD; } else if( node_name == "board_update" ) { type = TYPE_BOARD_UPDATE; } else if( node_name == "comment" ) { type = TYPE_COMMENT; } else if( node_name == "image" ) { type = TYPE_IMAGE; } else if( node_name == "link" ) { type = TYPE_LINK; } else if( node_name == "vboard" ) { type = TYPE_VBOARD; } else if( node_name == "subdir" ) { type = TYPE_DIR; } else if( node_name == "thread" ) { type = TYPE_THREAD; } else if( node_name == "thread_update" ) { type = TYPE_THREAD_UPDATE; } else if( node_name == "thread_old" ) { type = TYPE_THREAD_OLD; } else if( node_name == "aa" ) { type = TYPE_AA; } else if( node_name == "histitem" ) { type = TYPE_HISTITEM; } else if( node_name == "usrcmd" ) { type = TYPE_USRCMD; } else if( node_name == "linkfilter" ) { type = TYPE_LINKFILTER; } else if( node_name == "separator" ) { type = TYPE_SEPARATOR; } return type; } // // TYPE_ID からアイコンを取得 ( アイコンは icons/iconmanager.h を参照 ) // Glib::RefPtr< Gdk::Pixbuf > XML::get_icon( const int type_id ) { Glib::RefPtr< Gdk::Pixbuf > icon = ICON::get_icon( ICON::TRANSPARENT ); switch( type_id ) { case TYPE_DIR: icon = ICON::get_icon( ICON::DIR ); break; case TYPE_BOARD: icon = ICON::get_icon( ICON::BOARD ); break; case TYPE_BOARD_UPDATE: icon = ICON::get_icon( ICON::BOARD_UPDATE ); break; case TYPE_THREAD: icon = ICON::get_icon( ICON::THREAD ); break; case TYPE_THREAD_UPDATE: icon = ICON::get_icon( ICON::THREAD_UPDATE ); break; case TYPE_THREAD_OLD: icon = ICON::get_icon( ICON::THREAD_OLD ); break; case TYPE_IMAGE: icon = ICON::get_icon( ICON::IMAGE ); break; case TYPE_LINK: icon = ICON::get_icon( ICON::LINK ); break; case TYPE_VBOARD: icon = ICON::get_icon( ICON::BOARD ); break; case TYPE_USRCMD: icon = ICON::get_icon( ICON::THREAD ); break; } return icon; } jd-2.8.7-140104/src/xml/tools.h0000644000076400010400000000074510630003772012474 0ustar // License: GPL2 #ifndef _TOOLS_H #define _TOOLS_H #include #include namespace XML { // TYPE_ID から要素名を取得( TYPE_ID は global.h を参照 ) std::string get_name( const int type_id ); // 要素名から TYPE_ID を取得 int get_type( const std::string& node_name ); // TYPE_ID からアイコンを取得 ( アイコンは icons/iconmanager.h を参照 ) Glib::RefPtr< Gdk::Pixbuf > get_icon( const int type_id ); } #endif