Design for a possible reimplementation of the KDE help center ============================================================= Preludium --------- This document presents an alternative design for a 'help center' applicaiton in KDE. Lines which start with a # are supposed to be thoughts I had while writing this, much like the stuff you write on the side of a page when reading a book. Lines starting with ## were added by my as further comments - Cornelius And I'll have the ### lines - Lauri General ------- - main() instantiates a KHC::Application - KHC::Application() deals with parsing the commandline parameters and instantiates a KHC::MainWindow - KHC::MainWindow creates the main UI, setting up actions, using a QSplitter as it's mainwidget to separate a KHC::Navigator at the left from a KHC::View at the right That's the simple part. ;-) ## Apparently already done ;-) KHC::Navigator -------------- KHC::Navigator inherits QTabWidget and provides, on two tabs, a KHC::ContentsTab object and a KHC::SearchTab object. ## KHC::Navigator shouldn't inherit from QTabWidget. This limits flexibility. ## It can create a QTabWidget instance as aggregate just as well. # I fear premature generalization ("We could need that bit of flexibility one # day), aggregation adds a level of indirection through a pointer variable as # well. I would prefer not making the system more complex as long as we cannot # predict changes which justify doing so. 1.) KHC::ContentsTab provides the following entires: - Welcome to TDE - KDE user's manual - KDE FAQ - Contact information - Supporting KDE # Should we create an extra item for these five and put them in there? # Something like "General KDE" or so? OTOH that makes them less visible, and # these are really ought to be seen. - Frerich ## The items are ok, in principle, but we should have a look at the content of ## the documents they point at. This document could benefit from some attention. ### Yes, they would. Also, there are license issues with one of them. ### I'd personally like to do an entire rewrite of the User Manual, ### without GPL encumbrance and sans the content that hasn't changed since ### KDE 1.x days. The odds of me getting this done before KDE 3.1, slim to fair. - Application manuals - Tutorials - UNIX man pages - UNIX info pages - Glossary # Do we really need this "Tutorials" item at all? right now it holds only two # items, perhaps we can get rid of it. - Frerich ## Yes, please. ### There should be a "General" area, where documentation that isn't ### attached directly to an application can go. Tutorials might not be ### the best name for it I agree, but there is now some further content to ### add (the DCOP tutorial, for example, or any of the numerous tutorials ### on the websites, documenting things that aren't in the handbooks.q # Alright, after some talk on IRC this structure evolved: # # - Tasks - contains short, three to four paragraph documents about how to # solve an everyday task, examples: # Browsing the web # Send and receive email # How to view images # Playing sound files # Installing new KDE themes # How to configure KDE fonts # Getting in touch with KDE contributors # Supporting the KDE team # # - Guides - slightly longer, Mini-HOWTO style guides (about three to four # pages long, perhaps) which talk about tackling jobs which don't # occur very often, examples: ### I don't know about limiting the length. Some of these topics can stand ### a much longer document, but one of the things that differentiates them ### from the references is that they are not specific to a single application, ### nor are they complete references in the manner of the "KDE User Guide" ### Specificaly, the dcop tutorial we have is about 15 pages already, but if ### the user is interested in the topic, that isn't over much, and it's full of ### examples # How to debug KDE programs # Sending useful KDE bug reports # Extending KDE's service menus # Taking advantage of KDE's DCOP facilities # Creating panel applets # Phrasing questions most effectively # # - References - references. :-) # KDE API reference # KDE application manuals # Info pages # Man pages # FAQ # User's manual # # - Glossary - same as always. # - By topic # - Alphabetically # # My primary argument for such a structure is that it resembles a # task-oriented interface much more closely than the simple list of # application manuals. Imagine a user new to KDE who has a fairly precise # description of what he's trying to do in mind (think "I want to view an # image file") but no idea what tool to use for the job. The current list of # application manuals requires the user to browse all the manuals which seem # relevant, searching for the information he seeks. A task-oriented list # solves that issue. # This effectively enables people new to KDE in less time to become productive # (a task-oriented list isn't so useful for peoplew ho are familiar with KDE's # applications, of course). # Implementation-wise, we should perhaps stop using a TDEListView and use a # KOffice-style component selection widget like koshell has at the left? The first five items are generated by KHC::Navigator itself and are direct links to KDE documentations. The work of generating each of the last four items is (with one exception) delegated to four helper classes, which inherit a 'KHC::TreeBuilder' class which has the following interface: class KHC::TreeBuilder virtual void build( TDEListViewItem *parent ) = 0; ## What about the trees generated as children of the contents list view? # Oops, that's a typo, what you mean is what I originally intented: a # TreeBuilder should take a 'TDEListView' as it's parent, subclasses can then # overload that method (such as the KHC::TOCBuilder which will want to provide # a build( TDEListViewItem *parent ) method). # This concept of using a TreeBuilder baseclass might make it possible to turn # all the classes which use that interface into plugins. That way we could # e.g. have a ScrollKeeper plugin. - Frerich ## What exactly do you mean by plugin? A shared library loaded at run time or ## the desktop file based insertion of documents into the help center? # The former. The classes which inherit this interface are: - KHC::ManualTreeBuilder: responsible for generating the tree below the "Application manuals" item - KHC::TOCBuilder: responsible for generating a TOC tree below each of the manual trees items, so that you can choose Application Manuals->Editors->KWrite->Using KWrite->Menu bar transparently. This is the only builder which is not instantiated by KHC::ContentsTab but instead instantiated by KHC::ManualTreeBuilder - KHC::TutorialTreeBuilder: responsible for generating the tree below the "Tutorials" item - KHC::ManTreeBuilder: responsible for building the tree below the "UNIX man pages" item - KHC::InfoTreeBuilder: responsible for building the tree below the "UNIX info pages" item - KHC::GlossaryTreeBuilder: guess what ## - KHC::ScrollkeeperTreeBuilder ## It's certainly a good idea to move stuff like the info and man pages and ## scrollkeeper support to its own classes. What I consider as important is ## that the concept of representing the documentation by desktop meta files is ## used as far as possible. This makes the system very flexible and extandable. 2.) KHC::SearchTab provides a widget which lets the search through all available help repositories, also defining some flags such as 'Search by regexp' or 'Search case sensitive'. # I think this means that we have to create a 'DataCollection' class which # gets inherited by all classes which are "searchable". DataCollections should # also be able to contains multiple child DataCollection, so that we have e.g. # one DataCollection per application manual, and one "Manuals" collection # which contains all the application manual collections. # We'd probably also need a DataCollection for the info pages and man pages. # And later, in the far future, we might extent this concept to web searches, # so that e.g. Google represents a DataCollection which we can query. # I'm not yet decided how to do that properly, perhaps using multiple # inheritance, so that each TOCBuilder is a DataCollection - naw, we'd rather # have a "TableOfContents" class which contains a TOCBuilder, and is a # datacollection? Hm, not sure. # In any case DataCollections should some sort of plugins, so that we can add # e.g. new web search interfaces lateron. # - Frerich ## What you call a DataCollection is currently represented by the DocEntry ## objects. Each DocEntry object represents a document or a collection of ## documents. It has information about the name and description of the ## document, the location and how it can be searched. ## ## Currently this information is based on URLs or file names and is optimized ## to be used by scripts, e.g. CGI scripts. A little exception from this is ## the htdig support where just a keyword "SearchMethod=htdig" is put in the ## desktop file and the help center figures out how to perform that search by ## using a special class. This could be extended to cover other search methods ## like web searches or special search methods optimized for certain kind of ## documents. # I just thought about it - isn't that a bit overkill for the web search # stuff? I just thought about it - all we need to do is to copy the .desktop # files (at least some of them, like the ones for google, yahoo and excite) # from the enhanced browsing thing and treat those as plugin .desktop files. # We could show them in a listview on the Search tab, each found search engine # being represented by a checkable listview item. So, we just let the user # enter a term, replace the \{@} placeholder in the URIs specified in the # selected .desktop files with that term, send out a request via TDEIO and show # the results in our TDEHTMLPart (after all KHC::View is a TDEHTMLPart already). A # problem with this: How to display the multiple HTML pages returned by the # selected search engines? Using a QSplitter to split multiple TDEHTMLParts? # Hmm... just wondered... perhaps we can work around that by not showing the # returned HTML data at all but rather use a XSLT script (that is, one XSLT # script per web search) which transforms the returned search results into a # common format - that way, we could also filter out duplicates and then # transform that filtered output into a nice, uniform HTML page. How about # that? # I like this idea very much, I just thought it and noticed you wrote this # down already. What I thought of was having a .desktop/.xslt file pair per # search engine: each .desktop file holds at least the name of the engine (for # the listview) and a search URI with a placeholder, just like in your scenario. # In additionl there could be a X-KHelpCenter-XSLT key which defines which .xslt # stylesheet to use for that particular search engine. We then query that search # engine by replacing the placeholder in the URI with whatever the user entered # and hand it to TDEIO. All the HTML returned by the various search engines gets # then transformed into a custom, intermediate, XML dialect, using the XSLT # stylesheets define in the .desktop files. Using that intermediate step we # can nicely drop duplicate hits, for example, or create a list of hits in the # sidebar (much like http://www.copernic.com does). After that, we can use # another XSLT stylesheet to transform that cleaned XML tree into HTML which # we then feed to our TDEHTMLView. Since we then have one unified output, we don't # need to worry about having multiple TDEHTMLParts, and it's also nice because # the user doesn't see which search engine returned which hit. # A problem with this would be that we cannot tell how a particular search # engine treats boolean expressions (e.g. some search engines use 'foo AND bar', # others use '+foo +bar', a third variation is '"foo bar"'). We thus cannot # replace the placeholder in the URI but first have to translate the syntax # entered by the user into a syntax which is appropriate for each single news # engine. Right now I don't know how we could do this with just a .desktop/.xslt # pair. We could always use fullblown C++ plugins which hold code which is able # to do that translation, but I would really prefer to stick with .desktop files # now since they're much easier to create. # Another thing which would speak in favor of C++ plugins: different search # engines support different features (like, google can search more than just the # web, and you can sometimes tell a search engine to list only results in a # certain language, or with a certain encoding), so it would be nice if we could # let the user access those features: through a dialog which has to be tailored # to the possibilities of the respective search engine. I wonder whether we # could have some sort of XML tree which defines how an UI should look like, and # then let KHelpCenter create a dialog using that XML markup, but that idea is # very vague right now. # Hmm, I just tried it and the XSLT idea didn't really take off: the problem # is that many HTML pages returned by Google, Yahoo & co. don't seem to be # valid XML, which is why tools such as meinproc or xsltproc refuse to process # themm. :-/ KHC::View --------- KHC::View inherits TDEHTMLPart and does the actual job of showing some sort of document. Most importantly, it has a slot which passes it a KURL pointing to a document to show. KHC::View will invoke tdeio_help if necessary (if the URL's protocol == "help") by itself and otherwise use the plain URL. # TODO: Things I didn't really think about yet: the interface between the # navigator and the view. I think this has to be a bidirectional association # since the navigator can change the view (e.g. by clicking on a manual which # shows it in the view), but the view can also change the navigator (think of # clicking on a 'See also' link in the glossary which should also scroll to # the corresponding entry in the navigator). ## That's a very important aspect. We should have one central place where all ## document requests are processed and the necessary actions (like updating ## the navigator, loading a new page, caching the search results, etc.) are ## done. ## ## The TreeBuilder might need some interface to tell, if a certain URL exist ## in their tree, to make it possible to select content entries which aren't ## created yet, because they are only created on demand (like the application ## manuals). # Very good idea. Perhaps I think iterating over a list of TreeBuilder # instances and doing something like 'if ((*it)->canHandle(url)) # (*it)->selectItem(url)' which checks whether a TreeBuilder provides an item # which corresponds to an URL (hmm, this makes me think, TreeBuilder is a bad # name. Perhaps just 'Tree'?) and selects it (using # QListView::ensureItemVisible() or so) if requested. This probably implies. # that a TreeBuilder needs an internal QMap<KURL, QListViewItem *>. # Also, the whole search engine needs more thought, that DataCollection idea # seems promising to me but I'm not yet decided on how to do it properly. ## See above. We already have something which isn't too bad, I think. # I just thought about this a bit, I think KHC::MainWindow should act as the # interface between KHC::Navigator and KHC::View. ## I would prefer to have an extra class which does no GUI stuff, but passes ## URL requests around, does the needed processing and stores data, if needed ## (e.g. caching search results). # Agreed. ## One very important aspect of the help center is that it has to be fast. It's ## not acceptable to wait several seconds after clicking on the Help menu of an ## application. We should think about that. Perhaps we can do some tricks like ## showing the main window before creating the other widgets and processing data ## or something similar. We could also think about creating more stuff only on ## demand. # My perception is that filling the Navigator's listview takes a significant # amount of time, just like setting up the TDEHTML view (loading the stylesheet, # showing the welcome page). We could easily do taht in the background - show # the mainwindow, then tell the TreeBuilders to start populating (using a # QTimer with a timeout of 0, for a snappy GUI). Since they're collapsed at # the start, the users won't even notice (and we can "fake" that they're # already populated by calling setExpandable(true) for all of them (or letting # them do that themselves) at the start. ## Finally a crazy idea: Wouldn't it be cool, if we would make the manuals more ## interactive. So when you read about a certain menu or a certain dialog of an ## application you can click on a link in the manual and the menu or dialog gets ## opened in the real application, or some widgets get highlghted in the real ## application. Such a feature could also be used to create interactive ## tutorials, where you have a small helpcenter window and the application next ## to each other on the screen and you can go through the tutorial step by step ## and practice with the real application while reading the instructions. ## With the help of DCOP it shouldn't be too hard to implement such an ## interactive help system. Maybe it's even possible to do it in a general way ## in the libs, so that application authors don't have to think about that ## feature. # Hmm, that's an interesting idea. That takes KHelpCenter way beyond what it's # currently doing. I can imagine this: we introduce a virtual "dcop" protocol, # so that e.g. <ulink url="dcop:/kfortune/KFortuneIface/nextFortune"/> # represents the DCOP call 'dcop kfortune KFortuneIface nextfortune'. # KHelpCenter catches that protocol (oh dear, a lot of special cases with # gloss, info etc. already - guess another one won't hurt). That looks like a # good way for encapsulating DCOP calls. # Now, the problem is - the application has to provide a dedicated # "documentation" DCOP interface for this, with lots of calls for highlighting # the various widgets (hm, this probably means taht we can skip the first two # parts in our 'dcop' URL syntax, the application is known anyway, and the # interface is hardcoded in KHelpCenter). # So, what could happen is this: We have a piece of HTML in the documentation # for our SuperApp application which goes like 'The # <a href="dcop:highlightConnectButton">button labelled Connect</a> makes # SuperApp establish a connection.' - the user clicks on that link, # KHelpCenter catches a dcop: URL, checks whether SuperApp has already been # started. If not, it starts a SuperApp process and does the dcop call 'dcop # SuperApp DocIface highlightConnectButton' and SuperApp starts highlighting # that connect button. The thing is that this requires a lot of work on the # application side. The idea is very cool, but we'd have to think about # outsourceing parts of that functionality, either to KHelpCenter, or to # tdelibs. ## And another idea: The WhatsThis help texts describe all widgets of an ## application (provided that the texts are set by the developers). Currently ## they aren't accessible very easily. You have to go to a special mode and ## can then click on one widget after another to get the help, if there is one. ## There is no visual indication which widgets have help and which not. But the ## application knows about the WhatsThis helps. Perhaps it's possible to use ## the Qt object inspection stuff to extract all the texts and put them on an ## automatically generated screenshot of the corresponding dialog and put this ## graphic into the docs. Maybe it's even possible to do this at run-time and ## decorate dialogs with all WhatsThis helps at once, if the user triggers this ## mode. # Hmm yes, that should be possible. Take the toplevel widget, use # TQObject::children() and iterate over all children, use QToolTip::textFor() to # check whether the given qwidget has a tooltip and if so, use QToolTip::tip() # to show the tooltip. # One could probably add a standard dcop call to TDEMainWindow, like # "showAllToolTips". KSnapShot could get a QCheckBox "Show all tooltips", and # if that box is checked it tells the selected window to show all it's # tooltips via that DCOP call right before it does the snapshot. The thing is # - is it possible to map the WinID of the window the user clicked on to # the process name we should send your DCOP call to? ## One thing we should also keep in mind is that it might be useful to provide ## the help center as a component. FOr example KDevelop has a very similar ## thing. It would be much nicer, if it could reuse the KHelpcenter code. This ## would probbaly also mean to at a DoxygenTreeBuilder or something similar. # That probably implies that instead of a QSplitter which holds the Navigator # and the View, we'd have a KHC::MainWidget KPart which in turn aggregates the # splitter. The DoxygenTreeBuilder sounds like a reason to make TreeBuilders # real plugins, with dynamically loaded libraries, so that KDevelop or other # "IDE"-like applications (perhaps a KOffice help system?) can have their # customized tree builders. Font Configuration ------------------ ### Many bug reports on KHelpCenter not honouring TDEHTML font settings, ### which is odd, because the stylesheet is intentionally loose, ### specifying only "sans-serif" as the font face. ### Ideas to fix: ### Help pages already make heavy use of the cascading feature of CSS, we ### ought to be able to leverage that by writing to perhaps the ### kde-localized.css file or a copy of it in $TDEHOME. There is already ### code in KControl to create a user CSS stylesheet, and we probably only ### need to configure the size and the face for KHC. ### Or, fix whatever is the reason KHC doesn't follow the rules. It could ### be encoding related, the help pages specify utf-8 as the encoding, and ### previous incarnations of the TDEHTML settings allowed fonts set on a ### per-encoding basis (at which time, this was apparently working, the bug ### reports dropped off, and only returned post KDE 3.0 # FWIW I added a simple font configuration facility a while back, which should # IMHO be sufficient for the vast majority of users.