
Originally Posted by
nroberts
Sigh...this is bad. Really bad. Just applying encapsulation willy-nilly is just not the way to do things.
Good thing I didn't say anything like that.
Answer: NO! Why? One word: composition. The fact that mapping from one thing to another is a specific and unique responsibility has not changed. Put that stuff into an object responsible for just that and then USE that object within the object you want to couple it to.
I don't see how using a signal mapper is in any way better than any of the other presented designs.
Well, unless you can show me where I'm wrong my answer is a very certain NO! Why? Because NONE of the objects in question depend upon it!
Objects don't depend on it, the overall functionality does. The sole fact that you need to create this object in addition to the objects you really need makes it a dependency. It's just an adapter between two data types but as such the functionality of the two incompatible interfaces depends on existance of this object. Existance of the show_m slot is meaningless to the whole problem, the method itself is useful without appointing shortcuts to widgets. The whole point is to extend the infrastructure to accept such shortcuts and not to map indices. Sure you can add several adapters doing nothing more than mapping between types or brewing coffee but that doesn't change the fact they won't make the original object accept shortcuts to popping up widgets.
You'll have to point out where you showed it wouldn't work because I not only missed it the first time but can't find it when I try to backtrack. In fact, I can only see where you claimed it didn't matter.
Geeez man...
tabWidget
->addTab
(new QDial);
QShortcut *sh1
= ...;
// to popup the calendar mapper->setMapping(sh1, 0);
mapper->setMapping(sh2, 1);
connect(sh1, SIGNAL(activated()), mapper, SLOT(map()));
connect(mapper, SIGNAL(mapped(int)), tabWidget, SLOT(setCurrentIndex(int)));
// some other scope, maybe written by some other person...
// this breaks the design:
tabWidget
->insertTab
(0,
new QWidget);
// now sh1 points to the QWidget and sh2 points to the calendar, oops...
tabWidget->addTab(new QCalendarWidget);
tabWidget->addTab(new QDial);
QSignalMapper *mapper = ...;
QShortcut *sh1 = ...; // to popup the calendar
QShortcut *sh2 = ... // to popup the dial
mapper->setMapping(sh1, 0);
mapper->setMapping(sh2, 1);
connect(sh1, SIGNAL(activated()), mapper, SLOT(map()));
connect(mapper, SIGNAL(mapped(int)), tabWidget, SLOT(setCurrentIndex(int)));
// some other scope, maybe written by some other person...
// this breaks the design:
tabWidget->insertTab(0, new QWidget); // now sh1 points to the QWidget and sh2 points to the calendar, oops...
To copy to clipboard, switch view to plain text mode
Now you can't possibly break this unless you really try it (WARNING, pseudocode!):
class TabWidgetWithShortcuts
: public QTabWidget { Q_OBJECT
public:
TWWS(...) : QTW(...) {}
void registerShortcut
(int page,
QShortcut *sh
) { if(page not in [0, count()-1] ) return;
m_list[page] = sh;
connect(sh,
SIGNAL(destroyed
(QObject*)),
this,
SLOT(_q_onShDestroyed
(QObject*)));
connect(sh, SIGNAL(activated()), this, SLOT(_q_activated()));
emit shortcutRegistered(page);
}
void unregisterShortcut(int page) {
if(!m_list.at(page)) return;
disconnect
(m_list.
at(page
),
SIGNAL(destroyed
(QObject*)),
this,
SLOT(_q_onShDestroyed
(QObject*)));
disconnect(sh, SIGNAL(activated()), this, SLOT(_q_activated()));
emit shortcutUnregistered(page);
m_list[page] = 0;
}
// check bounds, etc.
return m_list.at(page);
}
protected:
void tabInserted(int at) {
m_list.insert(at,0);
}
void tabRemoved(int at) {
unregisterShortcut(at);
m_list.removeAt(at);
}
private:
QList<QShortcut*> m_list;
private slots:
void _q_onShDestroyed
(QObject *o
) { // remove shortcut from list
}
void _q_activated() {
QShortcut *sh
= qobject_cast<QShortcut
*>
(sender
());
if(!sh) return;
setCurrentIndex(m_list.indexOf(sh));
}
signals:
void shortcutRegistered(int);
void shortcutUnregistered(int);
}
class TabWidgetWithShortcuts : public QTabWidget {
Q_OBJECT
public:
TWWS(...) : QTW(...) {}
void registerShortcut(int page, QShortcut *sh) {
if(page not in [0, count()-1] ) return;
m_list[page] = sh;
connect(sh, SIGNAL(destroyed(QObject*)), this, SLOT(_q_onShDestroyed(QObject*)));
connect(sh, SIGNAL(activated()), this, SLOT(_q_activated()));
emit shortcutRegistered(page);
}
void unregisterShortcut(int page) {
if(!m_list.at(page)) return;
disconnect(m_list.at(page), SIGNAL(destroyed(QObject*)), this, SLOT(_q_onShDestroyed(QObject*)));
disconnect(sh, SIGNAL(activated()), this, SLOT(_q_activated()));
emit shortcutUnregistered(page);
m_list[page] = 0;
}
QShortcut *shortcut(int page) const {
// check bounds, etc.
return m_list.at(page);
}
protected:
void tabInserted(int at) {
m_list.insert(at,0);
}
void tabRemoved(int at) {
unregisterShortcut(at);
m_list.removeAt(at);
}
private:
QList<QShortcut*> m_list;
private slots:
void _q_onShDestroyed(QObject *o) {
// remove shortcut from list
}
void _q_activated() {
QShortcut *sh = qobject_cast<QShortcut*>(sender());
if(!sh) return;
setCurrentIndex(m_list.indexOf(sh));
}
signals:
void shortcutRegistered(int);
void shortcutUnregistered(int);
}
To copy to clipboard, switch view to plain text mode
Go ahead, be picky... The hell with it, I'll add some signals to it, it's almost compilable anyway. Look maa... no signal mappers!
By the way, you can do the same with QActionGroup without the dedicated list as QActionGroup already has one embedded.
I don't know who "Daniel" is, but if it's "high_flyer" then I really suggest you reevaluate his proposed solution. It's not even valid C++, as has been pointed out already.
The idea matters, correctness of the code is exercised against a compiler. I'm sure you make syntax errors in your code too as we all do. If you want to find a flaw you will always find it in anything and at the same time you'll miss the bigger picture.
Bookmarks