bbs/.BOARDS bbs/.hushlogin bbs/0Announce/bms/deleted/.cvsignore bbs/0Announce/bms/deleted/.Names bbs/0Announce/bms/.cvsignore bbs/0Announce/bms/.Names bbs/0Announce/sysops/groups/junk/.cvsignore bbs/0Announce/sysops/groups/junk/.Names bbs/0Announce/sysops/groups/syssecurity/.cvsignore bbs/0Announce/sysops/groups/syssecurity/.Names bbs/0Announce/sysops/groups/.cvsignore bbs/0Announce/sysops/groups/.Names bbs/0Announce/sysops/.cvsignore bbs/0Announce/sysops/.Names bbs/0Announce/sysops/Firebird-30 bbs/0Announce/sysops/admin-manual bbs/0Announce/bbslist/yesterday bbs/0Announce/bbslist/.Names bbs/0Announce/bbslist/countusr bbs/0Announce/bbslist/board1 bbs/0Announce/bbslist/board2 bbs/0Announce/bbslist/countusr.last bbs/0Announce/bbslist/newacct.last bbs/0Announce/bbslist/newacct.today bbs/0Announce/bbslist/today bbs/0Announce/bbslist/topall bbs/0Announce/bbslist/toplogin bbs/0Announce/bbslist/toppost bbs/0Announce/bbslist/topstay bbs/0Announce/bbslist/.cvsignore bbs/0Announce/groups/GROUP_0/bbslists/.cvsignore bbs/0Announce/groups/GROUP_0/bbslists/.Names bbs/0Announce/groups/GROUP_0/newcomers/.cvsignore bbs/0Announce/groups/GROUP_0/newcomers/.Names bbs/0Announce/groups/GROUP_0/sysop/.cvsignore bbs/0Announce/groups/GROUP_0/sysop/.Names bbs/0Announce/groups/GROUP_0/vote/.cvsignore bbs/0Announce/groups/GROUP_0/vote/.Names bbs/0Announce/groups/GROUP_0/.cvsignore bbs/0Announce/groups/GROUP_0/.Names bbs/0Announce/groups/GROUP_7/notepad/.Names bbs/0Announce/groups/GROUP_7/.Names bbs/0Announce/groups/.cvsignore bbs/0Announce/groups/.Names bbs/0Announce/usermanual/value bbs/0Announce/usermanual/.Names bbs/0Announce/usermanual/Goodbye bbs/0Announce/usermanual/Boards bbs/0Announce/usermanual/Config bbs/0Announce/usermanual/Digest bbs/0Announce/usermanual/EGroup bbs/0Announce/usermanual/InfoEdit bbs/0Announce/usermanual/Help bbs/0Announce/usermanual/Service bbs/0Announce/usermanual/Mail bbs/0Announce/usermanual/boardmenu bbs/0Announce/usermanual/Talk bbs/0Announce/usermanual/advice bbs/0Announce/usermanual/enterbbs bbs/0Announce/usermanual/register bbs/0Announce/usermanual/telix bbs/0Announce/usermanual/.cvsignore bbs/0Announce/.cvsignore bbs/0Announce/.Names bbs/0Announce/.Search bbs/bbssrc/src/SO/thread.so bbs/bbssrc/src/SO/paging.c bbs/bbssrc/src/SO/socket.c bbs/bbssrc/src/SO/thread.c bbs/bbssrc/src/SO/paging.so bbs/bbssrc/src/SO/Makefile bbs/bbssrc/src/Install.sh.in bbs/bbssrc/src/Makefile bbs/bbssrc/src/admintool.c bbs/bbssrc/src/announce.c bbs/bbssrc/src/bbs.c bbs/bbssrc/src/bbsd.c bbs/bbssrc/src/bbsgopher.c bbs/bbssrc/src/bbsrf.c bbs/bbssrc/src/bcache.c bbs/bbssrc/src/bm.c bbs/bbssrc/src/boards.c bbs/bbssrc/src/chat.c bbs/bbssrc/src/comm_lists.c bbs/bbssrc/src/delete.c bbs/bbssrc/src/edit.c bbs/bbssrc/src/expire.c bbs/bbssrc/src/fileshm.c bbs/bbssrc/src/goodbye.c bbs/bbssrc/src/help.c bbs/bbssrc/src/io.c bbs/bbssrc/src/list.c bbs/bbssrc/src/mail.c bbs/bbssrc/src/main.c bbs/bbssrc/src/maintain.c bbs/bbssrc/src/modetype.c bbs/bbssrc/src/more.c bbs/bbssrc/src/namecomplete.c bbs/bbssrc/src/pass.c bbs/bbssrc/src/postheader.c bbs/bbssrc/src/read.c bbs/bbssrc/src/record.c bbs/bbssrc/src/register.c bbs/bbssrc/src/screen.c bbs/bbssrc/src/sendmsg.c bbs/bbssrc/src/station.c bbs/bbssrc/src/stuff.c bbs/bbssrc/src/talk.c bbs/bbssrc/src/term.c bbs/bbssrc/src/userinfo.c bbs/bbssrc/src/ver.sh bbs/bbssrc/src/vote.c bbs/bbssrc/src/xyz.c bbs/bbssrc/src/Install.sh.in.orig bbs/bbssrc/src/Install.sh bbs/bbssrc/src/bbsd bbs/bbssrc/src/chatd bbs/bbssrc/src/expire bbs/bbssrc/util/innbbsd/doc/release.0.44 bbs/bbssrc/util/innbbsd/doc/bbnnrp-generic-gateway bbs/bbssrc/util/innbbsd/doc/bbslink.8 bbs/bbssrc/util/innbbsd/doc/bbslink.patch bbs/bbssrc/util/innbbsd/doc/bbsnnrp.8 bbs/bbssrc/util/innbbsd/doc/ctlinnbbsd.8 bbs/bbssrc/util/innbbsd/doc/filter.doc bbs/bbssrc/util/innbbsd/doc/gateway.doc bbs/bbssrc/util/innbbsd/doc/gateway2.doc bbs/bbssrc/util/innbbsd/doc/history-corrupt bbs/bbssrc/util/innbbsd/doc/innbbsd.8 bbs/bbssrc/util/innbbsd/doc/mailing-list-reply bbs/bbssrc/util/innbbsd/doc/makedbz.8 bbs/bbssrc/util/innbbsd/doc/mkhistory.8 bbs/bbssrc/util/innbbsd/doc/multiple-feeds bbs/bbssrc/util/innbbsd/doc/newsfeeds.bbs.5 bbs/bbssrc/util/innbbsd/doc/nodelist.bbs.5 bbs/bbssrc/util/innbbsd/doc/relaese.0.50beta-5F bbs/bbssrc/util/innbbsd/doc/alt-gateways bbs/bbssrc/util/innbbsd/innd/timefmt.y bbs/bbssrc/util/innbbsd/innd/README bbs/bbssrc/util/innbbsd/innd/bbslib.pl.in bbs/bbssrc/util/innbbsd/innd/bbspost.c bbs/bbssrc/util/innbbsd/innd/bmpost bbs/bbssrc/util/innbbsd/innd/bntplink.in bbs/bbssrc/util/innbbsd/innd/in.bntpd.in bbs/bbssrc/util/innbbsd/innd/innbbslib.pl.in bbs/bbssrc/util/innbbsd/innd/inntobbs.in bbs/bbssrc/util/innbbsd/innd/mailpost.in bbs/bbssrc/util/innbbsd/innd/modify.doc bbs/bbssrc/util/innbbsd/innd/parsedate.c bbs/bbssrc/util/innbbsd/innd/rfc931.pl.in bbs/bbssrc/util/innbbsd/innd/tcp.pl.in bbs/bbssrc/util/innbbsd/innd/Makefile bbs/bbssrc/util/innbbsd/convert/hztty/tables/Makefile bbs/bbssrc/util/innbbsd/convert/hztty/tables/README bbs/bbssrc/util/innbbsd/convert/hztty/tables/gen_b2g.sh bbs/bbssrc/util/innbbsd/convert/hztty/tables/gen_ctab.c bbs/bbssrc/util/innbbsd/convert/hztty/HZ.spec bbs/bbssrc/util/innbbsd/convert/hztty/Makefile bbs/bbssrc/util/innbbsd/convert/hztty/README bbs/bbssrc/util/innbbsd/convert/hztty/b2g.c bbs/bbssrc/util/innbbsd/convert/hztty/b2g_tables.c bbs/bbssrc/util/innbbsd/convert/hztty/config.h bbs/bbssrc/util/innbbsd/convert/hztty/dummy_main.c bbs/bbssrc/util/innbbsd/convert/hztty/hz2gb.c bbs/bbssrc/util/innbbsd/convert/hztty/hztty.1 bbs/bbssrc/util/innbbsd/convert/hztty/io.c bbs/bbssrc/util/innbbsd/convert/hztty/io.h bbs/bbssrc/util/innbbsd/convert/hztty/log.c bbs/bbssrc/util/innbbsd/convert/hztty/main.c bbs/bbssrc/util/innbbsd/convert/hztty/tty.c bbs/bbssrc/util/innbbsd/convert/jis/sinocojg.cod bbs/bbssrc/util/innbbsd/convert/jis/ChangeLog bbs/bbssrc/util/innbbsd/convert/jis/Makefile bbs/bbssrc/util/innbbsd/convert/jis/README bbs/bbssrc/util/innbbsd/convert/jis/b2j bbs/bbssrc/util/innbbsd/convert/jis/j2b bbs/bbssrc/util/innbbsd/convert/jis/jis.c bbs/bbssrc/util/innbbsd/convert/jis/patch.c bbs/bbssrc/util/innbbsd/convert/jis/sinocobg.cod bbs/bbssrc/util/innbbsd/convert/jis/sinocobj.cod bbs/bbssrc/util/innbbsd/convert/jis/sinocode.c bbs/bbssrc/util/innbbsd/convert/jis/sinocode.man bbs/bbssrc/util/innbbsd/convert/jis/sinocogb.cod bbs/bbssrc/util/innbbsd/convert/jis/sinocogj.cod bbs/bbssrc/util/innbbsd/convert/jis/sinocojb.cod bbs/bbssrc/util/innbbsd/convert/jis/COPYING bbs/bbssrc/util/innbbsd/convert/util/b2g bbs/bbssrc/util/innbbsd/convert/util/b2j bbs/bbssrc/util/innbbsd/convert/util/g2b bbs/bbssrc/util/innbbsd/convert/util/j2b bbs/bbssrc/util/innbbsd/COPYRIGHT.nocem bbs/bbssrc/util/innbbsd/FEATURES bbs/bbssrc/util/innbbsd/INSTALL.nocem bbs/bbssrc/util/innbbsd/Makefile.in bbs/bbssrc/util/innbbsd/NOCEM.1 bbs/bbssrc/util/innbbsd/NOCEM.2 bbs/bbssrc/util/innbbsd/NOCEM.3 bbs/bbssrc/util/innbbsd/README bbs/bbssrc/util/innbbsd/README.-0.50beta-5F bbs/bbssrc/util/innbbsd/README.PalmBBS bbs/bbssrc/util/innbbsd/README.PowerBBS bbs/bbssrc/util/innbbsd/README.antispam bbs/bbssrc/util/innbbsd/README.nocem bbs/bbssrc/util/innbbsd/TODO bbs/bbssrc/util/innbbsd/TODO.nocem bbs/bbssrc/util/innbbsd/bbslib.c bbs/bbssrc/util/innbbsd/bbslib.h bbs/bbssrc/util/innbbsd/bbslink.c bbs/bbssrc/util/innbbsd/bbsnnrp.c bbs/bbssrc/util/innbbsd/clibrary.h bbs/bbssrc/util/innbbsd/daemon.c bbs/bbssrc/util/innbbsd/closeonexec.c bbs/bbssrc/util/innbbsd/connectsock.c bbs/bbssrc/util/innbbsd/ctlinnbbsd.c bbs/bbssrc/util/innbbsd/daemon.h bbs/bbssrc/util/innbbsd/dbz.c bbs/bbssrc/util/innbbsd/dbz.h bbs/bbssrc/util/innbbsd/dbz_query_sample.c bbs/bbssrc/util/innbbsd/dbzinnbbsd.c bbs/bbssrc/util/innbbsd/dbzserver.c bbs/bbssrc/util/innbbsd/dbztool.c bbs/bbssrc/util/innbbsd/echobbslib.c bbs/bbssrc/util/innbbsd/externs.h bbs/bbssrc/util/innbbsd/file.c bbs/bbssrc/util/innbbsd/filter.c bbs/bbssrc/util/innbbsd/his.c bbs/bbssrc/util/innbbsd/his.h bbs/bbssrc/util/innbbsd/hisconvert.in bbs/bbssrc/util/innbbsd/innbbsconf.h bbs/bbssrc/util/innbbsd/innbbsd.c bbs/bbssrc/util/innbbsd/innbbsd.h bbs/bbssrc/util/innbbsd/inndchannel.c bbs/bbssrc/util/innbbsd/inntobbs.c bbs/bbssrc/util/innbbsd/inntobbs.h bbs/bbssrc/util/innbbsd/killspam.c bbs/bbssrc/util/innbbsd/lang.c bbs/bbssrc/util/innbbsd/lang.h bbs/bbssrc/util/innbbsd/makedbz.c bbs/bbssrc/util/innbbsd/mkhistory.c bbs/bbssrc/util/innbbsd/ncmperm.bbs bbs/bbssrc/util/innbbsd/newsfeeds.bbs bbs/bbssrc/util/innbbsd/nntp.h bbs/bbssrc/util/innbbsd/nocem.c bbs/bbssrc/util/innbbsd/nocem.h bbs/bbssrc/util/innbbsd/nodelist.bbs bbs/bbssrc/util/innbbsd/parsdate.y bbs/bbssrc/util/innbbsd/pmain.c bbs/bbssrc/util/innbbsd/port.c bbs/bbssrc/util/innbbsd/qp_conv.c bbs/bbssrc/util/innbbsd/r_port.c bbs/bbssrc/util/innbbsd/receive_article.c bbs/bbssrc/util/innbbsd/rfc931.c bbs/bbssrc/util/innbbsd/version.h bbs/bbssrc/util/innbbsd/wildmat.c bbs/bbssrc/util/innbbsd/Makefile bbs/bbssrc/util/innbbsd/CHANGES bbs/bbssrc/util/innbbsd/CHANGES.nocem bbs/bbssrc/util/fingerd/00README bbs/bbssrc/util/fingerd/Makefile bbs/bbssrc/util/fingerd/fingerd.c bbs/bbssrc/util/fingerd/pathnames.h bbs/bbssrc/util/gopherd/00README bbs/bbssrc/util/gopherd/Makefile bbs/bbssrc/util/gopherd/gopherd.c bbs/bbssrc/util/in.zbbsd/00README bbs/bbssrc/util/deljunk/Makefile bbs/bbssrc/util/deljunk/deljunk.c bbs/bbssrc/util/local_utl/Makefile bbs/bbssrc/util/local_utl/account.c bbs/bbssrc/util/local_utl/averun.c bbs/bbssrc/util/local_utl/bbslocalmail.c bbs/bbssrc/util/local_utl/bbspop3d.c bbs/bbssrc/util/local_utl/bbstop.c bbs/bbssrc/util/local_utl/bfinger.c bbs/bbssrc/util/local_utl/birthday.c bbs/bbssrc/util/local_utl/chboard.c bbs/bbssrc/util/local_utl/dumpboardrc.c bbs/bbssrc/util/local_utl/horoscope.c bbs/bbssrc/util/local_utl/http-finger.c bbs/bbssrc/util/local_utl/loadrecord.c bbs/bbssrc/util/local_utl/mailreport.c bbs/bbssrc/util/local_utl/newacct.c bbs/bbssrc/util/local_utl/poststat.c bbs/bbssrc/util/local_utl/refriend.c bbs/bbssrc/util/local_utl/refriend2.c bbs/bbssrc/util/local_utl/rehome.c bbs/bbssrc/util/local_utl/remail.c bbs/bbssrc/util/local_utl/remake.c bbs/bbssrc/util/local_utl/renotepad.c bbs/bbssrc/util/local_utl/repass.c bbs/bbssrc/util/local_utl/resize.c bbs/bbssrc/util/local_utl/restruct.c bbs/bbssrc/util/local_utl/showuser.c bbs/bbssrc/util/local_utl/usage.c bbs/bbssrc/util/local_utl/Makefile.in bbs/bbssrc/util/mail2bbs/Makefile bbs/bbssrc/util/mail2bbs/bbsmail.in bbs/bbssrc/util/mail2bbs/mail-list.c bbs/bbssrc/util/mail2bbs/mail2bbs.c bbs/bbssrc/util/mail2bbs/mail2bbs.h bbs/bbssrc/util/mail2bbs/mailgate.pl.in bbs/bbssrc/util/mail2bbs/qp_conv.c bbs/bbssrc/util/mail2bbs/rfc931.pl bbs/bbssrc/util/mail2bbs/tcp.pl bbs/bbssrc/util/mail2bbs/Makefile.in bbs/bbssrc/util/telnetd/00README bbs/bbssrc/util/upgrade/include/new_struct.h bbs/bbssrc/util/upgrade/include/struct.2.5.h bbs/bbssrc/util/upgrade/include/struct.2.62M.h bbs/bbssrc/util/upgrade/include/struct.2.66M.h bbs/bbssrc/util/upgrade/include/struct.M2.h bbs/bbssrc/util/upgrade/00README bbs/bbssrc/util/upgrade/Makefile bbs/bbssrc/util/upgrade/refriend.c bbs/bbssrc/util/upgrade/rehome.c bbs/bbssrc/util/upgrade/repass.c bbs/bbssrc/util/upgrade/chboard.c bbs/bbssrc/lib/libBBS/dlm.o bbs/bbssrc/lib/libBBS/dlm.c bbs/bbssrc/lib/libBBS/fileio.c bbs/bbssrc/lib/libBBS/html.c bbs/bbssrc/lib/libBBS/mmdecode.c bbs/bbssrc/lib/libBBS/string.c bbs/bbssrc/lib/libBBS/string.o bbs/bbssrc/lib/libBBS/html.o bbs/bbssrc/lib/libBBS/mmdecode.o bbs/bbssrc/lib/libBBS/fileio.o bbs/bbssrc/lib/libBBS/Makefile bbs/bbssrc/lib/Makefile bbs/bbssrc/lib/libBBS.a bbs/bbssrc/include/os_dep.h bbs/bbssrc/include/bbs.h bbs/bbssrc/include/chat.h.in bbs/bbssrc/include/config.h.in bbs/bbssrc/include/edit.h bbs/bbssrc/include/functions.h bbs/bbssrc/include/modes.h bbs/bbssrc/include/os_dep.h.in bbs/bbssrc/include/permissions.h bbs/bbssrc/include/screen.h bbs/bbssrc/include/site_conf.h.in bbs/bbssrc/include/structs.h bbs/bbssrc/include/vote.h bbs/bbssrc/include/config.h bbs/bbssrc/include/chat.h bbs/bbssrc/include/bbsgopher.h bbs/bbssrc/doc/example/startbbs.sh bbs/bbssrc/doc/example/cron.bbs bbs/bbssrc/doc/example/ctm.sh bbs/bbssrc/doc/example/expire.ctl bbs/bbssrc/doc/example/sendmail-8.10.1-FreeBSD.cf bbs/bbssrc/doc/example/sendmail-8.10.1-Linux.cf bbs/bbssrc/doc/example/sendmail-8.11.1-FreeBSD.cf bbs/bbssrc/doc/example/sendmail-8.9.3-FreeBSD.cf bbs/bbssrc/doc/example/00README bbs/bbssrc/doc/00README bbs/bbssrc/doc/Admin_Manual bbs/bbssrc/doc/BBCall bbs/bbssrc/doc/Core_Team bbs/bbssrc/doc/FAQ bbs/bbssrc/doc/Firebird-30 bbs/bbssrc/doc/NoCem bbs/bbssrc/doc/Quick_Install bbs/bbssrc/doc/TW_NewsGroup_List bbs/bbssrc/doc/Upgrading bbs/bbssrc/TODO_List bbs/bbssrc/config.guess bbs/bbssrc/config.sub bbs/bbssrc/configure bbs/bbssrc/configure.in bbs/bbssrc/install.sh bbs/bbssrc/configure.orig bbs/bbssrc/configure.inf bbs/bbssrc/Makefile bbs/bbssrc/.reldate bbs/bbssrc/BUG_REPORT bbs/bbssrc/ChangeLog bbs/bbssrc/Makefile.in bbs/bin/www.sh bbs/bin/bbsnet.sh bbs/bin/bbstop.sh bbs/bin/cdict.sh bbs/bin/daily.sh bbs/bin/edict.sh bbs/bin/game.sh bbs/bin/gopher.sh bbs/bin/irc.sh bbs/bin/mvlogs.sh bbs/bin/showuser.sh bbs/bin/sysinfo.sh bbs/bin/archie.sh bbs/bin/bbsd bbs/bin/chatd bbs/bin/expire bbs/bin/paging.so bbs/bin/thread.so bbs/etc/posts/day bbs/etc/posts/month bbs/etc/posts/week bbs/etc/posts/year bbs/etc/autopost bbs/etc/bad_email bbs/etc/bad_id bbs/etc/boardref bbs/etc/chatstation bbs/etc/checknotepad bbs/etc/expire.ctl bbs/etc/expired bbs/etc/f_fill bbs/etc/firstlogin bbs/etc/fmail bbs/etc/goodbye bbs/etc/issue bbs/etc/loginfull bbs/etc/logout bbs/etc/mailcheck bbs/etc/mentor bbs/etc/menu.ini bbs/etc/newregister bbs/etc/regexpire bbs/etc/register bbs/etc/s_fill bbs/etc/showuser.msg bbs/etc/smail bbs/etc/sysops bbs/etc/user_full bbs/etc/whatdate bbs/etc/wmail bbs/etc/sysconf.ini bbs/help/votehelp bbs/help/boardreadhelp bbs/help/chathelp bbs/help/chatophelp bbs/help/edithelp bbs/help/friendshelp bbs/help/mailerror-explain bbs/help/mailreadhelp bbs/help/mainreadhelp bbs/help/morehelp bbs/help/msghelp bbs/help/rejectshelp bbs/help/userlisthelp bbs/help/usershelp bbs/help/announcereadhelp bbs/innd/black.list.general bbs/innd/newsfeeds.bbs bbs/innd/nodelist.bbs bbs/table/big5.0 bbs/table/big5.1 bbs/table/big5.2 bbs/table/big5.3 bbs/table/big5.4 bbs/table/big5.5 bbs/table/big5.6 bbs/table/big5.7 bbs/CONTRIB bbs/COPYING bbs/Version.Info bbs/Welcome bbs/Welcome2 bbs/boards/notepad/.DIR bbs/boards/notepad/.DIGEST bbs/boards/notepad/G.960994645.A bbs/boards/notepad/M.960994645.A bbs/boards/notepad/G.960994659.A bbs/boards/notepad/M.960994659.A bbs/boards/notepad/G.960994672.A bbs/boards/notepad/M.960994672.A @dirrm bbs/vote/vote @dirrm bbs/vote/syssecurity @dirrm bbs/vote/sysop @dirrm bbs/vote/notepad @dirrm bbs/vote/newcomers @dirrm bbs/vote/junk @dirrm bbs/vote/deleted @dirrm bbs/vote/bbslists @dirrm bbs/vote @dirrm bbs/tmp @dirrm bbs/table @dirrm bbs/mail/Z @dirrm bbs/mail/Y @dirrm bbs/mail/X @dirrm bbs/mail/W @dirrm bbs/mail/V @dirrm bbs/mail/U @dirrm bbs/mail/T @dirrm bbs/mail/S @dirrm bbs/mail/R @dirrm bbs/mail/Q @dirrm bbs/mail/P @dirrm bbs/mail/O @dirrm bbs/mail/N @dirrm bbs/mail/M @dirrm bbs/mail/L @dirrm bbs/mail/K @dirrm bbs/mail/J @dirrm bbs/mail/I @dirrm bbs/mail/H @dirrm bbs/mail/G @dirrm bbs/mail/F @dirrm bbs/mail/E @dirrm bbs/mail/D @dirrm bbs/mail/C @dirrm bbs/mail/B @dirrm bbs/mail/A @dirrm bbs/mail @dirrm bbs/log @dirrm bbs/innd @dirrm bbs/home/Z @dirrm bbs/home/Y @dirrm bbs/home/X @dirrm bbs/home/W @dirrm bbs/home/V @dirrm bbs/home/U @dirrm bbs/home/T @dirrm bbs/home/S @dirrm bbs/home/R @dirrm bbs/home/Q @dirrm bbs/home/P @dirrm bbs/home/O @dirrm bbs/home/N @dirrm bbs/home/M @dirrm bbs/home/L @dirrm bbs/home/K @dirrm bbs/home/J @dirrm bbs/home/I @dirrm bbs/home/H @dirrm bbs/home/G @dirrm bbs/home/F @dirrm bbs/home/E @dirrm bbs/home/D @dirrm bbs/home/C @dirrm bbs/home/B @dirrm bbs/home/A @dirrm bbs/home @dirrm bbs/help @dirrm bbs/etc/posts @dirrm bbs/etc @dirrm bbs/boards/vote @dirrm bbs/boards/syssecurity @dirrm bbs/boards/sysop @dirrm bbs/boards/notepad @dirrm bbs/boards/newcomers @dirrm bbs/boards/junk @dirrm bbs/boards/deleted @dirrm bbs/boards/bbslists @dirrm bbs/boards @dirrm bbs/bm @dirrm bbs/bin @dirrm bbs/bbssrc/util/upgrade/include @dirrm bbs/bbssrc/util/upgrade @dirrm bbs/bbssrc/util/telnetd @dirrm bbs/bbssrc/util/mail2bbs @dirrm bbs/bbssrc/util/local_utl @dirrm bbs/bbssrc/util/innbbsd/innd @dirrm bbs/bbssrc/util/innbbsd/doc @dirrm bbs/bbssrc/util/innbbsd/convert/util @dirrm bbs/bbssrc/util/innbbsd/convert/jis @dirrm bbs/bbssrc/util/innbbsd/convert/hztty/tables @dirrm bbs/bbssrc/util/innbbsd/convert/hztty @dirrm bbs/bbssrc/util/innbbsd/convert @dirrm bbs/bbssrc/util/innbbsd @dirrm bbs/bbssrc/util/in.zbbsd @dirrm bbs/bbssrc/util/gopherd @dirrm bbs/bbssrc/util/fingerd @dirrm bbs/bbssrc/util/express @dirrm bbs/bbssrc/util/deljunk @dirrm bbs/bbssrc/util @dirrm bbs/bbssrc/src/SO @dirrm bbs/bbssrc/src @dirrm bbs/bbssrc/lib/libBBS @dirrm bbs/bbssrc/lib @dirrm bbs/bbssrc/include @dirrm bbs/bbssrc/doc/example @dirrm bbs/bbssrc/doc @dirrm bbs/bbssrc @dirrm bbs/0Announce/usermanual @dirrm bbs/0Announce/sysops/groups/syssecurity @dirrm bbs/0Announce/sysops/groups/junk @dirrm bbs/0Announce/sysops/groups @dirrm bbs/0Announce/sysops @dirrm bbs/0Announce/groups/GROUP_7/notepad @dirrm bbs/0Announce/groups/GROUP_7 @dirrm bbs/0Announce/groups/GROUP_0/vote @dirrm bbs/0Announce/groups/GROUP_0/sysop @dirrm bbs/0Announce/groups/GROUP_0/newcomers @dirrm bbs/0Announce/groups/GROUP_0/bbslists @dirrm bbs/0Announce/groups/GROUP_0 @dirrm bbs/0Announce/groups @dirrm bbs/0Announce/bms/deleted @dirrm bbs/0Announce/bms @dirrm bbs/0Announce/bbslist @dirrm bbs/0Announce @unexec rmdir %D/bbs/log 2>/dev/null || true @dirrm bbs g> 2000-02-24 14:51:23 +0800 This were moved to widgets/e-text/ a while ago but never removed. They' href='/~lantw44/cgit/gsoc2013-evolution/commit/widgets/table/e-table-item.c?h=EVOLUTION_2_0_3&id=7699b8996aa2d9ae3fea0e94981637c98e89a273'>7699b8996a
1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932
2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132
2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240
2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* E-table-item.c: A GnomeCanvasItem that is a view of an ETableModel.
*
* Author:
* Miguel de Icaza (miguel@gnu.org)
*
* Copyright 1999, Helix Code, Inc.
*
* TODO:
* Add a border to the thing, so that focusing works properly.
*
*/
#include <config.h>
#include <stdio.h>
#include <gtk/gtksignal.h>
#include <gdk/gdkkeysyms.h>
#include <math.h>
#include "e-table-item.h"
#include "e-table-subset.h"
#include "e-cell.h"
#include "gal/widgets/e-canvas.h"
#include "gal/widgets/e-canvas-utils.h"
#include "gal/util/e-util.h"
#define PARENT_OBJECT_TYPE gnome_canvas_item_get_type ()
#define FOCUSED_BORDER 2
static GnomeCanvasItemClass *eti_parent_class;
enum {
CURSOR_CHANGE,
DOUBLE_CLICK,
RIGHT_CLICK,
CLICK,
KEY_PRESS,
LAST_SIGNAL
};
static gint eti_signals [LAST_SIGNAL] = { 0, };
enum {
ARG_0,
ARG_TABLE_HEADER,
ARG_TABLE_MODEL,
ARG_TABLE_SELECTION_MODEL,
ARG_TABLE_DRAW_GRID,
ARG_TABLE_DRAW_FOCUS,
ARG_CURSOR_MODE,
ARG_LENGTH_THRESHOLD,
ARG_CURSOR_ROW,
ARG_MINIMUM_WIDTH,
ARG_WIDTH,
ARG_HEIGHT,
};
static int eti_get_height (ETableItem *eti);
static int eti_get_minimum_width (ETableItem *eti);
static int eti_row_height (ETableItem *eti, int row);
static void e_table_item_focus (ETableItem *eti, int col, int row, GdkModifierType state);
static void eti_cursor_change (ETableSelectionModel *selection, int row, int col, ETableItem *eti);
static void eti_selection_change (ETableSelectionModel *selection, ETableItem *eti);
#if 0
static void eti_request_region_show (ETableItem *eti,
int start_col, int start_row,
int end_col, int end_row);
#endif
#define ETI_ROW_HEIGHT(eti,row) ((eti)->height_cache && (eti)->height_cache[(row)] != -1 ? (eti)->height_cache[(row)] : eti_row_height((eti),(row)))
inline static gint
model_to_view_row(ETableItem *eti, int row)
{
int i;
if (eti->uses_source_model) {
ETableSubset *etss = E_TABLE_SUBSET(eti->table_model);
if (eti->row_guess >= 0 && eti->row_guess < etss->n_map) {
if (etss->map_table[eti->row_guess] == row) {
return eti->row_guess;
}
}
for (i = 0; i < etss->n_map; i++) {
if (etss->map_table[i] == row)
return i;
}
return -1;
} else
return row;
}
inline static gint
view_to_model_row(ETableItem *eti, int row)
{
if (eti->uses_source_model) {
ETableSubset *etss = E_TABLE_SUBSET(eti->table_model);
if (row >= 0 && row < etss->n_map)
return etss->map_table[row];
else
return -1;
} else
return row;
}
inline static gint
model_to_view_col(ETableItem *eti, int col)
{
int i;
for (i = 0; i < eti->cols; i++) {
ETableCol *ecol = e_table_header_get_column (eti->header, i);
if (ecol->col_idx == col)
return i;
}
return -1;
}
inline static gint
view_to_model_col(ETableItem *eti, int col)
{
ETableCol *ecol = e_table_header_get_column (eti->header, col);
return ecol->col_idx;
}
static gboolean
eti_editing (ETableItem *eti)
{
if (eti->editing_col == -1)
return FALSE;
else
return TRUE;
}
/*
* During realization, we have to invoke the per-ecell realize routine
* (On our current setup, we have one e-cell per column.
*
* We might want to optimize this to only realize the unique e-cells:
* ie, a strings-only table, uses the same e-cell for every column, and
* we might want to avoid realizing each e-cell.
*/
static void
eti_realize_cell_views (ETableItem *eti)
{
int i;
for (i = 0; i < eti->n_cells; i++)
e_cell_realize (eti->cell_views [i]);
eti->cell_views_realized = 1;
}
static void
eti_attach_cell_views (ETableItem *eti)
{
int i;
g_assert (eti->header);
g_assert (eti->table_model);
/*
* Now realize the various ECells
*/
eti->n_cells = eti->cols;
eti->cell_views = g_new (ECellView *, eti->n_cells);
for (i = 0; i < eti->n_cells; i++){
ETableCol *ecol = e_table_header_get_column (eti->header, i);
eti->cell_views [i] = e_cell_new_view (ecol->ecell, eti->table_model, eti);
}
eti->needs_compute_height = 1;
e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
eti->needs_redraw = 1;
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
}
/*
* During unrealization: we invoke every e-cell (one per column in the current
* setup) to dispose all X resources allocated
*/
static void
eti_unrealize_cell_views (ETableItem *eti)
{
int i;
if (eti->cell_views_realized == 0)
return;
for (i = 0; i < eti->n_cells; i++)
e_cell_unrealize (eti->cell_views [i]);
eti->cell_views_realized = 0;
}
static void
eti_detach_cell_views (ETableItem *eti)
{
int i;
for (i = 0; i < eti->n_cells; i++){
e_cell_kill_view (eti->cell_views [i]);
eti->cell_views [i] = NULL;
}
g_free (eti->cell_views);
eti->cell_views = NULL;
eti->n_cells = 0;
}
static void
eti_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
double i2c [6];
ArtPoint c1, c2, i1, i2;
ETableItem *eti = E_TABLE_ITEM (item);
/* Wrong BBox's are the source of redraw nightmares */
gnome_canvas_item_i2c_affine (GNOME_CANVAS_ITEM (eti), i2c);
i1.x = eti->x1;
i1.y = eti->y1;
i2.x = eti->x1 + eti->width;
i2.y = eti->y1 + eti->height;
art_affine_point (&c1, &i1, i2c);
art_affine_point (&c2, &i2, i2c);
*x1 = c1.x;
*y1 = c1.y;
*x2 = c2.x + 1;
*y2 = c2.y + 1;
}
static void
eti_reflow (GnomeCanvasItem *item, gint flags)
{
ETableItem *eti = E_TABLE_ITEM (item);
if (eti->needs_compute_height) {
int new_height = eti_get_height (eti);
if (new_height != eti->height) {
eti->height = new_height;
e_canvas_item_request_parent_reflow (GNOME_CANVAS_ITEM (eti));
eti->needs_redraw = 1;
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
}
eti->needs_compute_height = 0;
}
if (eti->needs_compute_width) {
int new_width = eti_get_minimum_width (eti);
new_width = MAX(new_width, eti->minimum_width);
if (new_width != eti->width) {
eti->width = new_width;
e_canvas_item_request_parent_reflow (GNOME_CANVAS_ITEM (eti));
eti->needs_redraw = 1;
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
}
eti->needs_compute_width = 0;
}
}
/*
* GnomeCanvasItem::update method
*/
static void
eti_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
{
ArtPoint o1, o2;
ETableItem *eti = E_TABLE_ITEM (item);
if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->update)
(*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->update)(item, affine, clip_path, flags);
o1.x = item->x1;
o1.y = item->y1;
o2.x = item->x2;
o2.y = item->y2;
eti_bounds (item, &item->x1, &item->y1, &item->x2, &item->y2);
if (item->x1 != o1.x ||
item->y1 != o1.y ||
item->x2 != o2.x ||
item->y2 != o2.y) {
gnome_canvas_request_redraw (item->canvas, o1.x, o1.y, o2.x, o2.y);
eti->needs_redraw = 1;
}
if (eti->needs_redraw) {
gnome_canvas_request_redraw (item->canvas, item->x1, item->y1,
item->x2, item->y2);
eti->needs_redraw = 0;
}
}
/*
* eti_remove_table_model:
*
* Invoked to release the table model associated with this ETableItem
*/
static void
eti_remove_table_model (ETableItem *eti)
{
if (!eti->table_model)
return;
gtk_signal_disconnect (GTK_OBJECT (eti->table_model),
eti->table_model_pre_change_id);
gtk_signal_disconnect (GTK_OBJECT (eti->table_model),
eti->table_model_change_id);
gtk_signal_disconnect (GTK_OBJECT (eti->table_model),
eti->table_model_row_change_id);
gtk_signal_disconnect (GTK_OBJECT (eti->table_model),
eti->table_model_cell_change_id);
gtk_signal_disconnect (GTK_OBJECT (eti->table_model),
eti->table_model_row_inserted_id);
gtk_signal_disconnect (GTK_OBJECT (eti->table_model),
eti->table_model_row_deleted_id);
gtk_object_unref (GTK_OBJECT (eti->table_model));
if (eti->source_model)
gtk_object_unref (GTK_OBJECT (eti->source_model));
eti->table_model_pre_change_id = 0;
eti->table_model_change_id = 0;
eti->table_model_row_change_id = 0;
eti->table_model_cell_change_id = 0;
eti->table_model_row_inserted_id = 0;
eti->table_model_row_deleted_id = 0;
eti->table_model = NULL;
eti->source_model = NULL;
eti->uses_source_model = 0;
}
/*
* eti_remove_table_model:
*
* Invoked to release the table model associated with this ETableItem
*/
static void
eti_remove_table_selection_model (ETableItem *eti)
{
if (!eti->selection)
return;
gtk_signal_disconnect (GTK_OBJECT (eti->selection),
eti->selection_change_id);
gtk_signal_disconnect (GTK_OBJECT (eti->selection),
eti->cursor_change_id);
gtk_object_unref (GTK_OBJECT (eti->selection));
eti->selection_change_id = 0;
eti->cursor_change_id = 0;
eti->selection = NULL;
}
/*
* eti_remove_header_model:
*
* Invoked to release the header model associated with this ETableItem
*/
static void
eti_remove_header_model (ETableItem *eti)
{
if (!eti->header)
return;
gtk_signal_disconnect (GTK_OBJECT (eti->header),
eti->header_structure_change_id);
gtk_signal_disconnect (GTK_OBJECT (eti->header),
eti->header_dim_change_id);
gtk_signal_disconnect (GTK_OBJECT (eti->header),
eti->header_request_width_id);
if (eti->cell_views){
eti_unrealize_cell_views (eti);
eti_detach_cell_views (eti);
}
gtk_object_unref (GTK_OBJECT (eti->header));
eti->header_structure_change_id = 0;
eti->header_dim_change_id = 0;
eti->header_request_width_id = 0;
eti->header = NULL;
}
/*
* eti_row_height_real:
*
* Returns the height used by row @row. This does not include the one-pixel
* used as a separator between rows
*/
static int
eti_row_height_real (ETableItem *eti, int row)
{
const int cols = e_table_header_count (eti->header);
int col;
int h, max_h;
g_assert (cols == 0 || eti->cell_views);
max_h = 0;
for (col = 0; col < cols; col++){
h = e_cell_height (eti->cell_views [col], view_to_model_col(eti, col), col, row);
if (h > max_h)
max_h = h;
}
return max_h;
}
static gboolean
height_cache_idle(ETableItem *eti)
{
int changed = 0;
int i;
if (!eti->height_cache) {
eti->height_cache = g_new(int, eti->rows);
}
for (i = eti->height_cache_idle_count; i < eti->rows; i++) {
if (eti->height_cache[i] == -1) {
eti_row_height(eti, i);
changed ++;
if (changed >= 20)
break;
}
}
if (changed >= 20) {
eti->height_cache_idle_count = i;
return TRUE;
}
eti->height_cache_idle_id = 0;
return FALSE;
}
static void
free_height_cache (ETableItem *eti)
{
if (eti->height_cache)
g_free (eti->height_cache);
eti->height_cache = NULL;
eti->height_cache_idle_count = 0;
if (eti->height_cache_idle_id == 0)
eti->height_cache_idle_id = g_idle_add_full(G_PRIORITY_LOW, (GSourceFunc) height_cache_idle, eti, NULL);
}
static void
calculate_height_cache (ETableItem *eti)
{
int i;
free_height_cache(eti);
eti->height_cache = g_new(int, eti->rows);
for (i = 0; i < eti->rows; i++) {
eti->height_cache[i] = -1;
}
}
/*
* eti_row_height:
*
* Returns the height used by row @row. This does not include the one-pixel
* used as a separator between rows
*/
static int
eti_row_height (ETableItem *eti, int row)
{
if (!eti->height_cache) {
calculate_height_cache (eti);
}
if (eti->height_cache[row] == -1) {
eti->height_cache[row] = eti_row_height_real(eti, row);
if (row > 0 &&
eti->length_threshold != -1 &&
eti->rows > eti->length_threshold &&
eti->height_cache[row] != eti_row_height(eti, 0)) {
eti->needs_compute_height = 1;
e_canvas_item_request_reflow(GNOME_CANVAS_ITEM(eti));
}
}
return eti->height_cache[row];
}
/*
* eti_get_height:
*
* Returns the height of the ETableItem.
*
* The ETableItem might compute the whole height by asking every row its
* size. There is a special mode (designed to work when there are too
* many rows in the table that performing the previous step could take
* too long) set by the ETableItem->length_threshold that would determine
* when the height is computed by using the first row as the size for
* every other row in the ETableItem.
*/
static int
eti_get_height (ETableItem *eti)
{
const int rows = eti->rows;
int row;
int height;
if (rows == 0)
return 0;
if (eti->length_threshold != -1){
if (rows > eti->length_threshold){
int row_height = eti_row_height(eti, 0);
if (eti->height_cache) {
height = 0;
for (row = 0; row < rows; row++) {
if (eti->height_cache[row] == -1) {
height += (row_height + 1) * (rows - row);
break;
}
else
height += eti->height_cache[row] + 1;
}
} else
height = (eti_row_height (eti, 0) + 1) * rows;
/*
* 1 pixel at the top
*/
return height + 1;
}
}
height = 1;
for (row = 0; row < rows; row++)
height += eti_row_height (eti, row) + 1;
return height;
}
static int
eti_get_minimum_width (ETableItem *eti)
{
int width = 0;
int col;
for (col = 0; col < eti->cols; col++){
ETableCol *ecol = e_table_header_get_column (eti->header, col);
width += ecol->min_width;
}
return width;
}
static void
eti_item_region_redraw (ETableItem *eti, int x0, int y0, int x1, int y1)
{
GnomeCanvasItem *item = GNOME_CANVAS_ITEM (eti);
ArtDRect rect;
double i2c [6];
rect.x0 = x0;
rect.y0 = y0;
rect.x1 = x1;
rect.y1 = y1;
gnome_canvas_item_i2c_affine (item, i2c);
art_drect_affine_transform (&rect, &rect, i2c);
gnome_canvas_request_redraw (item->canvas, rect.x0, rect.y0, rect.x1, rect.y1);
}
/*
* Callback routine: invoked before the ETableModel has suffers a change
*/
static void
eti_table_model_pre_change (ETableModel *table_model, ETableItem *eti)
{
if (eti_editing (eti))
e_table_item_leave_edit (eti);
}
/*
* Callback routine: invoked when the ETableModel has suffered a change
*/
static void
eti_table_model_changed (ETableModel *table_model, ETableItem *eti)
{
#if 0
int view_row;
#endif
eti->rows = e_table_model_row_count (eti->table_model);
free_height_cache(eti);
eti->needs_compute_height = 1;
e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
eti->needs_redraw = 1;
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
#if 0
view_row = model_to_view_row(eti, eti->cursor_row);
if (view_row >= 0 && eti->cursor_col >= 0)
eti_request_region_show (eti, eti->cursor_col, view_row, eti->cursor_col, view_row);
#endif
}
/*
* Computes the distance between @start_row and @end_row in pixels
*/
static int
eti_row_diff (ETableItem *eti, int start_row, int end_row)
{
int row, total;
total = 0;
for (row = start_row; row < end_row; row++)
total += eti_row_height (eti, row) + 1;
return total;
}
/*
* eti_request_region_redraw:
*
* Request a canvas redraw on the range (start_col, start_row) to (end_col, end_row).
* This is inclusive (ie, you can use: 0,0-0,0 to redraw the first cell).
*
* The @border argument is a number of pixels around the region that should also be queued
* for redraw. This is typically used by the focus routines to queue a redraw for the
* border as well.
*/
static void
eti_request_region_redraw (ETableItem *eti,
int start_col, int start_row,
int end_col, int end_row, int border)
{
int x1, y1, width, height;
if (eti->rows > 0) {
x1 = e_table_header_col_diff (eti->header, 0, start_col);
y1 = eti_row_diff (eti, 0, start_row);
width = e_table_header_col_diff (eti->header, start_col, end_col + 1);
height = eti_row_diff (eti, start_row, end_row + 1);
eti_item_region_redraw (eti, eti->x1 + x1 - border,
eti->y1 + y1 - border,
eti->x1 + x1 + width + 1 + border,
eti->y1 + y1 + height + 1 + border);
}
}
/*
* eti_request_region_show
*
* Request a canvas show on the range (start_col, start_row) to (end_col, end_row).
* This is inclusive (ie, you can use: 0,0-0,0 to show the first cell).
*/
static void
eti_request_region_show (ETableItem *eti,
int start_col, int start_row,
int end_col, int end_row)
{
int x1, y1, x2, y2;
x1 = e_table_header_col_diff (eti->header, 0, start_col);
y1 = eti_row_diff (eti, 0, start_row);
x2 = x1 + e_table_header_col_diff (eti->header, start_col, end_col + 1);
y2 = y1 + eti_row_diff (eti, start_row, end_row + 1);
e_canvas_item_show_area(GNOME_CANVAS_ITEM(eti), x1, y1, x2, y2);
}
static void
eti_table_model_row_changed (ETableModel *table_model, int row, ETableItem *eti)
{
if (eti->renderers_can_change_size &&
eti->height_cache && eti->height_cache[row] != -1 &&
eti_row_height_real(eti, row) != eti->height_cache[row]) {
eti_table_model_changed (table_model, eti);
return;
}
eti_request_region_redraw (eti, 0, row, eti->cols, row, 0);
}
static void
eti_table_model_cell_changed (ETableModel *table_model, int col, int row, ETableItem *eti)
{
if (eti->renderers_can_change_size &&
eti->height_cache && eti->height_cache[row] != -1 &&
eti_row_height_real(eti, row) != eti->height_cache[row]) {
eti_table_model_changed (table_model, eti);
return;
}
eti_request_region_redraw (eti, 0, row, eti->cols -1, row, 0);
}
static void
eti_table_model_row_inserted (ETableModel *table_model, int row, ETableItem *eti)
{
eti->rows = e_table_model_row_count (eti->table_model);
if (eti->height_cache) {
eti->height_cache = g_renew(int, eti->height_cache, eti->rows);
memmove(eti->height_cache + row + 1, eti->height_cache + row, (eti->rows - 1 - row) * sizeof(int));
eti->height_cache[row] = -1;
}
eti->needs_compute_height = 1;
e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
eti->needs_redraw = 1;
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
}
static void
eti_table_model_row_deleted (ETableModel *table_model, int row, ETableItem *eti)
{
eti->rows = e_table_model_row_count (eti->table_model);
if (eti->height_cache)
memmove(eti->height_cache + row, eti->height_cache + row + 1, (eti->rows - row) * sizeof(int));
eti->needs_compute_height = 1;
e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
eti->needs_redraw = 1;
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
}
void
e_table_item_redraw_range (ETableItem *eti,
int start_col, int start_row,
int end_col, int end_row)
{
int border;
int cursor_col, cursor_row;
g_return_if_fail (eti != NULL);
g_return_if_fail (E_IS_TABLE_ITEM (eti));
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_col", &cursor_col,
"cursor_row", &cursor_row,
NULL);
if ((start_col == cursor_col) ||
(end_col == cursor_col) ||
(view_to_model_row(eti, start_row) == cursor_row) ||
(view_to_model_row(eti, end_row) == cursor_row))
border = 2;
else
border = 0;
eti_request_region_redraw(eti, start_col, start_row, end_col, end_row, border);
}
static void
eti_add_table_model (ETableItem *eti, ETableModel *table_model)
{
g_assert (eti->table_model == NULL);
eti->table_model = table_model;
gtk_object_ref (GTK_OBJECT (eti->table_model));
eti->table_model_pre_change_id = gtk_signal_connect (
GTK_OBJECT (table_model), "model_pre_change",
GTK_SIGNAL_FUNC (eti_table_model_pre_change), eti);
eti->table_model_change_id = gtk_signal_connect (
GTK_OBJECT (table_model), "model_changed",
GTK_SIGNAL_FUNC (eti_table_model_changed), eti);
eti->table_model_row_change_id = gtk_signal_connect (
GTK_OBJECT (table_model), "model_row_changed",
GTK_SIGNAL_FUNC (eti_table_model_row_changed), eti);
eti->table_model_cell_change_id = gtk_signal_connect (
GTK_OBJECT (table_model), "model_cell_changed",
GTK_SIGNAL_FUNC (eti_table_model_cell_changed), eti);
eti->table_model_row_inserted_id = gtk_signal_connect (
GTK_OBJECT (table_model), "model_row_inserted",
GTK_SIGNAL_FUNC (eti_table_model_row_inserted), eti);
eti->table_model_row_deleted_id = gtk_signal_connect (
GTK_OBJECT (table_model), "model_row_deleted",
GTK_SIGNAL_FUNC (eti_table_model_row_deleted), eti);
if (eti->header) {
eti_detach_cell_views (eti);
eti_attach_cell_views (eti);
}
if (E_IS_TABLE_SUBSET(table_model)) {
eti->uses_source_model = 1;
eti->source_model = E_TABLE_SUBSET(table_model)->source;
if (eti->source_model)
gtk_object_ref(GTK_OBJECT(eti->source_model));
}
eti_table_model_changed (table_model, eti);
}
static void
eti_add_table_selection_model (ETableItem *eti, ETableSelectionModel *selection)
{
g_assert (eti->selection == NULL);
eti->selection = selection;
gtk_object_ref (GTK_OBJECT (eti->selection));
eti->selection_change_id = gtk_signal_connect (
GTK_OBJECT (selection), "selection_changed",
GTK_SIGNAL_FUNC (eti_selection_change), eti);
eti->cursor_change_id = gtk_signal_connect (
GTK_OBJECT (selection), "cursor_changed",
GTK_SIGNAL_FUNC (eti_cursor_change), eti);
eti_selection_change(selection, eti);
}
static void
eti_header_dim_changed (ETableHeader *eth, int col, ETableItem *eti)
{
eti->needs_compute_width = 1;
e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
}
static void
eti_header_structure_changed (ETableHeader *eth, ETableItem *eti)
{
eti->cols = e_table_header_count (eti->header);
eti->width = e_table_header_total_width (eti->header);
/*
* There should be at least one column
* BUT: then you can't remove all columns from a header and add new ones.
*/
/*g_assert (eti->cols != 0);*/
if (eti->cell_views){
eti_unrealize_cell_views (eti);
eti_detach_cell_views (eti);
eti_attach_cell_views (eti);
eti_realize_cell_views (eti);
} else {
if (eti->table_model) {
eti_detach_cell_views (eti);
eti_attach_cell_views (eti);
}
}
eti->needs_compute_width = 1;
e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
}
static int
eti_request_column_width (ETableHeader *eth, int col, ETableItem *eti)
{
int width = 0;
if (eti->cell_views) {
width = e_cell_max_width (eti->cell_views[col], view_to_model_col(eti, col), col);
}
return width;
}
static void
eti_add_header_model (ETableItem *eti, ETableHeader *header)
{
g_assert (eti->header == NULL);
eti->header = header;
gtk_object_ref (GTK_OBJECT (header));
eti_header_structure_changed (header, eti);
eti->header_dim_change_id = gtk_signal_connect (
GTK_OBJECT (header), "dimension_change",
GTK_SIGNAL_FUNC (eti_header_dim_changed), eti);
eti->header_structure_change_id = gtk_signal_connect (
GTK_OBJECT (header), "structure_change",
GTK_SIGNAL_FUNC (eti_header_structure_changed), eti);
eti->header_request_width_id = gtk_signal_connect
(GTK_OBJECT (header), "request_width",
GTK_SIGNAL_FUNC (eti_request_column_width), eti);
}
/*
* GtkObject::destroy method
*/
static void
eti_destroy (GtkObject *object)
{
ETableItem *eti = E_TABLE_ITEM (object);
eti_remove_header_model (eti);
eti_remove_table_model (eti);
eti_remove_table_selection_model (eti);
if (eti->height_cache_idle_id)
g_source_remove(eti->height_cache_idle_id);
g_free (eti->height_cache);
if (eti->tooltip->window)
gtk_widget_destroy (eti->tooltip->window);
if (eti->tooltip->timer) {
gtk_timeout_remove (eti->tooltip->timer);
eti->tooltip->timer = 0;
}
g_free (eti->tooltip);
if (GTK_OBJECT_CLASS (eti_parent_class)->destroy)
(*GTK_OBJECT_CLASS (eti_parent_class)->destroy) (object);
}
static void
eti_set_arg (GtkObject *o, GtkArg *arg, guint arg_id)
{
GnomeCanvasItem *item;
ETableItem *eti;
int cursor_col;
item = GNOME_CANVAS_ITEM (o);
eti = E_TABLE_ITEM (o);
switch (arg_id){
case ARG_TABLE_HEADER:
eti_remove_header_model (eti);
eti_add_header_model (eti, E_TABLE_HEADER(GTK_VALUE_OBJECT (*arg)));
break;
case ARG_TABLE_MODEL:
eti_remove_table_model (eti);
eti_add_table_model (eti, E_TABLE_MODEL(GTK_VALUE_OBJECT (*arg)));
break;
case ARG_TABLE_SELECTION_MODEL:
eti_remove_table_selection_model (eti);
if (GTK_VALUE_OBJECT (*arg))
eti_add_table_selection_model (eti, E_TABLE_SELECTION_MODEL(GTK_VALUE_OBJECT (*arg)));
break;
case ARG_LENGTH_THRESHOLD:
eti->length_threshold = GTK_VALUE_INT (*arg);
break;
case ARG_TABLE_DRAW_GRID:
eti->draw_grid = GTK_VALUE_BOOL (*arg);
break;
case ARG_TABLE_DRAW_FOCUS:
eti->draw_focus = GTK_VALUE_BOOL (*arg);
break;
case ARG_CURSOR_MODE:
eti->cursor_mode = GTK_VALUE_INT (*arg);
break;
case ARG_MINIMUM_WIDTH:
case ARG_WIDTH:
if (eti->minimum_width == eti->width && GTK_VALUE_DOUBLE (*arg) > eti->width)
e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
eti->minimum_width = GTK_VALUE_DOUBLE (*arg);
if (eti->minimum_width < eti->width)
e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
break;
case ARG_CURSOR_ROW:
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_col", &cursor_col,
NULL);
e_table_item_focus (eti, cursor_col != -1 ? cursor_col : 0, view_to_model_row(eti, GTK_VALUE_INT (*arg)), 0);
break;
}
eti->needs_redraw = 1;
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(eti));
}
static void
eti_get_arg (GtkObject *o, GtkArg *arg, guint arg_id)
{
GnomeCanvasItem *item;
ETableItem *eti;
int row;
item = GNOME_CANVAS_ITEM (o);
eti = E_TABLE_ITEM (o);
switch (arg_id){
case ARG_WIDTH:
GTK_VALUE_DOUBLE (*arg) = eti->width;
break;
case ARG_HEIGHT:
GTK_VALUE_DOUBLE (*arg) = eti->height;
break;
case ARG_MINIMUM_WIDTH:
GTK_VALUE_DOUBLE (*arg) = eti->minimum_width;
break;
case ARG_CURSOR_ROW:
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_row", &row,
NULL);
GTK_VALUE_INT (*arg) = model_to_view_row(eti, row);
break;
default:
arg->type = GTK_TYPE_INVALID;
}
}
static void
eti_init (GnomeCanvasItem *item)
{
ETableItem *eti = E_TABLE_ITEM (item);
eti->editing_col = -1;
eti->editing_row = -1;
eti->height = 0;
eti->width = 0;
eti->minimum_width = 0;
eti->height_cache = NULL;
eti->height_cache_idle_id = 0;
eti->height_cache_idle_count = 0;
eti->length_threshold = -1;
eti->renderers_can_change_size = 1;
eti->uses_source_model = 0;
eti->source_model = NULL;
eti->row_guess = -1;
eti->cursor_mode = E_TABLE_CURSOR_SIMPLE;
eti->selection_change_id = 0;
eti->cursor_change_id = 0;
eti->selection = NULL;
eti->needs_redraw = 0;
eti->needs_compute_height = 0;
eti->tooltip = g_new0 (ETableTooltip, 1);
eti->tooltip->timer = 0;
eti->tooltip->window = NULL;
eti->tooltip->eti = GNOME_CANVAS_ITEM (eti);
e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (eti), eti_reflow);
}
#define gray50_width 2
#define gray50_height 2
static const char gray50_bits[] = {
0x02, 0x01, };
static void
eti_realize (GnomeCanvasItem *item)
{
ETableItem *eti = E_TABLE_ITEM (item);
GtkWidget *canvas_widget = GTK_WIDGET (item->canvas);
GdkWindow *window;
if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize)
(*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->realize)(item);
/*
* Gdk Resource allocation
*/
window = canvas_widget->window;
eti->fill_gc = gdk_gc_new (window);
eti->grid_gc = gdk_gc_new (window);
#if 0
/* This sets it to gray */
/* gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]); */
#else
gdk_gc_set_foreground (eti->grid_gc, &canvas_widget->style->dark [GTK_STATE_NORMAL]);
#endif
eti->focus_gc = gdk_gc_new (window);
gdk_gc_set_foreground (eti->focus_gc, &canvas_widget->style->bg [GTK_STATE_NORMAL]);
gdk_gc_set_background (eti->focus_gc, &canvas_widget->style->fg [GTK_STATE_NORMAL]);
eti->stipple = gdk_bitmap_create_from_data (NULL, gray50_bits, gray50_width, gray50_height);
gdk_gc_set_ts_origin (eti->focus_gc, 0, 0);
gdk_gc_set_stipple (eti->focus_gc, eti->stipple);
gdk_gc_set_fill (eti->focus_gc, GDK_OPAQUE_STIPPLED);
if (eti->cell_views == NULL)
eti_attach_cell_views (eti);
eti_realize_cell_views (eti);
eti->needs_compute_height = 1;
e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (eti));
eti->needs_redraw = 1;
gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (eti));
}
static void
eti_unrealize (GnomeCanvasItem *item)
{
ETableItem *eti = E_TABLE_ITEM (item);
if (eti_editing (eti))
e_table_item_leave_edit (eti);
gdk_gc_unref (eti->fill_gc);
eti->fill_gc = NULL;
gdk_gc_unref (eti->grid_gc);
eti->grid_gc = NULL;
gdk_gc_unref (eti->focus_gc);
eti->focus_gc = NULL;
gdk_bitmap_unref (eti->stipple);
eti->stipple = NULL;
eti_unrealize_cell_views (eti);
eti->height = 0;
if (GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->unrealize)
(*GNOME_CANVAS_ITEM_CLASS (eti_parent_class)->unrealize)(item);
}
static void
eti_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height)
{
ETableItem *eti = E_TABLE_ITEM (item);
const int rows = eti->rows;
const int cols = eti->cols;
int row, col, y1, y2;
int first_col, last_col, x_offset;
int first_row, last_row, y_offset, yd;
int x1, x2;
int f_x1, f_x2, f_y1, f_y2;
gboolean f_found;
double i2c [6];
ArtPoint eti_base, eti_base_item;
GtkWidget *canvas = GTK_WIDGET(item->canvas);
GdkColor *background;
/*
* Clear the background
*/
#if 0
gdk_draw_rectangle (
drawable, eti->fill_gc, TRUE,
eti->x1 - x, eti->y1 - y, eti->width, eti->height);
#endif
/*
* Find out our real position after grouping
*/
gnome_canvas_item_i2c_affine (item, i2c);
eti_base_item.x = eti->x1;
eti_base_item.y = eti->y1;
art_affine_point (&eti_base, &eti_base_item, i2c);
/*
* First column to draw, last column to draw
*/
first_col = -1;
last_col = x_offset = 0;
x1 = x2 = floor (eti_base.x);
for (col = 0; col < cols; col++, x1 = x2){
ETableCol *ecol = e_table_header_get_column (eti->header, col);
x2 = x1 + ecol->width;
if (x1 > (x + width))
break;
if (x2 < x)
continue;
if (first_col == -1){
x_offset = x1 - x;
first_col = col;
}
}
last_col = col;
/*
* Nothing to paint
*/
if (first_col == -1)
return;
/*
* Compute row span.
*/
first_row = -1;
y_offset = 0;
y1 = y2 = floor (eti_base.y) + 1;
for (row = 0; row < rows; row++, y1 = y2){
y2 += ETI_ROW_HEIGHT (eti, row) + 1;
if (y1 > y + height)
break;
if (y2 < y)
continue;
if (first_row == -1){
y_offset = y1 - y;
first_row = row;
}
}
last_row = row;
if (first_row == -1)
return;
/*
* Draw cells
*/
yd = y_offset;
f_x1 = f_x2 = f_y1 = f_y2 = -1;
f_found = FALSE;
if (eti->draw_grid && first_row == 0){
gdk_draw_line (
drawable, eti->grid_gc,
eti_base.x - x, yd, eti_base.x + eti->width - x, yd);
}
yd++;
for (row = first_row; row < last_row; row++){
int xd, height;
gboolean selected;
gint cursor_col, cursor_row;
height = ETI_ROW_HEIGHT (eti, row);
xd = x_offset;
/* printf ("paint: %d %d\n", yd, yd + height); */
selected = e_table_selection_model_is_row_selected(eti->selection, view_to_model_row(eti,row));
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_col", &cursor_col,
"cursor_row", &cursor_row,
NULL);
for (col = first_col; col < last_col; col++){
ETableCol *ecol = e_table_header_get_column (eti->header, col);
ECellView *ecell_view = eti->cell_views [col];
gboolean col_selected = selected;
ECellFlags flags;
switch (eti->cursor_mode) {
case E_TABLE_CURSOR_SIMPLE:
if (cursor_col == ecol->col_idx && cursor_row == view_to_model_row(eti, row))
col_selected = !col_selected;
break;
case E_TABLE_CURSOR_LINE:
/* Nothing */
break;
}
if (col_selected){
if (GTK_WIDGET_HAS_FOCUS(canvas))
background = &canvas->style->bg [GTK_STATE_SELECTED];
else
background = &canvas->style->bg [GTK_STATE_ACTIVE];
} else {
#if 0
if (row % 2)
#endif
background = &canvas->style->base [GTK_STATE_NORMAL];
#if 0
else
background = &canvas->style->base [GTK_STATE_SELECTED];
#endif
}
gdk_gc_set_foreground (eti->fill_gc, background);
gdk_draw_rectangle (drawable, eti->fill_gc, TRUE,
xd, yd, ecol->width, height);
flags = col_selected ? E_CELL_SELECTED : 0;
flags |= GTK_WIDGET_HAS_FOCUS(canvas) ? E_CELL_FOCUSED : 0;
switch (ecol->justification) {
case GTK_JUSTIFY_LEFT:
flags |= E_CELL_JUSTIFY_LEFT;
break;
case GTK_JUSTIFY_RIGHT:
flags |= E_CELL_JUSTIFY_RIGHT;
break;
case GTK_JUSTIFY_CENTER:
flags |= E_CELL_JUSTIFY_CENTER;
break;
case GTK_JUSTIFY_FILL:
flags |= E_CELL_JUSTIFY_FILL;
break;
}
e_cell_draw (ecell_view, drawable, ecol->col_idx, col, row, flags,
xd, yd, xd + ecol->width, yd + height);
if (view_to_model_col(eti, col) == cursor_col && view_to_model_row(eti, row) == cursor_row){
f_x1 = xd;
f_x2 = xd + ecol->width;
f_y1 = yd;
f_y2 = yd + height;
f_found = TRUE;
}
xd += ecol->width;
}
yd += height;
if (eti->draw_grid)
gdk_draw_line (
drawable, eti->grid_gc,
eti_base.x - x, yd, eti_base.x + eti->width - x, yd);
yd++;
}
if (eti->draw_grid){
int xd = x_offset;
for (col = first_col; col <= last_col; col++){
ETableCol *ecol = e_table_header_get_column (eti->header, col);
gdk_draw_line (
drawable, eti->grid_gc,
xd, y_offset, xd, yd - 1);
/*
* This looks wierd, but it is to draw the last line
*/
if (ecol)
xd += ecol->width;
}
}
/*
* Draw focus
*/
if (f_found && eti->draw_focus){
gdk_draw_rectangle (drawable, eti->focus_gc, FALSE,
f_x1 + 1, f_y1, f_x2 - f_x1 - 2, f_y2 - f_y1 - 1);
}
}
static double
eti_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
GnomeCanvasItem **actual_item)
{
*actual_item = item;
return 0.0;
}
static gboolean
find_cell (ETableItem *eti, double x, double y, int *col_res, int *row_res, double *x1_res, double *y1_res)
{
const int cols = eti->cols;
const int rows = eti->rows;
gdouble x1, y1, x2, y2;
int col, row;
/* FIXME: this routine is inneficient, fix later */
if (cols == 0 || rows == 0)
return FALSE;
x -= eti->x1;
y -= eti->y1;
x1 = 0;
for (col = 0; col < cols - 1; col++, x1 = x2){
ETableCol *ecol = e_table_header_get_column (eti->header, col);
if (x < x1)
return FALSE;
x2 = x1 + ecol->width;
if (x <= x2)
break;
}
y1 = y2 = 0;
for (row = 0; row < rows - 1; row++, y1 = y2){
if (y < y1)
return FALSE;
y2 += ETI_ROW_HEIGHT (eti, row) + 1;
if (y <= y2)
break;
}
*col_res = col;
if (x1_res)
*x1_res = x - x1;
*row_res = row;
if (y1_res)
*y1_res = y - y1;
return TRUE;
}
static void
eti_cursor_move (ETableItem *eti, gint row, gint column)
{
e_table_item_leave_edit (eti);
e_table_item_focus (eti, view_to_model_col(eti, column), view_to_model_row(eti, row), 0);
}
static void
eti_cursor_move_left (ETableItem *eti)
{
int cursor_col, cursor_row;
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_col", &cursor_col,
"cursor_row", &cursor_row,
NULL);
eti_cursor_move (eti, model_to_view_row(eti, cursor_row), model_to_view_col(eti, cursor_col) - 1);
}
static void
eti_cursor_move_right (ETableItem *eti)
{
int cursor_col, cursor_row;
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_col", &cursor_col,
"cursor_row", &cursor_row,
NULL);
eti_cursor_move (eti, model_to_view_row(eti, cursor_row), model_to_view_col(eti, cursor_col) + 1);
}
static void
eti_cursor_move_up (ETableItem *eti)
{
int cursor_col, cursor_row;
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_col", &cursor_col,
"cursor_row", &cursor_row,
NULL);
eti_cursor_move (eti, model_to_view_row(eti, cursor_row) - 1, model_to_view_col(eti, cursor_col));
}
static void
eti_cursor_move_down (ETableItem *eti)
{
int cursor_col, cursor_row;
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_col", &cursor_col,
"cursor_row", &cursor_row,
NULL);
eti_cursor_move (eti, model_to_view_row(eti, cursor_row) + 1, model_to_view_col(eti, cursor_col));
}
static int
_do_tooltip (ETableItem *eti)
{
ECellView *ecell_view;
int x = 0, y = 0;
int i;
if (eti_editing (eti))
return FALSE;
ecell_view = eti->cell_views[eti->tooltip->col];
for (i = 0; i < eti->tooltip->col; i++)
x += eti->header->columns[i]->width;
eti->tooltip->x = x;
for (i = 0; i < eti->tooltip->row; i++)
y += (ETI_ROW_HEIGHT (eti, i) + 1);
eti->tooltip->y = y;
eti->tooltip->row_height = ETI_ROW_HEIGHT (eti, i);
e_cell_show_tooltip (ecell_view,
view_to_model_col (eti, eti->tooltip->col),
eti->tooltip->col,
eti->tooltip->row,
eti->tooltip);
return FALSE;
}
/* FIXME: cursor */
static int
eti_event (GnomeCanvasItem *item, GdkEvent *e)
{
ETableItem *eti = E_TABLE_ITEM (item);
ECellView *ecell_view;
gint return_val = TRUE;
switch (e->type){
case GDK_BUTTON_PRESS: {
double x1, y1;
int col, row;
gint cursor_row, cursor_col;
if (eti->tooltip->timer) {
gtk_timeout_remove (eti->tooltip->timer);
eti->tooltip->timer = 0;
}
e_canvas_item_grab_focus(GNOME_CANVAS_ITEM(eti));
switch (e->button.button) {
case 1: /* Fall through. */
case 2:
gnome_canvas_item_w2i (item, &e->button.x, &e->button.y);
if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
return TRUE;
return_val = FALSE;
gtk_signal_emit (GTK_OBJECT (eti), eti_signals [CLICK],
row, view_to_model_col(eti, col), e, &return_val);
if (return_val)
return TRUE;
e_table_selection_model_do_something(eti->selection, view_to_model_row(eti, row), view_to_model_col(eti, col), e->button.state);
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_row", &cursor_row,
"cursor_col", &cursor_col,
NULL);
if (cursor_row == view_to_model_row(eti, row) && cursor_col == view_to_model_col(eti, col)){
if ((!eti_editing(eti)) && e_table_model_is_cell_editable(eti->selection->model, cursor_col, cursor_row)) {
e_table_item_enter_edit (eti, col, row);
}
ecell_view = eti->cell_views [col];
/*
* Adjust the event positions
*/
e->button.x = x1;
e->button.y = y1;
e_cell_event (ecell_view, e, view_to_model_col(eti, col), col, row);
}
break;
case 3:
gnome_canvas_item_w2i (item, &e->button.x, &e->button.y);
if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
return TRUE;
e_table_selection_model_maybe_do_something(eti->selection, view_to_model_row(eti, row), view_to_model_col(eti, col), 0);
gtk_signal_emit (GTK_OBJECT (eti), eti_signals [RIGHT_CLICK],
row, view_to_model_col(eti, col), e, &return_val);
break;
case 4:
case 5:
return FALSE;
break;
}
break;
}
case GDK_BUTTON_RELEASE: {
double x1, y1;
int col, row;
gint cursor_row, cursor_col;
if (eti->tooltip->timer) {
gtk_timeout_remove (eti->tooltip->timer);
eti->tooltip->timer = 0;
}
if (eti->tooltip->window) {
gtk_widget_destroy (eti->tooltip->window);
eti->tooltip->window = NULL;
}
switch (e->button.button) {
case 1: /* Fall through. */
case 2:
gnome_canvas_item_w2i (item, &e->button.x, &e->button.y);
if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
return TRUE;
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_row", &cursor_row,
"cursor_col", &cursor_col,
NULL);
if (cursor_row == view_to_model_row(eti, row) && cursor_col == view_to_model_col(eti, col)){
ecell_view = eti->cell_views [col];
/*
* Adjust the event positions
*/
e->button.x = x1;
e->button.y = y1;
e_cell_event (ecell_view, e, view_to_model_col(eti, col), col, row);
}
break;
case 3:
case 4:
case 5:
return FALSE;
break;
}
break;
}
case GDK_2BUTTON_PRESS: {
double x1, y1;
int col, row;
if (e->button.button == 5 ||
e->button.button == 4)
return FALSE;
gnome_canvas_item_w2i (item, &e->button.x, &e->button.y);
if (!find_cell (eti, e->button.x, e->button.y, &col, &row, &x1, &y1))
return TRUE;
gtk_signal_emit (GTK_OBJECT (eti), eti_signals [DOUBLE_CLICK],
row);
break;
}
case GDK_MOTION_NOTIFY: {
int col, row;
double x1, y1;
gint cursor_col, cursor_row;
gnome_canvas_item_w2i (item, &e->motion.x, &e->motion.y);
if (!find_cell (eti, e->motion.x, e->motion.y, &col, &row, &x1, &y1))
return TRUE;
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_row", &cursor_row,
"cursor_col", &cursor_col,
NULL);
if (eti->tooltip->timer > 0)
gtk_timeout_remove (eti->tooltip->timer);
eti->tooltip->col = col;
eti->tooltip->row = row;
eti->tooltip->cx = e->motion.x;
eti->tooltip->cy = e->motion.y;
eti->tooltip->timer = gtk_timeout_add (1000, (GSourceFunc)_do_tooltip, eti);
if (cursor_row == view_to_model_row(eti, row) && cursor_col == view_to_model_col(eti, col)){
ecell_view = eti->cell_views [col];
/*
* Adjust the event positions
*/
e->motion.x = x1;
e->motion.y = y1;
e_cell_event (ecell_view, e, view_to_model_col(eti, col), col, row);
}
break;
}
case GDK_KEY_PRESS: {
gint cursor_row, cursor_col;
gint handled = TRUE;
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_row", &cursor_row,
"cursor_col", &cursor_col,
NULL);
if (cursor_col == -1)
return FALSE;
switch (e->key.keyval){
case GDK_Left:
if (eti_editing (eti)) {
handled = FALSE;
break;
}
if (cursor_col != view_to_model_col(eti, 0))
eti_cursor_move_left (eti);
break;
case GDK_Right:
if (eti_editing (eti)) {
handled = FALSE;
break;
}
if (cursor_col != view_to_model_col(eti, eti->cols - 1))
eti_cursor_move_right (eti);
break;
case GDK_Up:
if (cursor_row != view_to_model_row(eti, 0))
eti_cursor_move_up (eti);
else
return_val = FALSE;
break;
case GDK_Down:
if (cursor_row != view_to_model_row(eti, eti->rows - 1))
eti_cursor_move_down (eti);
else
return_val = FALSE;
break;
case GDK_Tab:
case GDK_KP_Tab:
case GDK_ISO_Left_Tab:
if ((e->key.state & GDK_SHIFT_MASK) != 0){
/* shift tab */
if (cursor_col != view_to_model_col(eti, 0))
eti_cursor_move_left (eti);
else if (cursor_row != view_to_model_row(eti, 0))
eti_cursor_move (eti, model_to_view_row(eti, cursor_row) - 1, eti->cols - 1);
else
return_val = FALSE;
} else {
if (cursor_col != view_to_model_col (eti, eti->cols - 1))
eti_cursor_move_right (eti);
else if (cursor_row != view_to_model_row(eti, eti->rows - 1))
eti_cursor_move (eti, model_to_view_row(eti, cursor_row) + 1, 0);
else
return_val = FALSE;
}
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_row", &cursor_row,
"cursor_col", &cursor_col,
NULL);
if (cursor_col >= 0 && cursor_row >= 0 && return_val &&
(!eti_editing(eti)) && e_table_model_is_cell_editable(eti->selection->model, cursor_col, cursor_row)) {
e_table_item_enter_edit (eti, model_to_view_col(eti, cursor_col), model_to_view_row(eti, cursor_row));
}
break;
case GDK_Return:
case GDK_KP_Enter:
case GDK_ISO_Enter:
case GDK_3270_Enter:
if (eti_editing (eti)){
e_table_item_leave_edit (eti);
#if 0
ecell_view = eti->cell_views [eti->editing_col];
e_cell_event (ecell_view, e, view_to_model_col(eti, eti->editing_col), eti->editing_col, eti->editing_row);
#endif
}
return_val = FALSE;
gtk_signal_emit (GTK_OBJECT (eti), eti_signals [KEY_PRESS],
model_to_view_row(eti, cursor_row), cursor_col, e, &return_val);
break;
default:
handled = FALSE;
break;
}
if (!handled) {
if (!eti_editing (eti)){
gint col, row;
row = model_to_view_row(eti, cursor_row);
col = model_to_view_col(eti, cursor_col);
if (col != -1 && row != -1 && e_table_model_is_cell_editable(eti->selection->model, cursor_col, cursor_row)) {
e_table_item_enter_edit (eti, col, row);
}
}
if (!eti_editing (eti)){
gtk_signal_emit (GTK_OBJECT (eti), eti_signals [KEY_PRESS],
model_to_view_row(eti, cursor_row), cursor_col, e, &return_val);
} else {
ecell_view = eti->cell_views [eti->editing_col];
e_cell_event (ecell_view, e, view_to_model_col(eti, eti->editing_col), eti->editing_col, eti->editing_row);
}
}
break;
}
case GDK_KEY_RELEASE: {
gint cursor_row, cursor_col;
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_row", &cursor_row,
"cursor_col", &cursor_col,
NULL);
if (cursor_col == -1)
return FALSE;
if (eti_editing (eti)){
ecell_view = eti->cell_views [eti->editing_col];
e_cell_event (ecell_view, e, view_to_model_col(eti, eti->editing_col), eti->editing_col, eti->editing_row);
}
break;
}
case GDK_LEAVE_NOTIFY:
case GDK_ENTER_NOTIFY:
if (eti->tooltip->timer > 0)
gtk_timeout_remove (eti->tooltip->timer);
eti->tooltip->timer = 0;
break;
default:
return_val = FALSE;
}
return return_val;
}
static void
eti_class_init (GtkObjectClass *object_class)
{
GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class;
ETableItemClass *eti_class = (ETableItemClass *) object_class;
eti_parent_class = gtk_type_class (PARENT_OBJECT_TYPE);
object_class->destroy = eti_destroy;
object_class->set_arg = eti_set_arg;
object_class->get_arg = eti_get_arg;
item_class->update = eti_update;
item_class->realize = eti_realize;
item_class->unrealize = eti_unrealize;
item_class->draw = eti_draw;
item_class->point = eti_point;
item_class->event = eti_event;
eti_class->cursor_change = NULL;
eti_class->double_click = NULL;
eti_class->right_click = NULL;
eti_class->click = NULL;
eti_class->key_press = NULL;
gtk_object_add_arg_type ("ETableItem::ETableHeader", GTK_TYPE_OBJECT,
GTK_ARG_WRITABLE, ARG_TABLE_HEADER);
gtk_object_add_arg_type ("ETableItem::ETableModel", GTK_TYPE_OBJECT,
GTK_ARG_WRITABLE, ARG_TABLE_MODEL);
gtk_object_add_arg_type ("ETableItem::table_selection_model", GTK_TYPE_OBJECT,
GTK_ARG_WRITABLE, ARG_TABLE_SELECTION_MODEL);
gtk_object_add_arg_type ("ETableItem::drawgrid", GTK_TYPE_BOOL,
GTK_ARG_WRITABLE, ARG_TABLE_DRAW_GRID);
gtk_object_add_arg_type ("ETableItem::drawfocus", GTK_TYPE_BOOL,
GTK_ARG_WRITABLE, ARG_TABLE_DRAW_FOCUS);
gtk_object_add_arg_type ("ETableItem::cursor_mode", GTK_TYPE_INT,
GTK_ARG_WRITABLE, ARG_CURSOR_MODE);
gtk_object_add_arg_type ("ETableItem::length_threshold", GTK_TYPE_INT,
GTK_ARG_WRITABLE, ARG_LENGTH_THRESHOLD);
gtk_object_add_arg_type ("ETableItem::minimum_width", GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE, ARG_MINIMUM_WIDTH);
gtk_object_add_arg_type ("ETableItem::width", GTK_TYPE_DOUBLE,
GTK_ARG_READWRITE, ARG_WIDTH);
gtk_object_add_arg_type ("ETableItem::height", GTK_TYPE_DOUBLE,
GTK_ARG_READABLE, ARG_HEIGHT);
gtk_object_add_arg_type ("ETableItem::cursor_row", GTK_TYPE_INT,
GTK_ARG_READWRITE, ARG_CURSOR_ROW);
eti_signals [CURSOR_CHANGE] =
gtk_signal_new ("cursor_change",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET (ETableItemClass, cursor_change),
gtk_marshal_NONE__INT,
GTK_TYPE_NONE, 1, GTK_TYPE_INT);
eti_signals [DOUBLE_CLICK] =
gtk_signal_new ("double_click",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET (ETableItemClass, double_click),
gtk_marshal_NONE__INT,
GTK_TYPE_NONE, 1, GTK_TYPE_INT);
eti_signals [RIGHT_CLICK] =
gtk_signal_new ("right_click",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET (ETableItemClass, right_click),
e_marshal_INT__INT_INT_POINTER,
GTK_TYPE_INT, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
eti_signals [CLICK] =
gtk_signal_new ("click",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET (ETableItemClass, click),
e_marshal_INT__INT_INT_POINTER,
GTK_TYPE_INT, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
eti_signals [KEY_PRESS] =
gtk_signal_new ("key_press",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET (ETableItemClass, key_press),
e_marshal_INT__INT_INT_POINTER,
GTK_TYPE_INT, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
gtk_object_class_add_signals (object_class, eti_signals, LAST_SIGNAL);
}
GtkType
e_table_item_get_type (void)
{
static GtkType type = 0;
if (!type){
GtkTypeInfo info = {
"ETableItem",
sizeof (ETableItem),
sizeof (ETableItemClass),
(GtkClassInitFunc) eti_class_init,
(GtkObjectInitFunc) eti_init,
NULL, /* reserved 1 */
NULL, /* reserved 2 */
(GtkClassInitFunc) NULL
};
type = gtk_type_unique (PARENT_OBJECT_TYPE, &info);
}
return type;
}
void
e_table_item_set_cursor (ETableItem *eti, int col, int row)
{
e_table_item_focus(eti, col, view_to_model_row(eti, row), 0);
}
static void
e_table_item_focus (ETableItem *eti, int col, int row, GdkModifierType state)
{
g_return_if_fail (eti != NULL);
g_return_if_fail (E_IS_TABLE_ITEM (eti));
if (row == -1) {
row = view_to_model_row(eti, eti->rows - 1);
}
if (col == -1) {
col = eti->cols - 1;
}
if (row != -1) {
e_table_selection_model_do_something(eti->selection,
row, col,
state);
}
}
gint
e_table_item_get_focused_column (ETableItem *eti)
{
int cursor_col;
g_return_val_if_fail (eti != NULL, -1);
g_return_val_if_fail (E_IS_TABLE_ITEM (eti), -1);
gtk_object_get(GTK_OBJECT(eti->selection),
"cursor_col", &cursor_col,
NULL);
return cursor_col;
}
gboolean
e_table_item_is_row_selected (ETableItem *eti, int row)
{
g_return_val_if_fail (eti != NULL, FALSE);
g_return_val_if_fail (E_IS_TABLE_ITEM (eti), FALSE);
return e_table_selection_model_is_row_selected(eti->selection, row);
}
static void
eti_cursor_change (ETableSelectionModel *selection, int row, int col, ETableItem *eti)
{
int view_row = model_to_view_row(eti, row);
int view_col = model_to_view_col(eti, col);
if (view_row == -1 || view_col == -1) {
e_table_item_leave_edit (eti);
return;
}
eti_request_region_show (eti, view_col, view_row, view_col, view_row);
e_canvas_item_grab_focus(GNOME_CANVAS_ITEM(eti));
if (eti_editing(eti))
e_table_item_leave_edit (eti);
gtk_signal_emit (GTK_OBJECT (eti), eti_signals [CURSOR_CHANGE],
view_row);
eti->needs_redraw = TRUE;
gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(eti));
}
static void
eti_selection_change (ETableSelectionModel *selection, ETableItem *eti)
{
eti->needs_redraw = TRUE;
gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(eti));
}
void
e_table_item_enter_edit (ETableItem *eti, int col, int row)
{
g_return_if_fail (eti != NULL);
g_return_if_fail (E_IS_TABLE_ITEM (eti));
if (eti_editing (eti))
e_table_item_leave_edit(eti);
eti->editing_col = col;
eti->editing_row = row;
eti->edit_ctx = e_cell_enter_edit (eti->cell_views [col], view_to_model_col(eti, col), col, row);
}
void
e_table_item_leave_edit (ETableItem *eti)
{
int col, row;
void *edit_ctx;
g_return_if_fail (eti != NULL);
g_return_if_fail (E_IS_TABLE_ITEM (eti));
if (!eti_editing (eti))
return;
col = eti->editing_col;
row = eti->editing_row;
edit_ctx = eti->edit_ctx;
eti->editing_col = -1;
eti->editing_row = -1;
eti->edit_ctx = NULL;
e_cell_leave_edit (eti->cell_views [col],
view_to_model_col(eti, col),
col, row, edit_ctx);
}
void
e_table_item_compute_location (ETableItem *eti,
int *x,
int *y,
int *row,
int *col)
{
if (!find_cell (eti, *x, *y, col, row, NULL, NULL)) {
*y -= eti_get_height(eti);
}
}
typedef struct {
ETableItem *item;
int rows_printed;
} ETableItemPrintContext;
static gdouble *
e_table_item_calculate_print_widths (ETableHeader *eth, gdouble width)
{
int i;
double extra;
double expansion;
int last_resizable = -1;
gdouble scale = 300.0L / 70.0L;
gdouble *widths = g_new(gdouble, e_table_header_count(eth));
/* - 1 to account for the last pixel border. */
extra = width - 1;
expansion = 0;
for (i = 0; i < eth->col_count; i++) {
extra -= eth->columns[i]->min_width * scale;
if (eth->columns[i]->resizeable && eth->columns[i]->expansion > 0)
last_resizable = i;
expansion += eth->columns[i]->resizeable ? eth->columns[i]->expansion : 0;
widths[i] = eth->columns[i]->min_width * scale;
}
for (i = 0; i <= last_resizable; i++) {
widths[i] += extra * (eth->columns[i]->resizeable ? eth->columns[i]->expansion : 0)/expansion;
}
return widths;
}
static gdouble
eti_printed_row_height (ETableItem *eti, gdouble *widths, GnomePrintContext *context, gint row)
{
int col;
int cols = eti->cols;
gdouble height = 0;
for (col = 0; col < cols; col++) {
ECellView *ecell_view = eti->cell_views [col];
gdouble this_height = e_cell_print_height (ecell_view, context, view_to_model_col(eti, col), col, row,
widths[col] - 1);
if (this_height > height)
height = this_height;
}
return height;
}
#define CHECK(x) if((x) == -1) return -1;
static gint
gp_draw_rect (GnomePrintContext *context, gdouble x, gdouble y, gdouble width, gdouble height)
{
CHECK(gnome_print_moveto(context, x, y));
CHECK(gnome_print_lineto(context, x + width, y));
CHECK(gnome_print_lineto(context, x + width, y - height));
CHECK(gnome_print_lineto(context, x, y - height));
CHECK(gnome_print_lineto(context, x, y));
return gnome_print_fill(context);
}
static void
e_table_item_print_page (EPrintable *ep,
GnomePrintContext *context,
gdouble width,
gdouble height,
gboolean quantize,
ETableItemPrintContext *itemcontext)
{
ETableItem *eti = itemcontext->item;
const int rows = eti->rows;
const int cols = eti->cols;
int rows_printed = itemcontext->rows_printed;
gdouble *widths;
int row, col;
gdouble yd = height;
widths = e_table_item_calculate_print_widths (itemcontext->item->header, width);
/*
* Draw cells
*/
if (eti->draw_grid){
gp_draw_rect(context, 0, yd, width, 1);
}
yd--;
for (row = rows_printed; row < rows; row++){
gdouble xd = 1, row_height;
row_height = eti_printed_row_height(eti, widths, context, row);
if (quantize) {
if (yd - row_height - 1 < 0 && row != rows_printed) {
break;
}
} else {
if (yd < 0) {
break;
}
}
for (col = 0; col < cols; col++){
ECellView *ecell_view = eti->cell_views [col];
if (gnome_print_gsave(context) == -1)
/* FIXME */;
if (gnome_print_translate(context, xd, yd - row_height) == -1)
/* FIXME */;
if (gnome_print_moveto(context, 0, 0) == -1)
/* FIXME */;
if (gnome_print_lineto(context, widths[col] - 1, 0) == -1)
/* FIXME */;
if (gnome_print_lineto(context, widths[col] - 1, row_height) == -1)
/* FIXME */;
if (gnome_print_lineto(context, 0, row_height) == -1)
/* FIXME */;
if (gnome_print_lineto(context, 0, 0) == -1)
/* FIXME */;
if (gnome_print_clip(context) == -1)
/* FIXME */;
e_cell_print (ecell_view, context, view_to_model_col(eti, col), col, row,
widths[col] - 1, row_height);
if (gnome_print_grestore(context) == -1)
/* FIXME */;
xd += widths[col];
}
yd -= row_height;
if (eti->draw_grid){
gp_draw_rect(context, 0, yd, width, 1);
}
yd--;
}
itemcontext->rows_printed = row;
if (eti->draw_grid){
gdouble xd = 0;
for (col = 0; col < cols; col++){
gp_draw_rect(context, xd, height, 1, height - yd);
xd += widths[col];
}
gp_draw_rect(context, xd, height, 1, height - yd);
}
g_free (widths);
}
static gboolean
e_table_item_data_left (EPrintable *ep,
ETableItemPrintContext *itemcontext)
{
ETableItem *item = itemcontext->item;
int rows_printed = itemcontext->rows_printed;
gtk_signal_emit_stop_by_name(GTK_OBJECT(ep), "data_left");
return rows_printed < item->rows;
}
static void
e_table_item_reset (EPrintable *ep,
ETableItemPrintContext *itemcontext)
{
itemcontext->rows_printed = 0;
}
static gdouble
e_table_item_height (EPrintable *ep,
GnomePrintContext *context,
gdouble width,
gdouble max_height,
gboolean quantize,
ETableItemPrintContext *itemcontext)
{
ETableItem *item = itemcontext->item;
const int rows = item->rows;
int rows_printed = itemcontext->rows_printed;
gdouble *widths;
int row;
gdouble yd = 0;
widths = e_table_item_calculate_print_widths (itemcontext->item->header, width);
/*
* Draw cells
*/
yd++;
for (row = rows_printed; row < rows; row++){
gdouble row_height;
row_height = eti_printed_row_height(item, widths, context, row);
if (quantize) {
if (max_height != -1 && yd + row_height + 1 > max_height && row != rows_printed) {
break;
}
} else {
if (max_height != -1 && yd > max_height) {
break;
}
}
yd += row_height;
yd++;
}
g_free (widths);
if (max_height != -1 && (!quantize) && yd > max_height)
yd = max_height;
gtk_signal_emit_stop_by_name(GTK_OBJECT(ep), "height");
return yd;
}
static gboolean
e_table_item_will_fit (EPrintable *ep,
GnomePrintContext *context,
gdouble width,
gdouble max_height,
gboolean quantize,
ETableItemPrintContext *itemcontext)
{
ETableItem *item = itemcontext->item;
const int rows = item->rows;
int rows_printed = itemcontext->rows_printed;
gdouble *widths;
int row;
gdouble yd = 0;
gboolean ret_val = TRUE;
widths = e_table_item_calculate_print_widths (itemcontext->item->header, width);
/*
* Draw cells
*/
yd++;
for (row = rows_printed; row < rows; row++){
gdouble row_height;
row_height = eti_printed_row_height(item, widths, context, row);
if (quantize) {
if (max_height != -1 && yd + row_height + 1 > max_height && row != rows_printed) {
ret_val = FALSE;
break;
}
} else {
if (max_height != -1 && yd > max_height) {
ret_val = FALSE;
break;
}
}
yd += row_height;
yd++;
}
g_free (widths);
gtk_signal_emit_stop_by_name(GTK_OBJECT(ep), "will_fit");
return ret_val;
}
static void
e_table_item_printable_destroy (GtkObject *object,
ETableItemPrintContext *itemcontext)
{
gtk_object_unref(GTK_OBJECT(itemcontext->item));
g_free(itemcontext);
}
EPrintable *
e_table_item_get_printable (ETableItem *item)
{
EPrintable *printable = e_printable_new();
ETableItemPrintContext *itemcontext;
itemcontext = g_new(ETableItemPrintContext, 1);
itemcontext->item = item;
gtk_object_ref(GTK_OBJECT(item));
itemcontext->rows_printed = 0;
gtk_signal_connect (GTK_OBJECT(printable),
"print_page",
GTK_SIGNAL_FUNC(e_table_item_print_page),
itemcontext);
gtk_signal_connect (GTK_OBJECT(printable),
"data_left",
GTK_SIGNAL_FUNC(e_table_item_data_left),
itemcontext);
gtk_signal_connect (GTK_OBJECT(printable),
"reset",
GTK_SIGNAL_FUNC(e_table_item_reset),
itemcontext);
gtk_signal_connect (GTK_OBJECT(printable),
"height",
GTK_SIGNAL_FUNC(e_table_item_height),
itemcontext);
gtk_signal_connect (GTK_OBJECT(printable),
"will_fit",
GTK_SIGNAL_FUNC(e_table_item_will_fit),
itemcontext);
gtk_signal_connect (GTK_OBJECT(printable),
"destroy",
GTK_SIGNAL_FUNC(e_table_item_printable_destroy),
itemcontext);
return printable;
}