icinga2/icinga-studio/mainform.cpp

317 lines
9.1 KiB
C++

/******************************************************************************
* Icinga 2 *
* Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/) *
* *
* 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; either version 2 *
* of the License, or (at your option) any later version. *
* *
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
#include "icinga-studio/mainform.hpp"
#include "icinga-studio/aboutform.hpp"
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <wx/msgdlg.h>
using namespace icinga;
MainForm::MainForm(wxWindow *parent, const Url::Ptr& url)
: MainFormBase(parent)
{
#ifdef _WIN32
SetIcon(wxICON(icinga));
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
#endif /* _WIN32 */
String port = url->GetPort();
if (port.IsEmpty())
port = "5665";
m_ApiClient = new ApiClient(url->GetHost(), port, url->GetUsername(), url->GetPassword());
m_ApiClient->GetTypes(boost::bind(&MainForm::TypesCompletionHandler, this, _1, _2, true));
std::string title = url->Format() + " - Icinga Studio";
SetTitle(title);
m_ObjectsList->InsertColumn(0, "Name", 0, 300);
m_PropertyGrid->SetColumnCount(3);
}
void MainForm::TypesCompletionHandler(boost::exception_ptr eptr, const std::vector<ApiType::Ptr>& types, bool forward)
{
if (forward) {
CallAfter(boost::bind(&MainForm::TypesCompletionHandler, this, eptr, types, false));
return;
}
m_TypesTree->DeleteAllItems();
if (eptr) {
try {
boost::rethrow_exception(eptr);
} catch (const std::exception& ex) {
std::string message = "HTTP query failed: " + std::string(ex.what());
wxMessageBox(message, "Icinga Studio", wxOK | wxCENTRE | wxICON_ERROR, this);
Close();
return;
}
}
wxTreeItemId rootNode = m_TypesTree->AddRoot("root");
for (const ApiType::Ptr& type : types) {
m_Types[type->Name] = type;
}
for (const ApiType::Ptr& type : types) {
if (type->Abstract)
continue;
bool configObject = false;
ApiType::Ptr currentType = type;
for (;;) {
if (currentType->BaseName.IsEmpty())
break;
currentType = m_Types[currentType->BaseName];
if (!currentType)
break;
if (currentType->Name == "ConfigObject") {
configObject = true;
break;
}
}
if (configObject) {
std::string name = type->Name;
m_TypesTree->AppendItem(rootNode, name, 0);
}
}
}
void MainForm::OnTypeSelected(wxTreeEvent& event)
{
wxTreeItemId selectedId = m_TypesTree->GetSelection();
wxString typeName = m_TypesTree->GetItemText(selectedId);
ApiType::Ptr type = m_Types[typeName.ToStdString()];
std::vector<String> attrs;
attrs.push_back("__name");
m_ApiClient->GetObjects(type->PluralName, boost::bind(&MainForm::ObjectsCompletionHandler, this, _1, _2, true),
std::vector<String>(), attrs);
}
static bool ApiObjectLessComparer(const ApiObject::Ptr& o1, const ApiObject::Ptr& o2)
{
return o1->Name < o2->Name;
}
void MainForm::ObjectsCompletionHandler(boost::exception_ptr eptr, const std::vector<ApiObject::Ptr>& objects, bool forward)
{
if (forward) {
CallAfter(boost::bind(&MainForm::ObjectsCompletionHandler, this, eptr, objects, false));
return;
}
m_ObjectsList->DeleteAllItems();
m_PropertyGrid->Clear();
if (eptr) {
try {
boost::rethrow_exception(eptr);
} catch (const std::exception& ex) {
std::string message = "HTTP query failed: " + std::string(ex.what());
wxMessageBox(message, "Icinga Studio", wxOK | wxCENTRE | wxICON_ERROR, this);
return;
}
}
std::vector<ApiObject::Ptr> sortedObjects = objects;
std::sort(sortedObjects.begin(), sortedObjects.end(), ApiObjectLessComparer);
for (const ApiObject::Ptr& object : sortedObjects) {
std::string name = object->Name;
m_ObjectsList->InsertItem(0, name);
}
}
void MainForm::OnObjectSelected(wxListEvent& event)
{
wxTreeItemId selectedId = m_TypesTree->GetSelection();
wxString typeName = m_TypesTree->GetItemText(selectedId);
ApiType::Ptr type = m_Types[typeName.ToStdString()];
long itemIndex = -1;
std::string objectName;
while ((itemIndex = m_ObjectsList->GetNextItem(itemIndex,
wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != wxNOT_FOUND) {
objectName = m_ObjectsList->GetItemText(itemIndex);
break;
}
if (objectName.empty())
return;
std::vector<String> names;
names.push_back(objectName);
m_ApiClient->GetObjects(type->PluralName, boost::bind(&MainForm::ObjectDetailsCompletionHandler, this, _1, _2, true),
names, std::vector<String>(), std::vector<String>(), true);
}
wxPGProperty *MainForm::ValueToProperty(const String& name, const Value& value)
{
wxPGProperty *prop;
if (value.IsNumber()) {
prop = new wxFloatProperty(name.GetData(), wxPG_LABEL, value);
prop->SetAttribute(wxPG_ATTR_UNITS, "Number");
return prop;
} else if (value.IsBoolean()) {
prop = new wxBoolProperty(name.GetData(), wxPG_LABEL, value);
prop->SetAttribute(wxPG_ATTR_UNITS, "Boolean");
return prop;
} else if (value.IsObjectType<Array>()) {
wxArrayString val;
Array::Ptr arr = value;
{
ObjectLock olock(arr);
for (const Value& aitem : arr) {
String val1 = aitem;
val.Add(val1.GetData());
}
}
prop = new wxArrayStringProperty(name.GetData(), wxPG_LABEL, val);
prop->SetAttribute(wxPG_ATTR_UNITS, "Array");
return prop;
} else if (value.IsObjectType<Dictionary>()) {
wxStringProperty *prop = new wxStringProperty(name.GetData(), wxPG_LABEL);
Dictionary::Ptr dict = value;
{
ObjectLock olock(dict);
for (const Dictionary::Pair& kv : dict) {
if (kv.first != "type")
prop->AppendChild(ValueToProperty(kv.first, kv.second));
}
}
String type = "Dictionary";
if (dict->Contains("type"))
type = dict->Get("type");
prop->SetAttribute(wxPG_ATTR_UNITS, type.GetData());
return prop;
} else if (value.IsEmpty() && !value.IsString()) {
prop = new wxStringProperty(name.GetData(), wxPG_LABEL, "");
prop->SetAttribute(wxPG_ATTR_UNITS, "Empty");
return prop;
} else {
String val = value;
prop = new wxStringProperty(name.GetData(), wxPG_LABEL, val.GetData());
prop->SetAttribute(wxPG_ATTR_UNITS, "String");
return prop;
}
}
void MainForm::ObjectDetailsCompletionHandler(boost::exception_ptr eptr, const std::vector<ApiObject::Ptr>& objects, bool forward)
{
if (forward) {
CallAfter(boost::bind(&MainForm::ObjectDetailsCompletionHandler, this, eptr, objects, false));
return;
}
m_PropertyGrid->Clear();
if (eptr) {
try {
boost::rethrow_exception(eptr);
} catch (const std::exception& ex) {
std::string message = "HTTP query failed: " + std::string(ex.what());
wxMessageBox(message, "Icinga Studio", wxOK | wxCENTRE | wxICON_ERROR, this);
}
}
wxTreeItemId selectedId = m_TypesTree->GetSelection();
wxString typeName = m_TypesTree->GetItemText(selectedId);
ApiType::Ptr type = m_Types[typeName.ToStdString()];
String nameAttr = type->Name.ToLower() + ".__name";
if (objects.empty())
return;
ApiObject::Ptr object = objects[0];
std::map<String, wxStringProperty *> parents;
for (const auto& kv : object->Attrs) {
std::vector<String> tokens;
boost::algorithm::split(tokens, kv.first, boost::is_any_of("."));
std::map<String, wxStringProperty *>::const_iterator it = parents.find(tokens[0]);
wxStringProperty *parent;
if (it == parents.end()) {
parent = new wxStringProperty(tokens[0].GetData(), wxPG_LABEL);
parent->SetAttribute(wxPG_ATTR_UNITS, "Object");
parents[tokens[0]] = parent;
} else
parent = it->second;
wxPGProperty *prop = ValueToProperty(tokens[1], kv.second);
parent->AppendChild(prop);
}
/* Make sure the property node for the real object (as opposed to joined objects) is the first one */
String propName = type->Name.ToLower();
wxStringProperty *objProp = parents[propName];
if (objProp) {
m_PropertyGrid->Append(objProp);
m_PropertyGrid->SetPropertyReadOnly(objProp);
parents.erase(propName);
}
for (const auto& kv : parents) {
m_PropertyGrid->Append(kv.second);
m_PropertyGrid->SetPropertyReadOnly(kv.second);
}
m_PropertyGrid->FitColumns();
}
void MainForm::OnQuitClicked(wxCommandEvent& event)
{
Close();
}
void MainForm::OnAboutClicked(wxCommandEvent& event)
{
AboutForm form(this);
form.ShowModal();
}