/***** * * TOra - An Oracle Toolkit for DBA's and developers * Copyright (C) 2003-2005 Quest Software, Inc * Portions Copyright (C) 2005 Other Contributors * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; only version 2 of * the License is valid for this program. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * As a special exception, you have permission to link this program * with the Oracle Client libraries and distribute executables, as long * as you follow the requirements of the GNU GPL in regard to all of the * software in the executable aside from Oracle client libraries. * * Specifically you are not permitted to link this program with the * Qt/UNIX, Qt/Windows or Qt Non Commercial products of TrollTech. * And you are not permitted to distribute binaries compiled against * these libraries without written consent from Quest Software, Inc. * Observe that this does not disallow linking to the Qt Free Edition. * * You may link this product with any GPL'd Qt library such as Qt/Free * * All trademarks belong to their respective owners. * *****/ #include "utils.h" #include "toalert.h" #include "toconf.h" #include "toconnection.h" #include "tomain.h" #include "tomemoeditor.h" #include "tonoblockquery.h" #include "toresultview.h" #include "toresultview.h" #include "tosql.h" #include "totool.h" #ifndef WIN32 #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #ifdef TO_KDE # include #endif #include "toalert.moc" #include "icons/commit.xpm" #include "icons/return.xpm" #include "icons/toalert.xpm" #include "icons/toworksheet.xpm" #include "icons/trash.xpm" class toAlertTool : public toTool { protected: std::map Windows; virtual const char **pictureXPM(void) { return const_cast(toalert_xpm); } public: toAlertTool() : toTool(330, "Alert Messenger") { } virtual const char *menuItem() { return "Alert Messenger"; } virtual QWidget *toolWindow(QWidget *parent, toConnection &connection) { std::map::iterator i = Windows.find(&connection); if (i != Windows.end()) { (*i).second->setFocus(); return NULL; } else { QWidget *window = new toAlert(parent, connection); Windows[&connection] = window; return window; } } void closeWindow(toConnection &connection) { std::map::iterator i = Windows.find(&connection); if (i != Windows.end()) Windows.erase(i); } }; static toAlertTool AlertTool; #define TIMEOUT 1 static toSQL SQLHost("toAlert:Hostname", "SELECT machine\n" " FROM v$session\n" " WHERE sid=(SELECT MIN(sid)\n" " FROM v$mystat)", "Get hostname of current connection"); toAlert::toAlert(QWidget *main, toConnection &connection) : toToolWidget(AlertTool, "alert.html", main, connection), Connection(connection) { QToolBar *toolbar = toAllocBar(this, tr("Alert Messenger")); QString def; try { toQList lst = toQuery::readQuery(connection, SQLHost); def += toShift(lst); if (!def.isEmpty()) def += QString::fromLatin1(":"); } catch (...) {} def += connection.user(); new QLabel(tr("Registered") + " ", toolbar, TO_KDE_TOOLBAR_WIDGET); Registered = new QComboBox(toolbar, TO_KDE_TOOLBAR_WIDGET); Registered->insertItem(def); Registered->setEditable(true); Registered->setDuplicatesEnabled(false); Registered->setCurrentItem(0); connect(Registered, SIGNAL(activated(int)), this, SLOT(add ())); AddNames.insert(AddNames.end(), def); new QToolButton(QPixmap(const_cast(commit_xpm)), tr("Register current"), tr("Register current"), this, SLOT(add ()), toolbar); new QToolButton(QPixmap(const_cast(trash_xpm)), tr("Remove registered"), tr("Remove registered"), this, SLOT(remove ()), toolbar); toolbar->addSeparator(); new QLabel(tr("Name") + " ", toolbar, TO_KDE_TOOLBAR_WIDGET); Name = new QLineEdit(toolbar, TO_KDE_TOOLBAR_WIDGET); Name->setText(def); connect(Name, SIGNAL(returnPressed()), this, SLOT(send())); new QLabel(tr("Message") + " ", toolbar, TO_KDE_TOOLBAR_WIDGET); Message = new QLineEdit(toolbar, TO_KDE_TOOLBAR_WIDGET); connect(Message, SIGNAL(returnPressed()), this, SLOT(send())); new QToolButton(QPixmap(const_cast(toworksheet_xpm)), tr("Edit message in memo"), tr("Edit message in memo"), this, SLOT(memo()), toolbar); toolbar->setStretchableWidget(Message); new QToolButton(QPixmap(const_cast(return_xpm)), tr("Send alert"), tr("Send alert"), this, SLOT(send()), toolbar); connect(&Timer, SIGNAL(timeout()), this, SLOT(poll())); Timer.start(TIMEOUT*1000); Alerts = new toListView(this); Alerts->addColumn(tr("Time")); Alerts->addColumn(tr("Name")); Alerts->addColumn(tr("Message")); ToolMenu = NULL; connect(toMainWidget()->workspace(), SIGNAL(windowActivated(QWidget *)), this, SLOT(windowActivated(QWidget *))); State = Started; try { toThread *thread = new toThread(new pollTask(*this)); thread->start(); } catch (...) { toStatusMessage(tr("Failed to start polling thread, try closing some other tools and restart Alert Messenger")); } setFocusProxy(Message); } void toAlert::windowActivated(QWidget *widget) { if (widget == this) { if (!ToolMenu) { ToolMenu = new QPopupMenu(this); ToolMenu->insertItem(tr("&Add name"), Registered, SLOT(setFocus()), toKeySequence(tr("Alt+R", "Alert|Add Name"))); ToolMenu->insertItem(QPixmap(const_cast(trash_xpm)), tr("&Remove name"), this, SLOT(remove (void)), toKeySequence(tr("Ctrl+Backspace", "Alert|Remove name"))); ToolMenu->insertSeparator(); ToolMenu->insertItem(tr("Edit &name"), Name, SLOT(setFocus()), toKeySequence(tr("Alt+N", "Alert|Edit name"))); ToolMenu->insertItem(tr("Edit &message"), Message, SLOT(setFocus()), toKeySequence(tr("Alt+M", "Alert|Message"))); ToolMenu->insertItem(QPixmap(const_cast(toworksheet_xpm)), tr("&Message in memo..."), this, SLOT(memo(void)), toKeySequence(tr("Ctrl+M", "Alert|Message in memo"))); ToolMenu->insertItem(QPixmap(const_cast(return_xpm)), tr("&Send alert"), this, SLOT(send(void)), toKeySequence(tr("Ctrl+Return", "Alert|Send alert"))); toMainWidget()->menuBar()->insertItem(tr("&Alert"), ToolMenu, -1, toToolMenuIndex()); } } else { delete ToolMenu; ToolMenu = NULL; } } toAlert::~toAlert() { try { Lock.lock(); State = Quit; while (State != Done) { Lock.unlock(); Semaphore.down(); Lock.lock(); } Lock.unlock(); AlertTool.closeWindow(connection()); } TOCATCH } static toSQL SQLRegister("toAlert:Register", "BEGIN SYS.DBMS_ALERT.REGISTER(:name); END;", "Register an alert name, must have same binds"); static toSQL SQLRemove("toAlert:Remove", "BEGIN SYS.DBMS_ALERT.REMOVE(:name); END;", "Remove a registered an alert name, must have same binds"); static toSQL SQLRemoveAll("toAlert:RemoveAll", "BEGIN SYS.DBMS_ALERT.REMOVEALL; END;", "Remove all registered alerts"); static toSQL SQLPoll("toAlert:PollAlert", "BEGIN\n" " SYS.DBMS_ALERT.WAITANY(:name,:msg,\n" " :stat,:tim);\n" "END;", "Poll for alert, must have same binds"); static toSQL SQLSignal("toAlert:Signal", "BEGIN\n" " SYS.DBMS_ALERT.SIGNAL(:name,:msg);\n" "END;", "Signal alert, must have same binds"); void toAlert::pollTask::run(void) { Parent.Lock.lock(); bool fatal = false; while (Parent.State != Quit && !fatal) { Parent.Lock.unlock(); try { { toLocker lock (Parent.Lock) ; fatal = true; { for (std::list::iterator i = Parent.AddNames.begin(); i != Parent.AddNames.end(); i++) { Parent.Names.insert(Parent.Names.end(), *i); Parent.Connection.execute(SQLRegister, *i); } } Parent.AddNames.clear(); for (std::list::iterator i = Parent.DelNames.begin(); i != Parent.DelNames.end(); i++) { std::list::iterator j = std::find(Parent.Names.begin(), Parent.Names.end(), *i); if (j != Parent.Names.end()) { Parent.Names.erase(j); Parent.Connection.execute(SQLRemove, *i); } } Parent.DelNames.clear(); fatal = false; } { toLocker lock (Parent.Lock) ; std::list::iterator i = Parent.SendAlerts.begin(); std::list::iterator j = Parent.SendMessages.begin(); while (i != Parent.SendAlerts.end() && j != Parent.SendMessages.end()) { Parent.Connection.execute(SQLSignal, *i, *j); i++; j++; } Parent.SendAlerts.clear(); Parent.SendMessages.clear(); Parent.Connection.commit(); } Parent.Lock.lock(); if (Parent.Names.size()) { Parent.Lock.unlock(); toQuery query(Parent.Connection, SQLPoll, QString::number(TIMEOUT)); QString name = query.readValue(); QString msg = query.readValue(); if (query.readValue().toInt() == 0) { toLocker lock (Parent.Lock) ; Parent.NewAlerts.insert(Parent.NewAlerts.end(), name); Parent.NewMessages.insert(Parent.NewMessages.end(), msg); } } else { Parent.Lock.unlock(); #ifndef WIN32 sleep(TIMEOUT); #else Sleep(TIMEOUT*1000); #endif } } catch (const QString &str) { Parent.Lock.lock(); Parent.Error.sprintf("Exception in alert polling:\n%s", (const char *)str.latin1()); fprintf(stderr, "%s\n", (const char *)Parent.Error); Parent.Lock.unlock(); } catch (...) { Parent.Lock.lock(); Parent.Error.sprintf("Unexpected exception in alert in polling."); fprintf(stderr, "%s\n", (const char *)Parent.Error); Parent.Lock.unlock(); } Parent.Lock.lock(); } if (Parent.Names.size() > 0) try { Parent.Connection.execute(SQLRemoveAll); } catch (...) {} Parent.State = Done; Parent.Semaphore.up(); Parent.Lock.unlock(); } void toAlert::poll(void) { try { toLocker lock (Lock) ; if (Error) { toStatusMessage(Error); Error = QString::null; } std::list::iterator i = NewAlerts.begin(); std::list::iterator j = NewMessages.begin(); while (i != NewAlerts.end() && j != NewMessages.end()) { QListViewItem *item = new toResultViewMLine(Alerts, NULL, toNow(connection())); item->setText(1, *i); item->setText(2, *j); i++; j++; } NewAlerts.clear(); NewMessages.clear(); } TOCATCH } void toAlert::send(void) { if (!Name->text().isEmpty() && !Message->text().isEmpty()) { toLocker lock (Lock) ; SendAlerts.insert(SendAlerts.end(), Name->text()); SendMessages.insert(SendMessages.end(), Message->text()); Message->clear(); } } void toAlert::memo(void) { toMemoEditor *memo = new toMemoEditor(this, Message->text(), 0, 0); connect(memo, SIGNAL(changeData(int, int, const QString &)), this, SLOT(changeMessage(int, int, const QString &))); } void toAlert::changeMessage(int, int, const QString &str) { Message->setText(str); } void toAlert::remove (void) { toLocker lock (Lock) ; QString name = Registered->currentText(); if (!name.isEmpty()) { std::list::iterator i = std::find(AddNames.begin(), AddNames.end(), name); if (i != AddNames.end()) AddNames.erase(i); i = std::find(Names.begin(), Names.end(), name); if (i != Names.end()) { if (std::find(DelNames.begin(), DelNames.end(), name) == DelNames.end()) DelNames.insert(DelNames.end(), name); } } if (Registered->count() > 0) Registered->removeItem(Registered->currentItem()); if (Registered->count() > 0) Registered->setCurrentItem(0); } void toAlert::add (void) { Registered->lineEdit()->selectAll(); QString name = Registered->currentText(); if (!name.isEmpty()) { std::list::iterator i = std::find(DelNames.begin(), DelNames.end(), name); if (i == DelNames.end()) { i = std::find(Names.begin(), Names.end(), name); if (i == Names.end()) { i = std::find(AddNames.begin(), AddNames.end(), name); if (i == AddNames.end()) { AddNames.insert(AddNames.end(), name); } } } else { DelNames.erase(i); } } for (int i = 0;i < Registered->count();i++) if (Registered->text(i) == name) return ; Registered->insertItem(name); Name->setText(name); }