1 /***************************************************************************
2 robjectbrowser - description
3 -------------------
4 begin : Thu Aug 19 2004
5 copyright : (C) 2004 - 2017 by Thomas Friedrichsmeier
6 email : thomas.friedrichsmeier@kdemail.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 #include "robjectbrowser.h"
18
19 #include <qlayout.h>
20 #include <qpushbutton.h>
21 #include <QFocusEvent>
22 #include <QVBoxLayout>
23 #include <QMenu>
24 #include <QInputDialog>
25
26 #include <KLocalizedString>
27 #include <kmessagebox.h>
28
29 #include "../rkward.h"
30 #include "rkhelpsearchwindow.h"
31 #include "../rkglobals.h"
32 #include "../core/robjectlist.h"
33 #include "../core/renvironmentobject.h"
34 #include "../core/rkmodificationtracker.h"
35 #include "../rbackend/rkrinterface.h"
36 #include "../misc/rkobjectlistview.h"
37 #include "../misc/rkdummypart.h"
38 #include "../misc/rkstandardicons.h"
39 #include "../misc/rkstandardactions.h"
40 #include "rkworkplace.h"
41 #include "../dataeditor/rkeditor.h"
42
43 #include "../debug.h"
44
45 // static
46 RObjectBrowser* RObjectBrowser::object_browser = 0;
47
RObjectBrowser(QWidget * parent,bool tool_window,const char * name)48 RObjectBrowser::RObjectBrowser (QWidget *parent, bool tool_window, const char *name) : RKMDIWindow (parent, WorkspaceBrowserWindow, tool_window, name) {
49 RK_TRACE (APP);
50
51 internal = 0;
52 locked = true;
53
54 QVBoxLayout *layout = new QVBoxLayout (this);
55 layout->setContentsMargins (0, 0, 0, 0);
56 layout_widget = new QWidget (this);
57 layout->addWidget (layout_widget);
58 layout_widget->setFocusPolicy (Qt::StrongFocus);
59
60 RKDummyPart *part = new RKDummyPart (this, layout_widget);
61 setPart (part);
62 setMetaInfo (i18n ("R workspace browser"), QUrl ("rkward://page/rkward_workspace_browser"), RKSettings::PageObjectBrowser);
63 initializeActivationSignals ();
64
65 setCaption (i18n ("R Workspace"));
66 }
67
~RObjectBrowser()68 RObjectBrowser::~RObjectBrowser () {
69 RK_TRACE (APP);
70 }
71
unlock()72 void RObjectBrowser::unlock () {
73 RK_TRACE (APP);
74
75 locked = false;
76 if (!isHidden ()) {
77 initialize ();
78 }
79 }
80
showEvent(QShowEvent * e)81 void RObjectBrowser::showEvent (QShowEvent *e) {
82 RK_TRACE (APP);
83
84 initialize ();
85 RKMDIWindow::showEvent (e);
86 }
87
initialize()88 void RObjectBrowser::initialize () {
89 RK_TRACE (APP);
90
91 if (internal) return;
92 if (locked) return;
93
94 RK_DEBUG (APP, DL_INFO, "creating workspace browser");
95
96 internal = new RObjectBrowserInternal (layout_widget, this);
97 QVBoxLayout *l = new QVBoxLayout (layout_widget);
98 l->setContentsMargins (0, 0, 0, 0);
99 l->addWidget (internal);
100
101 setFocusProxy (internal);
102 setMinimumSize (internal->minimumSize ());
103 }
104
105
106 ///////////////////////// RObjectBrowserInternal /////////////////////////////
RObjectBrowserInternal(QWidget * parent,RObjectBrowser * browser)107 RObjectBrowserInternal::RObjectBrowserInternal (QWidget *parent, RObjectBrowser *browser) : QWidget (parent) {
108 RK_TRACE (APP);
109 setFocusPolicy (Qt::ClickFocus);
110
111 QVBoxLayout *vbox = new QVBoxLayout (this);
112 vbox->setContentsMargins (0, 0, 0, 0);
113
114 list_view = new RKObjectListView (true, this);
115 vbox->addWidget (list_view->getSettings ()->filterWidget (this));
116 vbox->addWidget (list_view);
117
118 update_button = new QPushButton (i18n ("Update"), this);
119 vbox->addWidget (update_button);
120
121 actions.insert (Help, RKStandardActions::functionHelp (browser, this));
122 actions.insert (SearchOnline, RKStandardActions::onlineHelp (browser, this));
123 actions.insert (Edit, new QAction (i18n ("Edit"), this));
124 connect (actions[Edit], &QAction::triggered, this, &RObjectBrowserInternal::popupEdit);
125 actions.insert (View, new QAction (i18n ("View"), this));
126 connect (actions[View], &QAction::triggered, this, &RObjectBrowserInternal::popupView);
127 actions.insert (Rename, new QAction (i18n ("Rename"), this));
128 connect (actions[Rename], &QAction::triggered, this, &RObjectBrowserInternal::popupRename);
129 actions.insert (Copy, new QAction (i18n ("Copy to new symbol"), this));
130 connect (actions[Copy], &QAction::triggered, this, &RObjectBrowserInternal::popupCopy);
131 actions.insert (CopyToGlobalEnv, new QAction (i18n ("Copy to .GlobalEnv"), this));
132 connect (actions[CopyToGlobalEnv], &QAction::triggered, this, &RObjectBrowserInternal::popupCopyToGlobalEnv);
133 actions.insert (Delete, new QAction (i18n ("Delete"), this));
134 connect (actions[Delete], &QAction::triggered, this, &RObjectBrowserInternal::popupDelete);
135 actions.insert (Unload, new QAction (i18n ("Unload Package"), this));
136 connect (actions[Unload], &QAction::triggered, this, &RObjectBrowserInternal::popupUnload);
137 actions.insert (LoadUnloadPackages, new QAction (i18n ("Load / Unload Packages"), this));
138 connect (actions[LoadUnloadPackages], &QAction::triggered, RKWardMainWindow::getMain(), &RKWardMainWindow::slotFileLoadLibs);
139
140 QAction* sep = list_view->contextMenu ()->insertSeparator (list_view->contextMenu ()->actions ().value (0));
141 list_view->contextMenu ()->insertActions (sep, actions);
142
143 connect (list_view, &RKObjectListView::aboutToShowContextMenu, this, &RObjectBrowserInternal::contextMenuCallback);
144
145 connect (list_view, &QAbstractItemView::doubleClicked, this, &RObjectBrowserInternal::doubleClicked);
146
147 resize (minimumSizeHint ().expandedTo (QSize (400, 480)));
148
149 list_view->initialize ();
150 connect (update_button, &QPushButton::clicked, this, &RObjectBrowserInternal::updateButtonClicked);
151 }
152
~RObjectBrowserInternal()153 RObjectBrowserInternal::~RObjectBrowserInternal () {
154 RK_TRACE (APP);
155 }
156
focusInEvent(QFocusEvent * e)157 void RObjectBrowserInternal::focusInEvent (QFocusEvent *e) {
158 RK_TRACE (APP);
159
160 list_view->getSettings ()->filterWidget (this)->setFocus ();
161 if (e->reason () != Qt::MouseFocusReason) {
162 list_view->setObjectCurrent (RObjectList::getGlobalEnv (), true);
163 }
164 }
165
updateButtonClicked()166 void RObjectBrowserInternal::updateButtonClicked () {
167 RK_TRACE (APP);
168 RObjectList::getObjectList ()->updateFromR (0);
169 }
170
currentHelpContext(QString * symbol,QString * package)171 void RObjectBrowserInternal::currentHelpContext (QString* symbol, QString* package) {
172 RK_TRACE (APP);
173
174 RObject *object = list_view->menuObject ();
175 if (!object) return;
176 *symbol = object->getShortName ();
177 *package = object->isInGlobalEnv () ? QString () : object->toplevelEnvironment ()->packageName ();
178 }
179
popupEdit()180 void RObjectBrowserInternal::popupEdit () {
181 RK_TRACE (APP);
182 if (list_view->menuObject ()) RKWorkplace::mainWorkplace ()->editObject (list_view->menuObject ());
183 }
184
popupCopy()185 void RObjectBrowserInternal::popupCopy () {
186 RK_TRACE (APP);
187
188 bool ok;
189 RObject *object = list_view->menuObject ();
190 QString suggested_name = RObjectList::getGlobalEnv ()->validizeName (object->getShortName ());
191 QString name = QInputDialog::getText (this, i18n ("Copy object"), i18n ("Enter the name to copy to"), QLineEdit::Normal, suggested_name, &ok);
192
193 if (ok) {
194 QString valid = RObjectList::getGlobalEnv ()->validizeName (name);
195 if (valid != name) KMessageBox::sorry (this, i18n ("The name you specified was already in use or not valid. Renamed to %1", valid), i18n ("Invalid Name"));
196 RKGlobals::rInterface ()->issueCommand (RObject::rQuote (valid) + " <- " + object->getFullName (), RCommand::App | RCommand::ObjectListUpdate);
197 }
198 }
199
popupCopyToGlobalEnv()200 void RObjectBrowserInternal::popupCopyToGlobalEnv () {
201 RK_TRACE (APP);
202
203 RObject *object = list_view->menuObject ();
204 QString name = object->getShortName ();
205
206 QString valid = RObjectList::getGlobalEnv ()->validizeName (name);
207 if (valid != name) KMessageBox::sorry (this, i18n ("An object named '%1' already exists in the GlobalEnv. Created the copy as '%2' instead.", name, valid), i18n ("Name already in use"));
208 RKGlobals::rInterface ()->issueCommand (RObject::rQuote (valid) + " <- " + object->getFullName (), RCommand::App | RCommand::ObjectListUpdate);
209 }
210
popupView()211 void RObjectBrowserInternal::popupView () {
212 RK_TRACE (APP);
213 RKWorkplace::mainWorkplace ()->flushAllData ();
214 RKWorkplace::mainWorkplace ()->newObjectViewer (list_view->menuObject ());
215 }
216
popupDelete()217 void RObjectBrowserInternal::popupDelete () {
218 RK_TRACE (APP);
219 RKGlobals::tracker ()->removeObject (list_view->menuObject ());
220 }
221
popupUnload()222 void RObjectBrowserInternal::popupUnload () {
223 RK_TRACE (APP);
224
225 RObject *object = list_view->menuObject ();
226 RK_ASSERT (object);
227 RK_ASSERT (object->isType (RObject::PackageEnv));
228
229 QStringList messages = RObjectList::getObjectList ()->detachPackages (QStringList (object->getShortName ()));
230
231 if (!messages.isEmpty ()) KMessageBox::sorry (this, messages.join ("\n"));
232 }
233
popupRename()234 void RObjectBrowserInternal::popupRename () {
235 RK_TRACE (APP);
236 bool ok;
237 QString name = QInputDialog::getText (this, i18n ("Rename object"), i18n ("Enter the new name"), QLineEdit::Normal, list_view->menuObject ()->getShortName (), &ok);
238
239 if (ok) {
240 QString valid = static_cast<RContainerObject*> (list_view->menuObject ()->parentObject ())->validizeName (name);
241 if (valid != name) KMessageBox::sorry (this, i18n ("The name you specified was already in use or not valid. Renamed to %1", valid), i18n ("Invalid Name"));
242 RKGlobals::tracker ()->renameObject (list_view->menuObject (), valid);
243 }
244 }
245
contextMenuCallback(RObject *,bool *)246 void RObjectBrowserInternal::contextMenuCallback (RObject *, bool *) {
247 RK_TRACE (APP);
248 RObject *object = list_view->menuObject ();
249
250 if (!object) {
251 RK_ASSERT (actions.size () == ActionCount);
252 for (int i = 0; i < ActionCount; ++i) {
253 actions[i]->setVisible (false);
254 }
255 actions[LoadUnloadPackages]->setVisible (true);
256 return;
257 }
258
259 actions[Help]->setVisible (!(object->isType (RObject::ToplevelEnv) || object->isInGlobalEnv ()));
260 actions[Edit]->setText (object->canWrite () ? i18n ("Edit") : i18n ("View in editor (read-only)"));
261 actions[Edit]->setVisible (RKWorkplace::mainWorkplace ()->canEditObject (object));
262 actions[View]->setVisible (object->canRead ());
263 actions[Rename]->setVisible (object->canRename ());
264 actions[Copy]->setVisible (object->canRead () && (!object->isType (RObject::ToplevelEnv)));
265 actions[CopyToGlobalEnv]->setVisible (object->canRead () && (!object->isInGlobalEnv()) && (!object->isType (RObject::ToplevelEnv)));
266 actions[Delete]->setVisible (object->canRemove ());
267 actions[Unload]->setVisible (object->isType (RObject::PackageEnv));
268 actions[LoadUnloadPackages]->setVisible (object == RObjectList::getObjectList ());
269 }
270
doubleClicked(const QModelIndex & index)271 void RObjectBrowserInternal::doubleClicked (const QModelIndex& index) {
272 RK_TRACE (APP);
273
274 RObject *object = list_view->objectAtIndex (index);
275 if (!object) return;
276 if (object == RObjectList::getObjectList ()) return;
277
278 if (object->isInGlobalEnv ()) {
279 if (RKWorkplace::mainWorkplace ()->canEditObject (object)) {
280 RKWorkplace::mainWorkplace ()->editObject (object);
281 } else {
282 RKWorkplace::mainWorkplace ()->newObjectViewer (object);
283 }
284 } else {
285 RKHelpSearchWindow::mainHelpSearch ()->getFunctionHelp (object->getShortName (), object->toplevelEnvironment ()->packageName ());
286 }
287 }
288