1 /***************************************************************************
2                           rksaveobjectchooser  -  description
3                              -------------------
4     begin                : Mon Nov 27 2006
5     copyright            : (C) 2006, 2007, 2009, 2010 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 
18 #include "rksaveobjectchooser.h"
19 
20 #include <qlineedit.h>
21 #include <qcheckbox.h>
22 #include <qlabel.h>
23 #include <QVBoxLayout>
24 #include <QPushButton>
25 #include <QTimer>
26 #include <QDialog>
27 #include <QDialogButtonBox>
28 
29 #include <KLocalizedString>
30 
31 #include "../core/robjectlist.h"
32 #include "../core/renvironmentobject.h"
33 #include "../misc/rkobjectlistview.h"
34 
35 #include "../debug.h"
36 
RKSaveObjectChooser(QWidget * parent,const QString & initial)37 RKSaveObjectChooser::RKSaveObjectChooser (QWidget *parent, const QString &initial) : QWidget (parent), RObjectListener (RObjectListener::Other) {
38 	RK_TRACE (MISC);
39 
40 	object_exists = false;
41 	addNotificationType (RObjectListener::ObjectRemoved);
42 	addNotificationType (RObjectListener::ChildAdded);
43 	root_object = 0;
44 	current_object = 0;
45 
46 	QVBoxLayout *layout = new QVBoxLayout (this);
47 	layout->setContentsMargins (0, 0, 0, 0);
48 
49 	QHBoxLayout *hlayout = new QHBoxLayout ();
50 	root_label = new QLabel (this);
51 	hlayout->addWidget (root_label);
52 	hlayout->addStretch ();
53 	root_button = new QPushButton (i18n ("Change"), this);
54 	connect (root_button, &QPushButton::clicked, this, &RKSaveObjectChooser::selectRootObject);
55 	hlayout->addWidget (root_button);
56 	layout->addLayout (hlayout);
57 
58 	name_edit = new QLineEdit (this);
59 	name_edit->setText (initial);
60 	connect (name_edit, &QLineEdit::textChanged, this, &RKSaveObjectChooser::updateState);
61 	layout->addWidget (name_edit);
62 
63 	overwrite_confirm = new QCheckBox (this);
64 	connect (overwrite_confirm, &QCheckBox::stateChanged, this, &RKSaveObjectChooser::updateState);
65 	layout->addWidget (overwrite_confirm);
66 
67 	// initialize
68 	setRootObject (0);
69 }
70 
~RKSaveObjectChooser()71 RKSaveObjectChooser::~RKSaveObjectChooser () {
72 	RK_TRACE (MISC);
73 
74 	if (current_object) stopListenForObject (current_object);
75 	stopListenForObject (root_object);
76 }
77 
setRootObject(RObject * new_root)78 void RKSaveObjectChooser::setRootObject (RObject* new_root) {
79 	RK_TRACE (MISC);
80 
81 	if (root_object && (new_root == root_object)) {
82 		return;
83 	}
84 
85 	if (root_object) stopListenForObject (root_object);
86 	if (!new_root) new_root = RObjectList::getGlobalEnv ();
87 	else if (!new_root->isInGlobalEnv ()) new_root = RObjectList::getGlobalEnv ();
88 	else if (!new_root->isContainer ()) new_root = RObjectList::getGlobalEnv ();
89 	root_object = new_root;
90 	listenForObject (root_object);
91 
92 	root_label->setText (i18n ("Parent object: %1", root_object->getShortName ()));
93 
94 	updateState ();
95 }
96 
selectRootObject()97 void RKSaveObjectChooser::selectRootObject () {
98 	RK_TRACE (MISC);
99 
100 	// TODO: not very pretty, yet
101 	QDialog *dialog = new QDialog (this);
102 	dialog->setWindowTitle (i18n ("Select parent object"));
103 	dialog->setModal (true);
104 	QVBoxLayout *layout = new QVBoxLayout (dialog);
105 
106 	RKObjectListView* list_view = new RKObjectListView (false, dialog);
107 	list_view->setSelectionMode (QAbstractItemView::SingleSelection);
108 	list_view->initialize ();
109 	list_view->setObjectCurrent (root_object);
110 	connect (list_view, &QAbstractItemView::doubleClicked, dialog, &QDialog::accept);
111 	layout->addWidget (list_view);
112 
113 	QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog);
114 	connect (buttons->button (QDialogButtonBox::Ok), &QPushButton::clicked, dialog, &QDialog::accept);
115 	connect (buttons->button (QDialogButtonBox::Cancel), &QPushButton::clicked, dialog, &QDialog::reject);
116 	layout->addWidget (buttons);
117 
118 	dialog->exec ();
119 
120 	if (dialog->result () == QDialog::Accepted) {
121 		RObject::ObjectList sel = list_view->selectedObjects ();
122 		if (sel.isEmpty ()) setRootObject (0);
123 		else {
124 			RK_ASSERT (sel.size () == 1);
125 			setRootObject (sel[0]);
126 		}
127 	}
128 
129 	delete dialog;
130 }
131 
objectRemoved(RObject * removed)132 void RKSaveObjectChooser::objectRemoved (RObject* removed) {
133 	RK_TRACE (MISC);
134 
135 	if (removed == root_object) {
136 		setRootObject (0);
137 	} else if (removed == current_object) {
138 		stopListenForObject (removed);
139 		current_full_name.clear ();	// hack to achieve proper emit of change signal
140 		QTimer::singleShot (0, this, SLOT (updateState()));
141 	} else {
142 		RK_ASSERT (false);
143 	}
144 }
145 
childAdded(int,RObject * parent)146 void RKSaveObjectChooser::childAdded (int, RObject* parent) {
147 	RK_TRACE (MISC);
148 
149 	if (parent == root_object) {
150 		updateState ();
151 	} else {
152 		// unusual, but ok
153 		RK_ASSERT (parent == current_object);
154 	}
155 }
156 
setBaseName(const QString & name)157 void RKSaveObjectChooser::setBaseName (const QString &name) {
158 	RK_TRACE (MISC);
159 
160 	name_edit->setText (name);
161 	updateState ();
162 }
163 
isOk() const164 bool RKSaveObjectChooser::isOk () const {
165 	RK_TRACE (MISC);
166 
167 	if (name_edit->text ().isEmpty ()) return false;
168 	return ((!object_exists) || overwrite_confirm->isChecked ());
169 }
170 
updateState()171 void RKSaveObjectChooser::updateState () {
172 	RK_TRACE (MISC);
173 	RK_ASSERT (root_object && root_object->isContainer ());
174 
175 	QString new_name = static_cast<RContainerObject*> (root_object)->validizeName (name_edit->text (), false);
176 	if (current_object) stopListenForObject (current_object);
177 	current_object = root_object->findObject (new_name);
178 	new_name = root_object->makeChildName (new_name);	// make it the full name
179 	if (current_object) {
180 		object_exists = true;
181 		overwrite_confirm->setText (i18n ("Overwrite? (The given object name already exists)"));
182 		overwrite_confirm->setEnabled (true);
183 		listenForObject (current_object);
184 	} else {
185 		object_exists = false;
186 		overwrite_confirm->setText (i18n ("Overwrite?"));
187 		overwrite_confirm->setEnabled (false);
188 		overwrite_confirm->setChecked (false);
189 	}
190 
191 	if ((new_name != current_full_name) || (sender () == overwrite_confirm)) {
192 		current_full_name = new_name;
193 		emit (changed (isOk ()));
194 	}
195 }
196 
setBackgroundColor(const QColor & color)197 void RKSaveObjectChooser::setBackgroundColor (const QColor &color) {
198 	RK_TRACE (MISC);
199 
200 	QPalette palette = name_edit->palette ();
201 	palette.setColor (name_edit->backgroundRole (), color);
202 	name_edit->setPalette (palette);
203 }
204 
currentBaseName() const205 QString RKSaveObjectChooser::currentBaseName () const {
206 	return name_edit->text ();
207 }
208 
209