diff options
Diffstat (limited to 'tdeparts')
58 files changed, 9506 insertions, 0 deletions
diff --git a/tdeparts/AUTHORS b/tdeparts/AUTHORS new file mode 100644 index 000000000..7c8680a5a --- /dev/null +++ b/tdeparts/AUTHORS @@ -0,0 +1,11 @@ +KParts has been written by: +Simon Hausmann <[email protected]> +David Faure <[email protected]> + +KParts is inspired from KOParts, written by: +Torben Weis <[email protected]> + +Contributors: +Kurt Granroth <[email protected]> +Michael Koch <[email protected]> + diff --git a/tdeparts/CMakeLists.txt b/tdeparts/CMakeLists.txt new file mode 100644 index 000000000..267d64655 --- /dev/null +++ b/tdeparts/CMakeLists.txt @@ -0,0 +1,64 @@ +################################################# +# +# (C) 2010 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${TQT_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}/tdecore + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/dcop + ${CMAKE_SOURCE_DIR}/tdecore + ${CMAKE_SOURCE_DIR}/tdeui + ${CMAKE_SOURCE_DIR}/kio + ${CMAKE_SOURCE_DIR}/kio/kio + ${CMAKE_SOURCE_DIR}/kio/kfile +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### headers ################################### + +install( FILES + part.h plugin.h partmanager.h mainwindow.h dockmainwindow.h + event.h browserextension.h factory.h historyprovider.h + browserinterface.h genericfactory.h componentfactory.h + browserrun.h statusbarextension.h + DESTINATION ${INCLUDE_INSTALL_DIR}/tdeparts ) + + +##### other data ################################ + +install( FILES + kpart.desktop krop.desktop krwp.desktop browserview.desktop + DESTINATION ${SERVICETYPES_INSTALL_DIR} ) + + +#### tdeparts ##################################### + +set( target tdeparts ) + +set( ${target}_SRCS + part.cpp plugin.cpp partmanager.cpp mainwindow.cpp + dockmainwindow.cpp event.cpp browserextension.cpp + factory.cpp historyprovider.cpp browserinterface.cpp + browserrun.cpp statusbarextension.cpp +) + +tde_add_library( ${target} SHARED AUTOMOC + SOURCES ${${target}_SRCS} + VERSION 2.1.0 + LINK kio-shared + DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/tdeparts/COMMENTS b/tdeparts/COMMENTS new file mode 100644 index 000000000..abf24ca84 --- /dev/null +++ b/tdeparts/COMMENTS @@ -0,0 +1,605 @@ +2) provide some way to save/restore the positions of the menu/toolbar(s) + when changing the active part ( I remember Reggie asking for that :) + +(David) Sounds good. I might have a look at that next. +Comment : the menubar is cleared, not destroyed, so it seems we don't have +to do anything for it (it remains where it is). We still need to save +the BarPosition of the toolbars, though (see comment in +KTMainWindowGUIBuilder::createContainer). +(David) : With Torben's idea of inheriting KTMW, the problem of accessing +the BarPosition of the toolbars is solved. Nice :-) + +(David) Not sure we want to save whether the statusbar is shown/hidden. + +(Simon) Another thought: Perhaps we should store the geometry information of + the containers of the KPartHost in the KPart itself? + (something like KPart-Session Management ;-) +(David) Sounds strange (the child taking care of its host's containers...) +In SM, it's the host (the WM) that stores the position of its children (the +windows) :-) +One possible problem (I'm not sure) : are the toolbars shared between the host +and the part, or are there only toolbars for one and toolbars for the others ? +In the first case, there's a problem because the toolbar will remain when +switching part, so shouldn't get moved back when switching back. +In fact we only want to store the position of the toolbars that fully "belong" +to the part, right (i.e. that only contain items from the part) ? +In this case, yes, that could be saved in the part. + +-------------- + +4) Perhaps a part wants to know if it got activated, so we might want to + re-introduce that PartActivateEvent from tdelibs/tdeparts. + Question: Shall this event be sent when the GUI of the part is activated + or shall it be sent when the part "really" got activated (via KPartManager)? + +(David) Any example of usage ? +I think what it wants is "really" activated, no ? + +(Simon) Konqueror for example wants to know when it gets activated, in order to access the KPartHost + and query for the container objects (*bars) . + Hmmmmmm, that sounds like two possible events. A PartActivateEvent and a GUIActivateEvent... + What do you think? + +(David) 1 - I don't see the difference between "the gui of the part gets activated" and "the part +gets activated", in this simple model (no Document/View). The Part gets activated when you can see +its items in the menus/toolbars, there is no "in between" IMO ? + 2 - Remind me what konq does with the *bars when a part gets activated ? +I couldn't find anything with a quick grep in the sources... +I'm still looking for an example when it's useful :) + +(Simon) I think that's the whole idea of making KPartManager independent from + the guibuilder. Perhaps some apps wants to embed stuff without showing + the parts a full-fledged gui (remember the part-children thingy in the + old OpenParts? ;-) ) . Konqueror is one example. However I think + KOffice could benefit from this, too, for the inplace editing + (where the part is active, in terms of the KOffice document/view model, + but still has a different gui or even none at all) . + +(David) : I start to see :-) +But what I don't see is how does KPart know whether it's activated +simply or activated with its GUI... i.e. how does it know the way +it is embedded (with or without GUI items). Hmmm.. + + +(Simon) Konqueror (2) : When a parts get activated (this is "detected" via + KonqViewManager) , then in general the actions of the view get plugged + into the menus and the main toolbar (which is acccessed via + Shell::viewToolBar() (hmmm, I'm looking forward to the new KParts :-) +(David) Ah yes we don't have that in "example" currently. Dynamic actions. + So you would add an event (or signal) to KPart for that ? Sounds ok to me. + +(Simon) That means that the (old) KParts doesn't know anything about the + embedding in Konqueror. +(David) Didn't get that ?!? :-) + +-------------- + + BrowserView inheriting KReadOnlyPart is the way to go, IMHO. + + The question if Konqueror itself should be a KPart is difficult. + All the BrowserViews are embeddable already, so it's "questionable" + if it makes sense to have the embeddable Konqueror shell (KonqMainView) . + +(David) indeed. + + OTOH that shell makes these views "interact", makes them switch. So if + someone wants to embed a browse-all-stuff widget, then embedding Konqueror + would probably be cool, as the mainview handles all the stuff like determining + the correct mimetype, loading the view, receiving and sending openURL requests, etc. + Something like a shoot-and-forget for embedding ;-) (embed-and-forget ;) + Loading and saving in that case would mean save/load the view profile. + +(David) Hmmm... somebody wanting to embed a full konqy ? Component technology allows +you to avoid duplicate code by embedding a component that does what you want. Like tdevelop +embeds a kedit component. Which app would want to embed a huge component containing +a file maneger + a web browser + a generic viewer + ... ? I think this is not a component, +but an application. Views are components... + +(Simon) Yes, that is true. + What about this: We don't make Konqueror's Mainview a KPart, but still + use the XMLGUI and the pluginaction stuff. (because these two things + are importan and very nice IMHO). (I don't want to miss the action + stuff in Konqueror, neither you I guess :-) + +(David) Sure, actions rock. But KTMainWindowGUIBuilder exists for that exact +reason, no? The mainview would be a KTMainWindow, so its GUI is described in +XML and with actions. + + +------------ +(David) This lib offers : +KReadOnlyPart for viewers +KReadWritePart for editors +KPart for a generic part (?) + +We could easily port BrowserView to inherit KReadOnlyPart, and call it +KBrowserPart. +Proposed changes : +- The action stuff gets ported, of course (structs disappear) +- started/completed/canceled already exist -> removed +- setStatusBarText() -> see below, wondering about status bar +- setLocationBarURL() -> removed - konqueror will set it from url() + [ is that correct ? ] + +(Simon) I think we still need it. When a view gets a redirection signal, then + it wants to change the displayed URL. +(David) Ah right (I think support for redirection is missing from konqueror on +the whole, at other places). + +- openURLRequest and createNewWindow remain. + +(Simon) <sidenote> We will want to add a serviceType argument to openURLRequest. + At least we need it to get rid of these changeViewMode() hacks in + konq_htmlview/konq_iconview :P +(David) ok + +- popupMenu remains ? + +(Simon) What about putting that popupMenu into an extension interface, + contained in libkonq? IMHO the popupMenu is very libkonq specific. +(David) Depends how we want to handle the popupmenu in KonqHTMLView, for +instance. +At the moment it's missing, and it will be a problem when that view is moved to +tdelibs : no more libkonq for it. But anyway I agree : the part should +generally take care of its own menu (I'm thinking of KNotePadPart for instance) +Perhaps this would remain in KBrowserPart though (we need it in konqueror). + +---- + +On second thought : why should we make KReadOnlyPart different from +KBrowserPart ? +Any "viewer" should be embeddable in konqueror. The additional signals we +currently have in BrowserView could be simply added to KReadOnlyPart, and +it doesn't make it more complex (kedit can simply not care about the loading +progress, the popupMenu signal, ...) +In fact the loading progress should even be emitted by KReadOnlyPart +itself (it handles the kiojob), for the simple cases. Of course +konqueror views will reimplement openURL and send the signals themselves. +The main problem I see is that BrowserView is asynchronous +and KReadOnlyPart is .. a bit of both (asynchronous for remote URLs, +synchronous in openFile()). But for konqy, openFile() means nothing +and never gets called (because openURL is reimplemented). +For the history stuff, we can provide the default implementation +in KReadOnlyPart (just like we did in BrowserView). +About the "offset stuff" - well it even makes sense in kedit +so the host can ask for going to a particular line when opening the +file (hyper cool !). Anyway, for parts which have nothing to do with +offsets, this gets simply ignored. + +In short, we can take advantage of the fact that we have a lib now, +as opposed to an interface alone (BrowserView), and provide default +implementations (when possible, for example the history stuff) +which make every "viewer"-type part a part useable in konqueror +- but also in koffice, and whereever. + +This would reduce the number of "type of parts" and make it simpler +to embed anything into anything. OTOH, it makes KReadOnlyPart a bit more +difficult to understand. + +What do you think ? Did I overlook something ? + +(Simon) I don't think there's a problem with the async stuff + (BrowserView/KReadOnlyPart) . Mosfet's KGhostView browserview or + his dviview are both 100% like KReadOnlyPart (yes, they launch TDEIOJob::copy() + and copy the file to some local temp) . It works :-) and noone complains :-)) + -> I see no problem with that :-) +(David) Sure - but does that answer the question : KReadOnlyPart==KBrowserPart ? + Now that I think of it, it's probably not a good idea - there are many + things that BrowserPart has in addition, finally. I'm still not sure. I + like making it simple, but this might be an over-simplification. + +------------ + +(Simon) About KXMLGUIBuilder<->non-KTMW builder: One possible case coming to my mind are dialogs. If you want to +embed a small "part-applet" ;) (perhaps as embedded preview part for some open-foo-dialog?) , then a non-KTMW +builder might be useful (and might have containers) . +I don't see any problem in having a separate (abstract) interface for the GUI builder. We gain flexibility +IMHO, and taking into account that this KParts stuff should probably be something highly finalized for +KDE 2.0, its worth having as much flexibility as possible (while keeping it easy to use by providing the +easy-to-use KTMW implementation) , IMHO. + +(David) Excellent idea !! A part in a dialog :-) Don't think you can have that in Windows :-)) +But .. how can you have containers (menubars, toolbars, ...) in a dialog ? Or were you thinking of +another kind of container ? + +(Simon) Containers in a dialog? See kfd :-)) + (altho kfd uses ktmw AFAIK ;) +(David) ... because there is no support for toolbars in a dialog. + I still think you can't have containers in a QDialog :-) + +(Simon) Another possible thing is perhaps kpropsdlg. IMHO it'd be cool if + it would be very easy and simple to add new props pages for certain + mimetypes dynamically via shlibs. +(David) Sounds good but not very useful. :-) + +--------------- + +(Torben) I did not follow the latest discussions due to a lack of time. However, I made some + small remarks on stuff I did not understand (yet?). + +(Torben) KReadWritePart and KReadOnlyPart use the three signals canceled, started, completed in + two different contexts. One can not see wether a KReadWritePart started loading or + started saving. I would like to introduce + a) three new signals for KReadWritePart + b) A parameter to the signals telling wether this is a read or write operation. + Basically I am in favor for a small API -> b) + And b) is source compatible to the current solution! +(David) ok + +(Torben) In example.cpp addPart is called twice and each time the active part is changed. Would not it be + more clever to add parts and activate one later instead of activating the last one inserted ? +(David) no no, example.cpp doesn't even know when the active part changes. +Did you try running the example ? It features a part that is dynamically +embedded and de-embedded, the notepadpart. That's why there is an addPart() +call - to add the new part when the user asks for it. Not when the active part +changes. + +(Torben) You guys are busting QDOM. You can NOT assign an element of document A to an element of document B. + That means: There is no way to mix two documents. What you are doing is asking for trouble. + The ownerDocument() function will not work as one might expect after the assignment: The element + of B assigned to A will still claim to be a child of B :-( + And there are few chances that this may change in the Qt implementation in the next few weeks. +(to myself) I tro to fix that in QDom .... + +<weis> Hi +<dfaure> Hi ! +<weis> dfaure: Just looked into new tdeparts +<dfaure> ah ? +<weis> dfaure: You have a major problem: One can NOT mix QDomElements of different documents! +<dfaure> weis: why ? +<weis> dfaure: Because the ownerDocument wont change as one might expect. +<dfaure> weis: not sure I have the full picture (Simon did that part). What should we do instead ? +<weis> dfaure: Either I manage to hack QDom (very hard) or ..... dont know currently .... +<dfaure> the problem is .. memory management, right ? +<weis> dfaure: I just checked in my CVS irc stuff :-) +<dfaure> ok :-) +<weis> dfaure: Can you have a look at tdeparts/COMMENTS ? +-- +<dfaure> weis: you should have come before. coolo is talking about re-writing libkio. +<dfaure> well in fact he started the rewrite + dfaure having a look +<weis> dfaure: Unfortunately I am not paid for KDE but for Qt hacking :-( So I fear I have no time for kio anyway. +<dfaure> weis: I know that, but perhaps a little discussion would help him with the new design :) +<weis> dfaure: So you are not convinced by his design ? +<weis> dfaure: It is about this daemon that forks and loads ioslaves as libs, or ? +<dfaure> yes, this looks fine +<dfaure> but then what about filters, and especially the problem is the API +<dfaure> each slave currently implements stuff like recurse copying +<dfaure> and we would perfer that in a single location, obviously :-) +<weis> dfaure: Thta is true! +<weis> dfaure: The new design would mean: We write an abstract interface for basic IO stuff. +<dfaure> yup +<weis> dfaure: Basically every slave would have to implement usual UNIX IO functions. +<weis> dfaure: Does coolo want to do it that way ? +<dfaure> unix io ? +<dfaure> like read, write, open ? +<weis> dfaure: unix io: open/read/write/opendir ... +<dfaure> that would be great IMHO +<dfaure> I think he didn't realize that - the fact that moving the code to a central place involves switching to a lowlevel unix-like aPI for the slaves +<weis> dfaure: If I have a nested URL: Are we going to start two processes to get the URL from the net or one (with Coolos approach) +<weis> dfaure: Currently it is two processes. One for file and one for tar, for example. +<dfaure> weis: we're not sure. would one be ok ? (like opening the two libs and connecting signals and slots..) +-- +<dfaure> weis : > I think this KPartsMainWindow should inherit KTMainWindow directly +<dfaure> weis: I thought the whole idea was NOT to inherit KTM +<dfaure> so that one could use anything as a KTM child +<weis> dfaure: But this KTMainWindowGUIBuilder is already KTMainWindow dependenat. So why not derive ? +<dfaure> well we're back to the shell, then... +<weis> dfaure: Of course. Excuse me! +<dfaure> > Why should one want to access the parents containers? +<dfaure> know the View and Edit menus in konqueror ? +<dfaure> They are view dependant ... +<dfaure> and dynamically added into the menu +<dfaure> although ... we could use XML instead +<dfaure> can't remember why we don't +<weis> dfaure: Using XML seems to be the clean approach IMHO. +<dfaure> yes ... damn can't remember the reason +<dfaure> lazyness perhaps +<dfaure> :-) +<weis> dfaure: What about me hacking a KPartsMainWindow that resembles the old shell pattern. Since it is useful in many cases and easy to understand/use ? +<dfaure> yes, I guess it's ok to have a KTM child. The difference with the old shell is that the gui building is separate from it, right ? +<dfaure> in fact, do people already inherit KTM, usually ? +<dfaure> hmm ... they would simply inherit KPartMainWindow instead. +<weis> dfaure: Exactly. +<dfaure> so .... what was the problem with the shell ? +<weis> dfaure: The problem was ..... aehmmm ..... +<weis> .... there was some problem ..... +<dfaure> :-)))))) +<weis> dfaure: What about mergeXML? Can it move ? .... still thinking about shell .... +-- +<weis> dfaure: I know again! It may happen that the shell uses a widget which in turn uses a component. So the shell does not now that KParts are involved at all! +<weis> s/now/know/ +<dfaure> ah - and then the widget would NOT use KPartsMainWindow, right ? +<weis> dfaure: Yep! +<dfaure> ok +-- +<weis> dfaure: Another problem are nested KPartManagers. Imagine Widget W1 has some Parts P1 ... Pn. Part Pn has in turn a widget W2 that uses Parts P1_2...Pm_2. Then W1 and W2 would feature a KPartManager .... +<weis> dfaure: The general problem is: A widget may use parts internally but the one who uses the widget does (and should) not know that. +<dfaure> yes - I guess we need to try that, +<dfaure> I'm not sure what's needed for that to work +<weis> dfaure: Currently I am almost shure it wont work. +<weis> dfaure: We must ashure that there is only ONE GUIBuilder per main window. That is one thing to do. +<dfaure> ah yes +<weis> dfaure: If window W1 becomes active (focus) it may activate its KPartManager. If W2 becomes active its KPartManager may do something. +<weis> dfaure: Ooooops, I think I am on the wrong track perhaps..... +<weis> dfaure: I started dealing with tdeparts like I do with widgets. If a kpart is just a widget that you can load at runtime, then it wont do gui merging anyway. So may above example seems to be very theoretically, perhaps .... +<dfaure> yes, if you have two KPartManager you have a problem anyway (if the parts have a GUI) +<dfaure> you want only ONE part active at a time ... one gui . +<dfaure> so you can't have one part active in each kpartmanager, unless the whole partmanager can be deactivated. +<weis> dfaure: Correct. +<weis> dfaure: BUTTTH: Imagine you embed a browser widget. Would you expect that it suddenly plays around in your MenuBar and ToolBars? No, or ? It should only do so if you ask for it. +<dfaure> well I think _yes_ you would expect its actions to become available to the user, no ? +<weis> dfaure: Imagine you write a report generator that shows database queries using the browser view. Would you as a programmer want to have menu entries like "OpenURL" and "History" in your report generator? I would not. +<dfaure> hmmm ... then it's the HTML widget you're using, not the part... +<dfaure> when tdevelop embeds kwrite, it wants the actions from kwrite... +<dfaure> open file, save file, ... +<weis> dfaure: Well,. why not load a HTML widget at runtime as a part ... +<dfaure> sure, why not :-) +<dfaure> I suppose the answer is, as always : configurable. +<dfaure> as you said. +<weis> dfaure: Yep! +<weis> dfaure: But that luckily voids my above example. If W1 wants that parts of W2 change the GUI then it has to tell W2 about the GUIBuilder. If W1 does not want that, then it does not tell W2 and no GUI merging will be done. +<dfaure> yup +<weis> dfaure: This way we stay with one KPartManager and GUIBuilder and W1 is responsible of propagating it to W2 :-) Problem solved :-) + +-------------------------- + +David wondering about Status Bar +-------------------------------- +Should the statusbar be a *bar like toolbar/menubar, handled by the XML GUI building +(soon "KPartsMainWindow"), and shown/hidden depending on the +active part, OR a global statusbar, always shown or hidden, and +made available to the parts, through KPartManager or KPartsMainWindow ? + +Currently it's the first one, but since we removed access to the toplevel +containers, ... +Visually, I think I prefer the statusbar not to show/hide when the active +part changes. But for consistency with toolbars perhaps it should ? Dunno. + +(Simon) IMHO the statusbar should behave like toolbars. A part may "have" (allocate) a statusbar + or just leave out the <StatusBar/> tag. The question IMHO is: How can the part access the + statusbar? + Hmmmmmmmm, I think we should solve this by making use of the xmlgui concept: + (example) + <StatusBar> + <Action name="progressaction"/> + <Label><text>Blah</text></Label> + <StatusBar/> + I think that would solve the problem, and it's what we currently support/implemented. + What do you think? + (update) ahh, grmbl, it won't help much ;-) , as it makes KStatusBar::message() impossible.. + hmmmmmmm + *thinking* + I vote for keeping the currently implemented way (as described above) . Perhaps we should add + sth. like KPartManager::statusBarMessage() ? (as that message concept of kstatusbar is really + different to the container concept (which kstatusbar supports aswell...) . + +Torben brainstorming about Nested Parts +--------------------------------------- + +(In the following text I mix the words "components" and "parts". In addition I assume that + KPartManager and KPartHost become one class. ) + + +Imagine a very complex situation like this: + +KOfficeMainWindow (a tdeparts aware shell) + | + |- KWordView/Part (a koffice component) + | + |- KSpreadView/Part (a koffice component) + | + |- KReportGeneratorView/Part (a koffice component) + | + |- KHTMLBrowserView/Part (something like konqui, this is a kpart) + +Imagine all are added to one KPartManager. +Now the user clicks on the report generator and gets the +usual GUI merging. + +Now imagine the user pressed directly on the Browser that is used +by the report generator just to display some HTML. We would get GUI +merging so that the menus of the browser appear. +But that is a mistake! How the report is made visible is an implementation +detail of the report generator. And it is in turn an implementation detail of KWord +that is allows KSpread to play around in the menu/toolbars if activated. + +What we learn from that is the following: +Observation 1) Whether a part - that is the child of some other part - may do GUI merging or + not is determined by the parent part. + + +Another example: We use a widget Kalender which uses KSpread to display a table. + The KSpreadPart is turned into ReadOnly mode. + +KalenderMainWindow (this is NOT a parts enabled main window) + | + |-KalenderWidget (this is NOT a part) + | + |-KSpreadView (this is a part) + +Here KSpreadView is used like a usual widget. That means it does not get added to some KPartManager +and sees no KGUIBilder or stuff like that. "KalenderMainWindow" constructs the GUI itself. + +Observation 2) It should be possible to use a part just like a usual widget. So it must work without + a KGUIBuilder and without being added to some KPartManager. + +** (David) : I'll try that now. + +Lets extend the example: KalenderWidget shows a very nice kalender. That means it puts images +inside of KSpread by using KImage. + +KalenderMainWindow (this is NOT a parts enabled main window) + | + |-KalenderWidget (this is NOT a part) + | + |-KSpreadView (this is a part) + | + |- KImage (this is a part) + | + |- KImage (this is a part) + +Somehow KSpread must handle its children. It wants to know which one is active for example. +Usually KSpread would use KPartManager but it did not get one from its shell/parent. + +Observation 3) If a KPart is not added to some KPartManager then it creates its own KPartManager where + it insertes itself and its children (if there are any children). + +That has an impact on Observation 2 - since the KPart will create its own KPartManager, so we rewrite it like this: + +Observation 2b) It should be possible to use a part just like a usual widget. So it must work without a KGUIBuilder. + +This is no problem, since the Part never directly talks to the GUIBuilder anyway. + + +Now imagine someone made a KOffice component out of KalenderWidget and embeds it in KWord: + +KOfficeMainWindow (a tdeparts aware shell) + | + |- KWordView/Part (a koffice component) + | + |-KalenderWidget (this is NOT a part) + | + |-KSpreadView (this is a part) + | + |- KImage (this is a part) + | + |- KImage (this is a part) + +Do we want GUI merging with KSpread now? No, since the use of KSpread in KalenderWidget is +an implementation detail. In this case we get two KPartManagers. One belongs to the +KofficeMainWindow and is connected to the GUI Builder while the other one belongs to +KSpread and is NOT connected to some GUI builder. This will work magically if we obeye +observation 2b + 3. + +Observation 4) There may be multiple KPartManagers in one toplevel window, but only one is + associated with a GUIBuilder. That means the managers are not really nested. They + dont know about each others. + + +Lets take another look at our first example: + +KOfficeMainWindow (a tdeparts aware shell) + | + |- KWordView/Part (a koffice component) + | + |- KSpreadView/Part (a koffice component) + | + |- KReportGeneratorView/Part (a koffice component) + | + |- KHTMLBrowserView/Part (something like konqui, this is a kpart) + +The report generator does not want GUI merging of its HTML browser. But it wants to offer an action +called "HTMLSettings" to allow choosing the default font of the HTML Widget. Obviously this action +is offered by the HTMLBrowserView. So instead of reimplementing this action, the report generator +may propagate actions of the html browser. Its KPart::action() method just calls the browsers +action() function if queried for an action named "HTMLSettings". + +Observation 5) In addition to turning GUI building on or off for components one may do partial gui merging. + That means actions of some child component are propagated by the parent component. + +Observation5 does not cause additional code in libtdeparts. It just shows a possible usage and the flexibility of the +action concept. + + +Something else comes to my mind: We can safely reintroduce the shell pattern. The KPartManager/KHostPart is +split of the shell and that is a MUST. +But it does not make sense to create a KTMainWindow and then a KTMainWindowGUIBuilder to manage menubar/toolbars/statusbar. +Imagine an application that uses KTMainWindow. Either the application programmer knows that he wants to embed +some components and that they should use GUI merging => He can use KPartsMainWindow from the start. +Or the application programmer does not want that any component that it uses directly or indirectly merges in +its GUI. In this case he uses KTMainWindow and does not expect someone to override this decision by installing +a KTMainWindowGUIBuilder. + +Imagine someone is writing a time scheduler which uses a KalenderWidget Version 1.0: + +SchedulerMainWindow ( a KTMainWindow ) + | + |- SchedulerCanvas + | + |- KalenderWidget (which uses NO parts currently). + +Here no GUI merging happens. Now someone improves KalenderWidget in Version 2.0 to use +KSpread internally (once again: This is an implementation detail): + +SchedulerMainWindow ( a KTMainWindow ) + | + |- SchedulerCanvas + | + |- KalenderWidget (which USES parts now). + | + |- KSpreadView/Part + +When clicking on KSpread: Do you want GUI merging now? No! The GUI of the scheduler should stay +the same. Just the implementation of the KalenderWidget changed. + +Observation 6) The application programmer determines wether he wants GUI merging or not. That means it is his + decision to choose KTMainWindow or a GUI merging enabled KTMainWindow. And that in turn means that we can merge + KTMainWindow and KTMainWindowGUIBuilder in one class called KPartsMainWindow. + KPartsMainWindow will feature its special implementation of KPartManager (with KPartHost already merged with KPartManager). + +If some component wants to offer all of its functionality even in the case that nobody allowed it to do +GUI merging then the component can still put all of its actions in a QPopupMenu instead of the menubar. + + +Conclusion: +I think with this model we can have an object tree that mixes usual widgets and components in any order +and we always get it right. But it is late and I may get things wrong :-) +In addition my approach reduces the amount of classes and the complexity of the API (at least I hope so). + +Lets put the four most important things together: + +Point 1) The application developer decides wether his app (->toplevel window) features GUI merging or not. +Point 2) A part decides wether it allows its child parts to do GUI merging. +Point 3) If one part in the big object tree is not allowed to do GUI merging (that means it is not registered + at the KPartMainWindows KPartManager, but on some additional KPartManager) then none of its direct or + indirect child parts can ever do GUI merging. +Point 4) Wether some custom widget uses parts internally or not is an implementation detail and not visible to + the user of this custom widget. + + +(David) : I obviously agree with all this. This is a very nice derivation of +the few ideas we had on irc - making GUI merging configurable, at both ends in +fact, plus all the issues associated with nesting. + +(Simon) /me too :-) + +(David) Torben : perhaps you could also comment on the KReadOnlyPart ==? KBrowserPart issue ? +Look for "second thought" in this file. Trying to decide between +each read-only part can be embedded in konqueror and only those who implement +KBrowserPart can be embedded in konqueror... I realize in the first case even +ReadWrite parts would be embeddable since they inherit readonly part... A minor +issue compared to what's above though. + +(Torben) When I draw my university education out of the had (and my master thesis :-)) then + I think your problem can not be solved by deriving from some class but by doing + delegation. + It works like this: + We have KReadOnlyPart (short KROP) and KonqyViewerExtension (short KVE). KVE is just + a child of KROP that you can query with the QObject::child method. + Views which are konquy aware feature their own implementation of KVE and konquy is + happy :-) + If a KROP does not feature a KVE then Konqui installs a default KVE that just ignores + offsets etc. + I think the little difficulty is to implement the default KVE, but it should be possible. + With this solution we get both: Konquy can embed all KROPs and some KROPs can be Konquy + aware and we do not bloat the KROP interface. + +(Torben) About the fact that konqy can embed a KReadWritePart (short KRWP): + This is IMHO not a konqy problem but a KRWP design bug. KRWP overloads + KROP and changes the semantics (editing is possible). By default KRWP should + go into ReadOnly mode. Only if one calls rwpart->setEditable( TRUE ) it should + offer editing of the data. It may still happen that some KRWPs dont obeye the + "editable" flag, but that is a bug inside of the KRWP. + +(Simon) I definitely agree with all this :-) + + KROP -- (this is what konqueror embeds) + | + (child qobj) KonqyViewExtension (konqy specific stuff) + | + (current browserview extension objects) + ... + + Can we go for this? :-) + diff --git a/tdeparts/Mainpage.dox b/tdeparts/Mainpage.dox new file mode 100644 index 000000000..994503d44 --- /dev/null +++ b/tdeparts/Mainpage.dox @@ -0,0 +1,42 @@ +/** @mainpage Framework for Trinity Graphical Components + +This library implements the framework for Trinity parts, which are +elaborate widgets with a user-interface defined in terms of actions +(menu items, toolbar icons). See KParts::Part. + +The library also provides a framework for applications that want to +use parts. Such applications need to inherit their main window +from KParts::MainWindow and provide a so-called shell GUI, +which provides a basic skeleton GUI with part-independent functionality/actions. + +Some KParts applications won't be specific to a given part, but expect +to be able to embed, for instance, all types of viewers out there. For this +the basic functionality of any viewer has been implemented in +KParts::ReadOnlyPart, which viewer-like parts should inherit from. +The same applies to KParts::ReadWritePart, which is for editor-like parts. + +You can add actions to an existing KParts app from "outside", defining +the code for those actions in a shared library. This mechanism is +obviously called plugins, and implemented by KParts::Plugin. + +For a complete, and very simple, example of how to use KParts to display +any kind of file (i.e. making a generic viewer), see the documentation for +KParts::ComponentFactory::createPartInstanceFromQuery. + +@authors +Simon Hausmann \<[email protected]\><br> +David Faure \<[email protected]\><br> +Kurt Granroth \<[email protected]\><br> +Michael Koch \<[email protected]\> + +@maintainers +[Unknown/None] + +@licenses +@lgpl + +*/ + +// DOXYGEN_REFERENCES = tdecore tdeui kio +// DOXYGEN_SET_PROJECT_NAME = KParts +// vim:ts=4:sw=4:expandtab:filetype=doxygen diff --git a/tdeparts/Makefile.am b/tdeparts/Makefile.am new file mode 100644 index 000000000..8fea0f517 --- /dev/null +++ b/tdeparts/Makefile.am @@ -0,0 +1,32 @@ +####### General stuff + +AM_LDFLAGS = $(LDFLAGS_AS_NEEDED) + +INCLUDES= -I$(srcdir)/../ -I$(top_srcdir)/kio/ -I$(top_srcdir)/libltdl \ + -I$(top_srcdir)/kfile $(all_includes) +libtdeparts_la_LDFLAGS = $(KDE_MT_LDFLAGS) -version-info 3:0:1 -no-undefined +libtdeparts_la_LIBADD = $(LIB_KIO) $(LIB_QT) $(LIB_TDEUI) $(LIB_TDECORE) $(top_builddir)/dcop/libDCOP.la + +check-local: + (cd tests && $(MAKE) check ) + +####### Files + +lib_LTLIBRARIES = libtdeparts.la + +libtdeparts_la_SOURCES = part.cpp plugin.cpp partmanager.cpp mainwindow.cpp dockmainwindow.cpp \ + event.cpp browserextension.cpp factory.cpp historyprovider.cpp \ + browserinterface.cpp browserrun.cpp statusbarextension.cpp + +tdepartsincludedir = $(includedir)/tdeparts +tdepartsinclude_HEADERS = part.h plugin.h partmanager.h mainwindow.h dockmainwindow.h event.h \ + browserextension.h factory.h historyprovider.h browserinterface.h genericfactory.h \ + componentfactory.h browserrun.h statusbarextension.h + +libtdeparts_la_METASOURCES = AUTO + +servicetype_DATA = kpart.desktop krop.desktop krwp.desktop browserview.desktop +servicetypedir = $(kde_servicetypesdir) + +DOXYGEN_REFERENCES = tdecore tdeui tdefx kio +include ../admin/Doxyfile.am diff --git a/tdeparts/browserextension.cpp b/tdeparts/browserextension.cpp new file mode 100644 index 000000000..630e4cb5a --- /dev/null +++ b/tdeparts/browserextension.cpp @@ -0,0 +1,732 @@ + /* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "browserextension.h" + +#include <tqapplication.h> +#include <tqclipboard.h> +#include <tqtimer.h> +#include <tqobjectlist.h> +#include <tqmetaobject.h> +#include <tqregexp.h> +#include <tqstrlist.h> +#include <tqstylesheet.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstaticdeleter.h> +#include <kurifilter.h> +#include <assert.h> + +using namespace KParts; + +const char *OpenURLEvent::s_strOpenURLEvent = "KParts/BrowserExtension/OpenURLevent"; + +class OpenURLEvent::OpenURLEventPrivate +{ +public: + OpenURLEventPrivate() + { + } + ~OpenURLEventPrivate() + { + } +}; + +OpenURLEvent::OpenURLEvent( ReadOnlyPart *part, const KURL &url, const URLArgs &args ) +: Event( s_strOpenURLEvent ), m_part( part ), m_url( url ), m_args( args ) +{ +// d = new OpenURLEventPrivate(); +} + +OpenURLEvent::~OpenURLEvent() +{ +// delete d; +} + +namespace KParts +{ + +struct URLArgsPrivate +{ + URLArgsPrivate() { + doPost = false; + redirectedRequest = false; + lockHistory = false; + newTab = false; + forcesNewWindow = false; + } + TQString contentType; // for POST + TQMap<TQString, TQString> metaData; + bool doPost; + bool redirectedRequest; + bool lockHistory; + bool newTab; + bool forcesNewWindow; +}; + +} + +URLArgs::URLArgs() +{ + reload = false; + xOffset = 0; + yOffset = 0; + trustedSource = false; + d = 0L; // Let's build it on demand for now +} + + +URLArgs::URLArgs( bool _reload, int _xOffset, int _yOffset, const TQString &_serviceType ) +{ + reload = _reload; + xOffset = _xOffset; + yOffset = _yOffset; + serviceType = _serviceType; + d = 0L; // Let's build it on demand for now +} + +URLArgs::URLArgs( const URLArgs &args ) +{ + d = 0L; + (*this) = args; +} + +URLArgs &URLArgs::operator=(const URLArgs &args) +{ + if (this == &args) return *this; + + delete d; d= 0; + + reload = args.reload; + xOffset = args.xOffset; + yOffset = args.yOffset; + serviceType = args.serviceType; + postData = args.postData; + frameName = args.frameName; + docState = args.docState; + trustedSource = args.trustedSource; + + if ( args.d ) + d = new URLArgsPrivate( * args.d ); + + return *this; +} + +URLArgs::~URLArgs() +{ + delete d; + d = 0; +} + +void URLArgs::setContentType( const TQString & contentType ) +{ + if (!d) + d = new URLArgsPrivate; + d->contentType = contentType; +} + +void URLArgs::setRedirectedRequest( bool redirected ) +{ + if (!d) + d = new URLArgsPrivate; + d->redirectedRequest = redirected; +} + +bool URLArgs::redirectedRequest () const +{ + return d ? d->redirectedRequest : false; +} + +TQString URLArgs::contentType() const +{ + return d ? d->contentType : TQString::null; +} + +TQMap<TQString, TQString> &URLArgs::metaData() +{ + if (!d) + d = new URLArgsPrivate; + return d->metaData; +} + +void URLArgs::setDoPost( bool enable ) +{ + if ( !d ) + d = new URLArgsPrivate; + d->doPost = enable; +} + +bool URLArgs::doPost() const +{ + return d ? d->doPost : false; +} + +void URLArgs::setLockHistory( bool lock ) +{ + if (!d) + d = new URLArgsPrivate; + d->lockHistory = lock; +} + +bool URLArgs::lockHistory() const +{ + return d ? d->lockHistory : false; +} + +void URLArgs::setNewTab( bool newTab ) +{ + if (!d) + d = new URLArgsPrivate; + d->newTab = newTab; +} + +bool URLArgs::newTab() const +{ + return d ? d->newTab : false; +} + +void URLArgs::setForcesNewWindow( bool forcesNewWindow ) +{ + if (!d) + d = new URLArgsPrivate; + d->forcesNewWindow = forcesNewWindow; +} + +bool URLArgs::forcesNewWindow() const +{ + return d ? d->forcesNewWindow : false; +} + +namespace KParts +{ + +struct WindowArgsPrivate +{ +}; + +} + +WindowArgs::WindowArgs() +{ + x = y = width = height = -1; + fullscreen = false; + menuBarVisible = true; + toolBarsVisible = true; + statusBarVisible = true; + scrollBarsVisible = true; + resizable = true; + lowerWindow = false; + d = 0; +} + +WindowArgs::WindowArgs( const WindowArgs &args ) +{ + d = 0; + (*this) = args; +} + +WindowArgs::~WindowArgs() +{ + delete d; +} + +WindowArgs &WindowArgs::operator=( const WindowArgs &args ) +{ + if ( this == &args ) return *this; + + delete d; d = 0; + + x = args.x; + y = args.y; + width = args.width; + height = args.height; + fullscreen = args.fullscreen; + menuBarVisible = args.menuBarVisible; + toolBarsVisible = args.toolBarsVisible; + statusBarVisible = args.statusBarVisible; + scrollBarsVisible = args.scrollBarsVisible; + resizable = args.resizable; + lowerWindow = args.lowerWindow; + + /* + if ( args.d ) + { + [ ... ] + } + */ + + return *this; +} + +WindowArgs::WindowArgs( const TQRect &_geometry, bool _fullscreen, bool _menuBarVisible, + bool _toolBarsVisible, bool _statusBarVisible, bool _resizable ) +{ + d = 0; + x = _geometry.x(); + y = _geometry.y(); + width = _geometry.width(); + height = _geometry.height(); + fullscreen = _fullscreen; + menuBarVisible = _menuBarVisible; + toolBarsVisible = _toolBarsVisible; + statusBarVisible = _statusBarVisible; + resizable = _resizable; + lowerWindow = false; +} + +WindowArgs::WindowArgs( int _x, int _y, int _width, int _height, bool _fullscreen, + bool _menuBarVisible, bool _toolBarsVisible, + bool _statusBarVisible, bool _resizable ) +{ + d = 0; + x = _x; + y = _y; + width = _width; + height = _height; + fullscreen = _fullscreen; + menuBarVisible = _menuBarVisible; + toolBarsVisible = _toolBarsVisible; + statusBarVisible = _statusBarVisible; + resizable = _resizable; + lowerWindow = false; +} + +namespace KParts +{ + +// Internal class, use to store the status of the actions +class KBitArray +{ +public: + int val; + KBitArray() { val = 0; } + bool operator [](int index) { return (val & (1 << index)) ? true : false; } + void setBit(int index, bool value) { + if (value) val = val | (1 << index); + else val = val & ~(1 << index); + } +}; + +class BrowserExtensionPrivate +{ +public: + BrowserExtensionPrivate() + { + m_browserInterface = 0; + } + ~BrowserExtensionPrivate() + { + } + + struct DelayedRequest { + KURL m_delayedURL; + KParts::URLArgs m_delayedArgs; + }; + TQValueList<DelayedRequest> m_requests; + bool m_urlDropHandlingEnabled; + KBitArray m_actionStatus; + TQMap<int, TQString> m_actionText; + BrowserInterface *m_browserInterface; +}; + +} + +BrowserExtension::ActionSlotMap * BrowserExtension::s_actionSlotMap = 0L; +static KStaticDeleter<BrowserExtension::ActionSlotMap> actionSlotMapsd; +BrowserExtension::ActionNumberMap * BrowserExtension::s_actionNumberMap = 0L; +static KStaticDeleter<BrowserExtension::ActionNumberMap> actionNumberMapsd; + +BrowserExtension::BrowserExtension( KParts::ReadOnlyPart *parent, + const char *name ) +: TQObject( parent, name), m_part( parent ) +{ + //kdDebug() << "BrowserExtension::BrowserExtension() " << this << endl; + d = new BrowserExtensionPrivate; + d->m_urlDropHandlingEnabled = false; + + if ( !s_actionSlotMap ) + // Create the action-slot map + createActionSlotMap(); + + // Set the initial status of the actions depending on whether + // they're supported or not + ActionSlotMap::ConstIterator it = s_actionSlotMap->begin(); + ActionSlotMap::ConstIterator itEnd = s_actionSlotMap->end(); + TQStrList slotNames = metaObject()->slotNames(); + for ( int i=0 ; it != itEnd ; ++it, ++i ) + { + // Does the extension have a slot with the name of this action ? + d->m_actionStatus.setBit( i, slotNames.contains( it.key()+"()" ) ); + } + + connect( m_part, TQT_SIGNAL( completed() ), + this, TQT_SLOT( slotCompleted() ) ); + connect( this, TQT_SIGNAL( openURLRequest( const KURL &, const KParts::URLArgs & ) ), + this, TQT_SLOT( slotOpenURLRequest( const KURL &, const KParts::URLArgs & ) ) ); + connect( this, TQT_SIGNAL( enableAction( const char *, bool ) ), + this, TQT_SLOT( slotEnableAction( const char *, bool ) ) ); + connect( this, TQT_SIGNAL( setActionText( const char *, const TQString& ) ), + this, TQT_SLOT( slotSetActionText( const char *, const TQString& ) ) ); +} + +BrowserExtension::~BrowserExtension() +{ + //kdDebug() << "BrowserExtension::~BrowserExtension() " << this << endl; + delete d; +} + +void BrowserExtension::setURLArgs( const URLArgs &args ) +{ + m_args = args; +} + +URLArgs BrowserExtension::urlArgs() const +{ + return m_args; +} + +int BrowserExtension::xOffset() +{ + return 0; +} + +int BrowserExtension::yOffset() +{ + return 0; +} + +void BrowserExtension::saveState( TQDataStream &stream ) +{ + stream << m_part->url() << (TQ_INT32)xOffset() << (TQ_INT32)yOffset(); +} + +void BrowserExtension::restoreState( TQDataStream &stream ) +{ + KURL u; + TQ_INT32 xOfs, yOfs; + stream >> u >> xOfs >> yOfs; + + URLArgs args( urlArgs() ); + args.xOffset = xOfs; + args.yOffset = yOfs; + + setURLArgs( args ); + + m_part->openURL( u ); +} + +bool BrowserExtension::isURLDropHandlingEnabled() const +{ + return d->m_urlDropHandlingEnabled; +} + +void BrowserExtension::setURLDropHandlingEnabled( bool enable ) +{ + d->m_urlDropHandlingEnabled = enable; +} + +void BrowserExtension::slotCompleted() +{ + //empty the argument stuff, to avoid bogus/invalid values when opening a new url + setURLArgs( URLArgs() ); +} + +void BrowserExtension::pasteRequest() +{ + TQCString plain( "plain" ); + TQString url = TQApplication::clipboard()->text(plain, TQClipboard::Selection).stripWhiteSpace(); + // Remove linefeeds and any whitespace surrounding it. + url.remove(TQRegExp("[\\ ]*\\n+[\\ ]*")); + + // Check if it's a URL + TQStringList filters = KURIFilter::self()->pluginNames(); + filters.remove( "kuriikwsfilter" ); + filters.remove( "localdomainurifilter" ); + KURIFilterData filterData; + filterData.setData( url ); + filterData.setCheckForExecutables( false ); + if ( KURIFilter::self()->filterURI( filterData, filters ) ) + { + switch ( filterData.uriType() ) + { + case KURIFilterData::LOCAL_FILE: + case KURIFilterData::LOCAL_DIR: + case KURIFilterData::NET_PROTOCOL: + slotOpenURLRequest( filterData.uri(), KParts::URLArgs() ); + break; + case KURIFilterData::ERROR: + KMessageBox::sorry( m_part->widget(), filterData.errorMsg() ); + break; + default: + break; + } + } + else if ( KURIFilter::self()->filterURI( filterData, "kuriikwsfilter" ) && url.length() < 250 ) + { + if ( KMessageBox::questionYesNo( m_part->widget(), + i18n( "<qt>Do you want to search the Internet for <b>%1</b>?" ).arg( TQStyleSheet::escape(url) ), + i18n( "Internet Search" ), KGuiItem( i18n( "&Search" ), "find"), + KStdGuiItem::cancel(), "MiddleClickSearch" ) == KMessageBox::Yes) + slotOpenURLRequest( filterData.uri(), KParts::URLArgs() ); + } +} + +void BrowserExtension::slotOpenURLRequest( const KURL &url, const KParts::URLArgs &args ) +{ + //kdDebug() << this << " BrowserExtension::slotOpenURLRequest(): url=" << url.url() << endl; + BrowserExtensionPrivate::DelayedRequest req; + req.m_delayedURL = url; + req.m_delayedArgs = args; + d->m_requests.append( req ); + TQTimer::singleShot( 0, this, TQT_SLOT( slotEmitOpenURLRequestDelayed() ) ); +} + +void BrowserExtension::slotEmitOpenURLRequestDelayed() +{ + if (d->m_requests.isEmpty()) return; + BrowserExtensionPrivate::DelayedRequest req = d->m_requests.front(); + d->m_requests.pop_front(); + emit openURLRequestDelayed( req.m_delayedURL, req.m_delayedArgs ); + // tricky: do not do anything here! (no access to member variables, etc.) +} + +void BrowserExtension::setBrowserInterface( BrowserInterface *impl ) +{ + d->m_browserInterface = impl; +} + +BrowserInterface *BrowserExtension::browserInterface() const +{ + return d->m_browserInterface; +} + +void BrowserExtension::slotEnableAction( const char * name, bool enabled ) +{ + //kdDebug() << "BrowserExtension::slotEnableAction " << name << " " << enabled << endl; + ActionNumberMap::ConstIterator it = s_actionNumberMap->find( name ); + if ( it != s_actionNumberMap->end() ) + { + d->m_actionStatus.setBit( it.data(), enabled ); + //kdDebug() << "BrowserExtension::slotEnableAction setting bit " << it.data() << " to " << enabled << endl; + } + else + kdWarning() << "BrowserExtension::slotEnableAction unknown action " << name << endl; +} + +bool BrowserExtension::isActionEnabled( const char * name ) const +{ + int actionNumber = (*s_actionNumberMap)[ name ]; + return d->m_actionStatus[ actionNumber ]; +} + +void BrowserExtension::slotSetActionText( const char * name, const TQString& text ) +{ + kdDebug() << "BrowserExtension::slotSetActionText " << name << " " << text << endl; + ActionNumberMap::ConstIterator it = s_actionNumberMap->find( name ); + if ( it != s_actionNumberMap->end() ) + { + d->m_actionText[ it.data() ] = text; + } + else + kdWarning() << "BrowserExtension::slotSetActionText unknown action " << name << endl; +} + +TQString BrowserExtension::actionText( const char * name ) const +{ + int actionNumber = (*s_actionNumberMap)[ name ]; + TQMap<int, TQString>::ConstIterator it = d->m_actionText.find( actionNumber ); + if ( it != d->m_actionText.end() ) + return *it; + return TQString::null; +} + +// for compatibility +BrowserExtension::ActionSlotMap BrowserExtension::actionSlotMap() +{ + return *actionSlotMapPtr(); +} + +BrowserExtension::ActionSlotMap * BrowserExtension::actionSlotMapPtr() +{ + if (!s_actionSlotMap) + createActionSlotMap(); + return s_actionSlotMap; +} + +void BrowserExtension::createActionSlotMap() +{ + assert(!s_actionSlotMap); + s_actionSlotMap = actionSlotMapsd.setObject( s_actionSlotMap, new ActionSlotMap ); + + s_actionSlotMap->insert( "cut", TQT_SLOT( cut() ) ); + s_actionSlotMap->insert( "copy", TQT_SLOT( copy() ) ); + s_actionSlotMap->insert( "paste", TQT_SLOT( paste() ) ); + s_actionSlotMap->insert( "rename", TQT_SLOT( rename() ) ); + s_actionSlotMap->insert( "trash", TQT_SLOT( trash() ) ); + s_actionSlotMap->insert( "del", TQT_SLOT( del() ) ); + s_actionSlotMap->insert( "properties", TQT_SLOT( properties() ) ); + s_actionSlotMap->insert( "editMimeType", TQT_SLOT( editMimeType() ) ); + s_actionSlotMap->insert( "print", TQT_SLOT( print() ) ); + // Tricky. Those aren't actions in fact, but simply methods that a browserextension + // can have or not. No need to return them here. + //s_actionSlotMap->insert( "reparseConfiguration", TQT_SLOT( reparseConfiguration() ) ); + //s_actionSlotMap->insert( "refreshMimeTypes", TQT_SLOT( refreshMimeTypes() ) ); + // nothing for setSaveViewPropertiesLocally either + + // Create the action-number map + assert(!s_actionNumberMap); + s_actionNumberMap = actionNumberMapsd.setObject( s_actionNumberMap, new ActionNumberMap ); + ActionSlotMap::ConstIterator it = s_actionSlotMap->begin(); + ActionSlotMap::ConstIterator itEnd = s_actionSlotMap->end(); + for ( int i=0 ; it != itEnd ; ++it, ++i ) + { + //kdDebug(1202) << " action " << it.key() << " number " << i << endl; + s_actionNumberMap->insert( it.key(), i ); + } +} + +BrowserExtension *BrowserExtension::childObject( TQObject *obj ) +{ + if ( !obj || obj->childrenListObject().isEmpty() ) + return 0L; + + // we try to do it on our own, in hope that we are faster than + // queryList, which looks kind of big :-) + const TQObjectList children = obj->childrenListObject(); + TQObjectListIt it( children ); + for (; it.current(); ++it ) + if ( it.current()->inherits( "KParts::BrowserExtension" ) ) + return static_cast<KParts::BrowserExtension *>( it.current() ); + + return 0L; +} + +namespace KParts +{ + +class BrowserHostExtension::BrowserHostExtensionPrivate +{ +public: + BrowserHostExtensionPrivate() + { + } + ~BrowserHostExtensionPrivate() + { + } + + KParts::ReadOnlyPart *m_part; +}; + +} + +BrowserHostExtension::BrowserHostExtension( KParts::ReadOnlyPart *parent, const char *name ) + : TQObject( parent, name ) +{ + d = new BrowserHostExtensionPrivate; + d->m_part = parent; +} + +BrowserHostExtension::~BrowserHostExtension() +{ + delete d; +} + +TQStringList BrowserHostExtension::frameNames() const +{ + return TQStringList(); +} + +const TQPtrList<KParts::ReadOnlyPart> BrowserHostExtension::frames() const +{ + return TQPtrList<KParts::ReadOnlyPart>(); +} + +bool BrowserHostExtension::openURLInFrame( const KURL &, const KParts::URLArgs & ) +{ + return false; +} + +BrowserHostExtension *BrowserHostExtension::childObject( TQObject *obj ) +{ + if ( !obj || obj->childrenListObject().isEmpty() ) + return 0L; + + // we try to do it on our own, in hope that we are faster than + // queryList, which looks kind of big :-) + const TQObjectList children = obj->childrenListObject(); + TQObjectListIt it( children ); + for (; it.current(); ++it ) + if ( it.current()->inherits( "KParts::BrowserHostExtension" ) ) + return static_cast<KParts::BrowserHostExtension *>( it.current() ); + + return 0L; +} + +void BrowserExtension::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +BrowserHostExtension * +BrowserHostExtension::findFrameParent(KParts::ReadOnlyPart *callingPart, const TQString &frame) +{ + FindFrameParentParams param; + param.parent = 0; + param.callingPart = callingPart; + param.frame = frame; + virtual_hook(VIRTUAL_FIND_FRAME_PARENT, ¶m); + return param.parent; +} + +void BrowserHostExtension::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +LiveConnectExtension::LiveConnectExtension( KParts::ReadOnlyPart *parent, const char *name ) : TQObject( parent, name) {} + +bool LiveConnectExtension::get( const unsigned long, const TQString &, Type &, unsigned long &, TQString & ) { + return false; +} + +bool LiveConnectExtension::put( const unsigned long, const TQString &, const TQString & ) { + return false; +} + +bool LiveConnectExtension::call( const unsigned long, const TQString &, const TQStringList &, Type &, unsigned long &, TQString & ) { + return false; +} + +void LiveConnectExtension::unregister( const unsigned long ) {} + +LiveConnectExtension *LiveConnectExtension::childObject( TQObject *obj ) +{ + if ( !obj || obj->childrenListObject().isEmpty() ) + return 0L; + + // we try to do it on our own, in hope that we are faster than + // queryList, which looks kind of big :-) + const TQObjectList children = obj->childrenListObject(); + TQObjectListIt it( children ); + for (; it.current(); ++it ) + if ( it.current()->inherits( "KParts::LiveConnectExtension" ) ) + return static_cast<KParts::LiveConnectExtension *>( it.current() ); + + return 0L; +} + +#include "browserextension.moc" diff --git a/tdeparts/browserextension.h b/tdeparts/browserextension.h new file mode 100644 index 000000000..8d3a109ff --- /dev/null +++ b/tdeparts/browserextension.h @@ -0,0 +1,832 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __tdeparts_browserextension_h__ +#define __tdeparts_browserextension_h__ + +#include <sys/types.h> + +#include <tqpoint.h> +#include <tqptrlist.h> +#include <tqdatastream.h> +#include <tqstringlist.h> +#include <tqpair.h> + +#include <tdeparts/part.h> +#include <tdeparts/event.h> + +class KFileItem; +typedef TQPtrList<KFileItem> KFileItemList; +class TQString; + +namespace KParts { + +class BrowserInterface; + +struct URLArgsPrivate; + +/** + * URLArgs is a set of arguments bundled into a structure, + * to allow specifying how a URL should be opened by openURL(). + * In other words, this is like arguments to openURL(), but without + * have to change the signature of openURL() (since openURL is a + * generic KParts method). + * The parts (with a browser extension) who care about urlargs will + * use those arguments, others will ignore them. + * + * This can also be used the other way round, when a part asks + * for a URL to be opened (with openURLRequest or createNewWindow). + */ +struct KPARTS_EXPORT URLArgs +{ + URLArgs(); + URLArgs( const URLArgs &args ); + URLArgs &operator=( const URLArgs &args); + + URLArgs( bool reload, int xOffset, int yOffset, const TQString &serviceType = TQString::null ); + virtual ~URLArgs(); + + /** + * This buffer can be used by the part to save and restore its contents. + * See KHTMLPart for instance. + */ + TQStringList docState; + + /** + * @p reload is set when the cache shouldn't be used (forced reload). + */ + bool reload; + /** + * @p xOffset is the horizontal scrolling of the part's widget + * (in case it's a scrollview). This is saved into the history + * and restored when going back in the history. + */ + int xOffset; + /** + * @p yOffset vertical scrolling position, xOffset. + */ + int yOffset; + /** + * The servicetype (usually mimetype) to use when opening the next URL. + */ + TQString serviceType; + + /** + * KHTML-specific field, contents of the HTTP POST data. + */ + TQByteArray postData; + + /** + * KHTML-specific field, header defining the type of the POST data. + */ + void setContentType( const TQString & contentType ); + /** + * KHTML-specific field, header defining the type of the POST data. + */ + TQString contentType() const; + /** + * KHTML-specific field, whether to do a POST instead of a GET, + * for the next openURL. + */ + void setDoPost( bool enable ); + + /** + * KHTML-specific field, whether to do a POST instead of a GET, + * for the next openURL. + */ + bool doPost() const; + + /** + * Whether to lock the history when opening the next URL. + * This is used during e.g. a redirection, to avoid a new entry + * in the history. + */ + void setLockHistory( bool lock ); + bool lockHistory() const; + + /** + * Whether the URL should be opened in a new tab instead in a new window. + */ + void setNewTab( bool newTab ); + bool newTab() const; + + /** + * Meta-data to associate with the next KIO operation + * @see TDEIO::TransferJob etc. + */ + TQMap<TQString, TQString> &metaData(); + + /** + * The frame in which to open the URL. KHTML/Konqueror-specific. + */ + TQString frameName; + + /** + * If true, the part who asks for a URL to be opened can be 'trusted' + * to execute applications. For instance, the directory views can be + * 'trusted' whereas HTML pages are not trusted in that respect. + */ + bool trustedSource; + + /** + * @return true if the request was a result of a META refresh/redirect request or + * HTTP redirect. + */ + bool redirectedRequest () const; + + /** + * Set the redirect flag to indicate URL is a result of either a META redirect + * or HTTP redirect. + * + * @param redirected + */ + void setRedirectedRequest(bool redirected); + + /** + * Set whether the URL specifies to be opened in a new window + * @since 3.4 + */ + void setForcesNewWindow( bool forcesNewWindow ); + + /** + * Whether the URL specifies to be opened in a new window + * @since 3.4 + */ + bool forcesNewWindow() const; + + URLArgsPrivate *d; +}; + +struct WindowArgsPrivate; + +/** + * The WindowArgs are used to specify arguments to the "create new window" + * call (see the createNewWindow variant that uses WindowArgs). + * The primary reason for this is the javascript window.open function. + */ +struct KPARTS_EXPORT WindowArgs +{ + WindowArgs(); + ~WindowArgs(); + WindowArgs( const WindowArgs &args ); + WindowArgs &operator=( const WindowArgs &args ); + WindowArgs( const TQRect &_geometry, bool _fullscreen, bool _menuBarVisible, + bool _toolBarsVisible, bool _statusBarVisible, bool _resizable ); + WindowArgs( int _x, int _y, int _width, int _height, bool _fullscreen, + bool _menuBarVisible, bool _toolBarsVisible, + bool _statusBarVisible, bool _resizable ); + + // Position + int x; + int y; + // Size + int width; + int height; + bool fullscreen; //defaults to false + bool menuBarVisible; //defaults to true + bool toolBarsVisible; //defaults to true + bool statusBarVisible; //defaults to true + bool resizable; //defaults to true + + bool lowerWindow; //defaults to false + bool scrollBarsVisible; //defaults to true + + WindowArgsPrivate *d; // don't use before KDE4, many KDE-3.x didn't have an explicit destructor +}; + +/** + * The KParts::OpenURLEvent event informs that a given part has opened a given URL. + * Applications can use this event to send this information to interested plugins. + * + * The event should be sent before opening the URL in the part, so that the plugins + * can use part()->url() to get the old URL. + */ +class KPARTS_EXPORT OpenURLEvent : public Event +{ +public: + OpenURLEvent( ReadOnlyPart *part, const KURL &url, const URLArgs &args = URLArgs() ); + virtual ~OpenURLEvent(); + + ReadOnlyPart *part() const { return m_part; } + KURL url() const { return m_url; } + URLArgs args() const { return m_args; } + + static bool test( const TQEvent *event ) { return Event::test( event, s_strOpenURLEvent ); } + +private: + static const char *s_strOpenURLEvent; + ReadOnlyPart *m_part; + KURL m_url; + URLArgs m_args; + + class OpenURLEventPrivate; + OpenURLEventPrivate *d; +}; + +class BrowserExtensionPrivate; + + /** + * The Browser Extension is an extension (yes, no kidding) to + * KParts::ReadOnlyPart, which allows a better integration of parts + * with browsers (in particular Konqueror). + * Remember that ReadOnlyPart only has openURL(KURL), with no other settings. + * For full-fledged browsing, we need much more than that, including + * many arguments about how to open this URL (see URLArgs), allowing + * parts to save and restore their data into the back/forward history, + * allowing parts to control the location bar URL, to requests URLs + * to be opened by the hosting browser, etc. + * + * The part developer needs to define its own class derived from BrowserExtension, + * to implement the virtual methods [and the standard-actions slots, see below]. + * + * The way to associate the BrowserExtension with the part is to simply + * create the BrowserExtension as a child of the part (in QObject's terms). + * The hosting application will look for it automatically. + * + * Another aspect of the browser integration is that a set of standard + * actions are provided by the browser, but implemented by the part + * (for the actions it supports). + * + * The following standard actions are defined by the host of the view : + * + * [selection-dependent actions] + * @li @p cut : Copy selected items to clipboard and store 'not cut' in clipboard. + * @li @p copy : Copy selected items to clipboard and store 'cut' in clipboard. + * @li @p paste : Paste clipboard into view URL. + * @li @p pasteTo(const KURL &) : Paste clipboard into given URL. + * @li @p rename : Rename item in place. + * @li @p trash : Move selected items to trash. + * @li @p del : Delete selected items (couldn't call it delete!). + * @li @p shred : Shred selected items (secure deletion) - DEPRECATED. + * @li @p properties : Show file/document properties. + * @li @p editMimeType : show file/document's mimetype properties. + * @li @p searchProvider : Lookup selected text at default search provider + * + * [normal actions] + * @li @p print : Print :-) + * @li @p reparseConfiguration : Re-read configuration and apply it. + * @li @p refreshMimeTypes : If the view uses mimetypes it should re-determine them. + * + * + * The view defines a slot with the name of the action in order to implement the action. + * The browser will detect the slot automatically and connect its action to it when + * appropriate (i.e. when the view is active). + * + * + * The selection-dependent actions are disabled by default and the view should + * enable them when the selection changes, emitting enableAction(). + * + * The normal actions do not depend on the selection. + * You need to enable 'print' when printing is possible - you can even do that + * in the constructor. + * + * A special case is the configuration slots, not connected to any action directly, + * and having parameters. + * + * [configuration slot] + * @li @p setSaveViewPropertiesLocally( bool ): If @p true, view properties are saved into .directory + * otherwise, they are saved globally. + * @li @p disableScrolling: no scrollbars + */ +class KPARTS_EXPORT BrowserExtension : public TQObject +{ + Q_OBJECT + TQ_PROPERTY( bool urlDropHandling READ isURLDropHandlingEnabled WRITE setURLDropHandlingEnabled ) +public: + /** + * Constructor + * + * @param parent The KParts::ReadOnlyPart that this extension ... "extends" :) + * @param name An optional name for the extension. + */ + BrowserExtension( KParts::ReadOnlyPart *parent, + const char *name = 0L ); + + + virtual ~BrowserExtension(); + + typedef uint PopupFlags; + + /** + * Set of flags passed via the popupMenu signal, to ask for some items in the popup menu. + * DefaultPopupItems: default value, no additional menu item + * ShowNavigationItems: show "back" and "forward" (usually done when clicking the background of the view, but not an item) + * ShowUp: show "up" (same thing, but not over e.g. HTTP). Requires ShowNavigationItems. + * ShowReload: show "reload" (usually done when clicking the background of the view, but not an item) + * ShowBookmark: show "add to bookmarks" (usually not done on the local filesystem) + * ShowCreateDirectory: show "create directory" (usually only done on the background of the view, or + * in hierarchical views like directory trees, where the new dir would be visible) + * ShowTextSelectionItems: set when selecting text, for a popup that only contains text-related items. + * NoDeletion: deletion, trashing and renaming not allowed (e.g. parent dir not writeable). + * (this is only needed if the protocol itself supports deletion, unlike e.g. HTTP) + * + * KDE4 TODO: add IsLink flag, for "Bookmark This Link" and linkactions merging group. + * [currently it depends on which signal is emitted] + * add ShowURLOperation flags for copy,cut,paste,rename,trash,del [same thing] + */ + enum { DefaultPopupItems=0x0000, ShowNavigationItems=0x0001, + ShowUp=0x0002, ShowReload=0x0004, ShowBookmark=0x0008, + ShowCreateDirectory=0x0010, ShowTextSelectionItems=0x0020, + NoDeletion=0x0040 ///< @since 3.4 + }; + + + /** + * Set the parameters to use for opening the next URL. + * This is called by the "hosting" application, to pass parameters to the part. + * @see URLArgs + */ + virtual void setURLArgs( const URLArgs &args ); + + /** + * Retrieve the set of parameters to use for opening the URL + * (this must be called from openURL() in the part). + * @see URLArgs + */ + URLArgs urlArgs() const; + + /** + * Returns the current x offset. + * + * For a scrollview, implement this using contentsX(). + */ + virtual int xOffset(); + /** + * Returns the current y offset. + * + * For a scrollview, implement this using contentsY(). + */ + virtual int yOffset(); + + /** + * Used by the browser to save the current state of the view + * (in order to restore it if going back in navigation). + * + * If you want to save additional properties, reimplement it + * but don't forget to call the parent method (probably first). + */ + virtual void saveState( TQDataStream &stream ); + + /** + * Used by the browser to restore the view in the state + * it was when we left it. + * + * If you saved additional properties, reimplement it + * but don't forget to call the parent method (probably first). + */ + virtual void restoreState( TQDataStream &stream ); + + /** + * Returns whether url drop handling is enabled. + * See setURLDropHandlingEnabled for more information about this + * property. + */ + bool isURLDropHandlingEnabled() const; + + /** + * Enables or disables url drop handling. URL drop handling is a property + * describing whether the hosting shell component is allowed to install an + * event filter on the part's widget, to listen for URI drop events. + * Set it to true if you are exporting a BrowserExtension implementation and + * do not provide any special URI drop handling. If set to false you can be + * sure to receive all those URI drop events unfiltered. Also note that the + * implementation as of Konqueror installs the event filter only on the part's + * widget itself, not on child widgets. + */ + void setURLDropHandlingEnabled( bool enable ); + + void setBrowserInterface( BrowserInterface *impl ); + BrowserInterface *browserInterface() const; + + /** + * @return the status (enabled/disabled) of an action. + * When the enableAction signal is emitted, the browserextension + * stores the status of the action internally, so that it's possible + * to query later for the status of the action, using this method. + */ + bool isActionEnabled( const char * name ) const; + + /** + * @return the text of an action, if it was set explicitely by the part. + * When the setActionText signal is emitted, the browserextension + * stores the text of the action internally, so that it's possible + * to query later for the text of the action, using this method. + * @since 3.5 + */ + TQString actionText( const char * name ) const; + + typedef TQMap<TQCString,TQCString> ActionSlotMap; + /** + * Returns a map containing the action names as keys and corresponding + * TQT_SLOT()'ified method names as data entries. + * + * This is very useful for + * the host component, when connecting the own signals with the + * extension's slots. + * Basically you iterate over the map, check if the extension implements + * the slot and connect to the slot using the data value of your map + * iterator. + * Checking if the extension implements a certain slot can be done like this: + * + * \code + * extension->metaObject()->slotNames().contains( actionName + "()" ) + * \endcode + * + * (note that @p actionName is the iterator's key value if already + * iterating over the action slot map, returned by this method) + * + * Connecting to the slot can be done like this: + * + * \code + * connect( yourObject, TQT_SIGNAL( yourSignal() ), + * extension, mapIterator.data() ) + * \endcode + * + * (where "mapIterator" is your TQMap<TQCString,TQCString> iterator) + */ + static ActionSlotMap actionSlotMap(); + + /** + * @return a pointer to the static action-slot map. Preferred method to get it. + * The map is created if it doesn't exist yet + */ + static ActionSlotMap * actionSlotMapPtr(); + + /** + * Queries @p obj for a child object which inherits from this + * BrowserExtension class. Convenience method. + */ + static BrowserExtension *childObject( TQObject *obj ); + + /** + * Asks the hosting browser to perform a paste (using openURLRequestDelayed) + * @since 3.2 + */ + void pasteRequest(); + +// KDE invents support for public signals... +#undef signals +#define signals public +signals: +#undef signals +#define signals protected + /** + * Enables or disable a standard action held by the browser. + * + * See class documentation for the list of standard actions. + */ + void enableAction( const char * name, bool enabled ); + + /** + * Change the text of a standard action held by the browser. + * This can be used to change "Paste" into "Paste Image" for instance. + * + * See class documentation for the list of standard actions. + * @since 3.5 + */ + void setActionText( const char * name, const TQString& text ); + + /** + * Asks the host (browser) to open @p url. + * To set a reload, the x and y offsets, the service type etc., fill in the + * appropriate fields in the @p args structure. + * Hosts should not connect to this signal but to openURLRequestDelayed. + */ + void openURLRequest( const KURL &url, const KParts::URLArgs &args = KParts::URLArgs() ); + + /** + * This signal is emitted when openURLRequest is called, after a 0-seconds timer. + * This allows the caller to terminate what it's doing first, before (usually) + * being destroyed. Parts should never use this signal, hosts should only connect + * to this signal. + */ + void openURLRequestDelayed( const KURL &url, const KParts::URLArgs &args = KParts::URLArgs() ); + + /** + * Tells the hosting browser that the part opened a new URL (which can be + * queried via KParts::Part::url(). + * + * This helps the browser to update/create an entry in the history. + * The part may @em not emit this signal together with openURLRequest(). + * Emit openURLRequest() if you want the browser to handle a URL the user + * asked to open (from within your part/document). This signal however is + * useful if you want to handle URLs all yourself internally, while still + * telling the hosting browser about new opened URLs, in order to provide + * a proper history functionality to the user. + * An example of usage is a html rendering component which wants to emit + * this signal when a child frame document changed its URL. + * Conclusion: you probably want to use openURLRequest() instead. + */ + void openURLNotify(); + + /** + * Updates the URL shown in the browser's location bar to @p url. + */ + void setLocationBarURL( const TQString &url ); + + /** + * Sets the URL of an icon for the currently displayed page. + */ + void setIconURL( const KURL &url ); + + /** + * Asks the hosting browser to open a new window for the given @p url. + * + * The @p args argument is optional additional information for the + * browser, + * @see KParts::URLArgs + */ + void createNewWindow( const KURL &url, const KParts::URLArgs &args = KParts::URLArgs() ); + + /** + * Asks the hosting browser to open a new window for the given @p url + * and return a reference to the content part. + * The request for a reference to the part is only fullfilled/processed + * if the serviceType is set in the @p args . (otherwise the request cannot be + * processed synchroniously. + */ + void createNewWindow( const KURL &url, const KParts::URLArgs &args, + const KParts::WindowArgs &windowArgs, KParts::ReadOnlyPart *&part ); + + /** + * Since the part emits the jobid in the started() signal, + * progress information is automatically displayed. + * + * However, if you don't use a TDEIO::Job in the part, + * you can use loadingProgress() and speedProgress() + * to display progress information. + */ + void loadingProgress( int percent ); + /** + * @see loadingProgress + */ + void speedProgress( int bytesPerSecond ); + + void infoMessage( const TQString & ); + + /** + * Emit this to make the browser show a standard popup menu + * at the point @p global for the files @p items. + */ + void popupMenu( const TQPoint &global, const KFileItemList &items ); + + /** + * Emit this to make the browser show a standard popup menu + * at the point @p global for the files @p items. + * + * The GUI described by @p client is being merged with the popupmenu of the host + */ + void popupMenu( KXMLGUIClient *client, const TQPoint &global, const KFileItemList &items ); + + void popupMenu( KXMLGUIClient *client, const TQPoint &global, const KFileItemList &items, const KParts::URLArgs &args, KParts::BrowserExtension::PopupFlags i ); + + /** + * Emit this to make the browser show a standard popup menu + * at the point @p global for the given @p url. + * + * Give as much information + * about this URL as possible, like the @p mimeType and the file type + * (@p mode: S_IFREG, S_IFDIR...) + */ + void popupMenu( const TQPoint &global, const KURL &url, + const TQString &mimeType, mode_t mode = (mode_t)-1 ); + + /** + * Emit this to make the browser show a standard popup menu + * at the point @p global for the given @p url. + * + * Give as much information + * about this URL as possible, like the @p mimeType and the file type + * (@p mode: S_IFREG, S_IFDIR...) + * The GUI described by @p client is being merged with the popupmenu of the host + */ + void popupMenu( KXMLGUIClient *client, + const TQPoint &global, const KURL &url, + const TQString &mimeType, mode_t mode = (mode_t)-1 ); + + /** + * Emit this to make the browser show a standard popup menu + * at the point @p global for the given @p url. + * + * Give as much information + * about this URL as possible, like @p args.mimeType and the file type + * (@p mode: S_IFREG, S_IFDIR...) + * The GUI described by @p client is being merged with the popupmenu of the host + */ + void popupMenu( KXMLGUIClient *client, + const TQPoint &global, const KURL &url, + const KParts::URLArgs &args, KParts::BrowserExtension::PopupFlags i, mode_t mode = (mode_t)-1 ); + + /** + * Inform the hosting application about the current selection. + * Used when a set of files/URLs is selected (with full information + * about those URLs, including size, permissions etc.) + */ + void selectionInfo( const KFileItemList &items ); + /** + * Inform the hosting application about the current selection. + * Used when some text is selected. + */ + void selectionInfo( const TQString &text ); + /** + * Inform the hosting application about the current selection. + * Used when a set of URLs is selected. + */ + void selectionInfo( const KURL::List &urls ); + + /** + * Inform the hosting application that the user moved the mouse over an item. + * Used when the mouse is on an URL. + */ + void mouseOverInfo( const KFileItem* item ); + + /** + * Ask the hosting application to add a new HTML (aka Mozilla/Netscape) + * SideBar entry. + */ + void addWebSideBar(const KURL &url, const TQString& name); + + /** + * Ask the hosting application to move the top level widget. + */ + void moveTopLevelWidget( int x, int y ); + + /** + * Ask the hosting application to resize the top level widget. + */ + void resizeTopLevelWidget( int w, int h ); + + /** + * Ask the hosting application to focus @p part. + * @since 3.4 + */ + void requestFocus(KParts::ReadOnlyPart *part); + + /** + * Tell the host (browser) about security state of current page + * enum PageSecurity { NotCrypted, Encrypted, Mixed }; + * @since 3.4 + */ + void setPageSecurity( int ); + +#define KPARTS_BROWSEREXTENSION_HAS_ITEMS_REMOVED + /** + * Inform the host about items that have been removed. + * @since 3.5.5 + */ + void itemsRemoved( const KFileItemList &items ); + +private slots: + void slotCompleted(); + void slotOpenURLRequest( const KURL &url, const KParts::URLArgs &args ); + void slotEmitOpenURLRequestDelayed(); + void slotEnableAction( const char *, bool ); + void slotSetActionText( const char*, const TQString& ); + +private: + KParts::ReadOnlyPart *m_part; + URLArgs m_args; +public: + typedef TQMap<TQCString,int> ActionNumberMap; + +private: + static ActionNumberMap * s_actionNumberMap; + static ActionSlotMap * s_actionSlotMap; + static void createActionSlotMap(); +protected: + virtual void virtual_hook( int id, void* data ); +private: + BrowserExtensionPrivate *d; +}; + +/** + * An extension class for container parts, i.e. parts that contain + * other parts. + * For instance a KHTMLPart hosts one part per frame. + */ +class KPARTS_EXPORT BrowserHostExtension : public TQObject +{ + Q_OBJECT +public: + BrowserHostExtension( KParts::ReadOnlyPart *parent, + const char *name = 0L ); + + virtual ~BrowserHostExtension(); + + /** + * Returns a list of the names of all hosted child objects. + * + * Note that this method does not query the child objects recursively. + */ + virtual TQStringList frameNames() const; + + /** + * Returns a list of pointers to all hosted child objects. + * + * Note that this method does not query the child objects recursively. + */ + virtual const TQPtrList<KParts::ReadOnlyPart> frames() const; + + /** + * Returns the part that contains @p frame and that may be accessed + * by @p callingPart + * @since 3.3 + */ + BrowserHostExtension *findFrameParent(KParts::ReadOnlyPart *callingPart, const TQString &frame); + + /** + * Opens the given url in a hosted child frame. The frame name is specified in the + * frameName variable in the urlArgs argument structure (see KParts::URLArgs ) . + */ + virtual bool openURLInFrame( const KURL &url, const KParts::URLArgs &urlArgs ); + + /** + * Queries @p obj for a child object which inherits from this + * BrowserHostExtension class. Convenience method. + */ + static BrowserHostExtension *childObject( TQObject *obj ); + +protected: + /** This 'enum' along with the structure below is NOT part of the public API. + * It's going to disappear in KDE 4.0 and is likely to change inbetween. + * + * @internal + */ + enum { VIRTUAL_FIND_FRAME_PARENT = 0x10 }; + struct FindFrameParentParams + { + BrowserHostExtension *parent; + KParts::ReadOnlyPart *callingPart; + TQString frame; + }; + + virtual void virtual_hook( int id, void* data ); +private: + class BrowserHostExtensionPrivate; + BrowserHostExtensionPrivate *d; +}; + +/** + * An extension class for LiveConnect, i.e\. a call from JavaScript + * from a HTML page which embeds this part. + * A part can have an object hierarchie by using objid as a reference + * to an object. + */ +class KPARTS_EXPORT LiveConnectExtension : public TQObject +{ + Q_OBJECT +public: + enum Type { + TypeVoid=0, TypeBool, TypeFunction, TypeNumber, TypeObject, TypeString + }; + typedef TQValueList<QPair<Type, TQString> > ArgList; + + LiveConnectExtension( KParts::ReadOnlyPart *parent, const char *name = 0L ); + + virtual ~LiveConnectExtension() {} + /** + * get a field value from objid, return true on success + */ + virtual bool get( const unsigned long objid, const TQString & field, Type & type, unsigned long & retobjid, TQString & value ); + /** + * put a field value in objid, return true on success + */ + virtual bool put( const unsigned long objid, const TQString & field, const TQString & value ); + /** + * calls a function of objid, return true on success + */ + virtual bool call( const unsigned long objid, const TQString & func, const TQStringList & args, Type & type, unsigned long & retobjid, TQString & value ); + /** + * notifies the part that there is no reference anymore to objid + */ + virtual void unregister( const unsigned long objid ); + + static LiveConnectExtension *childObject( TQObject *obj ); +signals: + /** + * notify an event from the part of object objid + */ + virtual void partEvent( const unsigned long objid, const TQString & event, const ArgList & args ); +}; + +} + +#endif + diff --git a/tdeparts/browserinterface.cpp b/tdeparts/browserinterface.cpp new file mode 100644 index 000000000..e02ae34cc --- /dev/null +++ b/tdeparts/browserinterface.cpp @@ -0,0 +1,58 @@ + +#include "browserinterface.h" + +#include <tqmetaobject.h> + +#include <config.h> +#include <tqucomextra_p.h> + +using namespace KParts; + +BrowserInterface::BrowserInterface( TQObject *parent, const char *name ) + : TQObject( parent, name ) +{ +} + +BrowserInterface::~BrowserInterface() +{ +} + +void BrowserInterface::callMethod( const char *name, const TQVariant &argument ) +{ + int slot = metaObject()->findSlot( name ); + + if ( slot == -1 ) + return; + + TQUObject o[ 2 ]; + TQStringList strLst; + uint i; + + switch ( argument.type() ) + { + case TQVariant::Invalid: + break; + case TQVariant::String: + static_TQUType_TQString.set( o + 1, argument.toString() ); + break; + case TQVariant::StringList: + strLst = argument.toStringList(); + static_TQUType_ptr.set( o + 1, &strLst ); + break; + case TQVariant::Int: + static_TQUType_int.set( o + 1, argument.toInt() ); + break; + case TQVariant::UInt: + i = argument.toUInt(); + static_TQUType_ptr.set( o + 1, &i ); + break; + case TQVariant::Bool: + static_TQUType_bool.set( o + 1, argument.toBool() ); + break; + default: return; + } + + tqt_invoke( slot, o ); +} + +#include "browserinterface.moc" diff --git a/tdeparts/browserinterface.h b/tdeparts/browserinterface.h new file mode 100644 index 000000000..82521376f --- /dev/null +++ b/tdeparts/browserinterface.h @@ -0,0 +1,54 @@ +#ifndef __browserinterface_h__ +#define __browserinterface_h__ + +#include <tqobject.h> +#include <tqvariant.h> + +#include <tdelibs_export.h> + +namespace KParts +{ + +/** + * The purpose of this interface is to allow a direct communication between + * a KPart and the hosting browser shell (for example Konqueror) . A + * shell implementing this interface can propagate it to embedded kpart + * components by using the setBrowserInterface call of the part's + * KParts::BrowserExtension object. + * + * This interface looks not very rich, but the main functionality is + * implemented using the callMethod method for part->shell + * communication and using Qt properties for allowing a part to + * to explicitly query information from the shell. + * + * Konqueror in particular, as 'reference' implementation, provides + * the following functionality through this interface: + * + * Qt properties: + * <code> + * TQ_PROPERTY( uint historyLength READ historyLength ); + * </code> + * + * Callable methods: + * <code> + * void goHistory( int ); + * </code> + * + */ +class KPARTS_EXPORT BrowserInterface : public TQObject +{ + Q_OBJECT +public: + BrowserInterface( TQObject *parent, const char *name = 0 ); + virtual ~BrowserInterface(); + + /** + * Perform a dynamic invocation of a method in the BrowserInterface + * implementation. Methods are to be implemented as simple Qt slots. + */ + void callMethod( const char *name, const TQVariant &argument ); +}; + +} + +#endif diff --git a/tdeparts/browserrun.cpp b/tdeparts/browserrun.cpp new file mode 100644 index 000000000..4cff3f8a4 --- /dev/null +++ b/tdeparts/browserrun.cpp @@ -0,0 +1,525 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2002 David Faure <[email protected]> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "browserrun.h" +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <kio/job.h> +#include <kio/scheduler.h> +#include <klocale.h> +#include <kprocess.h> +#include <kstringhandler.h> +#include <kuserprofile.h> +#include <ktempfile.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <assert.h> + +using namespace KParts; + +class BrowserRun::BrowserRunPrivate +{ +public: + bool m_bHideErrorDialog; + TQString contentDisposition; +}; + +BrowserRun::BrowserRun( const KURL& url, const KParts::URLArgs& args, + KParts::ReadOnlyPart *part, TQWidget* window, + bool removeReferrer, bool trustedSource ) + : KRun( url, window, 0 /*mode*/, false /*is_local_file known*/, false /* no GUI */ ), + m_args( args ), m_part( part ), m_window( window ), + m_bRemoveReferrer( removeReferrer ), m_bTrustedSource( trustedSource ) +{ + d = new BrowserRunPrivate; + d->m_bHideErrorDialog = false; +} + +// BIC: merge with above ctor +BrowserRun::BrowserRun( const KURL& url, const KParts::URLArgs& args, + KParts::ReadOnlyPart *part, TQWidget* window, + bool removeReferrer, bool trustedSource, bool hideErrorDialog ) + : KRun( url, window, 0 /*mode*/, false /*is_local_file known*/, false /* no GUI */ ), + m_args( args ), m_part( part ), m_window( window ), + m_bRemoveReferrer( removeReferrer ), m_bTrustedSource( trustedSource ) +{ + d = new BrowserRunPrivate; + d->m_bHideErrorDialog = hideErrorDialog; +} + +BrowserRun::~BrowserRun() +{ + delete d; +} + +void BrowserRun::init() +{ + if ( d->m_bHideErrorDialog ) + { + // ### KRun doesn't call a virtual method when it finds out that the URL + // is either malformed, or points to a non-existing local file... + // So we need to reimplement some of the checks, to handle m_bHideErrorDialog + if ( !m_strURL.isValid() ) { + redirectToError( TDEIO::ERR_MALFORMED_URL, m_strURL.url() ); + return; + } + if ( !m_bIsLocalFile && !m_bFault && m_strURL.isLocalFile() ) + m_bIsLocalFile = true; + + if ( m_bIsLocalFile ) { + struct stat buff; + if ( stat( TQFile::encodeName(m_strURL.path()), &buff ) == -1 ) + { + kdDebug(1000) << "BrowserRun::init : " << m_strURL.prettyURL() << " doesn't exist." << endl; + redirectToError( TDEIO::ERR_DOES_NOT_EXIST, m_strURL.path() ); + return; + } + m_mode = buff.st_mode; // while we're at it, save it for KRun::init() to use it + } + } + KRun::init(); +} + +void BrowserRun::scanFile() +{ + kdDebug(1000) << "BrowserRun::scanfile " << m_strURL.prettyURL() << endl; + + // Let's check for well-known extensions + // Not when there is a query in the URL, in any case. + // Optimization for http/https, findByURL doesn't trust extensions over http. + if ( m_strURL.query().isEmpty() && !m_strURL.protocol().startsWith("http") ) + { + KMimeType::Ptr mime = KMimeType::findByURL( m_strURL ); + assert( mime != 0L ); + if ( mime->name() != "application/octet-stream" || m_bIsLocalFile ) + { + kdDebug(1000) << "Scanfile: MIME TYPE is " << mime->name() << endl; + foundMimeType( mime->name() ); + return; + } + } + + if ( m_part ) + { + TQString proto = m_part->url().protocol().lower(); + + if (proto == "https" || proto == "webdavs") { + m_args.metaData().insert("main_frame_request", "TRUE" ); + m_args.metaData().insert("ssl_was_in_use", "TRUE" ); + m_args.metaData().insert("ssl_activate_warnings", "TRUE" ); + } else if (proto == "http" || proto == "webdav") { + m_args.metaData().insert("ssl_activate_warnings", "TRUE" ); + m_args.metaData().insert("ssl_was_in_use", "FALSE" ); + } + + // Set the PropagateHttpHeader meta-data if it has not already been set... + if (!m_args.metaData().contains("PropagateHttpHeader")) + m_args.metaData().insert("PropagateHttpHeader", "TRUE"); + } + + TDEIO::TransferJob *job; + if ( m_args.doPost() && m_strURL.protocol().startsWith("http")) + { + job = TDEIO::http_post( m_strURL, m_args.postData, false ); + job->addMetaData( "content-type", m_args.contentType() ); + } + else + job = TDEIO::get(m_strURL, m_args.reload, false); + + if ( m_bRemoveReferrer ) + m_args.metaData().remove("referrer"); + + job->addMetaData( m_args.metaData() ); + job->setWindow( m_window ); + connect( job, TQT_SIGNAL( result( TDEIO::Job *)), + this, TQT_SLOT( slotBrowserScanFinished(TDEIO::Job *))); + connect( job, TQT_SIGNAL( mimetype( TDEIO::Job *, const TQString &)), + this, TQT_SLOT( slotBrowserMimetype(TDEIO::Job *, const TQString &))); + m_job = job; +} + +void BrowserRun::slotBrowserScanFinished(TDEIO::Job *job) +{ + kdDebug(1000) << "BrowserRun::slotBrowserScanFinished" << endl; + if ( job->error() == TDEIO::ERR_IS_DIRECTORY ) + { + // It is in fact a directory. This happens when HTTP redirects to FTP. + // Due to the "protocol doesn't support listing" code in BrowserRun, we + // assumed it was a file. + kdDebug(1000) << "It is in fact a directory!" << endl; + // Update our URL in case of a redirection + m_strURL = static_cast<TDEIO::TransferJob *>(job)->url(); + m_job = 0; + foundMimeType( "inode/directory" ); + } + else + { + if ( job->error() ) + handleError( job ); + else + KRun::slotScanFinished(job); + } +} + +void BrowserRun::slotBrowserMimetype( TDEIO::Job *_job, const TQString &type ) +{ + Q_ASSERT( _job == m_job ); + TDEIO::TransferJob *job = static_cast<TDEIO::TransferJob *>(m_job); + // Update our URL in case of a redirection + //kdDebug(1000) << "old URL=" << m_strURL.url() << endl; + //kdDebug(1000) << "new URL=" << job->url().url() << endl; + m_strURL = job->url(); + kdDebug(1000) << "slotBrowserMimetype: found " << type << " for " << m_strURL.prettyURL() << endl; + + m_suggestedFilename = job->queryMetaData("content-disposition-filename"); + d->contentDisposition = job->queryMetaData("content-disposition-type"); + //kdDebug(1000) << "m_suggestedFilename=" << m_suggestedFilename << endl; + + // Make a copy to avoid a dead reference + TQString _type = type; + job->putOnHold(); + m_job = 0; + + KRun::setSuggestedFileName(m_suggestedFilename); + + foundMimeType( _type ); +} + +BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable( const TQString& _mimeType ) +{ + TQString mimeType( _mimeType ); + Q_ASSERT( !m_bFinished ); // only come here if the mimetype couldn't be embedded + // Support for saving remote files. + if ( mimeType != "inode/directory" && // dirs can't be saved + !m_strURL.isLocalFile() ) + { + if ( isTextExecutable(mimeType) ) + mimeType = TQString::fromLatin1("text/plain"); // view, don't execute + kdDebug(1000) << "BrowserRun: ask for saving" << endl; + KService::Ptr offer = KServiceTypeProfile::preferredService(mimeType, "Application"); + // ... -> ask whether to save + KParts::BrowserRun::AskSaveResult res = askSave( m_strURL, offer, mimeType, m_suggestedFilename ); + if ( res == KParts::BrowserRun::Save ) { + save( m_strURL, m_suggestedFilename ); + kdDebug(1000) << "BrowserRun::handleNonEmbeddable: Save: returning Handled" << endl; + m_bFinished = true; + return Handled; + } + else if ( res == KParts::BrowserRun::Cancel ) { + // saving done or canceled + kdDebug(1000) << "BrowserRun::handleNonEmbeddable: Cancel: returning Handled" << endl; + m_bFinished = true; + return Handled; + } + else // "Open" chosen (done by KRun::foundMimeType, called when returning NotHandled) + { + // If we were in a POST, we can't just pass a URL to an external application. + // We must save the data to a tempfile first. + if ( m_args.doPost() ) + { + kdDebug(1000) << "BrowserRun: request comes from a POST, can't pass a URL to another app, need to save" << endl; + m_sMimeType = mimeType; + TQString extension; + TQString fileName = m_suggestedFilename.isEmpty() ? m_strURL.fileName() : m_suggestedFilename; + int extensionPos = fileName.findRev( '.' ); + if ( extensionPos != -1 ) + extension = fileName.mid( extensionPos ); // keep the '.' + KTempFile tempFile( TQString::null, extension ); + KURL destURL; + destURL.setPath( tempFile.name() ); + TDEIO::Job *job = TDEIO::file_copy( m_strURL, destURL, 0600, true /*overwrite*/, false /*no resume*/, true /*progress info*/ ); + job->setWindow (m_window); + connect( job, TQT_SIGNAL( result( TDEIO::Job *)), + this, TQT_SLOT( slotCopyToTempFileResult(TDEIO::Job *)) ); + return Delayed; // We'll continue after the job has finished + } + } + } + + // Check if running is allowed + if ( !m_bTrustedSource && // ... and untrusted source... + !allowExecution( mimeType, m_strURL ) ) // ...and the user said no (for executables etc.) + { + m_bFinished = true; + return Handled; + } + + TDEIO::SimpleJob::removeOnHold(); // Kill any slave that was put on hold. + return NotHandled; +} + +//static +bool BrowserRun::allowExecution( const TQString &serviceType, const KURL &url ) +{ + if ( !isExecutable( serviceType ) ) + return true; + + if ( !url.isLocalFile() ) // Don't permit to execute remote files + return false; + + return ( KMessageBox::warningContinueCancel( 0, i18n( "Do you really want to execute '%1'? " ).arg( url.prettyURL() ), + i18n("Execute File?"), i18n("Execute") ) == KMessageBox::Continue ); +} + +static TQString makeQuestion( const KURL& url, const TQString& mimeType, const TQString& suggestedFilename ) +{ + TQString surl = KStringHandler::csqueeze( url.prettyURL() ); + KMimeType::Ptr mime = KMimeType::mimeType( mimeType ); + TQString comment = mimeType; + + // Test if the mimeType is not recognize as octet-stream. + // If so then keep mime-type as comment + if (mime->name() != KMimeType::defaultMimeType()) { + // The mime-type is known so display the comment instead of mime-type + comment = mime->comment(); + } + // The strange order in the i18n() calls below is due to the possibility + // of surl containing a '%' + if ( suggestedFilename.isEmpty() ) + return i18n("Open '%2'?\nType: %1").arg(comment, surl); + else + return i18n("Open '%3'?\nName: %2\nType: %1").arg(comment, suggestedFilename, surl); +} + +//static +BrowserRun::AskSaveResult BrowserRun::askSave( const KURL & url, KService::Ptr offer, const TQString& mimeType, const TQString & suggestedFilename ) +{ + // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC + // NOTE: Keep this function in sync with tdebase/kcontrol/filetypes/filetypedetails.cpp + // FileTypeDetails::updateAskSave() + + TQString question = makeQuestion( url, mimeType, suggestedFilename ); + + // Text used for the open button + TQString openText = (offer && !offer->name().isEmpty()) + ? i18n("&Open with '%1'").arg(offer->name()) + : i18n("&Open With..."); + + int choice = KMessageBox::questionYesNoCancel( + 0L, question, url.host(), + KStdGuiItem::saveAs(), openText, + TQString::fromLatin1("askSave")+ mimeType ); // dontAskAgainName, KEEP IN SYNC!!! + + return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel ); + // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC +} + +//static +BrowserRun::AskSaveResult BrowserRun::askEmbedOrSave( const KURL & url, const TQString& mimeType, const TQString & suggestedFilename, int flags ) +{ + // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC + // NOTE: Keep this funcion in sync with tdebase/kcontrol/filetypes/filetypedetails.cpp + // FileTypeDetails::updateAskSave() + + KMimeType::Ptr mime = KMimeType::mimeType( mimeType ); + // Don't ask for: + // - html (even new tabs would ask, due to about:blank!) + // - dirs obviously (though not common over HTTP :), + // - images (reasoning: no need to save, most of the time, because fast to see) + // e.g. postscript is different, because takes longer to read, so + // it's more likely that the user might want to save it. + // - multipart/* ("server push", see tdemultipart) + // - other strange 'internal' mimetypes like print/manager... + // KEEP IN SYNC!!! + if (flags != (int)AttachmentDisposition && ( + mime->is( "text/html" ) || + mime->is( "text/xml" ) || + mime->is( "inode/directory" ) || + mimeType.startsWith( "image" ) || + mime->is( "multipart/x-mixed-replace" ) || + mime->is( "multipart/replace" ) || + mimeType.startsWith( "print" ) ) ) + return Open; + + TQString question = makeQuestion( url, mimeType, suggestedFilename ); + + int choice = KMessageBox::questionYesNoCancel( + 0L, question, url.host(), + KStdGuiItem::saveAs(), KGuiItem( i18n( "&Open" ), "fileopen"), + TQString::fromLatin1("askEmbedOrSave")+ mimeType ); // dontAskAgainName, KEEP IN SYNC!!! + return choice == KMessageBox::Yes ? Save : ( choice == KMessageBox::No ? Open : Cancel ); + // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC +} + +// Default implementation, overridden in KHTMLRun +void BrowserRun::save( const KURL & url, const TQString & suggestedFilename ) +{ + simpleSave( url, suggestedFilename, m_window ); +} + +// static +void BrowserRun::simpleSave( const KURL & url, const TQString & suggestedFilename ) +{ + simpleSave (url, suggestedFilename, 0); +} + +void BrowserRun::simpleSave( const KURL & url, const TQString & suggestedFilename, + TQWidget* window ) +{ + // DownloadManager <-> konqueror integration + // find if the integration is enabled + // the empty key means no integration + // only use the downloadmanager for non-local urls + if ( !url.isLocalFile() ) + { + TDEConfig cfg("konquerorrc", false, false); + cfg.setGroup("HTML Settings"); + TQString downloadManger = cfg.readPathEntry("DownloadManager"); + if (!downloadManger.isEmpty()) + { + // then find the download manager location + kdDebug(1000) << "Using: "<<downloadManger <<" as Download Manager" <<endl; + TQString cmd=KStandardDirs::findExe(downloadManger); + if (cmd.isEmpty()) + { + TQString errMsg=i18n("The Download Manager (%1) could not be found in your $PATH ").arg(downloadManger); + TQString errMsgEx= i18n("Try to reinstall it \n\nThe integration with Konqueror will be disabled!"); + KMessageBox::detailedSorry(0,errMsg,errMsgEx); + cfg.writePathEntry("DownloadManager",TQString::null); + cfg.sync (); + } + else + { + // ### suggestedFilename not taken into account. Fix this (and + // the duplicated code) with shiny new KDownload class for 3.2 (pfeiffer) + // Until the shiny new class comes about, send the suggestedFilename + // along with the actual URL to download. (DA) + cmd += " " + TDEProcess::quote(url.url()); + if ( !suggestedFilename.isEmpty() ) + cmd +=" " + TDEProcess::quote(suggestedFilename); + + kdDebug(1000) << "Calling command " << cmd << endl; + // slave is already on hold (slotBrowserMimetype()) + TDEIO::Scheduler::publishSlaveOnHold(); + KRun::runCommand(cmd); + return; + } + } + } + + // no download manager available, let's do it ourself + KFileDialog *dlg = new KFileDialog( TQString::null, TQString::null /*all files*/, + window , "filedialog", true ); + dlg->setOperationMode( KFileDialog::Saving ); + dlg->setCaption(i18n("Save As")); + + dlg->setSelection( suggestedFilename.isEmpty() ? url.fileName() : suggestedFilename ); + if ( dlg->exec() ) + { + KURL destURL( dlg->selectedURL() ); + if ( destURL.isValid() ) + { + TDEIO::Job *job = TDEIO::copy( url, destURL ); + job->setWindow (window); + job->setAutoErrorHandlingEnabled( true ); + } + } + delete dlg; +} + +void BrowserRun::slotStatResult( TDEIO::Job *job ) +{ + if ( job->error() ) { + kdDebug(1000) << "BrowserRun::slotStatResult : " << job->errorString() << endl; + handleError( job ); + } else + KRun::slotStatResult( job ); +} + +void BrowserRun::handleError( TDEIO::Job * job ) +{ + if ( !job ) { // Shouldn't happen, see docu. + kdWarning(1000) << "BrowserRun::handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog << endl; + return; + } + + if (d->m_bHideErrorDialog && job->error() != TDEIO::ERR_NO_CONTENT) + { + redirectToError( job->error(), job->errorText() ); + return; + } + + // Reuse code in KRun, to benefit from d->m_showingError etc. + KRun::slotStatResult( job ); +} + +void BrowserRun::redirectToError( int error, const TQString& errorText ) +{ + /** + * To display this error in KHTMLPart instead of inside a dialog box, + * we tell konq that the mimetype is text/html, and we redirect to + * an error:/ URL that sends the info to tdehtml. + * + * The format of the error:/ URL is error:/?query#url, + * where two variables are passed in the query: + * error = int kio error code, errText = TQString error text from kio + * The sub-url is the URL that we were trying to open. + */ + KURL newURL(TQString("error:/?error=%1&errText=%2") + .arg( error ).arg( KURL::encode_string(errorText) ), 106 ); + m_strURL.setPass( TQString::null ); // don't put the password in the error URL + + KURL::List lst; + lst << newURL << m_strURL; + m_strURL = KURL::join( lst ); + //kdDebug(1202) << "BrowserRun::handleError m_strURL=" << m_strURL.prettyURL() << endl; + + m_job = 0; + foundMimeType( "text/html" ); +} + +void BrowserRun::slotCopyToTempFileResult(TDEIO::Job *job) +{ + if ( job->error() ) { + job->showErrorDialog( m_window ); + } else { + // Same as KRun::foundMimeType but with a different URL + (void) (KRun::runURL( static_cast<TDEIO::FileCopyJob *>(job)->destURL(), m_sMimeType )); + } + m_bFault = true; // see above + m_bFinished = true; + m_timer.start( 0, true ); +} + +bool BrowserRun::isTextExecutable( const TQString &serviceType ) +{ + return ( serviceType == "application/x-desktop" || + serviceType == "media/builtin-mydocuments" || + serviceType == "media/builtin-mycomputer" || + serviceType == "media/builtin-mynetworkplaces" || + serviceType == "media/builtin-printers" || + serviceType == "media/builtin-trash" || + serviceType == "media/builtin-webbrowser" || + serviceType == "application/x-shellscript" ); +} + +bool BrowserRun::isExecutable( const TQString &serviceType ) +{ + return KRun::isExecutable( serviceType ); +} + +bool BrowserRun::hideErrorDialog() const +{ + return d->m_bHideErrorDialog; +} + +TQString BrowserRun::contentDisposition() const { + return d->contentDisposition; +} + +#include "browserrun.moc" diff --git a/tdeparts/browserrun.h b/tdeparts/browserrun.h new file mode 100644 index 000000000..edd46d40d --- /dev/null +++ b/tdeparts/browserrun.h @@ -0,0 +1,194 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2002 David Faure <[email protected]> + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef tdeparts_browserrun_h +#define tdeparts_browserrun_h + +#include <krun.h> +#include <kservice.h> +#include <tdeparts/browserextension.h> + +namespace KParts { + + /** + * This class extends KRun to provide additional functionality for browsers: + * <ul> + * <li>"save or open" dialog boxes + * <li>"save" functionality + * <li>support for HTTP POST (including saving the result to a temp file if + * opening a separate application) + * <li>warning before launching executables off the web + * <li>custom error handling (i.e. treating errors as HTML pages) + * <li>generation of SSL metadata depending on the previous URL shown by the part + * </ul> + * + * @author David Faure <[email protected]> + */ + class KPARTS_EXPORT BrowserRun : public KRun + { + Q_OBJECT + public: + /** + * @param url the URL we're probing + * @param args URL args - includes data for a HTTP POST, etc. + * @param part the part going to open this URL - can be 0L if not created yet + * @param window the mainwindow - passed to TDEIO::Job::setWindow() + * @param removeReferrer if true, the "referrer" metadata from @p args isn't passed on + * @param trustedSource if false, a warning will be shown before launching an executable + * Always pass false for @p trustedSource, except for local directory views. + */ + BrowserRun( const KURL& url, const KParts::URLArgs& args, + KParts::ReadOnlyPart *part, TQWidget *window, + bool removeReferrer, bool trustedSource ); + + // BIC: merge with above constructor + /** + * @param url the URL we're probing + * @param args URL args - includes data for a HTTP POST, etc. + * @param part the part going to open this URL - can be 0L if not created yet + * @param window the mainwindow - passed to TDEIO::Job::setWindow() + * @param removeReferrer if true, the "referrer" metadata from @p args isn't passed on + * @param trustedSource if false, a warning will be shown before launching an executable. + * Always pass false for @p trustedSource, except for local directory views. + * @param hideErrorDialog if true, no dialog will be shown in case of errors. + * + */ + BrowserRun( const KURL& url, const KParts::URLArgs& args, + KParts::ReadOnlyPart *part, TQWidget *window, + bool removeReferrer, bool trustedSource, bool hideErrorDialog ); + + virtual ~BrowserRun(); + + //KParts::URLArgs urlArgs() const { return m_args; } + //KParts::ReadOnlyPart* part() const { return m_part; } + + /** + * @return the URL we're probing + */ + KURL url() const { return m_strURL; } + + /** + * @return true if no dialog will be shown in case of errors + */ + bool hideErrorDialog() const; + + /** + * @return Suggested filename given by the server (e.g. HTTP content-disposition filename) + */ + TQString suggestedFilename() const { return m_suggestedFilename; } + + /** + * @return Suggested disposition by the server (e.g. HTTP content-disposition) + * @since 3.5.2 + */ + TQString contentDisposition() const; + + bool serverSuggestsSave() const { return contentDisposition() == TQString::fromLatin1("attachment"); } + + enum AskSaveResult { Save, Open, Cancel }; + /** + * Ask the user whether to save or open a url in another application. + * @param url the URL in question + * @param offer the application that will be used to open the URL + * @param mimeType the mimetype of the URL + * @param suggestedFilename optional filename suggested by the server + * @return Save, Open or Cancel. + */ + static AskSaveResult askSave( const KURL & url, KService::Ptr offer, const TQString& mimeType, const TQString & suggestedFilename = TQString::null ); + + enum AskEmbedOrSaveFlags { InlineDisposition = 0, AttachmentDisposition = 1 }; + /** + * Similar to askSave() but for the case where the current application is + * able to embed the url itself (instead of passing it to another app). + * @param url the URL in question + * @param mimeType the mimetype of the URL + * @param suggestedFilename optional filename suggested by the server + * @param flags set to AttachmentDisposition if suggested by the server + * @return Save, Open or Cancel. + */ + static AskSaveResult askEmbedOrSave( const KURL & url, const TQString& mimeType, const TQString & suggestedFilename = TQString::null, int flags = 0 ); + + // virtual so that KHTML can implement differently (HTML cache) + virtual void save( const KURL & url, const TQString & suggestedFilename ); + + // static so that it can be called from other classes + static void simpleSave( const KURL & url, const TQString & suggestedFilename, + TQWidget* window ); + + /** BIC: Combine with the above function for KDE 4.0. */ + static void simpleSave( const KURL & url, const TQString & suggestedFilename ); + + static bool allowExecution( const TQString &serviceType, const KURL &url ); + + /** BIC: Obsoleted by KRun::isExecutable( const TQString &serviceType ); */ + static bool isExecutable( const TQString &serviceType ); + static bool isTextExecutable( const TQString &serviceType ); + + protected: + /** + * Reimplemented from KRun + */ + virtual void scanFile(); + /** + * Reimplemented from KRun + */ + virtual void init(); + /** + * Called when an error happens. + * NOTE: @p job could be 0L, if you passed hideErrorDialog=true. + * The default implementation shows a message box, but only when job != 0 .... + * It is strongly recommended to reimplement this method if + * you passed hideErrorDialog=true. + */ + virtual void handleError( TDEIO::Job * job ); + + /** + * NotHandled means that foundMimeType should call KRun::foundMimeType, + * i.e. launch an external app. + */ + enum NonEmbeddableResult { Handled, NotHandled, Delayed }; + + /** + * Helper for foundMimeType: call this if the mimetype couldn't be embedded + */ + NonEmbeddableResult handleNonEmbeddable( const TQString& mimeType ); + + protected slots: + void slotBrowserScanFinished(TDEIO::Job *job); + void slotBrowserMimetype(TDEIO::Job *job, const TQString &type); + void slotCopyToTempFileResult(TDEIO::Job *job); + virtual void slotStatResult( TDEIO::Job *job ); + + protected: + KParts::URLArgs m_args; + KParts::ReadOnlyPart *m_part; // QGuardedPtr? + TQGuardedPtr<TQWidget> m_window; + // Suggested filename given by the server (e.g. HTTP content-disposition) + // When set, we should really be saving instead of embedding + TQString m_suggestedFilename; + TQString m_sMimeType; + bool m_bRemoveReferrer; + bool m_bTrustedSource; + private: + void redirectToError( int error, const TQString& errorText ); + class BrowserRunPrivate; + BrowserRunPrivate* d; + + }; +} +#endif diff --git a/tdeparts/browserview.desktop b/tdeparts/browserview.desktop new file mode 100644 index 000000000..42d6131ec --- /dev/null +++ b/tdeparts/browserview.desktop @@ -0,0 +1,157 @@ +[Desktop Entry] +Type=ServiceType +X-TDE-ServiceType=Browser/View +X-TDE-Derived=KParts/ReadOnlyPart +Name=Browser View +Name[af]=Blaaier Besigtig +Name[ar]=عرض تصفحي +Name[az]=Səyyah Görünüşü +Name[be]=Выгляд аглядальніка +Name[bn]=ব্রাউজার দৃশ্য +Name[br]=Gwel Furchal +Name[bs]=Pogled za pretragu +Name[ca]=Vista del navegador +Name[cs]=Prohlížeč +Name[csb]=Wëzdrzatk przezérnika +Name[cy]=Golwg Porydd +Name[da]=Netsøgningsvisning +Name[de]=Browser-Ansicht +Name[el]=Προβολή εξερευνητή +Name[eo]=Rigardo de TTTilo +Name[es]=Vista de navegador +Name[et]=Brauseri vaade +Name[eu]=Arakatzailearen ikuspegia +Name[fa]=نمای مرورگر +Name[fi]=Selainnäkymä +Name[fr]=Affichage du navigateur +Name[fy]=Browserwerjefte +Name[ga]=Amharc Brabhsálaí +Name[gl]=Vista de Navegador +Name[he]=תצוגת דפדפן +Name[hi]=ब्राउज़र दर्शन +Name[hr]=Pogled pretraživača +Name[hu]=Böngészőnézet +Name[id]=View Browser +Name[is]=Vafrasýn +Name[it]=Vista browser +Name[ja]=ブラウズビュー +Name[ka]=ნუსხის ხედი +Name[kk]=Шолғыш көрнісі +Name[km]=ទិដ្ឋភាពកម្មវិធីរុករក +Name[ko]=탐색기 보기 +Name[lb]=Browser-Siicht +Name[lt]=Rodyti naršyklėje +Name[lv]=Pārlūka Skatījums +Name[mk]=Разгледување +Name[mn]=Хөтөч Харах +Name[ms]=Pelihat Pelayar +Name[mt]=Dehra Browser +Name[nb]=Nettleservisning +Name[nds]=Nettkieker-Ansicht +Name[ne]=ब्राउजर दृश्य +Name[nl]=Browserweergave +Name[nn]=Nettlesarvising +Name[nso]=Pono ya Seinyakisi +Name[oc]=Vista de navigador +Name[pa]=ਝਲਕ ਦਰਿਸ਼ +Name[pl]=Widok przeglądarki +Name[pt]=Navegação +Name[pt_BR]=Visão de navegador +Name[ro]=Vizualizare navigator +Name[ru]=Вид страницы +Name[rw]=Igaragaza Mucukumbuzi +Name[se]=Fierpmádatlogana čájeheapmi +Name[sk]=Prehliadač +Name[sl]=Pogled brskalnika +Name[sq]=Shikues për Shfletim +Name[sr]=Претраживачев приказ +Name[sr@Latn]=Pretraživačev prikaz +Name[sv]=Surfvy +Name[ta]=உலாவிக் காட்சி +Name[te]=అన్వేషి వీక్షణం +Name[tg]=Намуди Хониши Парешон +Name[th]=มุมมองแบบบราวเซอร์ +Name[tr]=Tarayıcı Görünümü +Name[tt]=Browser Küreneşe +Name[uk]=Вигляд "Навігація" +Name[uz]=Brauzerning koʻrinishi +Name[uz@cyrillic]=Браузернинг кўриниши +Name[ven]=U vhona ha Burausu +Name[vi]=Xem duyệt +Name[xh]=Imboniselo Yomkhangeli zincwadi +Name[zh_CN]=浏览器视图 +Name[zh_HK]=瀏覽器視圖 +Name[zh_TW]=瀏覽器視圖 +Name[zu]=Umbonisi Womgcingi + +# Arguments passed to the factory (e.g. view sub-type) +[PropertyDef::X-TDE-BrowserView-Args] +Type=TQString + +# If false, this component won't be used when clicking on a file, +# the user will have to use "Embed in..." to use it (or the application +# will have to explicitely embed this particular service, like for the sidebar) +[PropertyDef::X-TDE-BrowserView-AllowAsDefault] +Type=bool + +# If true, this component won't appear in the "Embed in..." popupmenu +[PropertyDef::X-TDE-BrowserView-HideFromMenus] +Type=bool + +# If true, the view will have its "linked" checkbox checked in Konqueror +# (Was initially for the sidebar, but it's a FollowActive nowadays) +[PropertyDef::X-TDE-BrowserView-LinkedView] +Type=bool + +# If true, this view shows a hierarchical view, i.e. more than one dir at a time +# This is used by KonqPopupMenu to know whether to offer "Create Directory" +# in the RMB menu on a directory (since it depends on whether the user would +# see that new dir). +[PropertyDef::X-TDE-BrowserView-HierarchicalView] +Type=bool + +# If true, the view is passive (can't be made the current active view) +[PropertyDef::X-TDE-BrowserView-PassiveMode] +Type=bool + +# If true, the view can only be there 0 or 1 time in a given window, +# and a toggle action for it will be created (examples: sidebar, konsolepart) +[PropertyDef::X-TDE-BrowserView-Toggable] +Type=bool + +# If the view is toggable, this defines its orientation (Horizontal or Vertical) +[PropertyDef::X-TDE-BrowserView-ToggableView-Orientation] +Type=TQString + +# The name of the property in the view, which the application should set +# in order to quickly switch the view mode (only meaningful in views that +# support multiple modes in the same widget, like the iconview) +[PropertyDef::X-TDE-BrowserView-ModeProperty] +Type=TQString + +# The value to set for the above property +[PropertyDef::X-TDE-BrowserView-ModePropertyValue] +Type=TQString + +# If true, this view will always "follow the active view" (and vice versa: +# when the active view goes to another url, this view will follow). +# Mostly used by the sidebar. +[PropertyDef::X-TDE-BrowserView-FollowActive] +Type=bool + +# If this property is set, this view is "builtin" to the application using it +# The value of the property is the application in question (e.g. "konqueror"). +# This is used 1) to set the active instance to the app's (so the bugs +# go to "konqueror" and not to "konqiconview") and 2) to let konq remember +# that this view was used last. We don't want special-purpose views +# (like Cervisia) to be reactivated (possibly on another directory) next time +# (famous bug). +[PropertyDef::X-TDE-BrowserView-Built-Into] +Type=TQString + +# If the part has a plugin for KHTML Javascript's window.navigator.plugins +# array, it should create a plugin info file and set this property to the +# file path here. The path should be relative to TDE's data dir +# ($TDEDIR/share/apps) +[PropertyDef::X-TDE-BrowserView-PluginsInfo] +Type=TQString diff --git a/tdeparts/componentfactory.h b/tdeparts/componentfactory.h new file mode 100644 index 000000000..6d1b7876b --- /dev/null +++ b/tdeparts/componentfactory.h @@ -0,0 +1,401 @@ +#ifndef __tdeparts_componentfactory_h__ +#define __tdeparts_componentfactory_h__ + +#include <tdeparts/factory.h> +#include <tdeparts/part.h> +#include <ktrader.h> +#include <tqmetaobject.h> + +namespace KParts +{ + + // this is a namespace and not a class because stupid egcs 1.1.2 doesn't grok + // static template methods in classes. !@%@#$! + /** + * Namespace for KParts components + */ + namespace ComponentFactory + { + /** + * This enum type defines the possible error cases that can happen + * when loading a component. + * + * <ul> + * <li><code>ErrNoServiceFound</code> - no service implementing the + * given mimetype and fullfilling the given constraint expression + * can be found.</li> + * <li><code>ErrServiceProvidesNoLibrary</code> - the specified service + * provides no shared library</li> + * <li><code>ErrNoLibrary</code> - the specified library could not be + * loaded. Use KLibLoader::lastErrorMessage for details.</li> + * <li><code>ErrNoFactory</code> - the library does not export a factory + * for creating components</li> + * <li><code>ErrNoComponent</code> - the factory does not support creating + * components of the specified type</li> + * </ul> + */ + enum ComponentLoadingError { ErrNoServiceFound = 1, + ErrServiceProvidesNoLibrary, + ErrNoLibrary, + ErrNoFactory, + ErrNoComponent }; + + /** + * This template function allows to ask the given factory to create an + * instance of the given template type. + * + * Example of usage: + * \code + * MyPlugin *plugin = KParts::ComponentFactory::createInstanceFromFactory<MyPlugin>( factory, parent ); + * \endcode + * + * @param factory The factory to ask for the creation of the component + * @param parent The parent object (see TQObject constructor) + * @param name The name of the object to create (see TQObject constructor) + * @param args A list of string arguments, passed to the factory and possibly + * to the component (see KLibFactory) + * @return A pointer to the newly created object or a null pointer if the + * factory was unable to create an object of the given type. + */ + template <class T> + static T *createInstanceFromFactory( KLibFactory *factory, TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList() ) + { + TQObject *object = factory->create( parent, name, + T::staticMetaObject()->className(), + args ); + + T *result = tqt_dynamic_cast<T *>( object ); + if ( !result ) + delete object; + return result; + } + + /** + * This template function allows to ask the given tdeparts factory to create an + * instance of the given template type. + * + * Example of usage: + * \code + * KViewPart *doc = KParts::ComponentFactory::createPartInstanceFromFactory<KViewPart>( factory, parent ); + * \endcode + * + * @param factory The factory to ask for the creation of the component + * @param parentWidget the parent widget for the part + * @param widgetName the name of the part's widget + * @param parent The parent object (see TQObject constructor) + * @param name The name of the object to create (see TQObject constructor) + * @param args A list of string arguments, passed to the factory and possibly + * to the component (see KLibFactory) + * @return A pointer to the newly created object or a null pointer if the + * factory was unable to create an object of the given type. + */ + template <class T> + static T *createPartInstanceFromFactory( KParts::Factory *factory, + TQWidget *parentWidget = 0, + const char *widgetName = 0, + TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList() ) + { + KParts::Part *object = factory->createPart( parentWidget, widgetName, + parent, name, + T::staticMetaObject()->className(), + args ); + + T *result = tqt_dynamic_cast<T *>( object ); + if ( !result ) + delete object; + return result; + } + + /** + * This template allows to load the specified library and ask the + * factory to create an instance of the given template type. + * + * @param libraryName The library to open + * @param parent The parent object (see TQObject constructor) + * @param name The name of the object to create (see TQObject constructor) + * @param args A list of string arguments, passed to the factory and possibly + * to the component (see KLibFactory) + * @param error + * @return A pointer to the newly created object or a null pointer if the + * factory was unable to create an object of the given type. + */ + template <class T> + static T *createInstanceFromLibrary( const char *libraryName, TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList(), + int *error = 0 ) + { + KLibrary *library = KLibLoader::self()->library( libraryName ); + if ( !library ) + { + if ( error ) + *error = ErrNoLibrary; + return 0; + } + KLibFactory *factory = library->factory(); + if ( !factory ) + { + library->unload(); + if ( error ) + *error = ErrNoFactory; + return 0; + } + T *res = createInstanceFromFactory<T>( factory, parent, name, args ); + if ( !res ) + { + library->unload(); + if ( error ) + *error = ErrNoComponent; + } + return res; + } + + template <class T> + static T *createPartInstanceFromLibrary( const char *libraryName, + TQWidget *parentWidget = 0, + const char *widgetName = 0, + TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList(), + int *error = 0 ) + { + KLibrary *library = KLibLoader::self()->library( libraryName ); + if ( !library ) + { + if ( error ) + *error = ErrNoLibrary; + return 0; + } + KLibFactory *factory = library->factory(); + if ( !factory ) + { + library->unload(); + if ( error ) + *error = ErrNoFactory; + return 0; + } + KParts::Factory *partFactory = tqt_dynamic_cast<KParts::Factory *>( factory ); + if ( !partFactory ) + { + library->unload(); + if ( error ) + *error = ErrNoFactory; + return 0; + } + T *res = createPartInstanceFromFactory<T>( partFactory, parentWidget, + widgetName, parent, name, args ); + if ( !res ) + { + library->unload(); + if ( error ) + *error = ErrNoComponent; + } + return res; + } + + template <class T> + static T *createInstanceFromService( const KService::Ptr &service, + TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList(), + int *error = 0 ) + { + TQString library = service->library(); + if ( library.isEmpty() ) + { + if ( error ) + *error = ErrServiceProvidesNoLibrary; + return 0; + } + + return createInstanceFromLibrary<T>( library.local8Bit().data(), parent, + name, args, error ); + } + + template <class T> + static T *createPartInstanceFromService( const KService::Ptr &service, + TQWidget *parentWidget = 0, + const char *widgetName = 0, + TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList(), + int *error = 0 ) + { + TQString library = service->library(); + if ( library.isEmpty() ) + { + if ( error ) + *error = ErrServiceProvidesNoLibrary; + return 0; + } + + return createPartInstanceFromLibrary<T>( library.local8Bit().data(), parentWidget, + widgetName, parent, name, args, error ); + } + + template <class T, class ServiceIterator> + static T *createInstanceFromServices( ServiceIterator begin, ServiceIterator end, + TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList(), + int *error = 0 ) + { + for (; begin != end; ++begin ) + { + KService::Ptr service = *begin; + + if ( error ) + *error = 0; + + T *component = createInstanceFromService<T>( service, parent, name, + args, error ); + if ( component ) + return component; + } + + if ( error ) + *error = ErrNoServiceFound; + + return 0; + + } + + template <class T, class ServiceIterator> + static T *createPartInstanceFromServices( ServiceIterator begin, + ServiceIterator end, + TQWidget *parentWidget = 0, + const char *widgetName = 0, + TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList(), + int *error = 0 ) + { + for (; begin != end; ++begin ) + { + KService::Ptr service = *begin; + + if ( error ) + *error = 0; + + T *component = createPartInstanceFromService<T>( service, parentWidget, + widgetName, parent, + name, args, error ); + if ( component ) + return component; + } + + if ( error ) + *error = ErrNoServiceFound; + + return 0; + + } + + /** + * This method creates and returns a plugin, from the trader query for a given serviceType. + * + * Example: + * \code + * KMyAppPlugin* plugin = KParts::ComponentFactory::createInstanceFromQuery<KMyAppPlugin>( serviceType, TQString::null, parentObject ); + * if ( plugin ) { + * .... + * } + * \endcode + * + * @param serviceType the type of service for which to find a plugin + * @param constraint an optional constraint to pass to the trader (see TDEIO::KTrader) + * @param parent the parent object for the part itself + * @param name the name that will be given to the part + * @param args A list of string arguments, passed to the factory and possibly + * to the component (see KLibFactory) + * @param error The int passed here will receive an error code in case of errors. + * (See enum #ComponentLoadingError) + * @return A pointer to the newly created object or a null pointer if the + * factory was unable to create an object of the given type. + */ + template <class T> + static T *createInstanceFromQuery( const TQString &serviceType, + const TQString &constraint = TQString::null, + TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList(), + int *error = 0 ) + { + KTrader::OfferList offers = KTrader::self()->query( serviceType, constraint ); + if ( offers.isEmpty() ) + { + if ( error ) + *error = ErrNoServiceFound; + return 0; + } + + return createInstanceFromServices<T>( offers.begin(), + offers.end(), + parent, name, args, error ); + } + + /** + * This method creates and returns a KParts part from a serviceType (e.g. a mimetype). + * + * You can use this method to create a generic viewer - that can display any + * kind of file, provided that there is a ReadOnlyPart installed for it - in 5 lines: + * \code + * // Given the following: KURL url, TQWidget* parentWidget and TQObject* parentObject. + * TQString mimetype = KMimeType::findByURL( url )->name(); + * KParts::ReadOnlyPart* part = KParts::ComponentFactory::createPartInstanceFromQuery<KParts::ReadOnlyPart>( mimetype, TQString::null, parentWidget, 0, parentObject, 0 ); + * if ( part ) { + * part->openURL( url ); + * part->widget()->show(); // also insert the widget into a layout, or simply use a TQVBox as parentWidget + * } + * \endcode + * + * @param serviceType the type of service for which to find a part, e.g. a mimetype + * @param constraint an optional constraint to pass to the trader (see KTrader) + * @param parentWidget the parent widget, will be set as the parent of the part's widget + * @param widgetName the name that will be given to the part's widget + * @param parent the parent object for the part itself + * @param name the name that will be given to the part + * @param args A list of string arguments, passed to the factory and possibly + * to the component (see KLibFactory) + * @param error The int passed here will receive an error code in case of errors. + * (See enum #ComponentLoadingError) + * @return A pointer to the newly created object or a null pointer if the + * factory was unable to create an object of the given type. + */ + template <class T> + static T *createPartInstanceFromQuery( const TQString &serviceType, + const TQString &constraint, + TQWidget *parentWidget = 0, + const char *widgetName = 0, + TQObject *parent = 0, + const char *name = 0, + const TQStringList &args = TQStringList(), + int *error = 0 ) + { + KTrader::OfferList offers = KTrader::self()->query( serviceType, TQString::fromLatin1("KParts/ReadOnlyPart"), constraint, TQString::null ); + if ( offers.isEmpty() ) + { + if ( error ) + *error = ErrNoServiceFound; + return 0; + } + + return createPartInstanceFromServices<T>( offers.begin(), offers.end(), + parentWidget, widgetName, + parent, name, args, error ); + } + + } + +} + +/* + * vim: et sw=4 + */ + +#endif + diff --git a/tdeparts/design.h b/tdeparts/design.h new file mode 100644 index 000000000..ba608d777 --- /dev/null +++ b/tdeparts/design.h @@ -0,0 +1,28 @@ +/** + * @mainpage Framework for KDE graphical components + * + * + * + * This library implements the framework for KDE parts, which are + * elaborate widgets with a user-interface defined in terms of actions + * (menu items, toolbar icons). See KParts::Part. + * + * The library also provides a framework for applications that want to + * use parts. Such applications need to inherit their main window + * from KParts::MainWindow and provide a so-called shell GUI, + * which provides a basic skeleton GUI with part-independent functionality/actions. + * + * Some KParts applications won't be specific to a given part, but expect + * to be able to embed, for instance, all types of viewers out there. For this + * the basic functionality of any viewer has been implemented in + * KParts::ReadOnlyPart, which viewer-like parts should inherit from. + * The same applies to KParts::ReadWritePart, which is for editor-like parts. + * + * You can add actions to an existing KParts app from "outside", defining + * the code for those actions in a shared library. This mechanism is + * obviously called plugins, and implemented by KParts::Plugin. + * + * For a complete, and very simple, example of how to use KParts to display + * any kind of file (i.e. making a generic viewer), see the docu for + * KParts::ComponentFactory::createPartInstanceFromQuery() + */ diff --git a/tdeparts/dockmainwindow.cpp b/tdeparts/dockmainwindow.cpp new file mode 100644 index 000000000..ce462e691 --- /dev/null +++ b/tdeparts/dockmainwindow.cpp @@ -0,0 +1,166 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Falk Brettschneider <[email protected]> + (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <tdeparts/dockmainwindow.h> +#include <tdeparts/event.h> +#include <tdeparts/part.h> +#include <kaccel.h> +#include <tdeparts/plugin.h> +#include <kstatusbar.h> +#include <kinstance.h> +#include <khelpmenu.h> +#include <kstandarddirs.h> +#include <tqapplication.h> + +#include <kdebug.h> +#include <kxmlguifactory.h> + +#include <assert.h> + +using namespace KParts; + +namespace KParts +{ +class DockMainWindowPrivate +{ +public: + DockMainWindowPrivate() + { + m_activePart = 0; + m_bShellGUIActivated = false; + m_helpMenu = 0; + } + ~DockMainWindowPrivate() + { + } + + TQGuardedPtr<Part> m_activePart; + bool m_bShellGUIActivated; + KHelpMenu *m_helpMenu; +}; +} + +DockMainWindow::DockMainWindow( TQWidget* parent, const char *name, WFlags f ) + : KDockMainWindow( parent, name, f ) +{ + d = new DockMainWindowPrivate(); + PartBase::setPartObject( TQT_TQOBJECT(this) ); +} + +DockMainWindow::~DockMainWindow() +{ + delete d; +} + +void DockMainWindow::createGUI( Part * part ) +{ + kdDebug(1000) << TQString(TQString("DockMainWindow::createGUI for %1").arg(part?part->name():"0L")) << endl; + + KXMLGUIFactory *factory = guiFactory(); + + setUpdatesEnabled( false ); + + TQPtrList<Plugin> plugins; + + if ( d->m_activePart ) + { + kdDebug(1000) << TQString(TQString("deactivating GUI for %1").arg(d->m_activePart->name())) << endl; + + GUIActivateEvent ev( false ); + TQApplication::sendEvent( d->m_activePart, &ev ); + + factory->removeClient( d->m_activePart ); + + disconnect( d->m_activePart, TQT_SIGNAL( setWindowCaption( const TQString & ) ), + this, TQT_SLOT( setCaption( const TQString & ) ) ); + disconnect( d->m_activePart, TQT_SIGNAL( setStatusBarText( const TQString & ) ), + this, TQT_SLOT( slotSetStatusBarText( const TQString & ) ) ); + } + + if ( !d->m_bShellGUIActivated ) + { + loadPlugins( TQT_TQOBJECT(this), this, TDEGlobal::instance() ); + createShellGUI(); + d->m_bShellGUIActivated = true; + } + + if ( part ) + { + // do this before sending the activate event + connect( part, TQT_SIGNAL( setWindowCaption( const TQString & ) ), + this, TQT_SLOT( setCaption( const TQString & ) ) ); + connect( part, TQT_SIGNAL( setStatusBarText( const TQString & ) ), + this, TQT_SLOT( slotSetStatusBarText( const TQString & ) ) ); + + factory->addClient( part ); + + GUIActivateEvent ev( true ); + TQApplication::sendEvent( part, &ev ); + + } + + setUpdatesEnabled( true ); + + d->m_activePart = part; +} + +void DockMainWindow::slotSetStatusBarText( const TQString & text ) +{ + statusBar()->message( text ); +} + +void DockMainWindow::createShellGUI( bool create ) +{ + bool bAccelAutoUpdate = accel()->setAutoUpdate( false ); + assert( d->m_bShellGUIActivated != create ); + d->m_bShellGUIActivated = create; + if ( create ) + { + if ( isHelpMenuEnabled() ) + d->m_helpMenu = new KHelpMenu( this, instance()->aboutData(), true, actionCollection() ); + + TQString f = xmlFile(); + setXMLFile( locate( "config", "ui/ui_standards.rc", instance() ) ); + if ( !f.isEmpty() ) + setXMLFile( f, true ); + else + { + TQString auto_file( instance()->instanceName() + "ui.rc" ); + setXMLFile( auto_file, true ); + } + + GUIActivateEvent ev( true ); + TQApplication::sendEvent( this, &ev ); + + guiFactory()->addClient( this ); + + } + else + { + GUIActivateEvent ev( false ); + TQApplication::sendEvent( this, &ev ); + + guiFactory()->removeClient( this ); + } + accel()->setAutoUpdate( bAccelAutoUpdate ); +} + +#include "dockmainwindow.moc" diff --git a/tdeparts/dockmainwindow.h b/tdeparts/dockmainwindow.h new file mode 100644 index 000000000..223bd3a42 --- /dev/null +++ b/tdeparts/dockmainwindow.h @@ -0,0 +1,88 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Falk Brettschneider <[email protected]> + (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __DOCKMAINWINDOW_H +#define __DOCKMAINWINDOW_H + +#include <tqptrlist.h> +#include <kaction.h> + +#include <kdockwidget.h> + +#include <tdeparts/part.h> + +class TQString; + +namespace KParts +{ + +class DockMainWindowPrivate; + +/** + * A KPart-aware main window with ability for docking widgets, whose user interface is described in XML. + * + * Inherit your main dock-window from this class + * and don't forget to call setXMLFile() in the inherited constructor. + * + * It implements all internal interfaces in the case of a KDockMainWindow as host: + * the builder and servant interface (for menu merging). + */ +class KPARTS_EXPORT DockMainWindow : public KDockMainWindow, virtual public PartBase +{ + Q_OBJECT + public: + /** + * Constructor, same signature as KDockMainWindow. + */ + DockMainWindow( TQWidget* parent = 0L, const char *name = 0L, WFlags f = (WFlags)WDestructiveClose ); + /** + * Destructor. + */ + virtual ~DockMainWindow(); + +protected slots: + + /** + * Create the GUI (by merging the host's and the active part's) + * + * Called on startup and whenever the active part changes. + * For this you need to connect this slot to the + * PartManager::activePartChanged() signal + * @param part The active part (set to 0L if no part). + */ + void createGUI( KParts::Part * part ); + + /** + * Called when the active part wants to change the statusbar message. + * Reimplement if your dock-mainwindow has a complex statusbar + * (with several items) + */ + virtual void slotSetStatusBarText( const TQString & ); + +protected: + virtual void createShellGUI( bool create = true ); + + private: + DockMainWindowPrivate *d; + }; + +} + +#endif diff --git a/tdeparts/event.cpp b/tdeparts/event.cpp new file mode 100644 index 000000000..a25d61640 --- /dev/null +++ b/tdeparts/event.cpp @@ -0,0 +1,58 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include <tdeparts/event.h> + +using namespace KParts; + +//the answer! +#define KPARTS_EVENT_MAGIC 42 + +Event::Event( const char *eventName ) + : TQCustomEvent( (TQEvent::Type)(TQEvent::User + KPARTS_EVENT_MAGIC), (void *)eventName ) +{ +} + +const char *Event::eventName() const +{ + if ( !test( this ) ) + return 0L; + + return (const char *)data(); +} + +bool Event::test( const TQEvent *event ) +{ + if ( !event ) + return false; + + return ( event->type() == (TQEvent::Type)(TQEvent::User + KPARTS_EVENT_MAGIC ) ); +} + +bool Event::test( const TQEvent *event, const char *name ) +{ + if ( !test( event ) ) + return false; + + return ( strcmp( name, (const char *)((TQCustomEvent *)event)->data() ) == 0 ); +} + +const char *GUIActivateEvent::s_strGUIActivateEvent = "KParts/GUIActivate"; +const char *PartActivateEvent::s_strPartActivateEvent = "KParts/PartActivateEvent"; +const char *PartSelectEvent::s_strPartSelectEvent = "KParts/PartSelectEvent"; diff --git a/tdeparts/event.h b/tdeparts/event.h new file mode 100644 index 000000000..65f1c7be9 --- /dev/null +++ b/tdeparts/event.h @@ -0,0 +1,120 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __tdeparts_event_h__ +#define __tdeparts_event_h__ + +#include <tqevent.h> + +#include <tdelibs_export.h> + +class TQWidget; + +namespace KParts +{ +class Part; + +/** + * Base class for all KParts events. + */ +class KPARTS_EXPORT Event : public TQCustomEvent +{ +public: + Event( const char *eventName ); + + virtual const char *eventName() const; + + static bool test( const TQEvent *event ); + static bool test( const TQEvent *event, const char *name ); +}; + +/** + * This event is sent to a Part when its GUI has been activated or deactivated. + * This is related to PartActivateEvent, but the difference is that + * GUIActivateEvent happens later (when the GUI is actually built), + * only for parts that have GUI elements, and only if using KParts::MainWindow. + * @see KParts::Part::guiActivateEvent() + */ +class KPARTS_EXPORT GUIActivateEvent : public Event +{ +public: + GUIActivateEvent( bool activated ) : Event( s_strGUIActivateEvent ), m_bActivated( activated ) {} + + bool activated() const { return m_bActivated; } + + static bool test( const TQEvent *event ) { return Event::test( event, s_strGUIActivateEvent ); } + +private: + static const char *s_strGUIActivateEvent; + bool m_bActivated; +}; + +/** + * This event is sent by the part manager when the active part changes. + * Each time the active part changes, it will send first a PartActivateEvent + * with activated=false, part=oldActivePart, widget=oldActiveWidget + * and then another PartActivateEvent + * with activated=true, part=newPart, widget=newWidget. + * @see KParts::Part::partActivateEvent + */ +class KPARTS_EXPORT PartActivateEvent : public Event +{ +public: + PartActivateEvent( bool activated, Part *part, TQWidget *widget ) : Event( s_strPartActivateEvent ), m_bActivated( activated ), m_part( part ), m_widget( widget ) {} + + bool activated() const { return m_bActivated; } + + Part *part() const { return m_part; } + TQWidget *widget() const { return m_widget; } + + static bool test( const TQEvent *event ) { return Event::test( event, s_strPartActivateEvent ); } + +private: + static const char *s_strPartActivateEvent; + bool m_bActivated; + Part *m_part; + TQWidget *m_widget; +}; + +/** + * This event is sent when a part is selected or deselected. + * @see KParts::PartManager::setSelectionPolicy + */ +class KPARTS_EXPORT PartSelectEvent : public Event +{ +public: + PartSelectEvent( bool selected, Part *part, TQWidget *widget ) : Event( s_strPartSelectEvent ), m_bSelected( selected ), m_part( part ), m_widget( widget ) {} + + bool selected() const { return m_bSelected; } + + Part *part() const { return m_part; } + TQWidget *widget() const { return m_widget; } + + static bool test( const TQEvent *event ) { return Event::test( event, s_strPartSelectEvent ); } + +private: + static const char *s_strPartSelectEvent; + bool m_bSelected; + Part *m_part; + TQWidget *m_widget; +}; + +} // namespace + +#endif diff --git a/tdeparts/factory.cpp b/tdeparts/factory.cpp new file mode 100644 index 000000000..a3985fd05 --- /dev/null +++ b/tdeparts/factory.cpp @@ -0,0 +1,82 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "factory.h" +#include "part.h" + +#include <tqwidget.h> + +#include <klocale.h> +#include <kglobal.h> +#include <kinstance.h> +#include <assert.h> + +using namespace KParts; + +Factory::Factory( TQObject *parent, const char *name ) +: KLibFactory( parent, name ) +{ +} + +Factory::~Factory() +{ +} + +Part *Factory::createPart( TQWidget *parentWidget, const char *widgetName, TQObject *parent, const char *name, const char *classname, const TQStringList &args ) +{ + Part* part = createPartObject( parentWidget, widgetName, parent, name, classname, args ); + if ( part ) + emit objectCreated( part ); + return part; +} + +const TDEInstance *Factory::partInstance() +{ + QueryInstanceParams params; + params.instance = 0; + virtual_hook( VIRTUAL_QUERY_INSTANCE_PARAMS, ¶ms ); + return params.instance; +} + +const TDEInstance *Factory::partInstanceFromLibrary( const TQCString &libraryName ) +{ + KLibrary *library = KLibLoader::self()->library( libraryName ); + if ( !library ) + return 0; + KLibFactory *factory = library->factory(); + if ( !factory ) + return 0; + KParts::Factory *pfactory = tqt_dynamic_cast<KParts::Factory *>( factory ); + if ( !pfactory ) + return 0; + return pfactory->partInstance(); +} + +Part *Factory::createPartObject( TQWidget *, const char *, TQObject *, const char *, const char *, const TQStringList & ) +{ + return 0; +} + +TQObject *Factory::createObject( TQObject *parent, const char *name, const char *classname, const TQStringList &args ) +{ + assert( !parent || parent->isWidgetType() ); + return createPart( TQT_TQWIDGET( parent ), name, parent, name, classname, args ); +} +#include "factory.moc" diff --git a/tdeparts/factory.h b/tdeparts/factory.h new file mode 100644 index 000000000..3a6f3e4ed --- /dev/null +++ b/tdeparts/factory.h @@ -0,0 +1,142 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __tdeparts_factory_h__ +#define __tdeparts_factory_h__ + +#include <klibloader.h> + +class TQWidget; + +namespace KParts +{ + +class Part; + +/** + * A generic factory object to create a Part. + * + * Factory is an abstract class. Reimplement the + * createPartObject() method to give it functionality. + * + * @see KLibFactory. + */ +class KPARTS_EXPORT Factory : public KLibFactory +{ + Q_OBJECT +public: + Factory( TQObject *parent = 0, const char *name = 0 ); + virtual ~Factory(); + + /** + * Creates a part. + * + * The TQStringList can be used to pass additional arguments to the part. + * If the part needs additional arguments, it should take them as + * name="value" pairs. This is the way additional arguments will get passed + * to the part from eg. tdehtml. You can for example embed the part into HTML + * by using the following code: + * \code + * <object type="my_mimetype" data="url_to_my_data"> + * <param name="name1" value="value1"> + * <param name="name2" value="value2"> + * </object> + * \endcode + * This could result in a call to + * \code + * createPart( parentWidget, name, parentObject, parentName, "KParts::Part", + * TQStringList("name1="value1"", "name2="value2") ); + * \endcode + * + * @returns the newly created part. + * + * createPart() automatically emits a signal KLibFactory::objectCreated to tell + * the library about its newly created object. This is very + * important for reference counting, and allows unloading the + * library automatically once all its objects have been destroyed. + */ + Part *createPart( TQWidget *parentWidget = 0, const char *widgetName = 0, TQObject *parent = 0, const char *name = 0, const char *classname = "KParts::Part", const TQStringList &args = TQStringList() ); + + /** + * If you have a part contained in a shared library you might want to query + * for meta-information like the about-data, or the TDEInstance in general. + * If the part is exported using KParts::GenericFactory then this method will + * return the instance that belongs to the part without the need to instantiate + * the part component. + */ + const TDEInstance *partInstance(); + + /** + * A convenience method for partInstance() that takes care of retrieving + * the factory for a given library name and calling partInstance() on it. + * + * @param libraryName name of the library to query the instance from + */ + static const TDEInstance *partInstanceFromLibrary( const TQCString &libraryName ); + +protected: + + /** + * Reimplement this method in your implementation to create the Part. + * + * The TQStringList can be used to pass additional arguments to the part. + * If the part needs additional arguments, it should take them as + * name="value" pairs. This is the way additional arguments will get passed + * to the part from eg. tdehtml. You can for example emebed the part into HTML + * by using the following code: + * \code + * <object type="my_mimetype" data="url_to_my_data"> + * <param name="name1" value="value1"> + * <param name="name2" value="value2"> + * </object> + * \endcode + * This could result in a call to + * \code + * createPart( parentWidget, name, parentObject, parentName, "Kparts::Part", + * TQStringList("name1="value1"", "name2="value2") ); + * \endcode + * + * @returns the newly created part. + */ + virtual Part *createPartObject( TQWidget *parentWidget = 0, const char *widgetName = 0, TQObject *parent = 0, const char *name = 0, const char *classname = "KParts::Part", const TQStringList &args = TQStringList() ) = 0; + + /** + * Reimplemented from KLibFactory. Calls createPart() + */ + virtual TQObject *createObject( TQObject *parent = 0, const char *name = 0, const char *classname = TQOBJECT_OBJECT_NAME_STRING, const TQStringList &args = TQStringList() ); + + /** This 'enum' along with the structure below is NOT part of the public API. + * It's going to disappear in KDE 4.0 and is likely to change inbetween. + * + * @internal + */ + enum { VIRTUAL_QUERY_INSTANCE_PARAMS = 0x10 }; + struct QueryInstanceParams + { + const TDEInstance *instance; + }; +}; + +} + +/* + * vim: et sw=4 + */ + +#endif diff --git a/tdeparts/genericfactory.h b/tdeparts/genericfactory.h new file mode 100644 index 000000000..40e61be9f --- /dev/null +++ b/tdeparts/genericfactory.h @@ -0,0 +1,203 @@ +#ifndef __tdeparts__genericfactory_h__ +#define __tdeparts__genericfactory_h__ + +#include <tdeparts/factory.h> +#include <tdeparts/part.h> +#include <kgenericfactory.h> +#include <kaboutdata.h> +#include <kdebug.h> + +namespace KParts +{ + + /** + * @internal + */ + template <class T> + class GenericFactoryBase : public KParts::Factory + { + public: + GenericFactoryBase() + { + if ( s_self ) + kdWarning() << "KParts::GenericFactory instantiated more than once!" << endl; + s_self = this; + } + virtual ~GenericFactoryBase() + { + delete s_aboutData; + delete s_instance; + s_aboutData = 0; + s_instance = 0; + s_self = 0; + } + + static TDEInstance *instance(); + static TDEAboutData *aboutData(); + + protected: + virtual TDEInstance *createInstance() + { + return new TDEInstance( aboutData() ); + } + + virtual void virtual_hook( int id, void *data ) + { + if ( id != VIRTUAL_QUERY_INSTANCE_PARAMS ) { + KParts::Factory::virtual_hook( id, data ); + return; + } + + QueryInstanceParams *params = reinterpret_cast<QueryInstanceParams *>( data ); + params->instance = instance(); + } + + private: + static GenericFactoryBase<T> *s_self; + static TDEInstance *s_instance; + static TDEAboutData *s_aboutData; + }; + + /** + * A template for a KParts::Factory implementation. It implements the pure virtual + * createPartObject method by instantiating the template argument when requested + * through the className field. In addition it is a container for a part's TDEInstance + * object, by providing a static TDEInstance *instance() method. + * + * The template argument has to inherit from KParts::Part and has to implement two methods: + * 1) There needs to be a public constructor with the following signature: + * MyPart( TQWidget *parentWidget, const char *widgetName, TQObject *parent, const char *name, const TQStringList& args ) + * + * 2) It needs to provide one static method to create a TDEAboutData object per + * request, holding information about the component's name, its authors, license, etc. + * The signature of that static method has to be + * TDEAboutData *createAboutData() + * + * The template will take care of memory management of the TDEInstance and the TDEAboutData object, + * meaning ownership of what createAboutData returns is passed to the caller (this template) . + * + * For advanced use you can also inherit from the template and re-implement additionally the + * virtual TDEInstance *createInstance() method, for example in case you want to extend the + * paths of your instance's KStandardDirs object. + * + * If a KParts::ReadOnlyPart is requested through this factory and the template argument + * implements a KParts::ReadWritePart then setReadWrite( false ) will automatically be + * called in createPartObject. + * + * Use the factory through the K_EXPORT_COMPONENT_FACTORY macro, like that: + * \code + * typedef KParts::GenericFactory<YourKPart> YourKPartFactory; + * K_EXPORT_COMPONENT_FACTORY( yourlibrary, YourKPartFactory ) + * \endcode + * yourlibrary is the library name that you compiled your KPart into. + */ + template <class T> + class GenericFactory : public GenericFactoryBase<T> + { + public: + GenericFactory() { } + + virtual KParts::Part *createPartObject( TQWidget *parentWidget, const char *widgetName, + TQObject *parent, const char *name, + const char *className, + const TQStringList &args ) + { + T *part = KDEPrivate::ConcreteFactory<T>::create( parentWidget, + widgetName, + parent, + name, + className, + args ); + + if ( part && !qstrcmp( className, "KParts::ReadOnlyPart" ) ) + { + KParts::ReadWritePart *rwp = tqt_dynamic_cast<KParts::ReadWritePart *>( part ); + if ( rwp ) + rwp->setReadWrite( false ); + } + return part; + } + }; + + template <class T1, class T2> + class GenericFactory< KTypeList<T1, T2> > : public GenericFactoryBase<T1> + { + public: + GenericFactory() { } + + virtual KParts::Part *createPartObject( TQWidget *parentWidget, const char *widgetName, + TQObject *parent, const char *name, + const char *className, + const TQStringList &args ) + { + TQObject *object = KDEPrivate::MultiFactory< KTypeList<T1, T2> >::create( parentWidget, + widgetName, + parent, name, + className, + args ); + + // (this cast is guaranteed to work...) + KParts::Part *part = tqt_dynamic_cast<KParts::Part *>( object ); + + if ( part && !qstrcmp( className, "KParts::ReadOnlyPart" ) ) + { + KParts::ReadWritePart *rwp = tqt_dynamic_cast<KParts::ReadWritePart *>( part ); + if ( rwp ) + rwp->setReadWrite( false ); + } + return part; + } + }; + + /** + * @internal + */ + template <class T> + GenericFactoryBase<T> *GenericFactoryBase<T>::s_self = 0; + + /** + * @internal + */ + template <class T> + TDEInstance *GenericFactoryBase<T>::s_instance = 0; + + /** + * @internal + */ + template <class T> + TDEAboutData *GenericFactoryBase<T>::s_aboutData = 0; + + /** + * @internal + */ + template <class T> + TDEInstance *GenericFactoryBase<T>::instance() + { + if ( !s_instance ) + { + if ( s_self ) + s_instance = s_self->createInstance(); + else + s_instance = new TDEInstance( aboutData() ); + } + return s_instance; + } + + /** + * @internal + */ + template <class T> + TDEAboutData *GenericFactoryBase<T>::aboutData() + { + if ( !s_aboutData ) + s_aboutData = T::createAboutData(); + return s_aboutData; + } + +} + +#endif + +/** + * vim: et sw=4 + */ diff --git a/tdeparts/historyprovider.cpp b/tdeparts/historyprovider.cpp new file mode 100644 index 000000000..17cf609a1 --- /dev/null +++ b/tdeparts/historyprovider.cpp @@ -0,0 +1,90 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Carsten Pfeiffer <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <tqdict.h> + +#include <kapplication.h> + +#include "historyprovider.h" + +using namespace KParts; +template class TQDict<void>; + +HistoryProvider * HistoryProvider::s_self = 0L; + +class HistoryProvider::HistoryProviderPrivate +{ +public: + HistoryProviderPrivate() + : dict( 1009 ) {} + + TQDict<void> dict; +}; + +HistoryProvider * HistoryProvider::self() +{ + if ( !s_self ) + s_self = new HistoryProvider( TQT_TQOBJECT(kapp), "history provider" ); + return s_self; +} + +HistoryProvider::HistoryProvider( TQObject *parent, const char *name ) + : TQObject( parent, name ) +{ + if ( !s_self ) + s_self = this; + + d = new HistoryProviderPrivate; +} + +HistoryProvider::~HistoryProvider() +{ + delete d; + + if ( s_self == this ) + s_self = 0; +} + +bool HistoryProvider::contains( const TQString& item ) const +{ + return (bool) d->dict.find( item ); +} + +void HistoryProvider::insert( const TQString& item ) +{ + // no need to allocate memory, we only want to have fast lookup, no mapping + d->dict.replace( item, (void*) 1 ); + emit inserted( item ); +} + +void HistoryProvider::remove( const TQString& item ) +{ + (void) d->dict.remove( item ); +} + +void HistoryProvider::clear() +{ + d->dict.clear(); + emit cleared(); +} + +void HistoryProvider::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +#include "historyprovider.moc" diff --git a/tdeparts/historyprovider.h b/tdeparts/historyprovider.h new file mode 100644 index 000000000..1123981ec --- /dev/null +++ b/tdeparts/historyprovider.h @@ -0,0 +1,109 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Carsten Pfeiffer <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KHISTORYPROVIDER_H +#define KHISTORYPROVIDER_H + +#include <tqdict.h> +#include <tqobject.h> + +#include <tdelibs_export.h> + +namespace KParts { + +/** + * Basic class to manage a history of "items". This class is only meant + * for fast lookup, if an item is in the history or not. + * + * May be subclassed to implement a persistent history for example. + * For usage with tdehtml, just create your provider and call the + * HistoryProvider constructor _before_ you do any tdehtml stuff. That way, + * tdehtml, using the self()-method, will use your subclassed provider. + * + * @author Carsten Pfeiffer <[email protected]> + */ +class KPARTS_EXPORT HistoryProvider : public TQObject +{ + Q_OBJECT + +public: + static HistoryProvider * self(); + + /** + * Creates a KHistoryProvider with an optional parent and name + */ + HistoryProvider( TQObject *parent = 0L, const char *name = 0 ); + + /** + * Destroys the provider. + */ + virtual ~HistoryProvider(); + + /** + * @returns true if @p item is present in the history. + */ + virtual bool contains( const TQString& item ) const; + + /** + * Inserts @p item into the history. + */ + virtual void insert( const TQString& item ); + + /** + * Removes @p item from the history. + */ + virtual void remove( const TQString& item ); + + /** + * Clears the history. The cleared() signal is emitted after clearing. + */ + virtual void clear(); + +signals: + /** + * Emitted after the history has been cleared. + */ + void cleared(); + + /** + * This signal is never emitted from this class, it is only meant as an + * interface for subclasses. Emit this signal to notify others that the + * history has changed. Put those items that were added or removed from the + * history into @p items. + */ + void updated( const TQStringList& items ); + + /** + * Emitted after the item has been inserted + */ + void inserted( const TQString& item ); + +private: + static HistoryProvider *s_self; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class HistoryProviderPrivate; + HistoryProviderPrivate *d; +}; + +} + +#endif // KHISTORYPROVIDER_H diff --git a/tdeparts/kpart.desktop b/tdeparts/kpart.desktop new file mode 100644 index 000000000..ba69bd704 --- /dev/null +++ b/tdeparts/kpart.desktop @@ -0,0 +1,85 @@ +[Desktop Entry] +Type=ServiceType +X-TDE-ServiceType=KPart +Comment=TDE Component +Comment[af]=Tde Komponent +Comment[ar]=عنصر كيدي +Comment[az]=TDE Komponenti +Comment[be]=Кампанент TDE +Comment[bn]=কে.ডি.ই. উপাদান +Comment[br]=Parzhioù TDE +Comment[bs]=TDE komponenta +Comment[ca]=Component del TDE +Comment[cs]=Komponenta TDE +Comment[csb]=Kòmpònent TDE +Comment[cy]=Cydran TDE +Comment[da]=TDE-komponent +Comment[de]=TDE-Komponente +Comment[el]=Στοιχείο του TDE +Comment[eo]=PDF-komponento +Comment[es]=Componente de TDE +Comment[et]=TDE komponent +Comment[eu]=TDEren osagaia +Comment[fa]=مؤلفۀ TDE +Comment[fi]=TDE-komponentti +Comment[fr]=Composant de TDE +Comment[fy]=TDE-komponint +Comment[ga]=Comhpháirt TDE +Comment[gl]=Compoñente de TDE +Comment[he]=רכיב TDE +Comment[hi]=केडीई के घटक +Comment[hr]=TDE komponenta +Comment[hu]=TDE-komponens +Comment[id]=Komponen TDE +Comment[is]=TDE eining +Comment[it]=Componente TDE +Comment[ja]=TDE コンポーネント +Comment[ka]=TDE კომპონენტი +Comment[kk]=TDE компоненті +Comment[km]=សមាសភាគ TDE +Comment[ko]=TDE 구성 요소 +Comment[lb]=TDE-Komponent +Comment[lt]=TDE komponentas +Comment[lv]=TDE Komponente +Comment[mk]=TDE компонента +Comment[mn]=TDE-бүрдэл хэсэг +Comment[ms]=Komponen TDE +Comment[mt]=Komponent tal-TDE +Comment[nb]=TDE-komponent +Comment[nds]=TDE-Komponent +Comment[ne]=TDE अवयव +Comment[nl]=TDE-component +Comment[nn]=TDE-komponent +Comment[nso]=Seripa sa TDE +Comment[oc]=Composant TDE +Comment[pa]=TDE ਭਾਗ +Comment[pl]=Składnik TDE +Comment[pt]=Componente TDE +Comment[pt_BR]=Componente TDE +Comment[ro]=Componentă TDE +Comment[ru]=Компонент TDE +Comment[rw]=Inyangingo TDE +Comment[se]=TDE oassi +Comment[sk]=TDE komponent +Comment[sl]=Komponenta TDE +Comment[sq]=Komponent i TDE-s +Comment[sr]=TDE-ова компонента +Comment[sr@Latn]=TDE-ova komponenta +Comment[ss]=Incenye ye TDE +Comment[sv]=TDE-komponent +Comment[ta]=கேடிஇ பகுதி +Comment[te]=కెడిఈ అంశం +Comment[tg]=Қисмати TDE +Comment[th]=ส่วนประกอบของ TDE +Comment[tr]=TDE Bileşeni +Comment[tt]=TDE Öleşe +Comment[uk]=Компонент TDE +Comment[uz]=TDE komponenti +Comment[uz@cyrillic]=TDE компоненти +Comment[ven]=Khomphonente ya TDE +Comment[vi]=Thành phần TDE. +Comment[xh]=Ingxenye ye TDE +Comment[zh_CN]=TDE 部件 +Comment[zh_HK]=TDE 元件 +Comment[zh_TW]=TDE 元件 +Comment[zu]=Ingxenye ye-TDE diff --git a/tdeparts/krop.desktop b/tdeparts/krop.desktop new file mode 100644 index 000000000..62de2d454 --- /dev/null +++ b/tdeparts/krop.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +Type=ServiceType +X-TDE-ServiceType=KParts/ReadOnlyPart +X-TDE-Derived=KPart +Comment=TDE Component +Comment[af]=Tde Komponent +Comment[ar]=عنصر كيدي +Comment[az]=TDE Komponenti +Comment[be]=Кампанент TDE +Comment[bn]=কে.ডি.ই. উপাদান +Comment[br]=Parzhioù TDE +Comment[bs]=TDE komponenta +Comment[ca]=Component del TDE +Comment[cs]=Komponenta TDE +Comment[csb]=Kòmpònent TDE +Comment[cy]=Cydran TDE +Comment[da]=TDE-komponent +Comment[de]=TDE-Komponente +Comment[el]=Στοιχείο του TDE +Comment[eo]=PDF-komponento +Comment[es]=Componente de TDE +Comment[et]=TDE komponent +Comment[eu]=TDEren osagaia +Comment[fa]=مؤلفۀ TDE +Comment[fi]=TDE-komponentti +Comment[fr]=Composant de TDE +Comment[fy]=TDE-komponint +Comment[ga]=Comhpháirt TDE +Comment[gl]=Compoñente de TDE +Comment[he]=רכיב TDE +Comment[hi]=केडीई के घटक +Comment[hr]=TDE komponenta +Comment[hu]=TDE-komponens +Comment[id]=Komponen TDE +Comment[is]=TDE eining +Comment[it]=Componente TDE +Comment[ja]=TDE コンポーネント +Comment[ka]=TDE კომპონენტი +Comment[kk]=TDE компоненті +Comment[km]=សមាសភាគ TDE +Comment[ko]=TDE 구성 요소 +Comment[lb]=TDE-Komponent +Comment[lt]=TDE komponentas +Comment[lv]=TDE Komponente +Comment[mk]=TDE компонента +Comment[mn]=TDE-бүрдэл хэсэг +Comment[ms]=Komponen TDE +Comment[mt]=Komponent tal-TDE +Comment[nb]=TDE-komponent +Comment[nds]=TDE-Komponent +Comment[ne]=TDE अवयव +Comment[nl]=TDE-component +Comment[nn]=TDE-komponent +Comment[nso]=Seripa sa TDE +Comment[oc]=Composant TDE +Comment[pa]=TDE ਭਾਗ +Comment[pl]=Składnik TDE +Comment[pt]=Componente TDE +Comment[pt_BR]=Componente TDE +Comment[ro]=Componentă TDE +Comment[ru]=Компонент TDE +Comment[rw]=Inyangingo TDE +Comment[se]=TDE oassi +Comment[sk]=TDE komponent +Comment[sl]=Komponenta TDE +Comment[sq]=Komponent i TDE-s +Comment[sr]=TDE-ова компонента +Comment[sr@Latn]=TDE-ova komponenta +Comment[ss]=Incenye ye TDE +Comment[sv]=TDE-komponent +Comment[ta]=கேடிஇ பகுதி +Comment[te]=కెడిఈ అంశం +Comment[tg]=Қисмати TDE +Comment[th]=ส่วนประกอบของ TDE +Comment[tr]=TDE Bileşeni +Comment[tt]=TDE Öleşe +Comment[uk]=Компонент TDE +Comment[uz]=TDE komponenti +Comment[uz@cyrillic]=TDE компоненти +Comment[ven]=Khomphonente ya TDE +Comment[vi]=Thành phần TDE. +Comment[xh]=Ingxenye ye TDE +Comment[zh_CN]=TDE 部件 +Comment[zh_HK]=TDE 元件 +Comment[zh_TW]=TDE 元件 +Comment[zu]=Ingxenye ye-TDE diff --git a/tdeparts/krwp.desktop b/tdeparts/krwp.desktop new file mode 100644 index 000000000..5c6bfee1a --- /dev/null +++ b/tdeparts/krwp.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +Type=ServiceType +X-TDE-ServiceType=KParts/ReadWritePart +X-TDE-Derived=KParts/ReadOnlyPart +Comment=TDE Component +Comment[af]=Tde Komponent +Comment[ar]=عنصر كيدي +Comment[az]=TDE Komponenti +Comment[be]=Кампанент TDE +Comment[bn]=কে.ডি.ই. উপাদান +Comment[br]=Parzhioù TDE +Comment[bs]=TDE komponenta +Comment[ca]=Component del TDE +Comment[cs]=Komponenta TDE +Comment[csb]=Kòmpònent TDE +Comment[cy]=Cydran TDE +Comment[da]=TDE-komponent +Comment[de]=TDE-Komponente +Comment[el]=Στοιχείο του TDE +Comment[eo]=PDF-komponento +Comment[es]=Componente de TDE +Comment[et]=TDE komponent +Comment[eu]=TDEren osagaia +Comment[fa]=مؤلفۀ TDE +Comment[fi]=TDE-komponentti +Comment[fr]=Composant de TDE +Comment[fy]=TDE-komponint +Comment[ga]=Comhpháirt TDE +Comment[gl]=Compoñente de TDE +Comment[he]=רכיב TDE +Comment[hi]=केडीई के घटक +Comment[hr]=TDE komponenta +Comment[hu]=TDE-komponens +Comment[id]=Komponen TDE +Comment[is]=TDE eining +Comment[it]=Componente TDE +Comment[ja]=TDE コンポーネント +Comment[ka]=TDE კომპონენტი +Comment[kk]=TDE компоненті +Comment[km]=សមាសភាគ TDE +Comment[ko]=TDE 구성 요소 +Comment[lb]=TDE-Komponent +Comment[lt]=TDE komponentas +Comment[lv]=TDE Komponente +Comment[mk]=TDE компонента +Comment[mn]=TDE-бүрдэл хэсэг +Comment[ms]=Komponen TDE +Comment[mt]=Komponent tal-TDE +Comment[nb]=TDE-komponent +Comment[nds]=TDE-Komponent +Comment[ne]=TDE अवयव +Comment[nl]=TDE-component +Comment[nn]=TDE-komponent +Comment[nso]=Seripa sa TDE +Comment[oc]=Composant TDE +Comment[pa]=TDE ਭਾਗ +Comment[pl]=Składnik TDE +Comment[pt]=Componente TDE +Comment[pt_BR]=Componente TDE +Comment[ro]=Componentă TDE +Comment[ru]=Компонент TDE +Comment[rw]=Inyangingo TDE +Comment[se]=TDE oassi +Comment[sk]=TDE komponent +Comment[sl]=Komponenta TDE +Comment[sq]=Komponent i TDE-s +Comment[sr]=TDE-ова компонента +Comment[sr@Latn]=TDE-ova komponenta +Comment[ss]=Incenye ye TDE +Comment[sv]=TDE-komponent +Comment[ta]=கேடிஇ பகுதி +Comment[te]=కెడిఈ అంశం +Comment[tg]=Қисмати TDE +Comment[th]=ส่วนประกอบของ TDE +Comment[tr]=TDE Bileşeni +Comment[tt]=TDE Öleşe +Comment[uk]=Компонент TDE +Comment[uz]=TDE komponenti +Comment[uz@cyrillic]=TDE компоненти +Comment[ven]=Khomphonente ya TDE +Comment[vi]=Thành phần TDE. +Comment[xh]=Ingxenye ye TDE +Comment[zh_CN]=TDE 部件 +Comment[zh_HK]=TDE 元件 +Comment[zh_TW]=TDE 元件 +Comment[zu]=Ingxenye ye-TDE diff --git a/tdeparts/mainwindow.cpp b/tdeparts/mainwindow.cpp new file mode 100644 index 000000000..37fc97acd --- /dev/null +++ b/tdeparts/mainwindow.cpp @@ -0,0 +1,191 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <tdeparts/mainwindow.h> +#include <tdeparts/event.h> +#include <tdeparts/part.h> +#include <tdeparts/plugin.h> +#include <kinstance.h> +#include <kstatusbar.h> +#include <khelpmenu.h> +#include <kstandarddirs.h> +#include <tqapplication.h> +#include <kxmlguifactory.h> + +#include <kaccel.h> +#include <kdebug.h> + +#include <assert.h> + +using namespace KParts; + +namespace KParts +{ +class MainWindowPrivate +{ +public: + MainWindowPrivate() + { + m_activePart = 0; + m_bShellGUIActivated = false; + m_helpMenu = 0; + } + ~MainWindowPrivate() + { + } + + TQGuardedPtr<Part> m_activePart; + bool m_bShellGUIActivated; + KHelpMenu *m_helpMenu; +}; +} + +MainWindow::MainWindow( TQWidget* parent, const char *name, WFlags f ) + : KMainWindow( parent, name, f ) +{ + d = new MainWindowPrivate(); + PartBase::setPartObject( TQT_TQOBJECT(this) ); +} + +MainWindow::MainWindow( const char *name, WFlags f ) + : KMainWindow( 0L, name, f ) +{ + d = new MainWindowPrivate(); + PartBase::setPartObject( TQT_TQOBJECT(this) ); +} + +MainWindow::MainWindow( int cflags, TQWidget* parent, const char *name, WFlags f ) + : KMainWindow( cflags, parent, name, f ) +{ + d = new MainWindowPrivate(); + PartBase::setPartObject( TQT_TQOBJECT(this) ); +} + +MainWindow::~MainWindow() +{ + delete d; +} + +void MainWindow::createGUI( Part * part ) +{ + kdDebug(1000) << "MainWindow::createGUI, part=" << part << " " << ( part ? part->className() : "" ) + << " " << ( part ? part->name() : "" ) + << endl; + + KXMLGUIFactory *factory = guiFactory(); + + assert( factory ); + + setUpdatesEnabled( false ); + + TQPtrList<Plugin> plugins; + + if ( d->m_activePart ) + { + kdDebug(1000) << "deactivating GUI for " << d->m_activePart << " " << d->m_activePart->className() + << " " << d->m_activePart->name() << endl; + + GUIActivateEvent ev( false ); + TQApplication::sendEvent( d->m_activePart, &ev ); + + factory->removeClient( d->m_activePart ); + + disconnect( d->m_activePart, TQT_SIGNAL( setWindowCaption( const TQString & ) ), + this, TQT_SLOT( setCaption( const TQString & ) ) ); + disconnect( d->m_activePart, TQT_SIGNAL( setStatusBarText( const TQString & ) ), + this, TQT_SLOT( slotSetStatusBarText( const TQString & ) ) ); + } + + if ( !d->m_bShellGUIActivated ) + { + loadPlugins( TQT_TQOBJECT(this), this, TDEGlobal::instance() ); + createShellGUI(); + d->m_bShellGUIActivated = true; + } + + if ( part ) + { + // do this before sending the activate event + connect( part, TQT_SIGNAL( setWindowCaption( const TQString & ) ), + this, TQT_SLOT( setCaption( const TQString & ) ) ); + connect( part, TQT_SIGNAL( setStatusBarText( const TQString & ) ), + this, TQT_SLOT( slotSetStatusBarText( const TQString & ) ) ); + + factory->addClient( part ); + + GUIActivateEvent ev( true ); + TQApplication::sendEvent( part, &ev ); + + if ( autoSaveSettings() ) + applyMainWindowSettings( TDEGlobal::config(), autoSaveGroup() ); + } + + setUpdatesEnabled( true ); + + d->m_activePart = part; +} + +void MainWindow::slotSetStatusBarText( const TQString & text ) +{ + statusBar()->message( text ); +} + +void MainWindow::createShellGUI( bool create ) +{ + bool bAccelAutoUpdate = accel()->setAutoUpdate( false ); + assert( d->m_bShellGUIActivated != create ); + d->m_bShellGUIActivated = create; + if ( create ) + { + if ( isHelpMenuEnabled() && !d->m_helpMenu ) + d->m_helpMenu = new KHelpMenu( this, instance()->aboutData(), true, actionCollection() ); + + TQString f = xmlFile(); + setXMLFile( locate( "config", "ui/ui_standards.rc", instance() ) ); + if ( !f.isEmpty() ) + setXMLFile( f, true ); + else + { + TQString auto_file( instance()->instanceName() + "ui.rc" ); + setXMLFile( auto_file, true ); + } + + GUIActivateEvent ev( true ); + TQApplication::sendEvent( this, &ev ); + + guiFactory()->addClient( this ); + } + else + { + GUIActivateEvent ev( false ); + TQApplication::sendEvent( this, &ev ); + + guiFactory()->removeClient( this ); + } + accel()->setAutoUpdate( bAccelAutoUpdate ); +} + +void KParts::MainWindow::saveNewToolbarConfig() +{ + createGUI( d->m_activePart ); + applyMainWindowSettings( TDEGlobal::config() ); +} + +#include "mainwindow.moc" diff --git a/tdeparts/mainwindow.h b/tdeparts/mainwindow.h new file mode 100644 index 000000000..b99527c00 --- /dev/null +++ b/tdeparts/mainwindow.h @@ -0,0 +1,120 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __MAINWINDOW_H +#define __MAINWINDOW_H + +#include <tqptrlist.h> +#include <kaction.h> + +#include <kmainwindow.h> + +#include <tdeparts/part.h> + +class TQString; + +namespace KParts +{ + +class MainWindowPrivate; + +/** + * A KPart-aware main window, whose user interface is described in XML. + * + * Inherit your main window from this class + * and don't forget to call setXMLFile() in the inherited constructor. + * + * It implements all internal interfaces in the case of a + * KMainWindow as host: the builder and servant interface (for menu + * merging). + */ +class KPARTS_EXPORT MainWindow : public KMainWindow, virtual public PartBase +{ + Q_OBJECT + public: + /** + * Constructor, same signature as KMainWindow. + */ +#ifdef qdoc + MainWindow( TQWidget* parent, const char *name = 0L, WFlags f = WType_TopLevel | WDestructiveClose ); +#else + MainWindow( TQWidget* parent, const char *name = 0L, WFlags f = (WFlags)(WType_TopLevel | WDestructiveClose) ); +#endif + /** + * Compatibility Constructor + */ +#ifdef qdoc + MainWindow( const char *name = 0L, WFlags f = WDestructiveClose ); +#else + MainWindow( const char *name = 0L, WFlags f = (WFlags)WDestructiveClose ); +#endif + /** + * Constructor with creation flags, see KMainWindow. + * @since 3.2 + */ +#ifdef qdoc + MainWindow( int cflags, TQWidget* parent, const char *name = 0L, WFlags f = WType_TopLevel | WDestructiveClose ); +#else + MainWindow( int cflags, TQWidget* parent, const char *name = 0L, WFlags f = (WFlags)(WType_TopLevel | WDestructiveClose) ); +#endif + /** + * Destructor. + */ + virtual ~MainWindow(); + +protected slots: + + /** + * Create the GUI (by merging the host's and the active part's) + * You _must_ call this in order to see any GUI being created. + * + * In a main window with multiple parts being shown (e.g. as in Konqueror) + * you need to connect this slot to the + * KPartManager::activePartChanged() signal + * + * @param part The active part (set to 0L if no part). + */ + void createGUI( KParts::Part * part ); + + /** + * Called when the active part wants to change the statusbar message + * Reimplement if your mainwindow has a complex statusbar + * (with several items) + */ + virtual void slotSetStatusBarText( const TQString & ); + + /** + * Rebuilds the GUI after KEditToolbar changed the toolbar layout. + * @see configureToolbars() + * KDE4: make this virtual. (For now we rely on the fact that it's called + * as a slot, so the metaobject finds it here). + */ + void saveNewToolbarConfig(); + +protected: + virtual void createShellGUI( bool create = true ); + +private: + MainWindowPrivate *d; +}; + +} + +#endif + diff --git a/tdeparts/part.cpp b/tdeparts/part.cpp new file mode 100644 index 000000000..94d096db5 --- /dev/null +++ b/tdeparts/part.cpp @@ -0,0 +1,705 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <tdeparts/part.h> +#include <tdeparts/event.h> +#include <tdeparts/plugin.h> +#include <tdeparts/mainwindow.h> +#include <tdeparts/partmanager.h> + +#include <tqapplication.h> +#include <tqfile.h> +#include <tqpoint.h> +#include <tqpointarray.h> +#include <tqpainter.h> +#include <tqtextstream.h> +#include <tqfileinfo.h> + +#include <kinstance.h> +#include <klocale.h> +#include <ktempfile.h> +#include <kmessagebox.h> +#include <kio/job.h> +#include <kstandarddirs.h> +#include <kfiledialog.h> +#include <kdirnotify_stub.h> + +#include <stdio.h> +#include <unistd.h> +#include <assert.h> +#include <kdebug.h> + +template class TQPtrList<KXMLGUIClient>; + +using namespace KParts; + +namespace KParts +{ + +class PartBasePrivate +{ +public: + PartBasePrivate() + { + m_pluginLoadingMode = PartBase::LoadPlugins; + } + ~PartBasePrivate() + { + } + PartBase::PluginLoadingMode m_pluginLoadingMode; +}; + +class PartPrivate +{ +public: + PartPrivate() + { + m_bSelectable = true; + } + ~PartPrivate() + { + } + + bool m_bSelectable; +}; +} + +PartBase::PartBase() +{ + d = new PartBasePrivate; + m_obj = 0L; +} + +PartBase::~PartBase() +{ + delete d; +} + +void PartBase::setPartObject( TQObject *obj ) +{ + m_obj = obj; +} + +TQObject *PartBase::partObject() const +{ + return m_obj; +} + +void PartBase::setInstance( TDEInstance *inst ) +{ + setInstance( inst, true ); +} + +void PartBase::setInstance( TDEInstance *inst, bool bLoadPlugins ) +{ + KXMLGUIClient::setInstance( inst ); + TDEGlobal::locale()->insertCatalogue( inst->instanceName() ); + // install 'instancename'data resource type + TDEGlobal::dirs()->addResourceType( inst->instanceName() + "data", + KStandardDirs::kde_default( "data" ) + + TQString::fromLatin1( inst->instanceName() ) + '/' ); + if ( bLoadPlugins ) + loadPlugins( m_obj, this, instance() ); +} + +void PartBase::loadPlugins( TQObject *parent, KXMLGUIClient *parentGUIClient, TDEInstance *instance ) +{ + if( d->m_pluginLoadingMode != DoNotLoadPlugins ) + Plugin::loadPlugins( parent, parentGUIClient, instance, d->m_pluginLoadingMode == LoadPlugins ); +} + +void PartBase::setPluginLoadingMode( PluginLoadingMode loadingMode ) +{ + d->m_pluginLoadingMode = loadingMode; +} + +Part::Part( TQObject *parent, const char* name ) + : TQObject( parent, name ) +{ + d = new PartPrivate; + m_widget = 0L; + m_manager = 0L; + PartBase::setPartObject( this ); +} + +Part::~Part() +{ + kdDebug(1000) << "Part::~Part " << this << endl; + + if ( m_widget ) + { + // We need to disconnect first, to avoid calling it ! + disconnect( m_widget, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotWidgetDestroyed() ) ); + } + + if ( m_manager ) + m_manager->removePart(this); + + if ( m_widget ) + { + kdDebug(1000) << "deleting widget " << m_widget << " " << m_widget->name() << endl; + delete (TQWidget*) m_widget; + } + + delete d; +} + +void Part::embed( TQWidget * parentWidget ) +{ + if ( widget() ) + widget()->reparent( parentWidget, 0, TQPoint( 0, 0 ), true ); +} + +TQWidget *Part::widget() +{ + return m_widget; +} + +void Part::setManager( PartManager *manager ) +{ + m_manager = manager; +} + +PartManager *Part::manager() const +{ + return m_manager; +} + +Part *Part::hitTest( TQWidget *widget, const TQPoint & ) +{ + if ( (TQWidget *)m_widget != widget ) + return 0L; + + return this; +} + +void Part::setWidget( TQWidget *widget ) +{ + assert ( !m_widget ); // otherwise we get two connects + m_widget = widget; + connect( m_widget, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotWidgetDestroyed() ) ); + + // Tell the actionCollection() which widget its + // action shortcuts should be connected to. + actionCollection()->setWidget( widget ); + + // Since KParts objects are XML-based, shortcuts should + // be connected to the widget when the XML settings + // are processed, rather than on KAction construction. + actionCollection()->setAutoConnectShortcuts( false ); +} + +void Part::setSelectable( bool selectable ) +{ + d->m_bSelectable = selectable; +} + +bool Part::isSelectable() const +{ + return d->m_bSelectable; +} + +void Part::customEvent( TQCustomEvent *event ) +{ + if ( PartActivateEvent::test( event ) ) + { + partActivateEvent( (PartActivateEvent *)event ); + return; + } + + if ( PartSelectEvent::test( event ) ) + { + partSelectEvent( (PartSelectEvent *)event ); + return; + } + + if ( GUIActivateEvent::test( event ) ) + { + guiActivateEvent( (GUIActivateEvent *)event ); + return; + } + + TQObject::customEvent( event ); +} + +void Part::partActivateEvent( PartActivateEvent * ) +{ +} + +void Part::partSelectEvent( PartSelectEvent * ) +{ +} + +void Part::guiActivateEvent( GUIActivateEvent * ) +{ +} + +TQWidget *Part::hostContainer( const TQString &containerName ) +{ + if ( !factory() ) + return 0L; + + return factory()->container( containerName, this ); +} + +void Part::slotWidgetDestroyed() +{ + kdDebug(1000) << "KPart::slotWidgetDestroyed(), deleting part " << name() << endl; + m_widget = 0; + delete this; +} + +////////////////////////////////////////////////// + +namespace KParts +{ + +class ReadOnlyPartPrivate +{ +public: + ReadOnlyPartPrivate() + { + m_job = 0L; + m_uploadJob = 0L; + m_showProgressInfo = true; + m_saveOk = false; + m_waitForSave = false; + m_duringSaveAs = false; + } + ~ReadOnlyPartPrivate() + { + } + + TDEIO::FileCopyJob * m_job; + TDEIO::FileCopyJob * m_uploadJob; + KURL m_originalURL; // for saveAs + TQString m_originalFilePath; // for saveAs + bool m_showProgressInfo : 1; + bool m_saveOk : 1; + bool m_waitForSave : 1; + bool m_duringSaveAs : 1; +}; + +} + +ReadOnlyPart::ReadOnlyPart( TQObject *parent, const char *name ) + : Part( parent, name ), m_bTemp( false ) +{ + d = new ReadOnlyPartPrivate; +} + +ReadOnlyPart::~ReadOnlyPart() +{ + ReadOnlyPart::closeURL(); + delete d; +} + +void ReadOnlyPart::setProgressInfoEnabled( bool show ) +{ + d->m_showProgressInfo = show; +} + +bool ReadOnlyPart::isProgressInfoEnabled() const +{ + return d->m_showProgressInfo; +} + +#ifndef KDE_NO_COMPAT +void ReadOnlyPart::showProgressInfo( bool show ) +{ + d->m_showProgressInfo = show; +} +#endif + +bool ReadOnlyPart::openURL( const KURL &url ) +{ + if ( !url.isValid() ) + return false; + if ( !closeURL() ) + return false; + m_url = url; + if ( m_url.isLocalFile() ) + { + emit started( 0 ); + m_file = m_url.path(); + bool ret = openFile(); + if (ret) + { + emit completed(); + emit setWindowCaption( m_url.prettyURL() ); + }; + return ret; + } + else + { + m_bTemp = true; + // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice) + TQString fileName = url.fileName(); + TQFileInfo fileInfo(fileName); + TQString ext = fileInfo.extension(); + TQString extension; + if ( !ext.isEmpty() && url.query().isNull() ) // not if the URL has a query, e.g. cgi.pl?something + extension = "."+ext; // keep the '.' + KTempFile tempFile( TQString::null, extension ); + m_file = tempFile.name(); + + KURL destURL; + destURL.setPath( m_file ); + d->m_job = TDEIO::file_copy( m_url, destURL, 0600, true, false, d->m_showProgressInfo ); + d->m_job->setWindow( widget() ? widget()->topLevelWidget() : 0 ); + emit started( d->m_job ); + connect( d->m_job, TQT_SIGNAL( result( TDEIO::Job * ) ), this, TQT_SLOT( slotJobFinished ( TDEIO::Job * ) ) ); + return true; + } +} + +void ReadOnlyPart::abortLoad() +{ + if ( d->m_job ) + { + //kdDebug(1000) << "Aborting job " << d->m_job << endl; + d->m_job->kill(); + d->m_job = 0; + } +} + +bool ReadOnlyPart::closeURL() +{ + abortLoad(); //just in case + + if ( m_bTemp ) + { + unlink( TQFile::encodeName(m_file) ); + m_bTemp = false; + } + // It always succeeds for a read-only part, + // but the return value exists for reimplementations + // (e.g. pressing cancel for a modified read-write part) + return true; +} + +void ReadOnlyPart::slotJobFinished( TDEIO::Job * job ) +{ + kdDebug(1000) << "ReadOnlyPart::slotJobFinished" << endl; + assert( job == d->m_job ); + d->m_job = 0; + if (job->error()) + emit canceled( job->errorString() ); + else + { + if ( openFile() ) + emit setWindowCaption( m_url.prettyURL() ); + emit completed(); + } +} + +void ReadOnlyPart::guiActivateEvent( GUIActivateEvent * event ) +{ + if (event->activated()) + { + if (!m_url.isEmpty()) + { + kdDebug(1000) << "ReadOnlyPart::guiActivateEvent -> " << m_url.prettyURL() << endl; + emit setWindowCaption( m_url.prettyURL() ); + } else emit setWindowCaption( "" ); + } +} + +bool ReadOnlyPart::openStream( const TQString& mimeType, const KURL& url ) +{ + if ( !closeURL() ) + return false; + m_url = url; + return doOpenStream( mimeType ); +} + +bool ReadOnlyPart::writeStream( const TQByteArray& data ) +{ + return doWriteStream( data ); +} + +bool ReadOnlyPart::closeStream() +{ + return doCloseStream(); +} + +////////////////////////////////////////////////// + +ReadWritePart::ReadWritePart( TQObject *parent, const char *name ) + : ReadOnlyPart( parent, name ), m_bModified( false ), m_bClosing( false ) +{ + m_bReadWrite = true; +} + +ReadWritePart::~ReadWritePart() +{ + // parent destructor will delete temp file + // we can't call our own closeURL() here, because + // "cancel" wouldn't cancel anything. We have to assume + // the app called closeURL() before destroying us. +} + +void ReadWritePart::setReadWrite( bool readwrite ) +{ + // Perhaps we should check isModified here and issue a warning if true + m_bReadWrite = readwrite; +} + +void ReadWritePart::setModified( bool modified ) +{ + kdDebug(1000) << "ReadWritePart::setModified( " << (modified ? "true" : "false") << ")" << endl; + if ( !m_bReadWrite && modified ) + { + kdError(1000) << "Can't set a read-only document to 'modified' !" << endl; + return; + } + m_bModified = modified; +} + +void ReadWritePart::setModified() +{ + setModified( true ); +} + +bool ReadWritePart::queryClose() +{ + if ( !isReadWrite() || !isModified() ) + return true; + + TQString docName = url().fileName(); + if (docName.isEmpty()) docName = i18n( "Untitled" ); + + int res = KMessageBox::warningYesNoCancel( widget(), + i18n( "The document \"%1\" has been modified.\n" + "Do you want to save your changes or discard them?" ).arg( docName ), + i18n( "Close Document" ), KStdGuiItem::save(), KStdGuiItem::discard() ); + + bool abortClose=false; + bool handled=false; + + switch(res) { + case KMessageBox::Yes : + sigQueryClose(&handled,&abortClose); + if (!handled) + { + if (m_url.isEmpty()) + { + KURL url = KFileDialog::getSaveURL(); + if (url.isEmpty()) + return false; + + saveAs( url ); + } + else + { + save(); + } + } else if (abortClose) return false; + return waitSaveComplete(); + case KMessageBox::No : + return true; + default : // case KMessageBox::Cancel : + return false; + } +} + +bool ReadWritePart::closeURL() +{ + abortLoad(); //just in case + if ( isReadWrite() && isModified() ) + { + if (!queryClose()) + return false; + } + // Not modified => ok and delete temp file. + return ReadOnlyPart::closeURL(); +} + +bool ReadWritePart::closeURL( bool promptToSave ) +{ + return promptToSave ? closeURL() : ReadOnlyPart::closeURL(); +} + +bool ReadWritePart::save() +{ + d->m_saveOk = false; + if ( m_file.isEmpty() ) // document was created empty + prepareSaving(); + if( saveFile() ) + return saveToURL(); + else + emit canceled(TQString::null); + return false; +} + +bool ReadWritePart::saveAs( const KURL & kurl ) +{ + if (!kurl.isValid()) + { + kdError(1000) << "saveAs: Malformed URL " << kurl.url() << endl; + return false; + } + d->m_duringSaveAs = true; + d->m_originalURL = m_url; + d->m_originalFilePath = m_file; + m_url = kurl; // Store where to upload in saveToURL + prepareSaving(); + bool result = save(); // Save local file and upload local file + if (result) + emit setWindowCaption( m_url.prettyURL() ); + else + { + m_url = d->m_originalURL; + m_file = d->m_originalFilePath; + d->m_duringSaveAs = false; + d->m_originalURL = KURL(); + d->m_originalFilePath = TQString::null; + } + + return result; +} + +// Set m_file correctly for m_url +void ReadWritePart::prepareSaving() +{ + // Local file + if ( m_url.isLocalFile() ) + { + if ( m_bTemp ) // get rid of a possible temp file first + { // (happens if previous url was remote) + unlink( TQFile::encodeName(m_file) ); + m_bTemp = false; + } + m_file = m_url.path(); + } + else + { // Remote file + // We haven't saved yet, or we did but locally - provide a temp file + if ( m_file.isEmpty() || !m_bTemp ) + { + KTempFile tempFile; + m_file = tempFile.name(); + m_bTemp = true; + } + // otherwise, we already had a temp file + } +} + +bool ReadWritePart::saveToURL() +{ + if ( m_url.isLocalFile() ) + { + setModified( false ); + emit completed(); + // if m_url is a local file there won't be a temp file -> nothing to remove + assert( !m_bTemp ); + d->m_saveOk = true; + d->m_duringSaveAs = false; + d->m_originalURL = KURL(); + d->m_originalFilePath = TQString::null; + return true; // Nothing to do + } + else + { + if (d->m_uploadJob) + { + unlink(TQFile::encodeName(d->m_uploadJob->srcURL().path())); + d->m_uploadJob->kill(); + d->m_uploadJob = 0; + } + KTempFile tempFile; + TQString uploadFile = tempFile.name(); + KURL uploadUrl; + uploadUrl.setPath( uploadFile ); + tempFile.unlink(); + // Create hardlink + if (::link(TQFile::encodeName(m_file), TQFile::encodeName(uploadFile)) != 0) + { + // Uh oh, some error happened. + return false; + } + d->m_uploadJob = TDEIO::file_move( uploadUrl, m_url, -1, true /*overwrite*/ ); + d->m_uploadJob->setWindow( widget() ? widget()->topLevelWidget() : 0 ); + connect( d->m_uploadJob, TQT_SIGNAL( result( TDEIO::Job * ) ), this, TQT_SLOT( slotUploadFinished (TDEIO::Job *) ) ); + return true; + } +} + +void ReadWritePart::slotUploadFinished( TDEIO::Job * ) +{ + if (d->m_uploadJob->error()) + { + unlink(TQFile::encodeName(d->m_uploadJob->srcURL().path())); + TQString error = d->m_uploadJob->errorString(); + d->m_uploadJob = 0; + if (d->m_duringSaveAs) { + m_url = d->m_originalURL; + m_file = d->m_originalFilePath; + } + emit canceled( error ); + } + else + { + KDirNotify_stub allDirNotify("*", "KDirNotify*"); + KURL dirUrl( m_url ); + dirUrl.setPath( dirUrl.directory() ); + allDirNotify.FilesAdded( dirUrl ); + + d->m_uploadJob = 0; + setModified( false ); + emit completed(); + d->m_saveOk = true; + } + d->m_duringSaveAs = false; + d->m_originalURL = KURL(); + d->m_originalFilePath = TQString::null; + if (d->m_waitForSave) + { + tqApp->exit_loop(); + } +} + +// Trolls: Nothing to see here, please step away. +void tqt_enter_modal( TQWidget *widget ); +void tqt_leave_modal( TQWidget *widget ); + +bool ReadWritePart::waitSaveComplete() +{ + if (!d->m_uploadJob) + return d->m_saveOk; + + d->m_waitForSave = true; + + TQWidget dummy(0,0,(WFlags)(WType_Dialog | WShowModal)); + dummy.setFocusPolicy( TQ_NoFocus ); + tqt_enter_modal(&dummy); + tqApp->enter_loop(); + tqt_leave_modal(&dummy); + + d->m_waitForSave = false; + + return d->m_saveOk; +} + +#include "part.moc" + +// vim:sw=2:ts=8:et diff --git a/tdeparts/part.h b/tdeparts/part.h new file mode 100644 index 000000000..6b2051f72 --- /dev/null +++ b/tdeparts/part.h @@ -0,0 +1,702 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef _KPART_H +#define _KPART_H + +#include <tqstring.h> +#include <tqdom.h> +#include <tqguardedptr.h> +#include <kurl.h> + +#include <kxmlguiclient.h> + +class TDEInstance; +class TQWidget; +class KAction; +class KActionCollection; +class TQEvent; +struct QUnknownInterface; + +namespace TDEIO { + class Job; +} + +namespace KParts +{ + +class PartManager; +class Plugin; +class PartPrivate; +class PartActivateEvent; +class PartSelectEvent; +class GUIActivateEvent; +class PartBasePrivate; + +/** + * Base class for all parts. + * + * @short Base class for all parts. + */ +class KPARTS_EXPORT PartBase : virtual public KXMLGUIClient +{ + friend class PartBasePrivate; +public: + + /** + * Constructor. + */ + PartBase(); + + /** + * Destructor. + */ + virtual ~PartBase(); + + /** + * Internal method. Called by KParts::Part to specify the parent object for plugin objects. + * + * @internal + */ + void setPartObject( TQObject *object ); + TQObject *partObject() const; + +protected: + /** + * Set the instance ( TDEInstance) for this part. + * + * Call this *first* in the inherited class constructor, + * because it loads the i18n catalogues. + */ + virtual void setInstance( TDEInstance *instance ); + + /** + * Set the instance ( TDEInstance) for this part. + * + * Call this *first* in the inherited class constructor, + * because it loads the i18n catalogues. + */ + virtual void setInstance( TDEInstance *instance, bool loadPlugins ); + + /** + * We have three different policies, whether to load new plugins or not. The + * value in the TDEConfig object of the TDEInstance object always overrides + * LoadPlugins and LoadPluginsIfEnabled. + */ + enum PluginLoadingMode { + /** + * Don't load any plugins at all. + */ + DoNotLoadPlugins = 0, + /** + * Load new plugins automatically. Can be + * overridden by the plugin if it sets + * EnabledByDefault=false in the corresponding + * .desktop file. + */ + LoadPlugins = 1, + /** + * New plugins are disabled by default. Can be + * overridden by the plugin if it sets + * EnabledByDefault=true in the corresponding + * .desktop file. + */ + LoadPluginsIfEnabled = 2 + }; + + /** + * Load the Plugins honoring the PluginLoadingMode. + * + * If you call this method in an already constructed GUI (like when the user + * has changed which plugins are enabled) you need to add the new plugins to + * the KXMLGUIFactory: + * \code + * if( factory() ) + * { + * TQPtrList<KParts::Plugin> plugins = KParts::Plugin::pluginObjects( this ); + * TQPtrListIterator<KParts::Plugin> it( plugins ); + * KParts::Plugin * plugin; + * while( ( plugin = it.current() ) != 0 ) + * { + * ++it; + * factory()->addClient( plugin ); + * } + * } + * \endcode + */ + void loadPlugins( TQObject *parent, KXMLGUIClient *parentGUIClient, TDEInstance *instance ); + + /** + * For a KParts::Part: call this before setInstance(). + * For a KParts::MainWindow: call this before createGUI(). + */ + void setPluginLoadingMode( PluginLoadingMode loadingMode ); + +private: + PartBasePrivate *d; + TQObject *m_obj; +}; + +/** + * Base class for parts. + * + * A "part" is a GUI component, featuring: + * @li A widget embeddedable in any application. + * @li GUI elements that will be merged in the "host" user interface + * (menubars, toolbars... ). + * + * <b>About the widget:</b>\n + * + * Note that KParts::Part does not inherit TQWidget. + * This is due to the fact that the "visual representation" + * will probably not be a mere TQWidget, but an elaborate one. + * That's why when implementing your KParts::Part (or derived) + * you should call KParts::Part::setWidget() in your constructor. + * + * <b>About the GUI elements:</b>\n + * + * Those elements trigger actions, defined by the part (action()). + * The layout of the actions in the GUI is defined by an XML file (setXMLFile()). + * + * See also ReadOnlyPart and ReadWritePart, which define the + * framework for a "viewer" part and for an "editor"-like part. + * Use Part directly only if your part doesn't fit into those. + */ +class KPARTS_EXPORT Part : public TQObject, public PartBase +{ + Q_OBJECT + +public: + + /** + * Constructor. + * + * @param parent Parent object of the part. + * @param name QT-internal name of the part. + */ + Part( TQObject *parent = 0, const char* name = 0 ); + + /** + * Destructor. + */ + virtual ~Part(); + + /** + * Embed this part into a host widget. + * + * You don't need to do this if you created the widget with the + * correct parent widget - this is just a TQWidget::reparent(). + * Note that the Part is still the holder + * of the TQWidget, meaning that if you delete the Part, + * then the widget gets destroyed as well, and vice-versa. + * This method is not recommended since creating the widget with the correct + * parent is simpler anyway. + */ + virtual void embed( TQWidget * parentWidget ); + + /** + * @return The widget defined by this part, set by setWidget(). + */ + virtual TQWidget *widget(); + + /** + * @internal + * Used by the part manager. + */ + virtual void setManager( PartManager * manager ); + + /** + * Returns the part manager handling this part, if any (0L otherwise). + */ + PartManager * manager() const; + + /** + * Returns the part (this, or a child part) at the given global position. + * This is called by the part manager to ask whether a part should be activated + * when clicking somewhere. In most cases the default implementation is enough. + * Reimplement this if your part has child parts in some areas (like in tdehtml or koffice) + * @param widget the part widget being clicked - usually the same as widget(), except in koffice. + * @param globalPos the mouse coordinates in global coordinates + */ + virtual Part *hitTest( TQWidget *widget, const TQPoint &globalPos ); + + /** + * @param selectable Indicates whether the part is selectable or not. + */ + virtual void setSelectable( bool selectable ); + + /** + * Returns whether the part is selectable or not. + */ + bool isSelectable() const; + +signals: + /** + * Emitted by the part, to set the caption of the window(s) + * hosting this part + */ + void setWindowCaption( const TQString & caption ); + /** + * Emited by the part, to set a text in the statusbar of the window(s) + * hosting this part + */ + void setStatusBarText( const TQString & text ); + +protected: + + /** + * Set the main widget. + * + * Call this in the Part-inherited class constructor. + */ + virtual void setWidget( TQWidget * widget ); + + /** + * @internal + */ + virtual void customEvent( TQCustomEvent *event ); + + /** + * Convenience method which is called when the Part received a PartActivateEvent . + * Reimplement this if you don't want to reimplement event and test for the event yourself + * or even install an event filter. + */ + virtual void partActivateEvent( PartActivateEvent *event ); + + /** + * Convenience method which is called when the Part received a + * PartSelectEvent . + * Reimplement this if you don't want to reimplement event and + * test for the event yourself or even install an event filter. + */ + virtual void partSelectEvent( PartSelectEvent *event ); + + /** + * Convenience method which is called when the Part received a + * GUIActivateEvent . + * Reimplement this if you don't want to reimplement event and + * test for the event yourself or even install an event filter. + */ + virtual void guiActivateEvent( GUIActivateEvent *event ); + + /** + * Convenience method for KXMLGUIFactory::container. + * @return a container widget owned by the Part's GUI. + */ + TQWidget *hostContainer( const TQString &containerName ); + +private slots: + void slotWidgetDestroyed(); + +private: + TQGuardedPtr<TQWidget> m_widget; + + PartManager * m_manager; + + PartPrivate *d; +}; + +class ReadWritePart; +class ReadOnlyPartPrivate; + +/** + * Base class for any "viewer" part. + * + * This class takes care of network transparency for you, + * in the simplest way (downloading to a temporary file, then letting the part + * load from the temporary file). + * To use the built-in network transparency, you only need to implement + * openFile(), not openURL(). + * + * To implement network transparency differently (e.g. for progressive loading, + * like a web browser does for instance), or to prevent network transparency + * (but why would you do that?), you can override openURL(). + * + * KParts Application can use the signals to show feedback while the URL is being loaded. + * + * ReadOnlyPart handles the window caption by setting it to the current URL + * (set in openURL(), and each time the part is activated). + * If you want another caption, set it in openFile() and + * (if the part might ever be used with a part manager) in guiActivateEvent() + */ +class KPARTS_EXPORT ReadOnlyPart : public Part +{ + Q_OBJECT + friend class ReadWritePart; +public: + /** + * Constructor + * See also Part for the setXXX methods to call. + */ + ReadOnlyPart( TQObject *parent = 0, const char *name = 0 ); + + /** + * Destructor + */ + virtual ~ReadOnlyPart(); + + /** + * Call this to turn off the progress info dialog used by + * the internal KIO job. Use this if you provide another way + * of displaying progress info (e.g. a statusbar), using the + * signals emitted by this class, and/or those emitted by + * the Job given by started. + */ + void setProgressInfoEnabled( bool show ); + + /** + * Returns whether the part shows the progress info dialog used by internal + * KIO job. + */ + bool isProgressInfoEnabled() const; + +#ifndef KDE_NO_COMPAT + void showProgressInfo( bool show ); +#endif + +public slots: + /** + * Only reimplement openURL if you don't want the network transparency support + * to download from the url into a temporary file (when the url isn't local). + * Otherwise, reimplement openFile() only . + * + * If you reimplement it, don't forget to set the caption, usually with + * emit setWindowCaption( url.prettyURL() ); + */ + virtual bool openURL( const KURL &url ); + +public: + /** + * Returns the currently in part used URL. + * + * @return The current used URL. + */ + KURL url() const { return m_url; } + + /** + * Called when closing the current url (e.g. document), for instance + * when switching to another url (note that openURL() calls it + * automatically in this case). + * If the current URL is not fully loaded yet, aborts loading. + * Deletes the temporary file used when the url is remote. + * @return always true, but the return value exists for reimplementations + */ + virtual bool closeURL(); + +public: + /** + * Initiate sending data to this part. + * This is an alternative to openURL, which allows the user of the part + * to load the data itself, and send it progressively to the part. + * + * @param mimeType the type of data that is going to be sent to this part. + * @param url the URL representing this data. Although not directly used, + * every ReadOnlyPart has a URL (see url()), so this simply sets it. + * @return true if the part supports progressive loading and accepts data, false otherwise. + */ + bool openStream( const TQString& mimeType, const KURL& url ); + + /** + * Send some data to the part. openStream must have been called previously, + * and must have returned true. + * @return true if the data was accepted by the part. If false is returned, + * the application should stop sending data, and doesn't have to call closeStream. + */ + bool writeStream( const TQByteArray& data ); + + /** + * Terminate the sending of data to the part. + * With some data types (text, html...) closeStream might never actually be called, + * in the case of continuous streams, for instance plain text or HTML data. + */ + bool closeStream(); + +private: // Makes no sense for inherited classes to call those. But make it protected there. + + /** + * Called by openStream to initiate sending of data. + * Parts which implement progress loading should check the @p mimeType + * parameter, and return true if they can accept a data stream of that type. + */ + virtual bool doOpenStream( const TQString& /*mimeType*/ ) { return false; } + /** + * Receive some data from the hosting application. + * In this method the part should attempt to display the data progressively. + * With some data types (text, html...) closeStream might never actually be called, + * in the case of continuous streams. This can't happen with e.g. images. + */ + virtual bool doWriteStream( const TQByteArray& /*data*/ ) { return false; } + /** + * This is called by closeStream(), to indicate that all the data has been sent. + * Parts should ensure that all of the data is displayed at this point. + * @return whether the data could be displayed correctly. + */ + virtual bool doCloseStream() { return false; } + +signals: + /** + * The part emits this when starting data. + * If using a TDEIO::Job, it sets the job in the signal, so that + * progress information can be shown. Otherwise, job is 0. + **/ + void started( TDEIO::Job * ); + + /** + * Emit this when you have completed loading data. + * Hosting apps will want to know when the process of loading the data + * is finished, so that they can access the data when everything is loaded. + **/ + void completed(); + + /** + * Same as the above signal except it indicates whether there is + * a pending action to be executed on a delay timer. An example of + * this is the meta-refresh tags on web pages used to reload/redirect + * after a certain period of time. This signal is useful if you want + * to give the user the ability to cancel such pending actions. + * + * @param pendingAction true if a pending action exists, false otherwise. + */ + void completed( bool pendingAction ); + + /** + * Emit this if loading is canceled by the user or by an error. + * @param errMsg the error message, empty if the user canceled the loading voluntarily. + */ + void canceled( const TQString &errMsg ); + +protected slots: + void slotJobFinished( TDEIO::Job * job ); + +protected: + /** + * If the part uses the standard implementation of openURL(), + * it must reimplement this, to open @p m_file. + * Otherwise simply define it to { return false; } + */ + virtual bool openFile() = 0; + + /** + * @internal + */ + void abortLoad(); + + /** + * Reimplemented from Part, so that the window caption is set to + * the current url (decoded) when the part is activated. + * This is the usual behavior in 99% of the apps. + * Reimplement if you don't like it - test for event->activated() ! + * + * Technical note : this is done with GUIActivateEvent and not with + * PartActivateEvent because it's handled by the mainwindow + * (which gets the even after the PartActivateEvent events have been sent) + */ + virtual void guiActivateEvent( GUIActivateEvent *event ); + + /** + * Remote (or local) url - the one displayed to the user. + */ + KURL m_url; + /** + * Local file - the only one the part implementation should deal with. + */ + TQString m_file; + /** + * If @p true, @p m_file is a temporary file that needs to be deleted later. + */ + bool m_bTemp; + +private: + ReadOnlyPartPrivate *d; +}; + +/** + * Base class for an "editor" part. + * + * This class handles network transparency for you. + * Anything that can open a URL, allow modifications, and save + * (to the same URL or a different one). + * + * A read-write part can be set to read-only mode, using setReadWrite(). + * + * Part writers : + * Any part inheriting ReadWritePart should check isReadWrite() + * before allowing any action that modifies the part. + * The part probably wants to reimplement setReadWrite, disable those + * actions. Don't forget to call the parent setReadWrite(). + */ +class KPARTS_EXPORT ReadWritePart : public ReadOnlyPart +{ + Q_OBJECT +public: + /** + * Constructor. + * See parent constructor for instructions. + */ + ReadWritePart( TQObject *parent = 0, const char *name = 0 ); + /** + * Destructor. + * Applications using a ReadWritePart should make sure, before + * destroying it, to call closeURL(). + * In KMainWindow::queryClose(), for instance, they should allow + * closing only if the return value of closeURL() was true. + * This allows to cancel. + */ + virtual ~ReadWritePart(); + + /** + * @return true if the part is in read-write mode + */ + bool isReadWrite() const { return m_bReadWrite; } + + /** + * Changes the behavior of this part to readonly or readwrite. + * @param readwrite set to true to enable readwrite mode + */ + virtual void setReadWrite ( bool readwrite = true ); + + /** + * @return true if the document has been modified. + */ + bool isModified() const { return m_bModified; } + + /** + * If the document has been modified, ask the user to save changes. + * This method is meant to be called from KMainWindow::queryClose(). + * It will also be called from closeURL(). + * + * @return true if closeURL() can be called without the user losing + * important data, false if the user chooses to cancel. + * + * @since 3.2 + */ + // TODO: Make virtual for KDE 4 + bool queryClose(); + + /** + * Called when closing the current url (e.g. document), for instance + * when switching to another url (note that openURL() calls it + * automatically in this case). + * + * If the current URL is not fully loaded yet, aborts loading. + * + * If isModified(), queryClose() will be called. + * + * @return false on cancel + */ + virtual bool closeURL(); + + /** + * Call this method instead of the above if you need control if + * the save prompt is shown. For example, if you call queryClose() + * from KMainWindow::queryClose(), you would not want to prompt + * again when closing the url. + * + * Equivalent to promptToSave ? closeURL() : ReadOnlyPart::closeURL() + * + * @since 3.2 + */ + // TODO: Make virtual for KDE 4 + bool closeURL( bool promptToSave ); + + /** + * Save the file to a new location. + * + * Calls save(), no need to reimplement + */ + virtual bool saveAs( const KURL &url ); + + /** + * Sets the modified flag of the part. + */ + virtual void setModified( bool modified ); + +signals: + /** + * @since 3.2, remove in KDE 4, when queryClose is made virtual + * + * set handled to true, if you don't want the default handling + * set abortClosing to true, if you handled the request, + * but for any reason don't want to allow closing the document + */ + void sigQueryClose(bool *handled, bool* abortClosing); + +public slots: + /** + * Call setModified() whenever the contents get modified. + * This is a slot for convenience, so that you can connect it + * to a signal, like textChanged(). + */ + virtual void setModified(); + + /** + * Save the file in the location from which it was opened. + * You can connect this to the "save" action. + * Calls saveFile() and saveToURL(), no need to reimplement. + */ + virtual bool save(); + + /** + * Waits for any pending upload job to finish and returns whether the + * last save() action was successful. + */ + bool waitSaveComplete(); + +protected: + /** + * Save to a local file. + * You need to implement it, to save to @p m_file. + * The framework takes care of re-uploading afterwards. + * + * @return true on success, false on failure. + * On failure the function should inform the user about the + * problem with an appropriate message box. Standard error + * messages can be constructed using TDEIO::buildErrorString() + * in combination with the error codes defined in kio/global.h + */ + virtual bool saveFile() = 0; + + /** + * Save the file. + * + * Uploads the file, if @p m_url is remote. + * This will emit started(), and either completed() or canceled(), + * in case you want to provide feedback. + * @return true on success, false on failure. + */ + virtual bool saveToURL(); + +protected slots: + /** + * @internal + */ + void slotUploadFinished( TDEIO::Job * job ); + +private: + void prepareSaving(); + +private: + bool m_bModified; + bool m_bReadWrite; + bool m_bClosing; +}; + +} // namespace + +#endif diff --git a/tdeparts/partmanager.cpp b/tdeparts/partmanager.cpp new file mode 100644 index 000000000..1af0f1ee3 --- /dev/null +++ b/tdeparts/partmanager.cpp @@ -0,0 +1,601 @@ +// -*- mode: c++; c-basic-offset: 2 -*- +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "partmanager.h" +#include <tdeparts/event.h> +#include <tdeparts/part.h> +#include <kglobal.h> +#include <kdebug.h> + +#include <tqapplication.h> + +//#define DEBUG_PARTMANAGER + +using namespace KParts; + +template class TQPtrList<Part>; + +namespace KParts { + +class PartManagerPrivate +{ +public: + PartManagerPrivate() + { + m_activeWidget = 0; + m_activePart = 0; + m_selectedPart = 0; + m_selectedWidget = 0; + m_bAllowNestedParts = false; + m_bIgnoreScrollBars = false; + m_activationButtonMask = Qt::LeftButton | Qt::MidButton | Qt::RightButton; + m_reason = PartManager::NoReason; + } + ~PartManagerPrivate() + { + } + void setReason( TQEvent* ev ) { + switch( ev->type() ) { + case TQEvent::MouseButtonPress: + case TQEvent::MouseButtonDblClick: { + TQMouseEvent* mev = TQT_TQMOUSEEVENT( ev ); + m_reason = mev->button() == Qt::LeftButton + ? PartManager::ReasonLeftClick + : ( mev->button() == Qt::MidButton + ? PartManager::ReasonMidClick + : PartManager::ReasonRightClick ); + break; + } + case TQEvent::FocusIn: + m_reason = TQT_TQFOCUSEVENT( ev )->reason(); + break; + default: + kdWarning(1000) << "PartManagerPrivate::setReason got unexpected ev type " << ev->type() << endl; + break; + } + } + + Part * m_activePart; + TQWidget *m_activeWidget; + + TQPtrList<Part> m_parts; + + PartManager::SelectionPolicy m_policy; + + Part *m_selectedPart; + TQWidget *m_selectedWidget; + + TQPtrList<TQWidget> m_managedTopLevelWidgets; + short int m_activationButtonMask; + bool m_bIgnoreScrollBars; + bool m_bAllowNestedParts; + int m_reason; +}; + +} + +PartManager::PartManager( TQWidget * parent, const char * name ) + : TQObject( parent, name ) +{ + d = new PartManagerPrivate; + + tqApp->installEventFilter( this ); + + d->m_policy = Direct; + + addManagedTopLevelWidget( parent ); +} + +PartManager::PartManager( TQWidget *topLevel, TQObject *parent, const char *name ) + : TQObject( parent, name ) +{ + d = new PartManagerPrivate; + + tqApp->installEventFilter( this ); + + d->m_policy = Direct; + + addManagedTopLevelWidget( topLevel ); +} + +PartManager::~PartManager() +{ + for ( TQPtrListIterator<TQWidget> it( d->m_managedTopLevelWidgets ); + it.current(); ++it ) + disconnect( it.current(), TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotManagedTopLevelWidgetDestroyed() ) ); + + for ( TQPtrListIterator<Part> it( d->m_parts ); it.current(); ++it ) + { + it.current()->setManager( 0 ); + } + + // core dumps ... setActivePart( 0L ); + tqApp->removeEventFilter( this ); + delete d; +} + +void PartManager::setSelectionPolicy( SelectionPolicy policy ) +{ + d->m_policy = policy; +} + +PartManager::SelectionPolicy PartManager::selectionPolicy() const +{ + return d->m_policy; +} + +void PartManager::setAllowNestedParts( bool allow ) +{ + d->m_bAllowNestedParts = allow; +} + +bool PartManager::allowNestedParts() const +{ + return d->m_bAllowNestedParts; +} + +void PartManager::setIgnoreScrollBars( bool ignore ) +{ + d->m_bIgnoreScrollBars = ignore; +} + +bool PartManager::ignoreScrollBars() const +{ + return d->m_bIgnoreScrollBars; +} + +void PartManager::setActivationButtonMask( short int buttonMask ) +{ + d->m_activationButtonMask = buttonMask; +} + +short int PartManager::activationButtonMask() const +{ + return d->m_activationButtonMask; +} + +bool PartManager::eventFilter( TQObject *obj, TQEvent *ev ) +{ + + if ( ev->type() != TQEvent::MouseButtonPress && + ev->type() != TQEvent::MouseButtonDblClick && + ev->type() != TQEvent::FocusIn ) + return false; + + if ( !obj->isWidgetType() ) + return false; + + TQWidget *w = TQT_TQWIDGET( obj ); + + if ( ( w->testWFlags( WType_Dialog ) && w->isModal() ) || + w->testWFlags( WType_Popup ) || w->testWFlags( WStyle_Tool ) ) + return false; + + TQMouseEvent* mev = 0L; + if ( ev->type() == TQEvent::MouseButtonPress || ev->type() == TQEvent::MouseButtonDblClick ) + { + mev = TQT_TQMOUSEEVENT( ev ); +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "PartManager::eventFilter button: " << mev->button() << " " << "d->m_activationButtonMask=" << d->m_activationButtonMask << endl; +#endif + if ( ( mev->button() & d->m_activationButtonMask ) == 0 ) + return false; // ignore this button + } + + Part * part; + while ( w ) + { + TQPoint pos; + + if ( !d->m_managedTopLevelWidgets.containsRef( w->topLevelWidget() ) ) + return false; + + if ( d->m_bIgnoreScrollBars && w->inherits( TQSCROLLBAR_OBJECT_NAME_STRING ) ) + return false; + + if ( mev ) // mouse press or mouse double-click event + { + pos = mev->globalPos(); + part = findPartFromWidget( w, pos ); + } else + part = findPartFromWidget( w ); + +#ifdef DEBUG_PARTMANAGER + TQCString evType = ( ev->type() == TQEvent::MouseButtonPress ) ? "MouseButtonPress" + : ( ev->type() == TQEvent::MouseButtonDblClick ) ? "MouseButtonDblClick" + : ( ev->type() == TQEvent::FocusIn ) ? "FocusIn" : "OTHER! ERROR!"; +#endif + if ( part ) // We found a part whose widget is w + { + if ( d->m_policy == PartManager::TriState ) + { + if ( ev->type() == TQEvent::MouseButtonDblClick ) + { + if ( part == d->m_activePart && w == d->m_activeWidget ) + return false; + +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "PartManager::eventFilter dblclick -> setActivePart" << part << endl; +#endif + d->setReason( ev ); + setActivePart( part, w ); + d->m_reason = NoReason; + return true; + } + + if ( ( d->m_selectedWidget != w || d->m_selectedPart != part ) && + ( d->m_activeWidget != w || d->m_activePart != part ) ) + { + if ( part->isSelectable() ) + setSelectedPart( part, w ); + else { +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "Part " << part << " (non-selectable) made active because " << w->className() << " got event" << " " << evType << endl; +#endif + d->setReason( ev ); + setActivePart( part, w ); + d->m_reason = NoReason; + } + return true; + } + else if ( d->m_selectedWidget == w && d->m_selectedPart == part ) + { +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "Part " << part << " made active (from selected) because " << w->className() << " got event" << " " << evType << endl; +#endif + d->setReason( ev ); + setActivePart( part, w ); + d->m_reason = NoReason; + return true; + } + else if ( d->m_activeWidget == w && d->m_activePart == part ) + { + setSelectedPart( 0L ); + return false; + } + + return false; + } + else if ( part != d->m_activePart ) + { +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "Part " << part << " made active because " << w->className() << " got event" << " " << evType << endl; +#endif + d->setReason( ev ); + setActivePart( part, w ); + d->m_reason = NoReason; + } + + return false; + } + + w = w->parentWidget(); + + if ( w && ( ( w->testWFlags( WType_Dialog ) && w->isModal() ) || + w->testWFlags( WType_Popup ) || w->testWFlags( WStyle_Tool ) ) ) + { +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << TQString("No part made active although %1/%2 got event - loop aborted").arg(obj->name()).arg(obj->className()) << endl; +#endif + return false; + } + + } + +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << TQString("No part made active although %1/%2 got event").arg(obj->name()).arg(obj->className()) << endl; +#endif + return false; +} + +Part * PartManager::findPartFromWidget( TQWidget * widget, const TQPoint &pos ) +{ + TQPtrListIterator<Part> it ( d->m_parts ); + for ( ; it.current() ; ++it ) + { + Part *part = it.current()->hitTest( widget, pos ); + if ( part && d->m_parts.findRef( part ) != -1 ) + return part; + } + return 0L; +} + +Part * PartManager::findPartFromWidget( TQWidget * widget ) +{ + TQPtrListIterator<Part> it ( d->m_parts ); + for ( ; it.current() ; ++it ) + { + if ( widget == it.current()->widget() ) + return it.current(); + } + return 0L; +} + +void PartManager::addPart( Part *part, bool setActive ) +{ + if ( d->m_parts.findRef( part ) != -1 ) // don't add parts more than once :) + { +#ifdef DEBUG_PARTMANAGER + kdWarning(1000) << k_funcinfo << part << " already added" << kdBacktrace(5) << endl; +#endif + return; + } + + d->m_parts.append( part ); + + part->setManager( this ); + + if ( setActive ) + { + setActivePart( part ); + if ( part->widget() ) + part->widget()->setFocus(); + } + + // Prevent focus problems + if ( part->widget() && part->widget()->focusPolicy() == TQ_NoFocus ) + { + kdWarning(1000) << "Part '" << part->name() << "' has a widget " << part->widget()->name() << " with a focus policy of NoFocus. It should have at least a ClickFocus policy, for part activation to work well." << endl; + } + if ( part->widget() && part->widget()->focusPolicy() == TQ_TabFocus ) + { + kdWarning(1000) << "Part '" << part->name() << "' has a widget " << part->widget()->name() << " with a focus policy of TabFocus. It should have at least a ClickFocus policy, for part activation to work well." << endl; + } + + if ( setActive && part->widget() ) + part->widget()->show(); + emit partAdded( part ); +} + +void PartManager::removePart( Part *part ) +{ + if ( d->m_parts.findRef( part ) == -1 ) + { + kdFatal(1000) << TQString(TQString("Can't remove part %1, not in KPartManager's list.").arg(part->name())) << endl; + return; + } + + //Warning. The part could be already deleted + //kdDebug(1000) << TQString("Part %1 removed").arg(part->name()) << endl; + int nb = d->m_parts.count(); + bool ok = d->m_parts.removeRef( part ); + Q_ASSERT( ok ); + Q_ASSERT( (int)d->m_parts.count() == nb-1 ); + part->setManager(0); + + emit partRemoved( part ); + + if ( part == d->m_activePart ) + setActivePart( 0 ); + if ( part == d->m_selectedPart ) + setSelectedPart( 0 ); +} + +void PartManager::replacePart( Part * oldPart, Part * newPart, bool setActive ) +{ + //kdDebug(1000) << "replacePart " << oldPart->name() << "-> " << newPart->name() << " setActive=" << setActive << endl; + // This methods does exactly removePart + addPart but without calling setActivePart(0) in between + if ( d->m_parts.findRef( oldPart ) == -1 ) + { + kdFatal(1000) << TQString(TQString("Can't remove part %1, not in KPartManager's list.").arg(oldPart->name())) << endl; + return; + } + + d->m_parts.removeRef( oldPart ); + oldPart->setManager(0); + + emit partRemoved( oldPart ); + + addPart( newPart, setActive ); +} + +void PartManager::setActivePart( Part *part, TQWidget *widget ) +{ + if ( part && d->m_parts.findRef( part ) == -1 ) + { + kdWarning( 1000 ) << "PartManager::setActivePart : trying to activate a non-registered part! " << part->name() << endl; + return; // don't allow someone call setActivePart with a part we don't know about + } + + //check whether nested parts are disallowed and activate the top parent part then, by traversing the + //tree recursively (Simon) + if ( part && !d->m_bAllowNestedParts ) + { + TQObject *parentPart = TQT_TQOBJECT(part->parent()); // ### this relies on people using KParts::Factory! + if ( parentPart && parentPart->inherits( "KParts::Part" ) ) + { + KParts::Part *parPart = static_cast<KParts::Part *>( parentPart ); + setActivePart( parPart, parPart->widget() ); + return; + } + } + +#ifdef DEBUG_PARTMANAGER + kdDebug(1000) << "PartManager::setActivePart d->m_activePart=" << d->m_activePart << "<->part=" << part + << " d->m_activeWidget=" << d->m_activeWidget << "<->widget=" << widget << endl; +#endif + + // don't activate twice + if ( d->m_activePart && part && d->m_activePart == part && + (!widget || d->m_activeWidget == widget) ) + return; + + KParts::Part *oldActivePart = d->m_activePart; + TQWidget *oldActiveWidget = d->m_activeWidget; + + setSelectedPart( 0L ); + + d->m_activePart = part; + d->m_activeWidget = widget; + + if ( oldActivePart ) + { + KParts::Part *savedActivePart = part; + TQWidget *savedActiveWidget = widget; + + PartActivateEvent ev( false, oldActivePart, oldActiveWidget ); + TQApplication::sendEvent( oldActivePart, &ev ); + if ( oldActiveWidget ) + { + disconnect( oldActiveWidget, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotWidgetDestroyed() ) ); + TQApplication::sendEvent( oldActiveWidget, &ev ); + } + + d->m_activePart = savedActivePart; + d->m_activeWidget = savedActiveWidget; + } + + if ( d->m_activePart ) + { + if ( !widget ) + d->m_activeWidget = part->widget(); + + PartActivateEvent ev( true, d->m_activePart, d->m_activeWidget ); + TQApplication::sendEvent( d->m_activePart, &ev ); + if ( d->m_activeWidget ) + { + connect( d->m_activeWidget, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotWidgetDestroyed() ) ); + TQApplication::sendEvent( d->m_activeWidget, &ev ); + } + } + // Set the new active instance in TDEGlobal + setActiveInstance( d->m_activePart ? d->m_activePart->instance() : 0L ); + + kdDebug(1000) << this << " emitting activePartChanged " << d->m_activePart << endl; + emit activePartChanged( d->m_activePart ); +} + +void PartManager::setActiveInstance( TDEInstance * instance ) +{ + // It's a separate method to allow redefining this behavior + TDEGlobal::_activeInstance = instance; +} + +Part *PartManager::activePart() const +{ + return d->m_activePart; +} + +TQWidget *PartManager::activeWidget() const +{ + return d->m_activeWidget; +} + +void PartManager::setSelectedPart( Part *part, TQWidget *widget ) +{ + if ( part == d->m_selectedPart && widget == d->m_selectedWidget ) + return; + + Part *oldPart = d->m_selectedPart; + TQWidget *oldWidget = d->m_selectedWidget; + + d->m_selectedPart = part; + d->m_selectedWidget = widget; + + if ( part && !widget ) + d->m_selectedWidget = part->widget(); + + if ( oldPart ) + { + PartSelectEvent ev( false, oldPart, oldWidget ); + TQApplication::sendEvent( oldPart, &ev ); + TQApplication::sendEvent( oldWidget, &ev ); + } + + if ( d->m_selectedPart ) + { + PartSelectEvent ev( true, d->m_selectedPart, d->m_selectedWidget ); + TQApplication::sendEvent( d->m_selectedPart, &ev ); + TQApplication::sendEvent( d->m_selectedWidget, &ev ); + } +} + +Part *PartManager::selectedPart() const +{ + return d->m_selectedPart; +} + +TQWidget *PartManager::selectedWidget() const +{ + return d->m_selectedWidget; +} + +void PartManager::slotObjectDestroyed() +{ + kdDebug(1000) << "KPartManager::slotObjectDestroyed()" << endl; + removePart( const_cast<Part *>( static_cast<const Part *>( sender() ) ) ); +} + +void PartManager::slotWidgetDestroyed() +{ + kdDebug(1000) << "KPartsManager::slotWidgetDestroyed()" << endl; + if ( static_cast<const TQWidget *>( sender() ) == d->m_activeWidget ) + setActivePart( 0L ); //do not remove the part because if the part's widget dies, then the + //part will delete itself anyway, invoking removePart() in its destructor +} + +const TQPtrList<Part> *PartManager::parts() const +{ + return &d->m_parts; +} + +void PartManager::addManagedTopLevelWidget( const TQWidget *topLevel ) +{ + if ( !topLevel->isTopLevel() ) + return; + + if ( d->m_managedTopLevelWidgets.containsRef( topLevel ) ) + return; + + d->m_managedTopLevelWidgets.append( topLevel ); + connect( topLevel, TQT_SIGNAL( destroyed() ), + this, TQT_SLOT( slotManagedTopLevelWidgetDestroyed() ) ); +} + +void PartManager::removeManagedTopLevelWidget( const TQWidget *topLevel ) +{ + if ( !topLevel->isTopLevel() ) + return; + + if ( d->m_managedTopLevelWidgets.findRef( topLevel ) == -1 ) + return; + + d->m_managedTopLevelWidgets.remove(); +} + +void PartManager::slotManagedTopLevelWidgetDestroyed() +{ + const TQWidget *widget = static_cast<const TQWidget *>( sender() ); + removeManagedTopLevelWidget( widget ); +} + +int PartManager::reason() const +{ + return d->m_reason; +} + +void PartManager::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +#include "partmanager.moc" diff --git a/tdeparts/partmanager.h b/tdeparts/partmanager.h new file mode 100644 index 000000000..604e5ff92 --- /dev/null +++ b/tdeparts/partmanager.h @@ -0,0 +1,289 @@ +// -*- mode: c++; c-basic-offset: 2 -*- +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __kpartmanager_h__ +#define __kpartmanager_h__ + +#include <tqobject.h> +#include <tqwidget.h> +#include <tqptrlist.h> + +#include <tdelibs_export.h> + +class TDEInstance; + +namespace KParts +{ + +class Part; + +class PartManagerPrivate; + +/** + * The part manager is an object which knows about a collection of parts + * (even nested ones) and handles activation/deactivation. + * + * Applications that want to embed parts without merging GUIs + * only use a KParts::PartManager. Those who want to merge GUIs use a + * KParts::MainWindow for example, in addition to a part manager. + * + * Parts know about the part manager to add nested parts to it. + * See also KParts::Part::manager() and KParts::Part::setManager(). + */ +class KPARTS_EXPORT PartManager : public TQObject +{ + Q_OBJECT + TQ_ENUMS( SelectionPolicy ) + TQ_PROPERTY( SelectionPolicy selectionPolicy READ selectionPolicy WRITE setSelectionPolicy ) + TQ_PROPERTY( bool allowNestedParts READ allowNestedParts WRITE setAllowNestedParts ) + TQ_PROPERTY( bool ignoreScrollBars READ ignoreScrollBars WRITE setIgnoreScrollBars ) +public: + /// Selection policy. The default policy of a PartManager is Direct. + enum SelectionPolicy { Direct, TriState }; + + /** + * This extends TQFocusEvent::Reason with the non-focus-event reasons for partmanager to activate a part. + * To test for "any focusin reason", use < ReasonLeftClick. + * NoReason usually means: explicit activation with @ref setActivePart. + * @since 3.3 + */ + enum Reason { ReasonLeftClick = 100, ReasonMidClick, ReasonRightClick, NoReason }; + + /** + * Constructs a part manager. + * + * @param parent The toplevel widget (window / dialog) the + * partmanager should monitor for activation/selection + * events + * @param name The object's name, if any. + */ + PartManager( TQWidget * parent, const char * name = 0L ); + /** + * Constructs a part manager. + * + * @param topLevel The toplevel widget (window / dialog ) the + * partmanager should monitor for activation/selection + * events + * @param parent The parent TQObject. + * @param name The object's name, if any. + */ + PartManager( TQWidget * topLevel, TQObject *parent, const char *name = 0 ); + virtual ~PartManager(); + + /** + * Sets the selection policy of the partmanager. + */ + void setSelectionPolicy( SelectionPolicy policy ); + /** + * Returns the current selection policy. + */ + SelectionPolicy selectionPolicy() const; + + /** + * Specifies whether the partmanager should handle/allow nested parts + * or not. + * + * This is a property the shell has to set/specify. Per + * default we assume that the shell cannot handle nested + * parts. However in case of a KOffice shell for example we allow + * nested parts. A Part is nested (a child part) if its parent + * object inherits KParts::Part. If a child part is activated and + * nested parts are not allowed/handled, then the top parent part in + * the tree is activated. + */ + void setAllowNestedParts( bool allow ); + /** + * @see setAllowNestedParts + */ + bool allowNestedParts() const; + + /** + * Specifies whether the partmanager should ignore mouse click events for + * scrollbars or not. If the partmanager ignores them, then clicking on the + * scrollbars of a non-active/non-selected part will not change the selection + * or activation state. + * + * The default value is false (read: scrollbars are NOT ignored). + */ + void setIgnoreScrollBars( bool ignore ); + /** + * @see setIgnoreScrollBars + */ + bool ignoreScrollBars() const; + + /** + * Specifies which mouse buttons the partmanager should react upon. + * By default it reacts on all mouse buttons (LMB/MMB/RMB). + * @param buttonMask a combination of TQt::ButtonState values e.g. Qt::LeftButton | Qt::MidButton + */ + void setActivationButtonMask( short int buttonMask ); + /** + * @see setActivationButtonMask + */ + short int activationButtonMask() const; + + /** + * @internal + */ + virtual bool eventFilter( TQObject *obj, TQEvent *ev ); + + /** + * Adds a part to the manager. + * + * Sets it to the active part automatically if @p setActive is true (default ). + * Behavior fix in KDE3.4: the part's widget is shown only if @p setActive is true, + * it used to be shown in all cases before. + */ + virtual void addPart( Part *part, bool setActive = true ); + + /** + * Removes a part from the manager (this does not delete the object) . + * + * Sets the active part to 0 if @p part is the activePart() . + */ + virtual void removePart( Part *part ); + + /** + * Replaces @p oldPart with @p newPart, and sets @p newPart as active if + * @p setActive is true. + * This is an optimised version of removePart + addPart + */ + virtual void replacePart( Part * oldPart, Part * newPart, bool setActive = true ); + + /** + * Sets the active part. + * + * The active part receives activation events. + * + * @p widget can be used to specify which widget was responsible for the activation. + * This is important if you have multiple views for a document/part, like in KOffice. + */ + virtual void setActivePart( Part *part, TQWidget *widget = 0L ); + + /** + * Returns the active part. + **/ + virtual Part *activePart() const; + + /** + * Returns the active widget of the current active part (see activePart()). + */ + virtual TQWidget *activeWidget() const; + + /** + * Sets the selected part. + * + * The selected part receives selection events. + * + * @p widget can be used to specify which widget was responsible for the selection. + * This is important if you have multiple views for a document/part, like in KOffice. + */ + virtual void setSelectedPart( Part *part, TQWidget *widget = 0L ); + + /** + * Returns the current selected part. + */ + virtual Part *selectedPart() const; + + /** + * Returns the selected widget of the current selected part (see selectedPart()). + */ + virtual TQWidget *selectedWidget() const; + + /** + * Returns the list of parts being managed by the partmanager. + */ + const TQPtrList<Part> *parts() const; + + /** + * Adds the @p topLevel widget to the list of managed toplevel widgets. + * Usually a PartManager only listens for events (for activation/selection) + * for one toplevel widget (and its children), the one specified in the + * constructor. Sometimes however (like for example when using the KDE dockwidget + * library), it is necessary to extend this. + */ + void addManagedTopLevelWidget( const TQWidget *topLevel ); + /** + * Removes the @p topLevel widget from the list of managed toplevel widgets. + * @see addManagedTopLevelWidget + */ + void removeManagedTopLevelWidget( const TQWidget *topLevel ); + + /** + * @return the reason for the last activePartChanged signal emitted. + * @see Reason + * @since 3.3 + */ + int reason() const; + +signals: + /** + * Emitted when a new part has been added. + * @see addPart() + **/ + void partAdded( KParts::Part *part ); + /** + * Emitted when a part has been removed. + * @see removePart() + **/ + void partRemoved( KParts::Part *part ); + /** + * Emitted when the active part has changed. + * @see setActivePart() + **/ + void activePartChanged( KParts::Part *newPart ); + +protected: + /** + * Changes the active instance when the active part changes. + * The active instance is used by KBugReport and KAboutDialog. + * Override if you really need to - usually you don't need to. + */ + virtual void setActiveInstance( TDEInstance * instance ); + +protected slots: + /** + * Removes a part when it is destroyed. + **/ + void slotObjectDestroyed(); + + /** + * @internal + */ + void slotWidgetDestroyed(); + + /** + * @internal + */ + void slotManagedTopLevelWidgetDestroyed(); +private: + Part * findPartFromWidget( TQWidget * widget, const TQPoint &pos ); + Part * findPartFromWidget( TQWidget * widget ); + +protected: + virtual void virtual_hook( int id, void* data ); +private: + PartManagerPrivate *d; +}; + +} + +#endif + diff --git a/tdeparts/plugin.cpp b/tdeparts/plugin.cpp new file mode 100644 index 000000000..457caa71f --- /dev/null +++ b/tdeparts/plugin.cpp @@ -0,0 +1,315 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <config.h> +#include <tdeparts/plugin.h> +#include <tdeparts/part.h> +#include <tdeparts/componentfactory.h> + +#include <assert.h> + +#include <tqfile.h> +#include <tqobjectlist.h> +#include <tqfileinfo.h> + +#include <klibloader.h> +#include <kinstance.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <kxmlguifactory.h> +#include <klocale.h> +#include <kconfig.h> +#include <ksimpleconfig.h> + +using namespace KParts; + +class Plugin::PluginPrivate +{ +public: + PluginPrivate() : m_parentInstance( 0 ) {} + + const TDEInstance *m_parentInstance; + TQString m_library; // filename of the library +}; + +Plugin::Plugin( TQObject* parent, const char* name ) + : TQObject( parent, name ) +{ + //kdDebug() << className() << endl; + d = new PluginPrivate(); +} + +Plugin::~Plugin() +{ + delete d; +} + +TQString Plugin::xmlFile() const +{ + TQString path = KXMLGUIClient::xmlFile(); + + if ( !d->m_parentInstance || ( path.length() > 0 && path[ 0 ] == '/' ) ) + return path; + + TQString absPath = locate( "data", TQString::fromLatin1( d->m_parentInstance->instanceName() ) + '/' + path ); + assert( !absPath.isEmpty() ); + return absPath; +} + +TQString Plugin::localXMLFile() const +{ + TQString path = KXMLGUIClient::xmlFile(); + + if ( !d->m_parentInstance || ( path.length() > 0 && path[ 0 ] == '/' ) ) + return path; + + TQString absPath = locateLocal( "data", TQString::fromLatin1( d->m_parentInstance->instanceName() ) + '/' + path ); + assert( !absPath.isEmpty() ); + return absPath; +} + +//static +TQValueList<Plugin::PluginInfo> Plugin::pluginInfos( const TDEInstance * instance ) +{ + if ( !instance ) + kdError(1000) << "No instance ???" << endl; + + TQValueList<PluginInfo> plugins; + + // KDE4: change * into *.rc and remove test for .desktop from the for loop below. + const TQStringList pluginDocs = instance->dirs()->findAllResources( + "data", instance->instanceName()+"/kpartplugins/*", true, false ); + + TQMap<TQString,TQStringList> sortedPlugins; + + TQStringList::ConstIterator pIt = pluginDocs.begin(); + TQStringList::ConstIterator pEnd = pluginDocs.end(); + for (; pIt != pEnd; ++pIt ) + { + TQFileInfo fInfo( *pIt ); + if ( fInfo.extension() == TQString::fromLatin1( "desktop" ) ) + continue; + + TQMap<TQString,TQStringList>::Iterator mapIt = sortedPlugins.find( fInfo.fileName() ); + if ( mapIt == sortedPlugins.end() ) + mapIt = sortedPlugins.insert( fInfo.fileName(), TQStringList() ); + + mapIt.data().append( *pIt ); + } + + TQMap<TQString,TQStringList>::ConstIterator mapIt = sortedPlugins.begin(); + TQMap<TQString,TQStringList>::ConstIterator mapEnd = sortedPlugins.end(); + for (; mapIt != mapEnd; ++mapIt ) + { + PluginInfo info; + TQString doc; + info.m_absXMLFileName = KXMLGUIClient::findMostRecentXMLFile( mapIt.data(), doc ); + if ( info.m_absXMLFileName.isEmpty() ) + continue; + + kdDebug( 1000 ) << "found KParts Plugin : " << info.m_absXMLFileName << endl; + info.m_relXMLFileName = "kpartplugins/"; + info.m_relXMLFileName += mapIt.key(); + + info.m_document.setContent( doc ); + if ( info.m_document.documentElement().isNull() ) + continue; + + plugins.append( info ); + } + + return plugins; +} + +void Plugin::loadPlugins( TQObject *parent, const TDEInstance *instance ) +{ + loadPlugins( parent, pluginInfos( instance ), instance ); +} + +void Plugin::loadPlugins( TQObject *parent, const TQValueList<PluginInfo> &pluginInfos, const TDEInstance *instance ) +{ + TQValueList<PluginInfo>::ConstIterator pIt = pluginInfos.begin(); + TQValueList<PluginInfo>::ConstIterator pEnd = pluginInfos.end(); + for (; pIt != pEnd; ++pIt ) + { + TQString library = (*pIt).m_document.documentElement().attribute( "library" ); + + if ( library.isEmpty() || hasPlugin( parent, library ) ) + continue; + + Plugin *plugin = loadPlugin( parent, TQFile::encodeName(library) ); + + if ( plugin ) + { + plugin->d->m_parentInstance = instance; + plugin->setXMLFile( (*pIt).m_relXMLFileName, false, false ); + plugin->setDOMDocument( (*pIt).m_document ); + + } + } + +} + +void Plugin::loadPlugins( TQObject *parent, const TQValueList<PluginInfo> &pluginInfos ) +{ + loadPlugins(parent, pluginInfos, 0); +} + +// static +Plugin* Plugin::loadPlugin( TQObject * parent, const char* libname ) +{ + Plugin* plugin = ComponentFactory::createInstanceFromLibrary<Plugin>( libname, parent, libname ); + if ( !plugin ) + return 0L; + plugin->d->m_library = libname; + return plugin; +} + +TQPtrList<KParts::Plugin> Plugin::pluginObjects( TQObject *parent ) +{ + TQPtrList<KParts::Plugin> objects; + + if (!parent ) + return objects; + + TQObjectList *plugins = parent->queryList( "KParts::Plugin", 0, false, false ); + + TQObjectListIt it( *plugins ); + for ( ; it.current() ; ++it ) + { + objects.append( static_cast<Plugin *>( it.current() ) ); + } + + delete plugins; + + return objects; +} + +bool Plugin::hasPlugin( TQObject* parent, const TQString& library ) +{ + TQObjectList *plugins = parent->queryList( "KParts::Plugin", 0, false, false ); + TQObjectListIt it( *plugins ); + for ( ; it.current() ; ++it ) + { + if ( static_cast<Plugin *>( it.current() )->d->m_library == library ) + { + delete plugins; + return true; + } + } + delete plugins; + return false; +} + +void Plugin::setInstance( TDEInstance *instance ) +{ + TDEGlobal::locale()->insertCatalogue( instance->instanceName() ); + KXMLGUIClient::setInstance( instance ); +} + +void Plugin::loadPlugins( TQObject *parent, KXMLGUIClient* parentGUIClient, TDEInstance* instance, bool enableNewPluginsByDefault ) +{ + TDEConfigGroup cfgGroup( instance->config(), "KParts Plugins" ); + TQValueList<PluginInfo> plugins = pluginInfos( instance ); + TQValueList<PluginInfo>::ConstIterator pIt = plugins.begin(); + TQValueList<PluginInfo>::ConstIterator pEnd = plugins.end(); + for (; pIt != pEnd; ++pIt ) + { + TQDomElement docElem = (*pIt).m_document.documentElement(); + TQString library = docElem.attribute( "library" ); + + if ( library.isEmpty() ) + continue; + + // Check configuration + const TQString name = docElem.attribute( "name" ); + + bool pluginEnabled = enableNewPluginsByDefault; + if ( cfgGroup.hasKey( name + "Enabled" ) ) + { + pluginEnabled = cfgGroup.readBoolEntry( name + "Enabled" ); + } + else + { // no user-setting, load plugin default setting + TQString relPath = TQString( instance->instanceName() ) + "/" + (*pIt).m_relXMLFileName; + relPath.truncate( relPath.findRev( '.' ) ); // remove extension + relPath += ".desktop"; + //kdDebug(1000) << "looking for " << relPath << endl; + const TQString desktopfile = instance->dirs()->findResource( "data", relPath ); + if( !desktopfile.isEmpty() ) + { + //kdDebug(1000) << "loadPlugins found desktop file for " << name << ": " << desktopfile << endl; + KSimpleConfig desktop( desktopfile, true ); + desktop.setDesktopGroup(); + pluginEnabled = desktop.readBoolEntry( + "X-TDE-PluginInfo-EnabledByDefault", enableNewPluginsByDefault ); + } + else + { + //kdDebug(1000) << "loadPlugins no desktop file found in " << relPath << endl; + } + } + + // search through already present plugins + TQObjectList *pluginList = parent->queryList( "KParts::Plugin", 0, false, false ); + TQObjectListIt it( *pluginList ); + bool pluginFound = false; + for ( ; it.current() ; ++it ) + { + Plugin * plugin = static_cast<Plugin *>( it.current() ); + if( plugin->d->m_library == library ) + { + // delete and unload disabled plugins + if( !pluginEnabled ) + { + kdDebug( 1000 ) << "remove plugin " << name << endl; + KXMLGUIFactory * factory = plugin->factory(); + if( factory ) + factory->removeClient( plugin ); + delete plugin; + } + + pluginFound = true; + break; + } + } + delete pluginList; + + // if the plugin is already loaded or if it's disabled in the + // configuration do nothing + if( pluginFound || !pluginEnabled ) + continue; + + kdDebug( 1000 ) << "load plugin " << name << endl; + Plugin *plugin = loadPlugin( parent, TQFile::encodeName(library) ); + + if ( plugin ) + { + plugin->d->m_parentInstance = instance; + plugin->setXMLFile( (*pIt).m_relXMLFileName, false, false ); + plugin->setDOMDocument( (*pIt).m_document ); + parentGUIClient->insertChildClient( plugin ); + } + } +} + +// vim:sw=4:et:sts=4 + +#include "plugin.moc" diff --git a/tdeparts/plugin.h b/tdeparts/plugin.h new file mode 100644 index 000000000..df1200ee9 --- /dev/null +++ b/tdeparts/plugin.h @@ -0,0 +1,177 @@ +/* This file is part of the KDE project + Copyright (C) 1999 Simon Hausmann <[email protected]> + (C) 1999 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef PLUGIN_H +#define PLUGIN_H + +#include <tqobject.h> +#include <kaction.h> +#include <kxmlguiclient.h> + +class TDEInstance; + +namespace KParts +{ + +/** + * A plugin is the way to add actions to an existing KParts application, + * or to a Part. + * + * The XML of those plugins looks exactly like of the shell or parts, + * with one small difference: The document tag should have an additional + * attribute, named "library", and contain the name of the library implementing + * the plugin. + * + * If you want this plugin to be used by a part, you need to + * install the rc file under the directory + * "data" (TDEDIR/share/apps usually)+"/instancename/kpartplugins/" + * where instancename is the name of the part's instance. + * + * You should also install a "plugin info" .desktop file with the same name. + * \see PluginInfo + */ +class KPARTS_EXPORT Plugin : public TQObject, virtual public KXMLGUIClient +{ + Q_OBJECT +public: + /** + * Struct holding information about a plugin + */ + struct PluginInfo + { + TQString m_relXMLFileName; ///< relative filename, i.e. kpartplugins/name + TQString m_absXMLFileName; ///< full path of most recent filename matching the relative filename + TQDomDocument m_document; + }; + + /** + * Construct a new KParts plugin. + */ + Plugin( TQObject* parent = 0, const char* name = 0 ); + /** + * Destructor. + */ + virtual ~Plugin(); + + /** + * Reimplemented for internal reasons + */ + virtual TQString xmlFile() const; + + /** + * Reimplemented for internal reasons + */ + virtual TQString localXMLFile() const; + + /** + * Load the plugin libraries from the directories appropriate + * to @p instance and make the Plugin objects children of @p parent. + * + * It is recommended to use the last loadPlugins method instead, + * to support enabling and disabling of plugins. + */ + static void loadPlugins( TQObject *parent, const TDEInstance * instance ); + + /** + * Load the plugin libraries specified by the list @p docs and make the + * Plugin objects children of @p parent . + * + * It is recommended to use the last loadPlugins method instead, + * to support enabling and disabling of plugins. + */ + static void loadPlugins( TQObject *parent, const TQValueList<PluginInfo> &pluginInfos ); + + /** + * Load the plugin libraries specified by the list @p pluginInfos, make the + * Plugin objects children of @p parent, and use the given @p instance. + * + * It is recommended to use the last loadPlugins method instead, + * to support enabling and disabling of plugins. + */ + static void loadPlugins( TQObject *parent, const TQValueList<PluginInfo> &pluginInfos, const TDEInstance * instance ); + + /** + * Load the plugin libraries for the given @p instance, make the + * Plugin objects children of @p parent, and insert the plugin as a child GUI client + * of @p parentGUIClient. + * + * This method uses the TDEConfig object of the given instance, to find out which + * plugins are enabled and which are disabled. What happens by default (i.e. + * for new plugins that are not in that config file) is controlled by + * @p enableNewPluginsByDefault. It can be overridden by the plugin if it + * sets the X-TDE-PluginInfo-EnabledByDefault key in the .desktop file + * (with the same name as the .rc file) + * + * If a disabled plugin is already loaded it will be removed from the GUI + * factory and deleted. + * + * This method is automatically called by KParts::Plugin and by KParts::MainWindow. + * + * If you call this method in an already constructed GUI (like when the user + * has changed which plugins are enabled) you need to add the new plugins to + * the KXMLGUIFactory: + * \code + * if( factory() ) + * { + * TQPtrList<KParts::Plugin> plugins = KParts::Plugin::pluginObjects( this ); + * TQPtrListIterator<KParts::Plugin> it( plugins ); + * KParts::Plugin * plugin; + * while( ( plugin = it.current() ) != 0 ) + * { + * ++it; + * factory()->addClient( plugin ); + * } + * } + * \endcode + */ + static void loadPlugins( TQObject *parent, KXMLGUIClient* parentGUIClient, TDEInstance* instance, bool enableNewPluginsByDefault = true ); + + /** + * Returns a list of plugin objects loaded for @p parent. This + * functions basically calls the queryList method of + * TQObject to retrieve the list of child objects inheriting + * KParts::Plugin . + **/ + static TQPtrList<Plugin> pluginObjects( TQObject *parent ); + +protected: + /** + * Look for plugins in the @p instance's "data" directory (+"/kpartplugins") + * + * @return A list of TQDomDocument s, containing the parsed xml documents returned by plugins. + */ + static TQValueList<Plugin::PluginInfo> pluginInfos( const TDEInstance * instance ); + + /** + * @internal + * @return The plugin created from the library @p libname + */ + static Plugin* loadPlugin( TQObject * parent, const char* libname ); + + virtual void setInstance( TDEInstance *instance ); + +private: + static bool hasPlugin( TQObject* parent, const TQString& library ); + class PluginPrivate; + PluginPrivate *d; +}; + +} + +#endif diff --git a/tdeparts/statusbarextension.cpp b/tdeparts/statusbarextension.cpp new file mode 100644 index 000000000..02dd79acb --- /dev/null +++ b/tdeparts/statusbarextension.cpp @@ -0,0 +1,178 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Daniel Molkentin <[email protected]> + Copyright (C) 2003 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "statusbarextension.h" + +#include <tqvaluelist.h> +#include <tqobjectlist.h> + +#include <kstatusbar.h> +#include <kmainwindow.h> +#include <kdebug.h> +#include <tdelibs_export.h> +#include <tdeparts/part.h> +#include <tdeparts/event.h> + +using namespace KParts; + +/////////////////////////////////////////////////////////////////// +// Helper Classes +/////////////////////////////////////////////////////////////////// + +class KParts::StatusBarItem { + public: + StatusBarItem() // for QValueList + : m_widget(0), m_visible(false) + {} + StatusBarItem( TQWidget * widget, int stretch, bool permanent ) + : m_widget(widget), m_stretch(stretch), m_permanent(permanent), m_visible(false) + {} + + TQWidget * widget() const { return m_widget; } + + void ensureItemShown( KStatusBar * sb ) + { + if ( !m_visible ) + { + sb->addWidget( m_widget, m_stretch, m_permanent ); + m_visible = true; + m_widget->show(); + } + } + void ensureItemHidden( KStatusBar * sb ) + { + if ( m_visible ) + { + sb->removeWidget( m_widget ); + m_visible = false; + m_widget->hide(); + } + } + private: + TQWidget * m_widget; + int m_stretch; + bool m_permanent; + bool m_visible; // true when the item has been added to the statusbar +}; + +/////////////////////////////////////////////////////////////////// + + +StatusBarExtension::StatusBarExtension(KParts::ReadOnlyPart *parent, const char* name) + : TQObject(parent, name), m_statusBar(0), d(0) +{ + parent->installEventFilter(this); +} + +StatusBarExtension::~StatusBarExtension() +{ +} + + +StatusBarExtension *StatusBarExtension::childObject( TQObject *obj ) +{ + if ( !obj || obj->childrenListObject().isEmpty() ) + return 0L; + + // we try to do it on our own, in hope that we are faster than + // queryList, which looks kind of big :-) + const TQObjectList children = obj->childrenListObject(); + TQObjectListIt it( children ); + for (; it.current(); ++it ) + if ( it.current()->inherits( "KParts::StatusBarExtension" ) ) + return static_cast<KParts::StatusBarExtension *>( it.current() ); + + return 0L; +} + +bool StatusBarExtension::eventFilter(TQObject * watched, TQEvent* ev) +{ + if ( !GUIActivateEvent::test( ev ) || + !watched->inherits("KParts::ReadOnlyPart") ) + return TQObject::eventFilter(watched, ev); + + KStatusBar * sb = statusBar(); + if ( !sb ) + return TQObject::eventFilter(watched, ev); + + GUIActivateEvent *gae = static_cast<GUIActivateEvent*>(ev); + + if ( gae->activated() ) + { + TQValueListIterator<StatusBarItem> it = m_statusBarItems.begin(); + for ( ; it != m_statusBarItems.end() ; ++it ) + (*it).ensureItemShown( sb ); + } + else + { + TQValueListIterator<StatusBarItem> it = m_statusBarItems.begin(); + for ( ; it != m_statusBarItems.end() ; ++it ) + (*it).ensureItemHidden( sb ); + } + + return false; + +} + +KStatusBar * StatusBarExtension::statusBar() const +{ + if ( !m_statusBar ) { + TQWidget* w = static_cast<KParts::ReadOnlyPart*>(parent())->widget(); + KMainWindow* mw = tqt_dynamic_cast<KMainWindow *>( w->topLevelWidget() ); + if ( mw ) + m_statusBar = mw->statusBar(); + } + return m_statusBar; +} + +void StatusBarExtension::setStatusBar( KStatusBar* status ) +{ + m_statusBar = status; +} + +void StatusBarExtension::addStatusBarItem( TQWidget * widget, int stretch, bool permanent ) +{ + m_statusBarItems.append( StatusBarItem( widget, stretch, permanent ) ); + TQValueListIterator<StatusBarItem> it = m_statusBarItems.fromLast(); + KStatusBar * sb = statusBar(); + Q_ASSERT(sb); + if (sb) + (*it).ensureItemShown( sb ); +} + +void StatusBarExtension::removeStatusBarItem( TQWidget * widget ) +{ + KStatusBar * sb = statusBar(); + TQValueListIterator<StatusBarItem> it = m_statusBarItems.begin(); + for ( ; it != m_statusBarItems.end() ; ++it ) + if ( (*it).widget() == widget ) + { + if ( sb ) + (*it).ensureItemHidden( sb ); + m_statusBarItems.remove( it ); + break; + } + if ( it == m_statusBarItems.end() ) + kdWarning(1000) << "StatusBarExtension::removeStatusBarItem. Widget not found : " << widget << endl; +} + +#include "statusbarextension.moc" + +// vim: ts=2 sw=2 et diff --git a/tdeparts/statusbarextension.h b/tdeparts/statusbarextension.h new file mode 100644 index 000000000..fa635a12b --- /dev/null +++ b/tdeparts/statusbarextension.h @@ -0,0 +1,126 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Daniel Molkentin <[email protected]> + Copyright (C) 2003 David Faure <[email protected]> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef KPARTS_STATUSBAREXTENSION_H +#define KPARTS_STATUSBAREXTENSION_H + +#include <tqwidget.h> +#include <tqvaluelist.h> + +#include <tdelibs_export.h> + +class KStatusBar; +class KMainWindow; +class TQEvent; + +namespace KParts +{ + + class ReadOnlyPart; + + // Defined in impl + class StatusBarItem; + + + /** + * @short An extension for KParts that allows more sophisticated statusbar handling + * + * Every part can use this class to customize the statusbar as long as it is active. + * Add items via addStatusBarItem() and remove an item with removeStatusBarItem(). + * + * IMPORTANT: do NOT add any items immediately after constructing the extension. + * Give the application time to set the statusbar in the extension if necessary. + * + * @since 3.2 + */ + class KPARTS_EXPORT StatusBarExtension : public TQObject + { + Q_OBJECT + + public: + StatusBarExtension( KParts::ReadOnlyPart *parent, const char *name=0L ); + ~StatusBarExtension(); + + /** + * This adds a widget to the statusbar for this part. + * If you use this method instead of using statusBar() directly, + * this extension will take care of removing the items when the parts GUI + * is deactivated and will re-add them when it is reactivated. + * The parameters are the same as TQStatusBar::addWidget(). + * + * Note that you can't use KStatusBar methods (inserting text items by id) + * but you can create a KStatusBarLabel with a dummy id instead, and use + * it directly in order to get the same look and feel. + * + * @param widget the widget to add + * @param stretch the stretch factor. 0 for a minimum size. + * @param permanent passed to TQStatusBar::addWidget as the "permanent" bool. + * Note that the item isn't really permanent though, it goes away when + * the part is unactivated. This simply controls where temporary messages + * hide the @p widget, and whether it's added to the left or to the right side. + * + * IMPORTANT: do NOT add any items immediately after constructing the extension. + * Give the application time to set the statusbar in the extension if necessary. + */ + void addStatusBarItem( TQWidget * widget, int stretch, bool permanent ); + + /** + * Remove a @p widget from the statusbar for this part. + */ + void removeStatusBarItem( TQWidget * widget ); + + /** + * @return the statusbar of the KMainWindow in which this part is currently embedded. + * WARNING: this could return 0L + */ + KStatusBar* statusBar() const; + + /** + * This allows the hosting application to set a particular KStatusBar + * for this part. If it doesn't do this, the statusbar used will be + * the one of the KMainWindow in which the part is embedded. + * Konqueror uses this to assign a view-statusbar to the part. + * The part should never call this method! + */ + void setStatusBar( KStatusBar* status ); + + /** + * Queries @p obj for a child object which inherits from this + * BrowserExtension class. Convenience method. + */ + static StatusBarExtension *childObject( TQObject *obj ); + + /** @internal */ + virtual bool eventFilter( TQObject *watched, TQEvent* ev ); + + private: + + TQValueList<StatusBarItem> m_statusBarItems; // Our statusbar items + mutable KStatusBar* m_statusBar; + + // for future extensions + class StatusBarExtensionPrivate; + StatusBarExtensionPrivate *d; + }; + +} +#endif // KPARTS_STATUSBAREXTENSION_H + +// vim: ts=2 sw=2 et diff --git a/tdeparts/tests/Makefile.am b/tdeparts/tests/Makefile.am new file mode 100644 index 000000000..df0a2a5be --- /dev/null +++ b/tdeparts/tests/Makefile.am @@ -0,0 +1,46 @@ + +INCLUDES= -I$(top_srcdir) -I$(top_srcdir)/libltdl -I$(top_srcdir)/kfile -I$(top_srcdir)/kio $(all_includes) +AM_LDFLAGS = $(all_libraries) +LDADD = $(LIB_KPARTS) + +check_PROGRAMS = tdepartstest normalktmtest ghostviewtest + +tdepartstest_SOURCES = example.cpp parts.cpp +tdepartstest_LDADD = libnotepad.la $(LIB_KPARTS) +normalktmtest_SOURCES = normalktm.cpp parts.cpp +normalktmtest_LDADD = libnotepad.la $(LIB_KPARTS) +ghostviewtest_SOURCES = ghostview.cpp +ghostviewtest_LDADD = $(LIB_KPARTS) + +# These are not really libraries, but modules dynamically opened. +# So they should be installed in kde_module_dir, which is usually $prefix/lib/trinity +kde_module_LTLIBRARIES = libspellcheckplugin.la libnotepadpart.la + +libspellcheckplugin_la_SOURCES = plugin_spellcheck.cpp +libspellcheckplugin_la_LIBADD = $(LIB_KPARTS) +libspellcheckplugin_la_LDFLAGS = -module $(KDE_PLUGIN) + +libnotepadpart_la_SOURCES = notepadpart.cpp +libnotepadpart_la_LIBADD = libnotepad.la $(LIB_KPARTS) +libnotepadpart_la_LDFLAGS = -module $(KDE_PLUGIN) + +noinst_LTLIBRARIES = libnotepad.la +libnotepad_la_SOURCES = notepad.cpp + +rcdir = $(kde_datadir)/tdepartstest +rc_DATA = tdepartstest_shell.rc + +testpartdir = $(kde_datadir)/tdepartstestpart +testpart_DATA = tdepartstest_part1.rc + +notepaddir = $(kde_datadir)/notepadpart +notepad_DATA = notepadpart.rc + +ghostviewtestdir = $(kde_datadir)/ghostviewtest +ghostviewtest_DATA = ghostviewtest_shell.rc + +pluginsdir = $(kde_datadir)/notepadpart/kpartplugins +plugins_DATA = plugin_foobar.rc plugin_spellcheck.rc + +METASOURCES = AUTO + diff --git a/tdeparts/tests/README b/tdeparts/tests/README new file mode 100644 index 000000000..a0bee7ca6 --- /dev/null +++ b/tdeparts/tests/README @@ -0,0 +1,5 @@ +In order to test embedding the notepad part in konqueror, you need +to "make install", to install the libs, and to copy notepad.desktop +into $TDEDIR/share/services/, and remove kwrite.desktop from +$TDEDIR/share/applnk/... (at least the ServiceTypes line of it) + diff --git a/tdeparts/tests/example.cpp b/tdeparts/tests/example.cpp new file mode 100644 index 000000000..e8495ffe9 --- /dev/null +++ b/tdeparts/tests/example.cpp @@ -0,0 +1,135 @@ + +#include "example.h" +#include "parts.h" +#include "notepad.h" + +#include <tqsplitter.h> +#include <tqcheckbox.h> +#include <tqdir.h> + +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <kapplication.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <klocale.h> + +Shell::Shell() +{ + setXMLFile( "tdepartstest_shell.rc" ); + + m_manager = new KParts::PartManager( this ); + + // When the manager says the active part changes, the builder updates (recreates) the GUI + connect( m_manager, TQT_SIGNAL( activePartChanged( KParts::Part * ) ), + this, TQT_SLOT( createGUI( KParts::Part * ) ) ); + + // We can do this "switch active part" because we have a splitter with + // two items in it. + // I wonder what tdevelop uses/will use to embed kedit, BTW. + m_splitter = new TQSplitter( this ); + + m_part1 = new Part1(this, m_splitter); + m_part2 = new Part2(this, m_splitter); + + KActionCollection *coll = actionCollection(); + + (void)new KAction( "&View local file", 0, this, TQT_SLOT( slotFileOpen() ), coll, "open_local_file" ); + (void)new KAction( "&View remote file", 0, this, TQT_SLOT( slotFileOpenRemote() ), coll, "open_remote_file" ); + + m_paEditFile = new KAction( "&Edit file", 0, this, TQT_SLOT( slotFileEdit() ), coll, "edit_file" ); + m_paCloseEditor = new KAction( "&Close file editor", 0, this, TQT_SLOT( slotFileCloseEditor() ), coll, "close_editor" ); + m_paCloseEditor->setEnabled(false); + KAction * paQuit = new KAction( "&Quit", 0, this, TQT_SLOT( close() ), coll, "shell_quit" ); + paQuit->setIconSet(TQIconSet(BarIcon("exit"))); + + (void)new KAction( "Yet another menu item", 0, coll, "shell_yami" ); + (void)new KAction( "Yet another submenu item", 0, coll, "shell_yasmi" ); + + setCentralWidget( m_splitter ); + m_splitter->setMinimumSize( 400, 300 ); + + m_splitter->show(); + + m_manager->addPart( m_part1, true ); // sets part 1 as the active part + m_manager->addPart( m_part2, false ); + m_editorpart = 0; +} + +Shell::~Shell() +{ + disconnect( m_manager, 0, this, 0 ); +} + +void Shell::slotFileOpen() +{ + if ( ! m_part1->openURL( locate("data", TDEGlobal::instance()->instanceName()+"/tdepartstest_shell.rc" ) ) ) + KMessageBox::error(this,"Couldn't open file !"); +} + +void Shell::slotFileOpenRemote() +{ + KURL u ( "http://www.kde.org/index.html" ); + if ( ! m_part1->openURL( u ) ) + KMessageBox::error(this,"Couldn't open file !"); +} + +void Shell::embedEditor() +{ + if ( m_manager->activePart() == m_part2 ) + createGUI( 0L ); + + // replace part2 with the editor part + delete m_part2; + m_part2 = 0L; + m_editorpart = new NotepadPart( m_splitter, "editor", + this, "NotepadPart" ); + m_editorpart->setReadWrite(); // read-write mode + m_manager->addPart( m_editorpart ); + m_paEditFile->setEnabled(false); + m_paCloseEditor->setEnabled(true); +} + +void Shell::slotFileCloseEditor() +{ + // It is very important to close the url of a read-write part + // before destroying it. This allows to save the document (if modified) + // and also to cancel. + if ( ! m_editorpart->closeURL() ) + return; + + // Is this necessary ? (David) + if ( m_manager->activePart() == m_editorpart ) + createGUI( 0L ); + + delete m_editorpart; + m_editorpart = 0L; + m_part2 = new Part2(this, m_splitter); + m_manager->addPart( m_part2 ); + m_paEditFile->setEnabled(true); + m_paCloseEditor->setEnabled(false); +} + +void Shell::slotFileEdit() +{ + if ( !m_editorpart ) + embedEditor(); + // TODO use KFileDialog to allow testing remote files + if ( ! m_editorpart->openURL( TQDir::current().absPath()+"/tdepartstest_shell.rc" ) ) + KMessageBox::error(this,"Couldn't open file !"); +} + +int main( int argc, char **argv ) +{ + TDEApplication app( argc, argv, "tdepartstest" ); + + Shell *shell = new Shell; + + shell->show(); + + app.exec(); + + return 0; +} + +#include "example.moc" diff --git a/tdeparts/tests/example.h b/tdeparts/tests/example.h new file mode 100644 index 000000000..b4bdead61 --- /dev/null +++ b/tdeparts/tests/example.h @@ -0,0 +1,39 @@ + +#ifndef __example_h__ +#define __example_h__ + +#include <tdeparts/partmanager.h> +#include <tdeparts/mainwindow.h> + +class KAction; +class TQWidget; + +class Shell : public KParts::MainWindow +{ + Q_OBJECT +public: + Shell(); + virtual ~Shell(); + +protected slots: + void slotFileOpen(); + void slotFileOpenRemote(); + void slotFileEdit(); + void slotFileCloseEditor(); + +protected: + void embedEditor(); + +private: + + KAction * m_paEditFile; + KAction * m_paCloseEditor; + + KParts::ReadOnlyPart *m_part1; + KParts::Part *m_part2; + KParts::ReadWritePart *m_editorpart; + KParts::PartManager *m_manager; + TQWidget *m_splitter; +}; + +#endif diff --git a/tdeparts/tests/ghostview.cpp b/tdeparts/tests/ghostview.cpp new file mode 100644 index 000000000..5d1bbe5b3 --- /dev/null +++ b/tdeparts/tests/ghostview.cpp @@ -0,0 +1,119 @@ +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <kapplication.h> +#include <kaction.h> +#include <klocale.h> +#include <kfiledialog.h> +#include <kmessagebox.h> +#include <kcmdlineargs.h> +#include <klibloader.h> + +#include <tqwidget.h> +#include <tqdir.h> +#include <tqfile.h> + +#include <ktrader.h> + +#include "ghostview.h" + +Shell::Shell() +{ + setXMLFile( "ghostviewtest_shell.rc" ); + + KAction * paOpen = new KAction( "&Open file" , "fileopen", 0, this, + TQT_SLOT( slotFileOpen() ), actionCollection(), "file_open" ); + + KAction * paQuit = new KAction( "&Quit" , "exit", 0, this, TQT_SLOT( close() ), actionCollection(), "file_quit" ); + + // Try to find a postscript component first + KTrader::OfferList offers = KTrader::self()->query("application/postscript", "('KParts/ReadOnlyPart' in ServiceTypes) or ('Browser/View' in ServiceTypes)"); + + KLibFactory *factory = 0; + m_gvpart = 0; + KTrader::OfferList::Iterator it(offers.begin()); + for( ; it != offers.end(); ++it) + { + KService::Ptr ptr = (*it); + + factory = KLibLoader::self()->factory( TQFile::encodeName(ptr->library()) ); + if (factory) + { + m_gvpart = static_cast<KParts::ReadOnlyPart *>(factory->create(this, ptr->name().latin1(), "KParts::ReadOnlyPart")); + setCentralWidget( m_gvpart->widget() ); + // Integrate its GUI + createGUI( m_gvpart ); + + break; + } + } + + // if we couldn't find a component with the trader, try the + // kghostview library directly. if this ever happens, then something + // is seriously screwed up, though -- the kghostview component + // should be picked up by the trader + if (!m_gvpart) + { + factory = KLibLoader::self()->factory( "libkghostview" ); + if (factory) + { + // Create the part + m_gvpart = (KParts::ReadOnlyPart *)factory->create( this, "kgvpart", + "KParts::ReadOnlyPart" ); + // Set the main widget + setCentralWidget( m_gvpart->widget() ); + // Integrate its GUI + createGUI( m_gvpart ); + } + else + { + KMessageBox::error(this, "No libkghostview found !"); + } + } + // Set a reasonable size + resize( 600, 350 ); +} + +Shell::~Shell() +{ + delete m_gvpart; +} + +void Shell::openURL( const KURL & url ) +{ + m_gvpart->openURL( url ); +} + +void Shell::slotFileOpen() +{ + KURL url = KFileDialog::getOpenURL( TQString::null, "*.ps|Postscript files (*.ps)", 0L, "file dialog" ); + + if( !url.isEmpty() ) + openURL( url ); +} + +static KCmdLineOptions options[] = +{ + { "+file(s)", "Files to load", 0 }, + KCmdLineLastOption +}; +static const char version[] = "v0.0.1 2000 (c) David Faure"; +static const char description[] = "This is a test shell for the kghostview part."; + +int main( int argc, char **argv ) +{ + TDECmdLineArgs::init(argc, argv, "ghostviewtest", description, version); + TDECmdLineArgs::addCmdLineOptions( options ); // Add my own options. + TDEApplication app; + TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs(); + Shell *shell = new Shell; + if ( args->count() == 1 ) + { + // Allow full paths, but also simple filenames from current dir + KURL url( TQDir::currentDirPath()+"/", args->arg(0) ); + shell->openURL( url ); + } + shell->show(); + return app.exec(); +} + +#include "ghostview.moc" diff --git a/tdeparts/tests/ghostview.h b/tdeparts/tests/ghostview.h new file mode 100644 index 000000000..2974ded5e --- /dev/null +++ b/tdeparts/tests/ghostview.h @@ -0,0 +1,22 @@ +#ifndef __example_h__ +#define __example_h__ + +#include <tdeparts/mainwindow.h> + +class Shell : public KParts::MainWindow +{ + Q_OBJECT +public: + Shell(); + virtual ~Shell(); + + void openURL( const KURL & url ); + +protected slots: + void slotFileOpen(); + +private: + KParts::ReadOnlyPart *m_gvpart; +}; + +#endif diff --git a/tdeparts/tests/ghostviewtest_shell.rc b/tdeparts/tests/ghostviewtest_shell.rc new file mode 100644 index 000000000..0bae67c82 --- /dev/null +++ b/tdeparts/tests/ghostviewtest_shell.rc @@ -0,0 +1,15 @@ +<!DOCTYPE kpartgui> +<kpartgui name="KGVShell"> +<MenuBar> + <Menu name="file"><Text>&File</Text> + <Action name="file_open"/> + <Action name="file_quit"/> + </Menu> +</MenuBar> +<ToolBar name="KGV-ToolBar"> + <Action name="file_open"/> + <Action name="file_quit"/> +</ToolBar> +<StatusBar/> +</kpartgui> + diff --git a/tdeparts/tests/normalktm.cpp b/tdeparts/tests/normalktm.cpp new file mode 100644 index 000000000..277f3ccde --- /dev/null +++ b/tdeparts/tests/normalktm.cpp @@ -0,0 +1,122 @@ + +#include "normalktm.h" +#include "parts.h" +#include "notepad.h" + +#include <tqsplitter.h> +#include <tqcheckbox.h> +#include <tqdir.h> + +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <kapplication.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <klocale.h> + +#include <kmenubar.h> + +Shell::Shell() +{ + // We can do this "switch active part" because we have a splitter with + // two items in it. + // I wonder what tdevelop uses/will use to embed kedit, BTW. + m_splitter = new TQSplitter( this ); + + m_part1 = new Part1(this, m_splitter); + m_part2 = new Part2(this, m_splitter); + + TQPopupMenu * pFile = new TQPopupMenu( this ); + menuBar()->insertItem( "File", pFile ); + TQObject * coll = this; + KAction * paLocal = new KAction( "&View local file", 0, this, TQT_SLOT( slotFileOpen() ), coll, "open_local_file" ); + // No XML : we need to plug our actions ourselves + paLocal->plug( pFile ); + + KAction * paRemote = new KAction( "&View remote file", 0, this, TQT_SLOT( slotFileOpenRemote() ), coll, "open_remote_file" ); + paRemote->plug( pFile ); + + m_paEditFile = new KAction( "&Edit file", 0, this, TQT_SLOT( slotFileEdit() ), coll, "edit_file" ); + m_paEditFile->plug( pFile ); + + m_paCloseEditor = new KAction( "&Close file editor", 0, this, TQT_SLOT( slotFileCloseEditor() ), coll, "close_editor" ); + m_paCloseEditor->setEnabled(false); + m_paCloseEditor->plug( pFile ); + + KAction * paQuit = new KAction( "&Quit", 0, this, TQT_SLOT( close() ), coll, "shell_quit" ); + paQuit->setIconSet(TQIconSet(BarIcon("exit"))); + paQuit->plug( pFile ); + + setCentralWidget( m_splitter ); + m_splitter->setMinimumSize( 400, 300 ); + + m_splitter->show(); + + m_editorpart = 0; +} + +Shell::~Shell() +{ +} + +void Shell::slotFileOpen() +{ + if ( ! m_part1->openURL( locate("data", TDEGlobal::instance()->instanceName()+"/tdepartstest_shell.rc" ) ) ) + KMessageBox::error(this,"Couldn't open file !"); +} + +void Shell::slotFileOpenRemote() +{ + KURL u ( "http://www.kde.org/index.html" ); + if ( ! m_part1->openURL( u ) ) + KMessageBox::error(this,"Couldn't open file !"); +} + +void Shell::embedEditor() +{ + // replace part2 with the editor part + delete m_part2; + m_part2 = 0L; + m_editorpart = new NotepadPart( m_splitter, "editor", + this, "NotepadPart" ); + m_editorpart->setReadWrite(); // read-write mode + ////// m_manager->addPart( m_editorpart ); + m_editorpart->widget()->show(); //// we need to do this in a normal KTM.... + m_paEditFile->setEnabled(false); + m_paCloseEditor->setEnabled(true); +} + +void Shell::slotFileCloseEditor() +{ + delete m_editorpart; + m_editorpart = 0L; + m_part2 = new Part2(this, m_splitter); + ////// m_manager->addPart( m_part2 ); + m_part2->widget()->show(); //// we need to do this in a normal KTM.... + m_paEditFile->setEnabled(true); + m_paCloseEditor->setEnabled(false); +} + +void Shell::slotFileEdit() +{ + if ( !m_editorpart ) + embedEditor(); + // TODO use KFileDialog to allow testing remote files + if ( ! m_editorpart->openURL( TQDir::current().absPath()+"/tdepartstest_shell.rc" ) ) + KMessageBox::error(this,"Couldn't open file !"); +} + +int main( int argc, char **argv ) +{ + TDEApplication app( argc, argv, "tdepartstest" ); // we cheat and call ourselves tdepartstest for Shell::slotFileOpen() + + Shell *shell = new Shell; + + shell->show(); + + app.exec(); + + return 0; +} + +#include "normalktm.moc" diff --git a/tdeparts/tests/normalktm.h b/tdeparts/tests/normalktm.h new file mode 100644 index 000000000..26a93a52a --- /dev/null +++ b/tdeparts/tests/normalktm.h @@ -0,0 +1,38 @@ + +#ifndef __normalktm_h__ +#define __normalktm_h__ + +#include <tdeparts/part.h> +#include <kmainwindow.h> + +class KAction; +class TQWidget; + +class Shell : public KMainWindow +{ + Q_OBJECT +public: + Shell(); + virtual ~Shell(); + +protected slots: + void slotFileOpen(); + void slotFileOpenRemote(); + void slotFileEdit(); + void slotFileCloseEditor(); + +protected: + void embedEditor(); + +private: + + KAction * m_paEditFile; + KAction * m_paCloseEditor; + + KParts::ReadOnlyPart *m_part1; + KParts::Part *m_part2; + KParts::ReadWritePart *m_editorpart; + TQWidget *m_splitter; +}; + +#endif diff --git a/tdeparts/tests/notepad.cpp b/tdeparts/tests/notepad.cpp new file mode 100644 index 000000000..6494288cd --- /dev/null +++ b/tdeparts/tests/notepad.cpp @@ -0,0 +1,101 @@ + +#include "notepad.h" +#include <tdeparts/partmanager.h> +#include <tdeparts/mainwindow.h> + +#include <tqsplitter.h> +#include <tqfile.h> +#include <tqtextstream.h> +#include <tqmultilineedit.h> + +#include <kaboutdata.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kaction.h> +#include <klocale.h> +#include <kstatusbar.h> +#include <kstandarddirs.h> + +NotepadPart::NotepadPart( TQWidget* parentWidget, const char*, + TQObject* parent, const char* name, + const TQStringList& ) + : KParts::ReadWritePart( parent, name ) +{ + setInstance( NotepadFactory::instance() ); + + m_edit = new TQMultiLineEdit( parentWidget, "NotepadPart's multiline edit" ); + setWidget( m_edit ); + + (void)new KAction( "Search and replace", 0, this, TQT_SLOT( slotSearchReplace() ), actionCollection(), "searchreplace" ); + setXMLFile( "notepadpart.rc" ); + setReadWrite( true ); +} + +NotepadPart::~NotepadPart() +{ +} + +void NotepadPart::setReadWrite( bool rw ) +{ + m_edit->setReadOnly( !rw ); + if (rw) + connect( m_edit, TQT_SIGNAL( textChanged() ), this, TQT_SLOT( setModified() ) ); + else + disconnect( m_edit, TQT_SIGNAL( textChanged() ), this, TQT_SLOT( setModified() ) ); + + ReadWritePart::setReadWrite( rw ); +} + +TDEAboutData* NotepadPart::createAboutData() +{ + return new TDEAboutData( "notepadpart", I18N_NOOP( "Notepad" ), "2.0" ); +} + +bool NotepadPart::openFile() +{ + kdDebug() << "NotepadPart: opening " << m_file << endl; + // Hehe this is from a tutorial I did some time ago :) + TQFile f(m_file); + TQString s; + if ( f.open(IO_ReadOnly) ) { + TQTextStream t( &f ); + while ( !t.eof() ) { + s += t.readLine() + "\n"; + } + f.close(); + } + m_edit->setText(s); + + emit setStatusBarText( m_url.prettyURL() ); + + return true; +} + +bool NotepadPart::saveFile() +{ + if ( !isReadWrite() ) + return false; + TQFile f(m_file); + TQString s; + if ( f.open(IO_WriteOnly) ) { + TQTextStream t( &f ); + t << m_edit->text(); + f.close(); + return true; + } else + return false; +} + +void NotepadPart::slotSearchReplace() +{ + // What's this ? (David) +/* + TQValueList<KParts::XMLGUIServant *> plugins = KParts::Plugin::pluginServants( this ); + TQValueList<KParts::XMLGUIServant *>::ConstIterator it = plugins.begin(); + TQValueList<KParts::XMLGUIServant *>::ConstIterator end = plugins.end(); + for (; it != end; ++it ) + factory()->removeServant( *it ); +*/ +} + +#include "notepad.moc" diff --git a/tdeparts/tests/notepad.desktop b/tdeparts/tests/notepad.desktop new file mode 100644 index 000000000..a529d69a1 --- /dev/null +++ b/tdeparts/tests/notepad.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +Name=Notepad (example) +Name[af]=Notablok (voorbeeld) +Name[ar]=مفكرة (مثال) +Name[az]=Qeyd dəftəri (misal) +Name[be]=Нататнік (узор) +Name[bn]=নোটপ্যাড (উদাহরণ) +Name[br]=Skrabvloc'h (skouer) +Name[bs]=Notepad (primjer) +Name[ca]=Bloc de notes (exemple) +Name[cs]=Poznámkový blok (příklad) +Name[csb]=Notownik (przëmiôr) +Name[cy]=Pad ysgrifennu (enghraifft) +Name[da]=Notepad (eksempel) +Name[de]=Notizblock-Beispiel +Name[el]=Σημειωματάριο (παράδειγμα) +Name[eo]=Notlibro (ekzemplo) +Name[es]=Bloc de notas (ejemplo) +Name[et]=Notepad (näidis) +Name[eu]=Notepad (adibidea) +Name[fa]=دفترچه یادداشت)مثال( +Name[fi]=Muistio (esimerkki) +Name[fr]=Bloc-notes (exemple) +Name[fy]=Skriuwboekje (foarbyld) +Name[ga]=Notepad (sampla) +Name[gl]=Caderno de Notas (exemplo) +Name[he]=פנקס רשימות (דוגמה) +Name[hi]=नोटपैड (उदाहरण) +Name[hr]=Notepad (primjer) +Name[hu]=Jegyzettömb (példa) +Name[id]=Notepad (contoh) +Name[is]=Notepad (sýnishorn) +Name[it]=Blocco note (esempio) +Name[ja]=ノートパッド (例) +Name[ka]=ბლიკნოტი (მაგალითი) +Name[kk]=Блокнот (мысал) +Name[km]=Notepad (ឧទាហរណ៍) +Name[ko]=쪽지장 (보기) +Name[lb]=Notizblock (Beispill) +Name[lt]=Notepad (pavyzdys) +Name[lv]=Notepads (piemērs) +Name[mk]=Тетратка (пример) +Name[mn]=Тэмдэглэлийн блок (Жишээ) +Name[ms]=Notepad (contoh) +Name[mt]=Notepad (eżempju) +Name[nb]=Notisblokk (eksempel) +Name[nds]=Notizzeddel (Bispeel) +Name[ne]=नोटप्याड (उदाहरण) +Name[nl]=Kladblok (voorbeeld) +Name[nn]=Notisblokk (døme) +Name[nso]=Notepad (mohlala) +Name[oc]=Bloc de notes (exemple) +Name[pa]=ਨੋਟਪੈਡ (ਉਦਾਹਰਨ) +Name[pl]=Notatnik (przykład) +Name[pt]=Bloco de Notas (exemplo) +Name[pt_BR]=Bloco de notas (exemplo) +Name[ro]=Notepad (exemplu) +Name[ru]=Блокнот (пример) +Name[rw]=Notepad (urugero) +Name[se]=Čállingirjjáš (ovdamearka) +Name[sk]=Poznámkový blok (Príklad) +Name[sl]=Beležnica (zgled) +Name[sq]=Notepad (shembull) +Name[sr]=Бележница (пример) +Name[sr@Latn]=Beležnica (primer) +Name[sv]=Notepad (exempel) +Name[ta]=நோட்பாட் (உதாரணம்) +Name[te]=నోట్ పేడ్ (ఉదాహరణ) +Name[tg]=Дафтари ёддошт (мисол) +Name[th]=โน้ตแพด (ตัวอย่าง) +Name[tr]=Not defteri (örnek) +Name[tt]=Däftär (ürnäk) +Name[uk]=Записна книжка (приклад) +Name[uz]=Yon daftarcha (misol) +Name[uz@cyrillic]=Ён дафтарча (мисол) +Name[ven]=Hau nwalela notsi (Tsumbo) +Name[vi]=Tập giấy (thí dụ) +Name[xh]=Iphetshan lokubhala (umzekelo) +Name[zh_CN]=记事本(例子) +Name[zh_HK]=記事本(範例) +Name[zh_TW]=記事本(範例) +Name[zu]=Incwadi yokubhala (umfanekiso) +MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++; +ServiceTypes=KParts/ReadOnlyPart +X-TDE-Library=libnotepadpart +Type=Service diff --git a/tdeparts/tests/notepad.h b/tdeparts/tests/notepad.h new file mode 100644 index 000000000..bd502599b --- /dev/null +++ b/tdeparts/tests/notepad.h @@ -0,0 +1,42 @@ + +#ifndef __notepad_h__ +#define __notepad_h__ + +#include <tdeparts/genericfactory.h> +#include <tdeparts/part.h> + +class TDEAboutData; +class TQMultiLineEdit; + +/** + * Who said writing a part should be complex ? :-) + * Here is a very simple kedit-like part + * @internal + */ +class NotepadPart : public KParts::ReadWritePart +{ + Q_OBJECT +public: + NotepadPart( TQWidget*, const char* widgetName, + TQObject* parent, const char* name, + const TQStringList& args = TQStringList() ); + virtual ~NotepadPart(); + + virtual void setReadWrite( bool rw ); + + static TDEAboutData* createAboutData(); + +protected: + virtual bool openFile(); + virtual bool saveFile(); + +protected slots: + void slotSearchReplace(); + +protected: + TQMultiLineEdit * m_edit; +}; + +typedef KParts::GenericFactory<NotepadPart> NotepadFactory; + +#endif diff --git a/tdeparts/tests/notepadpart.cpp b/tdeparts/tests/notepadpart.cpp new file mode 100644 index 000000000..072503fd1 --- /dev/null +++ b/tdeparts/tests/notepadpart.cpp @@ -0,0 +1,5 @@ +#include "notepad.h" + +// The entry point for the part. +K_EXPORT_COMPONENT_FACTORY( libnotepadpart, NotepadFactory ) + diff --git a/tdeparts/tests/notepadpart.rc b/tdeparts/tests/notepadpart.rc new file mode 100644 index 000000000..ba30eb322 --- /dev/null +++ b/tdeparts/tests/notepadpart.rc @@ -0,0 +1,14 @@ +<!DOCTYPE kpartgui> +<kpartgui name="NotepadPart" version="2"> +<MenuBar> + <Menu name="file"><Text>&File</Text> + <Menu name="NotepadSubMenu"><text>Notepad Stuff</text> + <Action name="searchreplace"/> + </Menu> + </Menu> + <Menu name="edit"><Text>&Edit</Text> + <Action name="searchreplace"/> + </Menu> +</MenuBar> +<StatusBar/> +</kpartgui> diff --git a/tdeparts/tests/parts.cpp b/tdeparts/tests/parts.cpp new file mode 100644 index 000000000..2fc63c225 --- /dev/null +++ b/tdeparts/tests/parts.cpp @@ -0,0 +1,90 @@ + +#include <tdeparts/event.h> + +#include "parts.h" + +#include <tqcheckbox.h> +#include <tqfile.h> +#include <tqdir.h> +#include <tqtextstream.h> +#include <tqmultilineedit.h> +#include <tqlineedit.h> +#include <tqvbox.h> + +#include <kiconloader.h> +#include <kapplication.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kaction.h> +#include <klocale.h> + +Part1::Part1( TQObject *parent, TQWidget * parentWidget ) + : KParts::ReadOnlyPart( parent, "Part1" ) +{ + m_instance = new TDEInstance( "tdepartstestpart" ); + setInstance( m_instance ); + m_edit = new TQMultiLineEdit( parentWidget ); + setWidget( m_edit ); + setXMLFile( "tdepartstest_part1.rc" ); + + /*KAction * paBlah = */ new KAction( "Blah", "filemail", 0, actionCollection(), "p1_blah" ); +} + +Part1::~Part1() +{ + delete m_instance; +} + +bool Part1::openFile() +{ + kdDebug() << "Part1: opening " << TQFile::encodeName(m_file) << endl; + // Hehe this is from a tutorial I did some time ago :) + TQFile f(m_file); + TQString s; + if ( f.open(IO_ReadOnly) ) { + TQTextStream t( &f ); + while ( !t.eof() ) { + s += t.readLine() + "\n"; + } + f.close(); + } else + return false; + m_edit->setText(s); + + emit setStatusBarText( m_url.prettyURL() ); + + return true; +} + +Part2::Part2( TQObject *parent, TQWidget * parentWidget ) + : KParts::Part( parent, "Part2" ) +{ + m_instance = new TDEInstance( "part2" ); + setInstance( m_instance ); + TQWidget * w = new TQWidget( parentWidget, "Part2Widget" ); + setWidget( w ); + + TQCheckBox * cb = new TQCheckBox( "something", w ); + + TQLineEdit * l = new TQLineEdit( "something", widget() ); + l->move(0,50); + // Since the main widget is a dummy one, we HAVE to set + // strong focus for it, otherwise we get the + // the famous activating-file-menu-switches-part bug. + w->setFocusPolicy( TQWidget::ClickFocus ); + + // setXMLFile( ... ); // no actions currently +} + +Part2::~Part2() +{ + delete m_instance; +} + +void Part2::guiActivateEvent( KParts::GUIActivateEvent * event ) +{ + if (event->activated()) + emit setWindowCaption("[part2 activated]"); +} + +#include "parts.moc" diff --git a/tdeparts/tests/parts.h b/tdeparts/tests/parts.h new file mode 100644 index 000000000..37af4911e --- /dev/null +++ b/tdeparts/tests/parts.h @@ -0,0 +1,43 @@ + +#ifndef __parts_h__ +#define __parts_h__ + +#include <tdeparts/part.h> + +class TQMultiLineEdit; +namespace KParts { +class GUIActivateEvent; +}; + +class Part1 : public KParts::ReadOnlyPart +{ + Q_OBJECT +public: + Part1( TQObject *parent, TQWidget * parentWidget ); + virtual ~Part1(); + +protected: + virtual bool openFile(); + +protected: + TQMultiLineEdit * m_edit; + TDEInstance *m_instance; +}; + +class Part2 : public KParts::Part +{ + Q_OBJECT +public: + Part2( TQObject *parent, TQWidget * parentWidget ); + virtual ~Part2(); + +protected: + // This is not mandatory - only if you care about setting the + // part caption when the part is used in a multi-part environment + // (i.e. in a part manager) + // There is a default impl for ReadOnlyPart... + virtual void guiActivateEvent( KParts::GUIActivateEvent * ); + TDEInstance *m_instance; +}; + +#endif diff --git a/tdeparts/tests/plugin_foobar.rc b/tdeparts/tests/plugin_foobar.rc new file mode 100644 index 000000000..e614e505f --- /dev/null +++ b/tdeparts/tests/plugin_foobar.rc @@ -0,0 +1,12 @@ +<!DOCTYPE kpartplugin> +<kpartplugin library="libfoobar"> +<MenuBar> + <Menu name="file"><Text>&File</Text> + <Action name="searchreplace"/> + </Menu> + <Menu name="woohoo"><Text>fun</Text> + <Action name="searchreplace"/> + </Menu> +</MenuBar> +<ToolBar name="gah"/> +</kpartplugin> diff --git a/tdeparts/tests/plugin_spellcheck.cpp b/tdeparts/tests/plugin_spellcheck.cpp new file mode 100644 index 000000000..5521bf22f --- /dev/null +++ b/tdeparts/tests/plugin_spellcheck.cpp @@ -0,0 +1,39 @@ +#include "notepad.h" // this plugin applies to a notepad part +#include <tqmultilineedit.h> +#include "plugin_spellcheck.h" +#include <kaction.h> +#include <kgenericfactory.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kdebug.h> + +PluginSpellCheck::PluginSpellCheck( TQObject* parent, const char* name, + const TQStringList& ) + : Plugin( parent, name ) +{ + (void) new KAction( "&Select current line (plugin)", 0, this, TQT_SLOT(slotSpellCheck()), + actionCollection(), "spellcheck" ); +} + +PluginSpellCheck::~PluginSpellCheck() +{ +} + +void PluginSpellCheck::slotSpellCheck() +{ + kdDebug() << "Plugin parent : " << parent()->name() << " (" << parent()->className() << ")" << endl; + // The parent is assumed to be a NotepadPart + if ( !parent()->inherits("NotepadPart") ) + KMessageBox::error(0L,"You just called the spell-check action on a wrong part (not NotepadPart)"); + else + { + NotepadPart * part = (NotepadPart *) parent(); + TQMultiLineEdit * widget = (TQMultiLineEdit *) part->widget(); + widget->selectAll(); //selects current line ! + } +} + +K_EXPORT_COMPONENT_FACTORY( libspellcheckplugin, + KGenericFactory<PluginSpellCheck> ); + +#include <plugin_spellcheck.moc> diff --git a/tdeparts/tests/plugin_spellcheck.h b/tdeparts/tests/plugin_spellcheck.h new file mode 100644 index 000000000..d27966c0c --- /dev/null +++ b/tdeparts/tests/plugin_spellcheck.h @@ -0,0 +1,18 @@ +#ifndef __plugin_spellcheck_h +#define __plugin_spellcheck_h + +#include <tdeparts/plugin.h> + +class PluginSpellCheck : public KParts::Plugin +{ + Q_OBJECT +public: + PluginSpellCheck( TQObject* parent = 0, const char* name = 0, + const TQStringList& = TQStringList() ); + virtual ~PluginSpellCheck(); + +public slots: + void slotSpellCheck(); +}; + +#endif diff --git a/tdeparts/tests/plugin_spellcheck.rc b/tdeparts/tests/plugin_spellcheck.rc new file mode 100644 index 000000000..1980186cf --- /dev/null +++ b/tdeparts/tests/plugin_spellcheck.rc @@ -0,0 +1,15 @@ +<!DOCTYPE kpartplugin> +<kpartplugin library="libspellcheckplugin"> +<MenuBar> + <Menu name="edit"><Text>&Edit</Text> + <Action name="spellcheck"/> + </Menu> + <Menu name="SomePluginMenu"><text>Some Cool Plugin Menu</text> + <Action name="spellcheck"/> + <Action name="searchreplace"/> + <Menu name="WhatASubMenu"><text>Yep</text> + <Action name="searchreplace"/> + </Menu> + </Menu> +</MenuBar> +</kpartplugin> diff --git a/tdeparts/tests/tdepartstest_part1.rc b/tdeparts/tests/tdepartstest_part1.rc new file mode 100644 index 000000000..9f4a75687 --- /dev/null +++ b/tdeparts/tests/tdepartstest_part1.rc @@ -0,0 +1,18 @@ +<!DOCTYPE kpartgui> +<kpartgui name="Part"> +<MenuBar> + <Menu name="file"><Text>&File</Text> + <Action name="p1_blah"/> + </Menu> + <Menu name="Part1Menu"><text>Part1's Menu</text> + <Action name="p1_blah"/> + <Menu name="Part1Sub"><text>Stupid Submenu</text> + <Action name="p1_blah"/> + </Menu> + </Menu> +</MenuBar> +<ToolBar name="Part1-ToolBar"> + <Action name="p1_blah"/> +</ToolBar> +<StatusBar/> +</kpartgui> diff --git a/tdeparts/tests/tdepartstest_shell.rc b/tdeparts/tests/tdepartstest_shell.rc new file mode 100644 index 000000000..52790f9b6 --- /dev/null +++ b/tdeparts/tests/tdepartstest_shell.rc @@ -0,0 +1,28 @@ +<!DOCTYPE kpartgui> +<kpartgui name="Shell"> +<MenuBar> + <Menu name="file"><Text>&File</Text> + <Action name="open_local_file"/> + <Action name="open_remote_file"/> + <Separator/> + <Action name="edit_file"/> + <Action name="close_editor"/> + <Merge name="NotepadPart"/> + <Separator/> + <Merge/> + <Separator/> + <Action name="shell_quit"/> + </Menu> + <Merge/> + <Menu name="blah"><Text>BlahFoo</Text> + <Action name="shell_yami"/> + <Menu name="nonsense"><Text>Dummdidumm</Text> + <Action name="shell_yasmi"/> + </Menu> + </Menu> +</MenuBar> +<ToolBar name="mainToolBar"> + <Action name="shell_quit"/> +</ToolBar> +<StatusBar/> +</kpartgui> |