Compare commits

..
38 Commits
Author SHA1 Message Date
schetnikovich 03e3592443 bin/tag 2016-04-18 13:58:36 +03:00
schetnikovich c113244319 Minor UI improvement for "Ask for password" dialog 2016-04-14 12:55:18 +03:00
schetnikovich 3a64e1310b Do not log password 2016-04-13 17:34:35 +03:00
schetnikovich 306b759b74 Fixed incorrect validation on SSH tab 2016-04-13 16:53:29 +03:00
schetnikovich 5976884b0f Details about SSH server, user name and private key file path when asked about password/passphrase. 2016-04-13 15:10:53 +03:00
schetnikovich ee907c3321 Disable and clear password and passphrase fields when "Ask password each time" checkbox is selected 2016-04-13 13:43:42 +03:00
schetnikovich 86307a724f Different text for "ask password" and "ask passphrase" checkbox 2016-04-12 23:56:58 +03:00
schetnikovich 997aa44654 #609 Robomongo should not force to save SSH passwords
Added option to always ask user for SSH password or passphrase and never store it in a plain text
2016-04-12 21:05:38 +03:00
schetnikovich feb1d277e9 Support for "~" expansion and validation of file path for SSH private key 2016-04-12 19:33:07 +03:00
schetnikovich 7e1dac26f1 SSH tab moved before Advanced and other minor UI tweaks of settings tabs 2016-04-12 19:05:47 +03:00
schetnikovich a7b95d4caf #1074 Fixed: Crash when "Copy JSON" an object within an array 2016-04-12 17:46:23 +03:00
schetnikovich bb042fe70b Brace matching turned off on the Mac because of flickering issue with Scintilla 2016-04-12 16:38:18 +03:00
schetnikovich e50ee8fbee Turn off echo of autocompletion cache setup 2016-04-12 14:41:01 +03:00
schetnikovich 55d8a6ff76 DB collections autocompletion cached for fixed number of seconds 2016-04-12 14:05:12 +03:00
schetnikovich 576fc07b5b Limit serverHost to fixed number of characters 2016-04-12 10:10:20 +03:00
schetnikovich b4978269a5 Set focus to address textbox when SSH is enabled 2016-04-11 23:10:08 +03:00
schetnikovich 24e9a74a6c Fixed two issues of blinking text and UI
1. Latest version of QScintilla has a bug with lexers that makes UI blink when editing text. We downgraded back to v2.8.1
2. Adding of a new line to the script editor in the tab no longer forces unnecessary repaint and repositioning of widgets (no more blinking)
2016-04-11 21:40:09 +03:00
schetnikovich 61e79155b4 QScintilla downgraded to v2.8.4 (from v2.9.1) because of issue with lexers 2016-04-11 21:32:46 +03:00
schetnikovich d23d9a2e7a Ping timeout set to 3 seconds for the shell 2016-04-11 17:20:27 +03:00
schetnikovich ae13e30494 #1063 Fixed: OSX Edit/View Document Popup only opens on main display 2016-04-11 17:01:10 +03:00
schetnikovich 292c664941 Config-level settings for operation timeout: both for MongoDB client and for the shell 2016-04-11 15:36:53 +03:00
schetnikovich c78845571e Separate handling of NumberInt conversion 2016-04-11 09:25:09 +03:00
schetnikovich a0d5c67e48 #1069: Fixed: Double 0.0 gets converted to Int32 0 after editing 2016-04-10 18:28:47 +03:00
schetnikovich 059a3dcc37 Code style fixes for the most horrible disuse of whitespaces 2016-04-10 16:02:36 +03:00
schetnikovich d543bb4539 Unused variable removed 2016-04-10 14:44:02 +03:00
schetnikovich 3e8f800682 Handling of edge cases with proper reporting and changes in MongoWorker
1. Detailed error message link in Diagnostic window
2. Cleanup of opened MongoServers and SSH workers in case of failure
3. Better status messages in Diagnostic window when using SSH tunnel
4. Script engine is now starts after an attempt to connect to MongoDB
2016-04-10 14:09:58 +03:00
schetnikovich 368f2abe0d Diagnostic window resizes only if needed and without layout "jumps". 2016-04-09 12:48:35 +03:00
schetnikovich 1e8af399e7 Code typo fix 2016-04-08 21:39:24 +03:00
schetnikovich 72f669e189 Merge branch 'master' of github.com:paralect/robomongo 2016-04-08 21:15:50 +03:00
schetnikovich c787b54e7c Connection diagnostic rewritten
1. Checks creation of SSH tunnel
2. Checks connection to MongoDB
3. Checks ability to list databases
4. Checks ability to authorize
2016-04-08 21:15:08 +03:00
Dmitry Schetnikovich 3512be30cf Wrong header for Windows (fixed) 2016-04-07 15:32:01 +03:00
schetnikovich 0bb279eec8 Support for domain names and IPv6 address of remote SSH server 2016-04-07 15:18:48 +03:00
Dmitry Schetnikovich 75331d9025 Warnings-free compilation for MSVC (well, almost) 2016-04-06 19:09:13 +03:00
schetnikovich 99a46eafc8 Warnings-free compilation for Clang 2016-04-06 16:41:29 +03:00
Dmitry Schetnikovich ac9300f5be Better handling of client disconnection for SSH tunnel 2016-04-06 15:30:49 +03:00
Dmitry Schetnikovich 4e4e5154f4 Compilation of RC8 under Windows 2016-04-06 13:20:05 +03:00
schetnikovich b54c096762 Robomongo RC8 2016-04-05 16:29:51 +03:00
Dmitry Schetnikovich 5d409ec1de Merge pull request #1072 from paralect/ssh
Support for SSH protocol
2016-04-05 16:24:33 +03:00
786 changed files with 74174 additions and 123604 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
set(PROJECT_VERSION_MAJOR "0")
set(PROJECT_VERSION_MINOR "9")
set(PROJECT_VERSION_PATCH "0")
set(PROJECT_VERSION_BUILD "-RC7")
set(PROJECT_VERSION_BUILD "-RC8")
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${PROJECT_VERSION_BUILD}")
# Modules
Executable
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
BIN_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # Get directory of this file
PROJECT_DIR=$(dirname $BIN_DIR) # Get root directory of project
VERSION="$(echo $1 | tr '[A-Z]' '[a-z]')"
if [ -z "$VERSION" ]; then
echo "Usage: tag <name>"
echo "Example: tag 0.9.0-rc9"
exit
fi
if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ]; then
echo "Error: You are not on master branch"
exit
fi
cd $PROJECT_DIR
git tag -a "v${VERSION}" -m "${VERSION}"
git push --tags
+12
View File
@@ -52,6 +52,18 @@ elseif("${CMAKE_BUILD_TYPE}" MATCHES "MinSizeRel")
set(BUILD_MINSIZEREL TRUE)
endif()
# Compiler checks
# We check Clang using MATCH instead of strict equality, because as of CMake 3.0.0 the
# CMAKE_<LANG>_COMPILER_ID value for Apple-provided Clang is AppleClang. To test
# for both the Apple-provided Clang and the regular Clang we use MATCH.
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(COMPILER_CLANG TRUE)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "^GNU$")
set(COMPILER_GCC TRUE)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "^MSVC$")
set(COMPILER_MSVC TRUE)
endif()
# Link "groups" and "whole-archive" options
if(SYSTEM_LINUX OR SYSTEM_FREEBSD OR SYSTEM_OPENBSD)
set(LINK_LIBGROUP_START -Wl,--start-group)
+1
View File
@@ -10,6 +10,7 @@ elseif(SYSTEM_WINDOWS)
# The /MP option can reduce the total time to compile the source files. This option
# causes the compiler to create one or more copies of itself, each in a separate process.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} /MP")
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} psapi.lib bcrypt.lib Iphlpapi.lib dbghelp.lib ws2_32.lib winmm.lib version.lib")
endif()
+4
View File
@@ -5,6 +5,10 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
#set(sanitize "-fsanitize=address")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${sanitize}")
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${sanitize}")
set(SOURCES
# Isolated Scope #1
+5 -1
View File
@@ -39,11 +39,15 @@ int main(int argc, char *argv[], char** envp)
// This can cause a conflict when using POSIX functions, for instance, when
// converting between data types such as floats and strings, since the notation
// may differ between locales. To get around this problem, call the POSIX
// function setlocale(LC_NUMERIC,"C") right after initializing QApplication or
// function setlocale(LC_NUMERIC, "C") right after initializing QApplication or
// QCoreApplication to reset the locale that is used for number formatting to "C"-locale.
// (http://doc.qt.io/qt-5/qcoreapplication.html#locale-settings)
setlocale(LC_NUMERIC, "C");
#ifdef Q_OS_MAC
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
// Init GUI style
Robomongo::AppStyleUtils::initStyle();
+7
View File
@@ -33,12 +33,19 @@ void precisionAssert(const std::string &text, double d) {
std::stringstream s;
s.precision(std::numeric_limits<double>::digits10);
s << d;
if (d == (long long)d)
s << ".0";
std::cout << "Checking " << text << " - ";
assert(text == s.str());
std::cout << "Correct. " << std::endl;
}
void testPrecision() {
precisionAssert("-9.987654321", -9.987654321);
precisionAssert("-1.0", -1.0);
precisionAssert("-0.0", -0.0);
precisionAssert("0.0", 0.0);
precisionAssert("9.0", 9.0);
precisionAssert("9.8", 9.8);
precisionAssert("9.9", 9.9);
precisionAssert("9.98", 9.98);
+14
View File
@@ -30,4 +30,18 @@ namespace Robomongo
class MongoDocument;
typedef boost::shared_ptr<MongoDocument> MongoDocumentPtr;
enum ConnectionType {
// This type of connection is shown in Explorer and also
// opens SSH tunnel for Secondary connections (if needed)
ConnectionPrimary = 0,
// Never shown in Explorer and uses SSH tunnel from
// Primary connection (if needed)
ConnectionSecondary = 1,
// The same as Primary, but is specifically for testing
// connections.
ConnectionTest = 2
};
}
+2 -2
View File
@@ -10,9 +10,9 @@ namespace
template<typename type, int size>
inline type findTypeInArray(const char *(&arr)[size], const char *text)
{
for (int i=0; i < size;++i )
for (int i = 0; i < size; ++i )
{
if (strcmp(text,arr[i])==0)
if (strcmp(text, arr[i]) == 0)
{
return static_cast<type>(i);
}
+2 -2
View File
@@ -36,7 +36,7 @@ namespace Robomongo
char *data = new char[bytes];
const char *p = s.c_str();
for( size_t i = 0; i < bytes; i++ ) {
for (size_t i = 0; i < bytes; i++) {
data[i] = mongo::fromHex(p);
p += 2;
}
@@ -159,7 +159,7 @@ namespace Robomongo
mongo::BinDataType binType = element.binDataType();
if (binType != mongo::newUUID && binType != mongo::bdtUUID)
throw new std::invalid_argument("Binary subtype should be 3 (bdtUUID) or 4 (newUUID)");
throw std::invalid_argument("Binary subtype should be 3 (bdtUUID) or 4 (newUUID)");
int len;
const char *data = element.binData(len);
+89 -33
View File
@@ -1,5 +1,6 @@
#include "robomongo/core/domain/App.h"
#include <QHash>
#include <QInputDialog>
#include "robomongo/core/domain/MongoServer.h"
#include "robomongo/core/domain/MongoShell.h"
@@ -33,7 +34,7 @@ namespace Robomongo
}
App::App(EventBus *const bus) : QObject(),
_bus(bus) {
_bus(bus), _lastServerHandle(0) {
_bus->subscribe(this, EstablishSshConnectionResponse::Type);
_bus->subscribe(this, ListenSshConnectionResponse::Type);
_bus->subscribe(this, LogEvent::Type);
@@ -45,19 +46,63 @@ namespace Robomongo
std::for_each(_servers.begin(), _servers.end(), stdutils::default_delete<MongoServer*>());
}
bool App::openServer(ConnectionSettings *connection, ConnectionType type) {
SshSettings *ssh = connection->sshSettings();
if (ssh->enabled() && ssh->askPassword() &&
(type == ConnectionPrimary || type == ConnectionTest)) {
bool ok = false;
bool isByKey = ssh->authMethod() == "publickey";
std::string passText = isByKey ? "passphrase" : "password";
std::stringstream s;
s << "In order to continue, please provide the " << passText;
if (isByKey)
s << " for the key file";
s << "." << std::endl << std::endl;
if (ssh->authMethod() == "publickey")
s << "Private Key: " << ssh->privateKeyFile() << std::endl;
s << "Server: " << ssh->host() << std::endl;
s << "User: " << ssh->userName() << std::endl;
s << std::endl << "Enter your " << passText << " that will never be stored:";
QString userInput = QInputDialog::getText(NULL, tr("SSH Authentication"),
QtUtils::toQString(s.str()),
QLineEdit::Password, "", &ok);
if (!ok)
return false;
ssh->setAskedPassword(QtUtils::toStdString(userInput));
}
openServerInternal(connection, type);
return true;
}
/**
* Creates and opens new server connection.
* @param connection: ConnectionSettings, that will be owned by MongoServer.
* @param visible: should this server be visible in UI (explorer) or not.
*/
MongoServer *App::openServer(ConnectionSettings *connection, bool visible) {
if (visible)
MongoServer *App::openServerInternal(ConnectionSettings *connection, ConnectionType type) {
++_lastServerHandle;
if (type == ConnectionPrimary)
_bus->publish(new ConnectingEvent(this));
// When connection is not "visible" or do not have
// When connection is SECONDARY or do not have
// ssh settings enabled, continue without SSH Tunnel
if (!visible || !connection->sshSettings()->enabled()) {
return continueOpenServer(connection, visible);
if (type == ConnectionSecondary || !connection->sshSettings()->enabled()) {
return continueOpenServer(_lastServerHandle, connection, type);
}
// Open SSH channel and only after that open connection
@@ -67,7 +112,7 @@ namespace Robomongo
ConnectionSettings* settingsCopy = connection->clone();
SshTunnelWorker* sshWorker = new SshTunnelWorker(settingsCopy);
_bus->send(sshWorker, new EstablishSshConnectionRequest(this, sshWorker, settingsCopy, visible));
_bus->send(sshWorker, new EstablishSshConnectionRequest(this, _lastServerHandle, sshWorker, settingsCopy, type));
return NULL;
}
@@ -80,43 +125,46 @@ namespace Robomongo
_servers.erase(std::remove_if(_servers.begin(), _servers.end(), stdutils::RemoveIfFound<MongoServer*>(server)), _servers.end());
}
MongoShell *App::openShell(MongoCollection *collection,const QString &filePathToSave)
void App::openShell(MongoCollection *collection, const QString &filePathToSave)
{
ConnectionSettings *connection = collection->database()->server()->connectionRecord();
connection->setDefaultDatabase(collection->database()->name());
QString script = detail::buildCollectionQuery(collection->name(), "find({})");
return openShell(connection, ScriptInfo(script, true, CursorPosition(0, -2), QtUtils::toQString(collection->database()->name()),filePathToSave));
openShell(connection, ScriptInfo(script, true, CursorPosition(0, -2), QtUtils::toQString(collection->database()->name()), filePathToSave));
}
MongoShell *App::openShell(MongoServer *server,const QString &script, const std::string &dbName,
void App::openShell(MongoServer *server, const QString &script, const std::string &dbName,
bool execute, const QString &shellName,
const CursorPosition &cursorPosition,const QString &filePathToSave)
const CursorPosition &cursorPosition, const QString &filePathToSave)
{
ConnectionSettings *connection = server->connectionRecord();
if (!dbName.empty())
connection->setDefaultDatabase(dbName);
return openShell(connection, ScriptInfo(script, execute, cursorPosition, shellName,filePathToSave));
openShell(connection, ScriptInfo(script, execute, cursorPosition, shellName, filePathToSave));
}
MongoShell *App::openShell(MongoDatabase *database, const QString &script,
void App::openShell(MongoDatabase *database, const QString &script,
bool execute, const QString &shellName,
const CursorPosition &cursorPosition,const QString &filePathToSave)
const CursorPosition &cursorPosition, const QString &filePathToSave)
{
ConnectionSettings *connection = database->server()->connectionRecord();
connection->setDefaultDatabase(database->name());
return openShell(connection, ScriptInfo(script, execute, cursorPosition, shellName,filePathToSave));
openShell(connection, ScriptInfo(script, execute, cursorPosition, shellName, filePathToSave));
}
MongoShell *App::openShell(ConnectionSettings *connection, const ScriptInfo &scriptInfo)
void App::openShell(ConnectionSettings *connection, const ScriptInfo &scriptInfo)
{
MongoServer *server = openServer(connection, false);
MongoShell *shell = new MongoShell(server,scriptInfo);
MongoServer *server = openServerInternal(connection, ConnectionSecondary);
if (!server)
return;
MongoShell *shell = new MongoShell(server, scriptInfo);
_shells.push_back(shell);
_bus->publish(new OpeningShellEvent(this, shell));
shell->execute();
return shell;
return;
}
/**
@@ -126,7 +174,7 @@ namespace Robomongo
void App::closeShell(MongoShell *shell)
{
// Do nothing, if this shell not owned by this App.
MongoShellsContainerType::iterator it = std::find_if(_shells.begin(),_shells.end(),std::bind1st(std::equal_to<MongoShell *>(),shell));
MongoShellsContainerType::iterator it = std::find_if(_shells.begin(), _shells.end(), std::bind1st(std::equal_to<MongoShell *>(), shell));
if (it == _shells.end())
return;
@@ -135,16 +183,17 @@ namespace Robomongo
delete shell;
}
MongoServer* App::continueOpenServer(ConnectionSettings *connection, bool visible, int localport) {
MongoServer *App::continueOpenServer(int serverHandle, ConnectionSettings *connection, ConnectionType type, int localport) {
ConnectionSettings* settings = connection->clone();
// Modify connection settings when SSH tunnel is used
if (visible && settings->sshSettings()->enabled()) {
if ((type == ConnectionPrimary || type == ConnectionTest)
&& settings->sshSettings()->enabled()) {
settings->setServerHost("127.0.0.1");
settings->setServerPort(localport);
}
MongoServer *server = new MongoServer(settings, visible);
MongoServer *server = new MongoServer(serverHandle, settings, type);
_servers.push_back(server);
server->runWorkerThread();
@@ -156,36 +205,43 @@ namespace Robomongo
void App::handle(EstablishSshConnectionResponse *event) {
if (event->isError()) {
_bus->publish(new ConnectionFailedEvent(this, event->error().errorMessage()));
_bus->publish(new ConnectionFailedEvent(
this, event->serverHandle, event->connectionType, event->error().errorMessage(),
ConnectionFailedEvent::SshConnection));
return;
}
LOG_MSG(QString("SSH tunnel created successfully"), mongo::logger::LogSeverity::Info());
_bus->send(event->worker, new ListenSshConnectionRequest(this));
continueOpenServer(event->settings, event->visible, event->localport);
// record event->worker and delete when needed
continueOpenServer(event->serverHandle, event->settings, event->connectionType, event->localport);
_bus->send(event->worker, new ListenSshConnectionRequest(this, event->serverHandle, event->connectionType));
}
void App::handle(LogEvent *event) {
if (event->level == LogEvent::ERROR) {
if (event->level == LogEvent::RBM_ERROR) {
LOG_MSG(event->message, mongo::logger::LogSeverity::Error());
} else if (event->level == LogEvent::WARN) {
} else if (event->level == LogEvent::RBM_WARN) {
LOG_MSG(event->message, mongo::logger::LogSeverity::Warning());
} else if (event->level == LogEvent::INFO) {
} else if (event->level == LogEvent::RBM_INFO) {
LOG_MSG(event->message, mongo::logger::LogSeverity::Info());
} else if (event->level == LogEvent::DEBUG) {
} else if (event->level == LogEvent::RBM_DEBUG) {
LOG_MSG(event->message, mongo::logger::LogSeverity::Log());
}
}
void App::handle(ListenSshConnectionResponse *event) {
if (event->isError()) {
_bus->publish(new ConnectionFailedEvent(this, event->error().errorMessage()));
_bus->publish(new ConnectionFailedEvent(this, event->serverHandle, event->connectionType, event->error().errorMessage(),
ConnectionFailedEvent::SshChannel));
return;
}
LOG_MSG(QString("SSH tunnel closed."), mongo::logger::LogSeverity::Error());
}
void App::fireConnectionFailedEvent(int serverHandle, ConnectionType type, std::string errormsg,
ConnectionFailedEvent::Reason reason) {
_bus->publish(new ConnectionFailedEvent(this, serverHandle, type, errormsg, reason));
}
}
+17 -7
View File
@@ -47,8 +47,9 @@ namespace Robomongo
* @brief Creates and opens new server connection.
* @param connection: ConnectionSettings, that will be owned by MongoServer.
* @param visible: should this server be visible in UI (explorer) or not.
* @return Succeeded or not
*/
MongoServer *openServer(ConnectionSettings *connection, bool visible);
bool openServer(ConnectionSettings *connection, ConnectionType type);
/**
* @brief Closes MongoServer connection and frees all resources, owned
@@ -59,18 +60,18 @@ namespace Robomongo
/**
* @brief Open new shell based on specified collection
*/
MongoShell *openShell(MongoCollection *collection,const QString &filePathToSave=QString());
void openShell(MongoCollection *collection, const QString &filePathToSave = QString());
MongoShell *openShell(MongoServer *server, const QString &script, const std::string &dbName = std::string(),
void openShell(MongoServer *server, const QString &script, const std::string &dbName = std::string(),
bool execute = true, const QString &shellName = QString(),
const CursorPosition &cursorPosition = CursorPosition(), const QString &file = QString());
MongoShell *openShell(MongoDatabase *database, const QString &script,
void openShell(MongoDatabase *database, const QString &script,
bool execute = true, const QString &shellName = QString(),
const CursorPosition &cursorPosition = CursorPosition(), const QString &filePathToSave = QString());
MongoShell *openShell(ConnectionSettings *connection, const ScriptInfo &scriptInfo);
MongoServersContainerType getServers() const {return _servers; };
void openShell(ConnectionSettings *connection, const ScriptInfo &scriptInfo);
MongoServersContainerType getServers() const { return _servers; };
/**
* @brief Closes MongoShell and frees all resources, owned by specified MongoShell.
@@ -78,13 +79,18 @@ namespace Robomongo
*/
void closeShell(MongoShell *shell);
void fireConnectionFailedEvent(int serverHandle, ConnectionType type, std::string errormsg, ConnectionFailedEvent::Reason reason);
int getLastServerHandle() const { return _lastServerHandle; };
public Q_SLOTS:
void handle(EstablishSshConnectionResponse *event);
void handle(ListenSshConnectionResponse *event);
void handle(LogEvent *event);
private:
MongoServer* continueOpenServer(ConnectionSettings *connection, bool visible, int localport = 0);
MongoServer *openServerInternal(ConnectionSettings *connection, ConnectionType type);
MongoServer *continueOpenServer(int serverHandle, ConnectionSettings *connection, ConnectionType type, int localport = 0);
/**
* MongoServers, owned by this App.
@@ -97,5 +103,9 @@ namespace Robomongo
MongoShellsContainerType _shells;
EventBus *const _bus;
// Increase monotonically when new MongoServer is created
// Never decreases.
int _lastServerHandle;
};
}
+1 -1
View File
@@ -38,7 +38,7 @@ namespace Robomongo
std::vector<MongoDocumentPtr> MongoDocument::fromBsonObj(const std::vector<mongo::BSONObj> &bsonObjs)
{
std::vector<MongoDocumentPtr> list;
for (std::vector<mongo::BSONObj>::const_iterator it=bsonObjs.begin(); it!=bsonObjs.end(); ++it) {
for (std::vector<mongo::BSONObj>::const_iterator it = bsonObjs.begin(); it != bsonObjs.end(); ++it) {
list.push_back(fromBsonObj(*it));
}
+1 -1
View File
@@ -6,7 +6,7 @@ namespace Robomongo
{
MongoFunction::MongoFunction(const mongo::BSONObj &obj)
{
_name = BsonUtils::getField<mongo::String>(obj,"_id");
_name = BsonUtils::getField<mongo::String>(obj, "_id");
_code = obj.getField("value")._asCode();
}
+3 -3
View File
@@ -9,8 +9,8 @@ namespace Robomongo
std::string prepareServerAddress(const std::string &address)
{
size_t pos = address.find_first_of("{");
if (pos!=std::string::npos){
return address.substr(0,pos);
if (pos != std::string::npos) {
return address.substr(0, pos);
}
return address;
}
@@ -20,7 +20,7 @@ namespace Robomongo
CollectionInfo::CollectionInfo(const std::string &server, const std::string &database, const std::string &collection)
:_serverAddress(server),
_ns(database,collection)
_ns(database, collection)
{}
bool CollectionInfo::isValid() const
+32 -16
View File
@@ -7,19 +7,22 @@
#include "robomongo/core/mongodb/MongoWorker.h"
#include "robomongo/core/mongodb/SshTunnelWorker.h"
#include "robomongo/core/AppRegistry.h"
#include "robomongo/core/domain/App.h"
#include "robomongo/core/EventBus.h"
#include "robomongo/core/utils/QtUtils.h"
namespace Robomongo {
R_REGISTER_EVENT(MongoServerLoadingDatabasesEvent)
MongoServer::MongoServer(ConnectionSettings *settings, bool visible) : QObject(),
MongoServer::MongoServer(int handle, ConnectionSettings *settings, ConnectionType connectionType) : QObject(),
_version(0.0f),
_visible(visible),
_connectionType(connectionType),
_client(NULL),
_isConnected(false),
_settings(settings),
_bus(AppRegistry::instance().bus()) { }
_handle(handle),
_bus(AppRegistry::instance().bus()),
_app(AppRegistry::instance().app()) { }
bool MongoServer::isConnected() const {
return _isConnected;
@@ -49,7 +52,7 @@ namespace Robomongo {
* @throws MongoException, if fails
*/
void MongoServer::tryConnect() {
_bus->send(_client, new EstablishConnectionRequest(this));
_bus->send(_client, new EstablishConnectionRequest(this, _connectionType));
}
QStringList MongoServer::getDatabasesNames() const {
@@ -62,7 +65,7 @@ namespace Robomongo {
}
void MongoServer::createDatabase(const std::string &dbName) {
_bus->send(_client,new CreateDatabaseRequest(this, dbName));
_bus->send(_client, new CreateDatabaseRequest(this, dbName));
}
MongoDatabase *MongoServer::findDatabaseByName(const std::string &dbName) const {
@@ -76,7 +79,7 @@ namespace Robomongo {
}
void MongoServer::dropDatabase(const std::string &dbName) {
_bus->send(_client,new DropDatabaseRequest(this, dbName));
_bus->send(_client, new DropDatabaseRequest(this, dbName));
}
void MongoServer::insertDocuments(const std::vector<mongo::BSONObj> &objCont,
@@ -87,12 +90,12 @@ namespace Robomongo {
}
void MongoServer::insertDocument(const mongo::BSONObj &obj, const MongoNamespace &ns) {
_bus->send(_client,new InsertDocumentRequest(this, obj, ns));
_bus->send(_client, new InsertDocumentRequest(this, obj, ns));
}
void MongoServer::saveDocuments(const std::vector<mongo::BSONObj> &objCont, const MongoNamespace &ns) {
for (std::vector<mongo::BSONObj>::const_iterator it = objCont.begin(); it != objCont.end(); it++) {
saveDocument(*it,ns);
saveDocument(*it, ns);
}
}
@@ -126,7 +129,18 @@ namespace Robomongo {
ss << "Cannot connect to the MongoDB at " << connectionRecord()->getFullAddress()
<< ".\n\nError:\n" << event->error().errorMessage();
_bus->publish(new ConnectionFailedEvent(this, ss.str()));
ConnectionFailedEvent::Reason reason =
event->errorReason == EstablishConnectionResponse::MongoAuth ?
ConnectionFailedEvent::MongoAuth : ConnectionFailedEvent::MongoConnection;
// When connection cannot be established, we should
// cleanup this instance of MongoServer if it wasn't
// shown in UI (i.e. it is not a Secondary connection
// that is used for shells tab)
if (_connectionType == ConnectionPrimary || _connectionType == ConnectionTest)
_app->closeServer(this);
_app->fireConnectionFailedEvent(_handle, _connectionType, ss.str(), reason);
return;
}
@@ -134,14 +148,14 @@ namespace Robomongo {
_version = info._version;
_isConnected = true;
// Do nothing if this is not "visible" connection
if (!_visible) {
_bus->publish(new ConnectionEstablishedEvent(this, _connectionType));
// Do nothing if this is not a "primary" connection
if (_connectionType != ConnectionPrimary)
return;
}
_bus->publish(new ConnectionEstablishedEvent(this));
clearDatabases();
for(std::vector<std::string>::const_iterator it = info._databases.begin(); it != info._databases.end(); ++it) {
for (std::vector<std::string>::const_iterator it = info._databases.begin(); it != info._databases.end(); ++it) {
const std::string &name = *it;
MongoDatabase *db = new MongoDatabase(this, name);
addDatabase(db);
@@ -155,7 +169,7 @@ namespace Robomongo {
}
clearDatabases();
for(std::vector<std::string>::iterator it = event->databaseNames.begin(); it != event->databaseNames.end(); ++it) {
for (std::vector<std::string>::iterator it = event->databaseNames.begin(); it != event->databaseNames.end(); ++it) {
const std::string &name = *it;
MongoDatabase *db = new MongoDatabase(this, name);
addDatabase(db);
@@ -175,6 +189,8 @@ namespace Robomongo {
void MongoServer::runWorkerThread() {
_client = new MongoWorker(_settings->clone(),
AppRegistry::instance().settingsManager()->loadMongoRcJs(),
AppRegistry::instance().settingsManager()->batchSize());
AppRegistry::instance().settingsManager()->batchSize(),
AppRegistry::instance().settingsManager()->mongoTimeoutSec(),
AppRegistry::instance().settingsManager()->shellTimeoutSec());
}
}
+8 -6
View File
@@ -12,6 +12,7 @@ namespace Robomongo
class LoadDatabaseNamesResponse;
class InsertDocumentResponse;
class EventBus;
class App;
/**
* @brief MongoServer represents active connection to MongoDB server.
@@ -29,7 +30,7 @@ namespace Robomongo
* @param visible
* @param defaultDatabase
*/
MongoServer(ConnectionSettings *connectionRecord, bool visible);
MongoServer(int handle, ConnectionSettings *connectionRecord, ConnectionType connectionType);
~MongoServer();
void runWorkerThread();
@@ -63,7 +64,6 @@ namespace Robomongo
* @brief Loads databases of this server asynchronously.
*/
void loadDatabases();
bool visible() const { return _visible; }
MongoWorker *const client() const { return _client; }
protected Q_SLOTS:
@@ -76,13 +76,15 @@ namespace Robomongo
void clearDatabases();
void addDatabase(MongoDatabase *database);
MongoWorker* _client;
ConnectionSettings* _settings;
EventBus* _bus;
MongoWorker *_client;
ConnectionSettings *_settings;
EventBus *_bus;
App *_app;
float _version;
bool _visible;
ConnectionType _connectionType;
bool _isConnected;
int _handle;
QList<MongoDatabase *> _databases;
};
+2 -2
View File
@@ -38,12 +38,12 @@ namespace Robomongo
if (_scriptInfo.execute()) {
AppRegistry::instance().bus()->publish(new ScriptExecutingEvent(this));
AppRegistry::instance().bus()->send(_server->client(), new ExecuteScriptRequest(this, query(), dbName));
if(!_scriptInfo.script().isEmpty())
if (!_scriptInfo.script().isEmpty())
LOG_MSG(_scriptInfo.script(), mongo::logger::LogSeverity::Info());
} else {
AppRegistry::instance().bus()->publish(new ScriptExecutingEvent(this));
_scriptInfo.setScript("");
AppRegistry::instance().bus()->send(_server->client(), new ExecuteScriptRequest(this,query() , dbName));
AppRegistry::instance().bus()->send(_server->client(), new ExecuteScriptRequest(this, query() , dbName));
}
}
+2 -2
View File
@@ -10,7 +10,7 @@ namespace Robomongo
Q_OBJECT
public:
MongoShell(MongoServer *server,const ScriptInfo &scriptInfo);
MongoShell(MongoServer *server, const ScriptInfo &scriptInfo);
void open(const std::string &script, const std::string &dbName = std::string());
void query(int resultIndex, const MongoQueryInfo &info);
@@ -19,7 +19,7 @@ namespace Robomongo
MongoServer *server() const { return _server; }
std::string query() const;
void execute(const std::string &dbName = std::string());
bool isExecutable() const {return _scriptInfo.execute(); }
bool isExecutable() const { return _scriptInfo.execute(); }
const QString &title() const { return _scriptInfo.title(); }
const CursorPosition &cursor() const { return _scriptInfo.cursor(); }
void setScript(const QString &script) { return _scriptInfo.setScript(script); }
+7 -7
View File
@@ -12,15 +12,15 @@ namespace Robomongo
_version(version), _readOnly(false)
{
_id = obj.getField("_id").OID();
_name = BsonUtils::getField<mongo::String>(obj,"user");
_passwordHash = BsonUtils::getField<mongo::String>(obj,"pwd");
_name = BsonUtils::getField<mongo::String>(obj, "user");
_passwordHash = BsonUtils::getField<mongo::String>(obj, "pwd");
if (_version<minimumSupportedVersion) {
_readOnly = BsonUtils::getField<mongo::Bool>(obj,"readOnly");
_readOnly = BsonUtils::getField<mongo::Bool>(obj, "readOnly");
}
else {
_userSource = BsonUtils::getField<mongo::String>(obj,"userSource");
_userSource = BsonUtils::getField<mongo::String>(obj, "userSource");
std::vector<mongo::BSONElement> roles = BsonUtils::getField<mongo::Array>(obj, "roles");
for (std::vector<mongo::BSONElement>::const_iterator it = roles.begin(); it!= roles.end(); ++it)
for (std::vector<mongo::BSONElement>::const_iterator it = roles.begin(); it != roles.end(); ++it)
{
_role.push_back(BsonUtils::bsonelement_cast<std::string>(*it));
}
@@ -28,7 +28,7 @@ namespace Robomongo
}
MongoUser::MongoUser(const float version) :
_version(version),_readOnly(false),_role() {}
_version(version), _readOnly(false), _role() {}
mongo::BSONObj MongoUser::toBson() const
{
@@ -50,7 +50,7 @@ namespace Robomongo
builder.append("userSource", _userSource);
mongo::BSONArrayBuilder builderA;
for (RoleType::const_iterator it = _role.begin(); it!=_role.end(); ++it)
for (RoleType::const_iterator it = _role.begin(); it != _role.end(); ++it)
{
builderA << *it;
}
+18 -18
View File
@@ -38,7 +38,7 @@ namespace Robomongo
bool isMultiSelection(const QModelIndexList &indexes)
{
return indexes.count()>1;
return indexes.count() > 1;
}
bool isDocumentType(BsonTreeItem *item)
@@ -55,20 +55,20 @@ namespace Robomongo
QModelIndexList uniqueRows(QModelIndexList indexes, bool returnSuperParents)
{
QModelIndexList result;
for (QModelIndexList::const_iterator it = indexes.begin(); it!=indexes.end(); ++it)
for (QModelIndexList::const_iterator it = indexes.begin(); it != indexes.end(); ++it)
{
QModelIndex isUnique = *it;
Robomongo::BsonTreeItem *item = Robomongo::QtUtils::item<Robomongo::BsonTreeItem*>(isUnique);
if(item){
for (QModelIndexList::const_iterator jt = result.begin(); jt!=result.end(); ++jt)
if (item) {
for (QModelIndexList::const_iterator jt = result.begin(); jt != result.end(); ++jt)
{
Robomongo::BsonTreeItem *jItem = Robomongo::QtUtils::item<Robomongo::BsonTreeItem*>(*jt);
if (jItem && jItem->superParent() == item->superParent()){
if (jItem && jItem->superParent() == item->superParent()) {
isUnique = QModelIndex();
break;
}
}
if (isUnique.isValid()){
if (isUnique.isValid()) {
if (returnSuperParents) {
// Move index onto "super parent" element before pushing it into result set
QModelIndex parent = isUnique.parent();
@@ -187,7 +187,7 @@ namespace Robomongo
break;
}
isNeededRefresh=true;
isNeededRefresh = true;
_shell->server()->removeDocuments(query, _queryInfo._info._ns);
}
@@ -240,11 +240,11 @@ namespace Robomongo
int answer = QMessageBox::question(dynamic_cast<QWidget*>(_observer), "Delete", QString("Do you want to delete %1 selected documents?").arg(selectedIndexes.count()));
if (answer == QMessageBox::Yes) {
std::vector<BsonTreeItem*> items;
for (QModelIndexList::const_iterator it = selectedIndexes.begin(); it!= selectedIndexes.end(); ++it) {
for (QModelIndexList::const_iterator it = selectedIndexes.begin(); it != selectedIndexes.end(); ++it) {
BsonTreeItem *item = QtUtils::item<BsonTreeItem*>(*it);
items.push_back(item);
}
deleteDocuments(items,true);
deleteDocuments(items, true);
}
}
@@ -260,7 +260,7 @@ namespace Robomongo
BsonTreeItem *documentItem = QtUtils::item<BsonTreeItem*>(selectedIndex);
std::vector<BsonTreeItem*> vec;
vec.push_back(documentItem);
return deleteDocuments(vec,false);
return deleteDocuments(vec, false);
}
void Notifier::onEditDocument()
@@ -376,19 +376,19 @@ namespace Robomongo
QClipboard *clipboard = QApplication::clipboard();
// new Date(parseInt(this.valueOf().slice(0,8), 16)*1000);
QString hexTimestamp = documentItem->value().mid(10,8);
QString hexTimestamp = documentItem->value().mid(10, 8);
bool ok;
long long milliTimestamp = (long long)hexTimestamp.toLongLong(&ok,16)*1000;
long long milliTimestamp = (long long)hexTimestamp.toLongLong(&ok, 16)*1000;
bool isSupportedDate = (miutil::minDate < milliTimestamp) && (milliTimestamp < miutil::maxDate);
boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
boost::posix_time::time_duration diff = boost::posix_time::millisec(milliTimestamp);
boost::posix_time::ptime time = epoch + diff;
if(isSupportedDate)
if (isSupportedDate)
{
std::string date = miutil::isotimeString(time,false,false);
std::string date = miutil::isotimeString(time, false, false);
clipboard->setText("ISODate(\""+QString::fromStdString(date)+"\")");
}
else {
@@ -411,13 +411,13 @@ namespace Robomongo
QClipboard *clipboard = QApplication::clipboard();
mongo::BSONObj obj = documentItem->root();
if (documentItem != documentItem->superParent()){
obj = obj[QtUtils::toStdString(documentItem->key())].Obj();
if (documentItem != documentItem->superParent()) {
obj = obj[documentItem->fieldName()].Obj();
}
bool isArray = BsonUtils::isArray(documentItem->type());
std::string str = BsonUtils::jsonString(obj, mongo::TenGen, 1,
AppRegistry::instance().settingsManager()->uuidEncoding(),
AppRegistry::instance().settingsManager()->timeZone(),isArray);
AppRegistry::instance().settingsManager()->timeZone(), isArray);
const QString &json = QtUtils::toQString(str);
clipboard->setText(json);
+4 -4
View File
@@ -62,7 +62,7 @@ namespace
namespace Robomongo
{
ScriptInfo::ScriptInfo(const QString &script, bool execute,const CursorPosition &position,
ScriptInfo::ScriptInfo(const QString &script, bool execute, const CursorPosition &position,
const QString &title, const QString &filePath) :
_script(script),
_execute(execute),
@@ -73,10 +73,10 @@ namespace Robomongo
bool ScriptInfo::loadFromFile(const QString &filePath)
{
bool result = false;
QString filepath = QFileDialog::getOpenFileName(QApplication::activeWindow(), filePath,QString(), filterForScripts);
QString filepath = QFileDialog::getOpenFileName(QApplication::activeWindow(), filePath, QString(), filterForScripts);
if (!filepath.isEmpty()) {
QString out;
if (loadFromFileText(filepath,out)) {
if (loadFromFileText(filepath, out)) {
_script = out;
_filePath = filepath;
result = true;
@@ -95,7 +95,7 @@ namespace Robomongo
QString filepath = QFileDialog::getSaveFileName(QApplication::activeWindow(),
QObject::tr("Save As"), _filePath, filterForScripts);
if (saveToFileText(filepath,_script)) {
if (saveToFileText(filepath, _script)) {
_filePath = filepath;
return true;
}
+31 -7
View File
@@ -55,10 +55,12 @@ namespace mongo {
namespace Robomongo
{
ScriptEngine::ScriptEngine(ConnectionSettings *connection) :
ScriptEngine::ScriptEngine(ConnectionSettings *connection, int timeoutSec) :
_connection(connection),
_scope(NULL),
_engine(NULL),
_timeoutSec(timeoutSec),
_initialized(false),
_mutex(QMutex::Recursive) { }
ScriptEngine::~ScriptEngine()
@@ -141,13 +143,28 @@ namespace Robomongo
// Save original autocomplete function so it can be restored if overwritten by user preference
_scope->exec("DB.autocompleteOriginal = DB.autocomplete;", "(saveOriginalAutocomplete)", false, false, false);
// Cache result of original "DB.autocomplete"
// Cache invalidated by the invalidateDbCollectionsCache() method.
std::string cacheAutocompletion =
"__robomongoAutocompletionCache = null;"
"DB.autocompleteCached = function(obj) { "
" if (__robomongoAutocompletionCache == null) {"
" __robomongoAutocompletionCache = DB.autocompleteOriginal(obj);"
" }"
" return __robomongoAutocompletionCache;"
"}";
_scope->exec(cacheAutocompletion, "", false, false, false);
_initialized = true;
}
MongoShellExecResult ScriptEngine::exec(const std::string &originalScript, const std::string &dbName)
{
QMutexLocker lock(&_mutex);
if(!_scope)
if (!_scope)
return MongoShellExecResult();
/*
@@ -177,7 +194,7 @@ namespace Robomongo
use(dbName);
for(std::vector<std::string>::const_iterator it = statements.begin(); it != statements.end(); ++it)
for (std::vector<std::string>::const_iterator it = statements.begin(); it != statements.end(); ++it)
{
std::string statement = *it;
// clear global objects
@@ -190,8 +207,8 @@ namespace Robomongo
try {
QElapsedTimer timer;
timer.start();
if ( _scope->exec( statement , "(shell)" , false , true , false, 0 ) ) {
_scope->exec( "__robomongoLastRes = __lastres__; shellPrintHelper( __lastres__ );" , "(shell2)" , true , true , false, 0);
if ( _scope->exec( statement , "(shell)" , false , true , false, _timeoutSec * 1000) ) {
_scope->exec( "__robomongoLastRes = __lastres__; shellPrintHelper( __lastres__ );" , "(shell2)" , true , true , false, _timeoutSec * 1000);
}
qint64 elapsed = timer.elapsed();
@@ -252,7 +269,7 @@ namespace Robomongo
void ScriptEngine::ping()
{
QMutexLocker lock(&_mutex);
_scope->exec("if (db) { db.runCommand({ping:1}); }", "(ping)", false, false, false);
_scope->exec("if (db) { db.runCommand({ping:1}); }", "(ping)", false, false, false, 3000);
}
QStringList ScriptEngine::complete(const std::string &prefix, const AutocompletionMode mode)
@@ -262,7 +279,7 @@ namespace Robomongo
try {
if (mode == AutocompleteAll)
_scope->exec("DB.autocomplete = DB.autocompleteOriginal;", "", false, false, false);
_scope->exec("DB.autocomplete = DB.autocompleteCached;", "", false, false, false);
else if (mode == AutocompleteNoCollectionNames)
_scope->exec("DB.autocomplete = function(obj){return [];}", "", false, false, false);
@@ -413,4 +430,11 @@ namespace Robomongo
return true;
}
void ScriptEngine::invalidateDbCollectionsCache() {
if (!_initialized)
return;
_scope->exec("__robomongoAutocompletionCache = null;", "", false, false, false);
}
}
+5 -1
View File
@@ -15,7 +15,7 @@ namespace Robomongo
{
public:
ScriptEngine(ConnectionSettings *connection);
ScriptEngine(ConnectionSettings *connection, int timeoutSec);
~ScriptEngine();
void init(bool isLoadMongoJs);
@@ -27,6 +27,8 @@ namespace Robomongo
void ping();
QStringList complete(const std::string &prefix, const AutocompletionMode mode);
void invalidateDbCollectionsCache();
private:
ConnectionSettings *_connection;
@@ -39,8 +41,10 @@ namespace Robomongo
std::vector<std::string> statementize2(const std::string &script);
// void parseTree(JSParseNode * root, int indent, const std::string &script, std::vector<std::string> &list, bool topList);
int _timeoutSec;
mongo::ScriptEngine *_engine;
mongo::Scope *_scope;
QMutex _mutex;
bool _initialized;
};
}
+90 -47
View File
@@ -30,25 +30,39 @@ namespace Robomongo
{
R_EVENT
EstablishConnectionRequest(QObject *sender) :
Event(sender) {}
EstablishConnectionRequest(QObject *sender, ConnectionType connectionType) :
Event(sender),
connectionType(connectionType) {}
ConnectionType connectionType;
};
class EstablishConnectionResponse : public Event
{
R_EVENT
EstablishConnectionResponse(QObject *sender, const ConnectionInfo &info) :
Event(sender),
_info(info) {}
enum ErrorReason {
MongoConnection = 0,
MongoAuth = 1,
};
EstablishConnectionResponse(QObject *sender, const EventError &error) :
Event(sender, error),_info() {}
EstablishConnectionResponse(QObject *sender, const ConnectionInfo &info, ConnectionType connectionType) :
Event(sender),
_info(info),
connectionType(connectionType) {}
EstablishConnectionResponse(QObject *sender, const EventError &error, ConnectionType connectionType, ErrorReason errorReason) :
Event(sender, error),
_info(),
connectionType(connectionType),
errorReason(errorReason) {}
const ConnectionInfo &info() const{
return _info;
}
const ConnectionInfo _info;
ConnectionType connectionType;
ErrorReason errorReason;
};
@@ -109,7 +123,7 @@ namespace Robomongo
_databaseName(databaseName),
_collectionInfos(collectionInfos) { }
LoadCollectionNamesResponse(QObject *sender,const EventError &error) :
LoadCollectionNamesResponse(QObject *sender, const EventError &error) :
Event(sender, error) {}
std::string databaseName() const { return _databaseName; }
@@ -125,7 +139,7 @@ namespace Robomongo
R_EVENT
public:
LoadCollectionIndexesRequest(QObject *sender, const MongoCollectionInfo &collection) :
Event(sender),_collection(collection) {}
Event(sender), _collection(collection) {}
MongoCollectionInfo collection() const { return _collection; }
private:
const MongoCollectionInfo _collection;
@@ -148,7 +162,7 @@ namespace Robomongo
class EnsureIndexRequest : public Event
{
R_EVENT
EnsureIndexRequest(QObject *sender,const EnsureIndexInfo &oldInfo,const EnsureIndexInfo &newInfo) : Robomongo::Event(sender),oldInfo_(oldInfo),newInfo_(newInfo) {}
EnsureIndexRequest(QObject *sender, const EnsureIndexInfo &oldInfo, const EnsureIndexInfo &newInfo) : Robomongo::Event(sender), oldInfo_(oldInfo), newInfo_(newInfo) {}
const EnsureIndexInfo &oldInfo() const
{
return oldInfo_;
@@ -172,7 +186,7 @@ namespace Robomongo
_name(name) {}
MongoCollectionInfo collection() const { return _collection; }
std::string name() const {return _name;}
std::string name() const { return _name; }
private:
const MongoCollectionInfo _collection;
std::string _name;
@@ -182,14 +196,14 @@ namespace Robomongo
{
R_EVENT
public:
DeleteCollectionIndexResponse(QObject *sender, const MongoCollectionInfo &collection,const std::string &index) :
Event(sender),_collection(collection),_index(index) {}
DeleteCollectionIndexResponse(QObject *sender, const MongoCollectionInfo &collection, const std::string &index) :
Event(sender), _collection(collection), _index(index) {}
DeleteCollectionIndexResponse(QObject *sender, const EventError &error) :
Event(sender, error) {}
MongoCollectionInfo collection() const { return _collection; }
std::string index() const {return _index;}
std::string index() const { return _index; }
private:
MongoCollectionInfo _collection;
std::string _index;
@@ -199,11 +213,11 @@ namespace Robomongo
{
R_EVENT
public:
EditIndexRequest(QObject *sender, const MongoCollectionInfo &collection,const std::string &oldIndex,const std::string &newIndex) :
Event(sender),_collection(collection),_oldIndex(oldIndex),_newIndex(newIndex) {}
EditIndexRequest(QObject *sender, const MongoCollectionInfo &collection, const std::string &oldIndex, const std::string &newIndex) :
Event(sender), _collection(collection), _oldIndex(oldIndex), _newIndex(newIndex) {}
MongoCollectionInfo collection() const { return _collection; }
std::string oldIndex() const {return _oldIndex;}
std::string newIndex() const {return _newIndex;}
std::string oldIndex() const { return _oldIndex; }
std::string newIndex() const { return _newIndex; }
private:
const MongoCollectionInfo _collection;
std::string _oldIndex;
@@ -240,7 +254,7 @@ namespace Robomongo
_databaseName(databaseName),
_users(users) { }
LoadUsersResponse(QObject *sender,const EventError &error) :
LoadUsersResponse(QObject *sender, const EventError &error) :
Event(sender, error) {}
std::string databaseName() const { return _databaseName; }
@@ -282,7 +296,7 @@ namespace Robomongo
_databaseName(databaseName),
_functions(functions) { }
LoadFunctionsResponse(QObject *sender,const EventError &error) :
LoadFunctionsResponse(QObject *sender, const EventError &error) :
Event(sender, error) {}
std::string databaseName() const { return _databaseName; }
@@ -580,7 +594,7 @@ namespace Robomongo
_to(databaseTo, collection) {}
MongoWorker *worker() const { return _worker; }
MongoNamespace from() const { return _from;}
MongoNamespace from() const { return _from; }
MongoNamespace to() const { return _to; }
private:
MongoWorker *_worker;
@@ -806,7 +820,7 @@ namespace Robomongo
{
R_EVENT
AutocompleteResponse(QObject *sender,const QStringList &list, const std::string &prefix) :
AutocompleteResponse(QObject *sender, const QStringList &list, const std::string &prefix) :
Event(sender),
list(list),
prefix(prefix) {}
@@ -879,14 +893,25 @@ namespace Robomongo
{
R_EVENT
ConnectionFailedEvent(QObject *sender, const std::string& message) :
Event(sender),
message(message) {}
enum Reason {
MongoConnection = 1,
MongoAuth = 2,
SshConnection = 3,
SshChannel = 4
};
ConnectionFailedEvent(QObject *sender, const EventError &error) :
Event(sender, error) {}
ConnectionFailedEvent(QObject *sender, int serverHandle, ConnectionType connectionType,
const std::string& message, Reason reason) :
Event(sender),
message(message),
reason(reason),
serverHandle(serverHandle),
connectionType(connectionType) {}
std::string message;
Reason reason;
ConnectionType connectionType;
int serverHandle;
};
// class ScriptExecute
@@ -895,11 +920,13 @@ namespace Robomongo
{
R_EVENT
ConnectionEstablishedEvent(MongoServer *server) :
ConnectionEstablishedEvent(MongoServer *server, ConnectionType type) :
Event((QObject *)server),
server(server) { }
server(server),
connectionType(type) { }
MongoServer *server;
ConnectionType connectionType;
};
class DatabaseListLoadedEvent : public Event
@@ -996,38 +1023,43 @@ namespace Robomongo
{
R_EVENT
EstablishSshConnectionRequest(QObject *sender, SshTunnelWorker* worker, ConnectionSettings* settings, bool visible) :
EstablishSshConnectionRequest(QObject *sender, int serverHandle, SshTunnelWorker* worker, ConnectionSettings* settings, ConnectionType connectionType) :
Event(sender),
worker(worker),
settings(settings),
visible(visible) {}
serverHandle(serverHandle),
connectionType(connectionType) {}
ConnectionSettings* settings;
bool visible;
ConnectionType connectionType;
SshTunnelWorker* worker;
int serverHandle;
};
class EstablishSshConnectionResponse : public Event
{
R_EVENT
EstablishSshConnectionResponse(QObject *sender, SshTunnelWorker* worker, ConnectionSettings* settings, bool visible, int localport) :
EstablishSshConnectionResponse(QObject *sender, int serverHandle, SshTunnelWorker* worker, ConnectionSettings* settings, ConnectionType connectionType, int localport) :
Event(sender),
worker(worker),
settings(settings),
visible(visible),
connectionType(connectionType),
serverHandle(serverHandle),
localport(localport) {}
EstablishSshConnectionResponse(QObject *sender, const EventError &error, SshTunnelWorker* worker, ConnectionSettings* settings, bool visible) :
EstablishSshConnectionResponse(QObject *sender, int serverHandle, const EventError &error, SshTunnelWorker* worker, ConnectionSettings* settings, ConnectionType connectionType) :
Event(sender, error),
worker(worker),
settings(settings),
visible(visible) {}
serverHandle(serverHandle),
connectionType(connectionType) {}
ConnectionSettings* settings;
bool visible;
ConnectionType connectionType;
SshTunnelWorker* worker;
int localport;
int serverHandle;
};
/**
@@ -1038,23 +1070,34 @@ namespace Robomongo
{
R_EVENT
ListenSshConnectionRequest(QObject *sender) :
Event(sender) {}
ListenSshConnectionRequest(QObject *sender, int serverHandle, ConnectionType connectionType) :
Event(sender),
serverHandle(serverHandle),
connectionType(connectionType) {}
ConnectionType connectionType;
int serverHandle;
};
class ListenSshConnectionResponse : public Event
{
R_EVENT
ListenSshConnectionResponse(QObject *sender, ConnectionSettings* settings) :
ListenSshConnectionResponse(QObject *sender, int serverHandle, ConnectionSettings* settings, ConnectionType connectionType) :
Event(sender),
settings(settings) {}
settings(settings),
serverHandle(serverHandle),
connectionType(connectionType) {}
ListenSshConnectionResponse(QObject *sender, const EventError &error, ConnectionSettings* settings) :
ListenSshConnectionResponse(QObject *sender, const EventError &error, int serverHandle, ConnectionSettings* settings, ConnectionType connectionType) :
Event(sender, error),
settings(settings) {}
settings(settings),
serverHandle(serverHandle),
connectionType(connectionType) {}
ConnectionSettings* settings;
ConnectionType connectionType;
int serverHandle;
};
class LogEvent : public Event
@@ -1062,10 +1105,10 @@ namespace Robomongo
R_EVENT
enum LogLevel {
ERROR = 1,
WARN = 2,
INFO = 3,
DEBUG = 100 // log as much as possible
RBM_ERROR = 1,
RBM_WARN = 2,
RBM_INFO = 3,
RBM_DEBUG = 100 // log as much as possible
};
LogEvent(QObject *sender, const std::string& message, LogLevel level) :
+10 -10
View File
@@ -13,7 +13,7 @@ namespace
using namespace Robomongo::BsonUtils;
Robomongo::EnsureIndexInfo info(collection);
info._name = getField<mongo::String>(obj, "name");
mongo::BSONObj keyObj = getField<mongo::Object>(obj,"key");
mongo::BSONObj keyObj = getField<mongo::Object>(obj, "key");
if (keyObj.isValid()) {
info._request = jsonString(keyObj, mongo::TenGen, 1, Robomongo::DefaultEncoding, Robomongo::Utc);
}
@@ -56,7 +56,7 @@ namespace Robomongo
float result = 0.0f;
mongo::BSONObj resultObj;
_dbclient->runCommand("db", BSON("buildInfo" << "1"), resultObj);
std::string resultStr = BsonUtils::getField<mongo::String>(resultObj,"version");
std::string resultStr = BsonUtils::getField<mongo::String>(resultObj, "version");
result = atof(resultStr.c_str());
return result;
}
@@ -87,7 +87,7 @@ namespace Robomongo
float ver = getVersion();
while (cursor->more()) {
mongo::BSONObj bsonObj = cursor->next();
MongoUser user(ver,bsonObj);
MongoUser user(ver, bsonObj);
users.push_back(user);
}
@@ -157,13 +157,13 @@ namespace Robomongo
for (std::list<mongo::BSONObj>::iterator it = indexes.begin(); it != indexes.end(); ++it) {
mongo::BSONObj bsonObj = *it;
result.push_back(makeEnsureIndexInfoFromBsonObj(collection,bsonObj));
result.push_back(makeEnsureIndexInfoFromBsonObj(collection, bsonObj));
}
return result;
}
void MongoClient::ensureIndex(const EnsureIndexInfo &oldInfo,const EnsureIndexInfo &newInfo) const
void MongoClient::ensureIndex(const EnsureIndexInfo &oldInfo, const EnsureIndexInfo &newInfo) const
{
std::string ns = newInfo._collection.ns().toString();
@@ -172,8 +172,8 @@ namespace Robomongo
mongo::BSONObj keys = mongo::Robomongo::fromjson(newInfo._request);
mongo::BSONObjBuilder toSave;
bool cache=true;
int version =-1;
bool cache = true;
int version = -1;
toSave.append( "ns" , ns );
toSave.append( "key" , keys );
@@ -400,7 +400,7 @@ namespace Robomongo
}
}
void MongoClient::copyCollectionToDiffServer(mongo::DBClientBase *const fromServ,const MongoNamespace &from, const MongoNamespace &to)
void MongoClient::copyCollectionToDiffServer(mongo::DBClientBase *const fromServ, const MongoNamespace &from, const MongoNamespace &to)
{
if (!_dbclient->exists(to.toString()))
_dbclient->createCollection(to.toString());
@@ -497,9 +497,9 @@ namespace Robomongo
std::vector<MongoCollectionInfo> MongoClient::runCollStatsCommand(const std::vector<std::string> &namespaces)
{
std::vector<MongoCollectionInfo> infos;
for (std::vector<std::string>::const_iterator it = namespaces.begin(); it!=namespaces.end(); ++it) {
for (std::vector<std::string>::const_iterator it = namespaces.begin(); it != namespaces.end(); ++it) {
MongoCollectionInfo info = runCollStatsCommand(*it);
if (info.ns().isValid()){
if (info.ns().isValid()) {
infos.push_back(info);
}
}
+1 -1
View File
@@ -41,7 +41,7 @@ namespace Robomongo
void renameCollection(const MongoNamespace &ns, const std::string &newCollectionName);
void duplicateCollection(const MongoNamespace &ns, const std::string &newCollectionName);
void dropCollection(const MongoNamespace &ns);
void copyCollectionToDiffServer(mongo::DBClientBase *const,const MongoNamespace &from, const MongoNamespace &to);
void copyCollectionToDiffServer(mongo::DBClientBase *const, const MongoNamespace &from, const MongoNamespace &to);
void insertDocument(const mongo::BSONObj &obj, const MongoNamespace &ns);
void saveDocument(const mongo::BSONObj &obj, const MongoNamespace &ns);
+73 -25
View File
@@ -17,7 +17,8 @@
namespace Robomongo
{
MongoWorker::MongoWorker(ConnectionSettings *connection, bool isLoadMongoRcJs, int batchSize, QObject *parent) : QObject(parent),
MongoWorker::MongoWorker(ConnectionSettings *connection, bool isLoadMongoRcJs, int batchSize,
int mongoTimeoutSec, int shellTimeoutSec, QObject *parent) : QObject(parent),
_connection(connection),
_scriptEngine(NULL),
_dbclient(NULL),
@@ -25,11 +26,13 @@ namespace Robomongo
_isLoadMongoRcJs(isLoadMongoRcJs),
_batchSize(batchSize),
_timerId(-1),
_dbAutocompleteCacheTimerId(-1),
_mongoTimeoutSec(mongoTimeoutSec),
_shellTimeoutSec(shellTimeoutSec),
_isQuiting(0)
{
{
_thread = new QThread();
moveToThread(_thread);
VERIFY(connect( _thread, SIGNAL(started()), this, SLOT(init()) ));
VERIFY(connect( _thread, SIGNAL(finished()), _thread, SLOT(deleteLater()) ));
VERIFY(connect( _thread, SIGNAL(finished()), this, SLOT(deleteLater()) ));
_thread->start();
@@ -39,6 +42,13 @@ namespace Robomongo
{
if (_timerId == event->timerId()) {
keepAlive();
return;
}
if (_dbAutocompleteCacheTimerId == event->timerId() &&
_scriptEngine != NULL) {
_scriptEngine->invalidateDbCollectionsCache();
return;
}
}
@@ -70,11 +80,12 @@ namespace Robomongo
void MongoWorker::init()
{
try {
_scriptEngine = new ScriptEngine(_connection);
_scriptEngine = new ScriptEngine(_connection, _shellTimeoutSec);
_scriptEngine->init(_isLoadMongoRcJs);
_scriptEngine->use(_connection->defaultDatabase());
_scriptEngine->setBatchSize(_batchSize);
_timerId = startTimer(pingTimeMs);
_dbAutocompleteCacheTimerId = startTimer(30000);
} catch (const std::exception &ex) {
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
}
@@ -93,7 +104,12 @@ namespace Robomongo
MongoWorker::~MongoWorker()
{
killTimer(_timerId);
if (_timerId != -1)
killTimer(_timerId);
if (_dbAutocompleteCacheTimerId != -1)
killTimer(_dbAutocompleteCacheTimerId);
delete _dbclient;
delete _connection;
delete _scriptEngine;
@@ -116,9 +132,15 @@ namespace Robomongo
QMutexLocker lock(&_firstConnectionMutex);
try {
mongo::DBClientBase *conn = getConnection();
bool hasPrimary = _connection->hasEnabledPrimaryCredential();
if (hasPrimary) {
mongo::DBClientBase *conn = getConnection(true);
if (conn == NULL) {
reply(event->sender(), new EstablishConnectionResponse(this,
EventError("Network is unreachable"), event->connectionType,
EstablishConnectionResponse::MongoConnection));
return;
}
if (_connection->hasEnabledPrimaryCredential()) {
CredentialSettings *credentials = _connection->primaryCredential();
// Building BSON object:
@@ -138,21 +160,28 @@ namespace Robomongo
if (dbName.compare("admin") != 0) // dbName is NOT "admin"
_isAdmin = false;
}
boost::scoped_ptr<MongoClient> client(getClient());
std::vector<std::string> dbNames = getDatabaseNamesSafe();
reply(event->sender(), new EstablishConnectionResponse(this, ConnectionInfo(_connection->getFullAddress(), dbNames, client->getVersion()) ));
// If we do not have databases, it means that we are unable to
// execute "listdatabases" command and we have nothing to show.
if (dbNames.size() == 0)
throw mongo::DBException("Failed to execute \"listdatabases\" command.", 0);
init();
reply(event->sender(), new EstablishConnectionResponse(this, ConnectionInfo(_connection->getFullAddress(), dbNames, client->getVersion()), event->connectionType));
} catch(const std::exception &ex) {
reply(event->sender(), new EstablishConnectionResponse(this, EventError(ex.what())));
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
reply(event->sender(), new EstablishConnectionResponse(this, EventError(ex.what()), event->connectionType, EstablishConnectionResponse::MongoAuth));
}
}
std::string MongoWorker::getAuthBase() const
{
bool hasPrimary = _connection->hasEnabledPrimaryCredential();
if(hasPrimary){
if (_connection->hasEnabledPrimaryCredential())
return _connection->primaryCredential()->databaseName();
}
return std::string();
}
@@ -168,10 +197,9 @@ namespace Robomongo
try {
boost::scoped_ptr<MongoClient> client(getClient());
result = client->getDatabaseNames();
} catch(const std::exception &ex) {
} catch(const std::exception &) {
if (!authBase.empty())
result.push_back(authBase);
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
}
return result;
}
@@ -202,7 +230,7 @@ namespace Robomongo
if (dbNames.size()) {
reply(event->sender(), new LoadDatabaseNamesResponse(this, dbNames));
} else {
reply(event->sender(), new LoadDatabaseNamesResponse(this, EventError("Unable to load database names.")));
reply(event->sender(), new LoadDatabaseNamesResponse(this, EventError("Failed to execute \"listdatabases\" command.")));
}
} catch(const mongo::DBException &ex) {
reply(event->sender(), new LoadDatabaseNamesResponse(this, EventError(ex.what())));
@@ -263,7 +291,7 @@ namespace Robomongo
const EnsureIndexInfo &oldInfo = event->oldInfo();
try {
boost::scoped_ptr<MongoClient> client(getClient());
client->ensureIndex(oldInfo,newInfo);
client->ensureIndex(oldInfo, newInfo);
const std::vector<EnsureIndexInfo> &ind = client->getIndexes(newInfo._collection);
client->done();
@@ -278,7 +306,7 @@ namespace Robomongo
{
try {
boost::scoped_ptr<MongoClient> client(getClient());
client->dropIndexFromCollection(event->collection(),event->name());
client->dropIndexFromCollection(event->collection(), event->name());
client->done();
reply(event->sender(), new DeleteCollectionIndexResponse(this, event->collection(), event->name()));
} catch(const mongo::DBException &ex) {
@@ -291,7 +319,7 @@ namespace Robomongo
{
try {
boost::scoped_ptr<MongoClient> client(getClient());
client->renameIndexFromCollection(event->collection(),event->oldIndex(),event->newIndex());
client->renameIndexFromCollection(event->collection(), event->oldIndex(), event->newIndex());
const std::vector<EnsureIndexInfo> &ind = client->getIndexes(event->collection());
client->done();
@@ -372,6 +400,11 @@ namespace Robomongo
void MongoWorker::handle(ExecuteScriptRequest *event)
{
try {
if (!_scriptEngine) {
reply(event->sender(), new ExecuteScriptResponse(this, EventError("MongoDB Shell was not initialized")));
return;
}
MongoShellExecResult result = _scriptEngine->exec(event->script, event->databaseName);
reply(event->sender(), new ExecuteScriptResponse(this, result, event->script.empty()));
} catch(const mongo::DBException &ex) {
@@ -386,6 +419,10 @@ namespace Robomongo
void MongoWorker::handle(StopScriptRequest *)
{
try {
if (!_scriptEngine) {
return;
}
_scriptEngine->interrupt();
} catch(const mongo::DBException &ex) {
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
@@ -395,6 +432,11 @@ namespace Robomongo
void MongoWorker::handle(AutocompleteRequest *event)
{
try {
if (!_scriptEngine) {
reply(event->sender(), new AutocompleteResponse(this, EventError("MongoDB Shell was not initialized")));
return;
}
QStringList list = _scriptEngine->complete(event->prefix, event->mode);
reply(event->sender(), new AutocompleteResponse(this, list, event->prefix));
} catch(const mongo::DBException &ex) {
@@ -498,7 +540,7 @@ namespace Robomongo
try {
boost::scoped_ptr<MongoClient> client(getClient());
MongoWorker *cl = event->worker();
client->copyCollectionToDiffServer(cl->_dbclient,event->from(),event->to());
client->copyCollectionToDiffServer(cl->_dbclient, event->from(), event->to());
client->done();
reply(event->sender(), new CopyCollectionToDiffServerResponse(this));
@@ -564,13 +606,19 @@ namespace Robomongo
}
}
mongo::DBClientBase *MongoWorker::getConnection()
mongo::DBClientBase *MongoWorker::getConnection(bool mayReturnNull /* = false */)
{
if (!_dbclient) {
// Timeout for operations is 10 seconds.
// Timeout for operations
// Connect timeout is fixed, but short, at 5 seconds (see headers for DBClientConnection)
mongo::DBClientConnection *conn = new mongo::DBClientConnection(true, 10);
conn->connect(_connection->info());
mongo::DBClientConnection *conn = new mongo::DBClientConnection(true, _mongoTimeoutSec);
mongo::Status status = conn->connect(_connection->info());
if (!status.isOK() && mayReturnNull) {
delete conn;
return NULL;
}
_dbclient = conn;
}
return _dbclient;
+7 -3
View File
@@ -23,7 +23,8 @@ namespace Robomongo
public:
typedef std::vector<std::string> DatabasesContainerType;
explicit MongoWorker(ConnectionSettings *connection, bool isLoadMongoRcJs, int batchSize, QObject *parent = NULL);
explicit MongoWorker(ConnectionSettings *connection, bool isLoadMongoRcJs, int batchSize,
int mongoTimeoutSec, int shellTimeoutSec, QObject *parent = NULL);
~MongoWorker();
enum { pingTimeMs = 60 * 1000 };
void interrupt();
@@ -131,7 +132,7 @@ namespace Robomongo
std::string getAuthBase() const;
mongo::DBClientBase *_dbclient;
mongo::DBClientBase *getConnection();
mongo::DBClientBase *getConnection(bool mayReturnNull = false);
MongoClient *getClient();
/**
@@ -147,13 +148,16 @@ namespace Robomongo
const bool _isLoadMongoRcJs;
const int _batchSize;
int _timerId;
int _dbAutocompleteCacheTimerId;
int _mongoTimeoutSec;
int _shellTimeoutSec;
QAtomicInteger<int> _isQuiting;
ConnectionSettings *_connection;
// Collection of created databases.
// Starting from 3.0, MongoDB drops empty databases.
// It means, we do not find a way to create "empty" database.
// It means, we did not find a way to create "empty" database.
// We save all created databases in this collection and merge with
// list of real databases returned from MongoDB server.
std::unordered_set<std::string> _createdDbs;
+101 -70
View File
@@ -1,6 +1,8 @@
#include "robomongo/core/mongodb/SshTunnelWorker.h"
#include <QThread>
#include <QElapsedTimer>
#include "robomongo/core/utils/QtUtils.h"
#include "robomongo/core/utils/Logger.h"
#include "robomongo/core/settings/ConnectionSettings.h"
@@ -15,50 +17,23 @@ namespace Robomongo
{
SshTunnelWorker::SshTunnelWorker(ConnectionSettings *settings) : QObject(),
_settings(settings),
_sshConfig(NULL),
_sshSession(NULL)
_sshSession(NULL),
_configCreator(settings)
{
_thread = new QThread();
moveToThread(_thread);
VERIFY(connect(_thread, SIGNAL(started()), this, SLOT(init())));
VERIFY(connect(_thread, SIGNAL(finished()), _thread, SLOT(deleteLater())));
VERIFY(connect(_thread, SIGNAL(finished()), this, SLOT(deleteLater())));
_thread->start();
}
void SshTunnelWorker::init()
{
try {
SshSettings *ssh = _settings->sshSettings();
// We are going to access raw char* buffers, so prepare copies
// of strings (and rest of the things for symmetry)
_sshhost = ssh->host();
_sshport = ssh->port();
_remotehost = _settings->serverHost();
_remoteport = _settings->serverPort();
_localip = "127.0.0.1";
_localport = 27040;
_userName = ssh->userName();
_userPassword = ssh->userPassword();
_privateKeyFile = ssh->privateKeyFile();
_publicKeyFile = ssh->publicKeyFile();
_passphrase = ssh->passphrase();
_authMethod = ssh->authMethod(); // "password" or "publickey"
}
catch (const std::exception &ex) {
LOG_MSG(ex.what(), mongo::logger::LogSeverity::Error());
}
}
SshTunnelWorker::~SshTunnelWorker()
{
// QThread "_thread" and MongoWorker itself will be deleted later
// (see MongoWorker() constructor)
delete _settings;
delete _sshConfig;
printf("SSH tunnel closed.\n");
}
void SshTunnelWorker::stopAndDelete() {
@@ -71,30 +46,12 @@ namespace Robomongo
if (_isQuiting)
return;
_sshConfig = new rbm_ssh_tunnel_config;
_sshConfig->sshserverip = const_cast<char*>(_sshhost.c_str());
_sshConfig->sshserverport = static_cast<unsigned int>(_sshport);
_sshConfig->remotehost = const_cast<char*>(_remotehost.c_str());
_sshConfig->remoteport = static_cast<unsigned int>(_remoteport);
_sshConfig->localip = const_cast<char*>(_localip.c_str());
_sshConfig->localport = static_cast<unsigned int>(_localport);
_sshConfig->username = const_cast<char*>(_userName.c_str());
_sshConfig->password = const_cast<char*>(_userPassword.c_str());
_sshConfig->privatekeyfile = const_cast<char*>(_privateKeyFile.c_str());
_sshConfig->publickeyfile = _publicKeyFile.empty() ? NULL : const_cast<char*>(_publicKeyFile.c_str());
_sshConfig->passphrase = const_cast<char*>(_passphrase.c_str());
_sshConfig->authtype = (_authMethod == "publickey") ? RBM_SSH_AUTH_TYPE_PUBLICKEY : RBM_SSH_AUTH_TYPE_PASSWORD;
_sshConfig->logcontext = this;
_sshConfig->logcallback = &SshTunnelWorker::logCallbackHandler;
_sshConfig->loglevel = (rbm_ssh_log_type) _settings->sshSettings()->logLevel(); // RBM_SSH_LOG_TYPE_DEBUG;
if ((_sshSession = rbm_ssh_session_create(_sshConfig)) == 0) {
// Cleanup config structure
delete _sshConfig;
_sshConfig = NULL;
// Additionally configure "rbm_ssh_tunnel_config"
_configCreator.config()->logcontext = this;
_configCreator.config()->logcallback = &SshTunnelWorker::logCallbackHandler;
_configCreator.config()->loglevel = (rbm_ssh_log_type) _settings->sshSettings()->logLevel(); // RBM_SSH_LOG_TYPE_DEBUG;
if ((_sshSession = rbm_ssh_session_create(_configCreator.config())) == 0) {
// Not much we can say about this error
throw std::runtime_error("Failed to create SSH session");
}
@@ -113,20 +70,16 @@ namespace Robomongo
rbm_ssh_session_close(_sshSession);
_sshSession = NULL;
// Cleanup config
delete _sshConfig;
_sshConfig = NULL;
throw std::runtime_error(ss.str());
}
reply(event->sender(), new EstablishSshConnectionResponse(
this, event->worker, event->settings, event->visible, _sshConfig->localport));
this, event->serverHandle, event->worker, event->settings, event->connectionType, _configCreator.config()->localport));
} catch (const std::exception& ex) {
reply(event->sender(),
new EstablishSshConnectionResponse(this, EventError(ex.what()),
event->worker, event->settings, event->visible));
new EstablishSshConnectionResponse(this, event->serverHandle, EventError(ex.what()),
event->worker, event->settings, event->connectionType));
// In case of error in connection, we should cleanup SshTunnelWorker
stopAndDelete();
@@ -134,28 +87,50 @@ namespace Robomongo
}
void SshTunnelWorker::handle(ListenSshConnectionRequest *event) {
// do it here, i.e. cycle
try {
if (_isQuiting)
return;
if (_sshSession == NULL || _sshConfig == NULL)
if (_sshSession == NULL)
return;
// We are running this timer in order to distinguish between two
// types of errors:
// 1) SSH tunnel wasn't successfully created
// 2) SSH tunnel was disconnected
// This is used now only for UI error message, that we show to user.
QElapsedTimer timer;
timer.start();
// This function will block until all TCP connections disconnects.
// Initially, it will wait for at least one such connection.
if (rbm_ssh_open_tunnel(_sshSession) != 0) {
qint64 elapsed = timer.elapsed();
bool wasDisconnected = elapsed > 20000; // More than 20 seconds passed
// Prepare copy of error message (if any)
std::string error(_sshSession->lasterror);
std::stringstream ss;
ss << "You are disconnected from SSH tunnel ("
<< _settings->sshSettings()->host() << ":"
<< _settings->sshSettings()->port() << "). "
<< "Please initiate a new connection and reopen all tabs.\n\nError:\n"
<< error;
if (wasDisconnected) {
ss << "You are disconnected from SSH tunnel ("
<< _settings->sshSettings()->host() << ":"
<< _settings->sshSettings()->port() << "). "
<< "Please initiate a new connection and reopen all tabs.\n\nError:\n"
<< error;
} else {
ss << "Cannot establish SSH tunnel ("
<< _settings->sshSettings()->host() << ":"
<< _settings->sshSettings()->port() << "). "
<< "\n\nError:\n"
<< error;
}
// Cleanup session
rbm_ssh_session_close(_sshSession);
_sshSession = NULL;
throw std::runtime_error(ss.str());
}
@@ -164,7 +139,7 @@ namespace Robomongo
} catch (const std::exception& ex) {
reply(event->sender(),
new ListenSshConnectionResponse(this, EventError(ex.what()), _settings));
new ListenSshConnectionResponse(this, EventError(ex.what()), event->serverHandle, _settings, event->connectionType));
}
// When we done with SSH (i.e. rbm_ssh_open_tunnel exits) regardless
@@ -195,4 +170,60 @@ namespace Robomongo
void SshTunnelWorker::logCallbackHandler(void *context, char *message, int level) {
static_cast<SshTunnelWorker*>(context)->log(message, level);
}
/*
* SshTunnelConfigCreator
*/
SshTunnelConfigCreator::SshTunnelConfigCreator(ConnectionSettings *settings) {
SshSettings *ssh = settings->sshSettings();
// We are going to access raw char* buffers, so prepare copies
// of strings (and rest of the things for symmetry)
_sshhost = ssh->host();
_sshport = ssh->port();
_remotehost = settings->serverHost();
_remoteport = settings->serverPort();
_localip = "127.0.0.1";
_localport = 27040;
_userName = ssh->userName();
_userPassword = ssh->userPassword();
_privateKeyFile = ssh->privateKeyFile();
_publicKeyFile = ssh->publicKeyFile();
_passphrase = ssh->passphrase();
_authMethod = ssh->authMethod(); // "password" or "publickey"
// Use "askedPassword" for both passphrase and password if required
if (ssh->askPassword()) {
_passphrase = ssh->askedPassword();
_userPassword = ssh->askedPassword();
}
_sshConfig = new rbm_ssh_tunnel_config;
_sshConfig->sshserverhost = const_cast<char*>(_sshhost.c_str());
_sshConfig->sshserverport = static_cast<unsigned int>(_sshport);
_sshConfig->remotehost = const_cast<char*>(_remotehost.c_str());
_sshConfig->remoteport = static_cast<unsigned int>(_remoteport);
_sshConfig->localip = const_cast<char*>(_localip.c_str());
_sshConfig->localport = static_cast<unsigned int>(_localport);
_sshConfig->username = const_cast<char*>(_userName.c_str());
_sshConfig->password = const_cast<char*>(_userPassword.c_str());
_sshConfig->privatekeyfile = const_cast<char*>(_privateKeyFile.c_str());
_sshConfig->publickeyfile = _publicKeyFile.empty() ? NULL : const_cast<char*>(_publicKeyFile.c_str());
_sshConfig->passphrase = const_cast<char*>(_passphrase.c_str());
_sshConfig->authtype = (_authMethod == "publickey") ? RBM_SSH_AUTH_TYPE_PUBLICKEY : RBM_SSH_AUTH_TYPE_PASSWORD;
// Default settings
_sshConfig->logcontext = NULL;
_sshConfig->logcallback = NULL;
_sshConfig->loglevel = RBM_SSH_LOG_TYPE_ERROR;
}
SshTunnelConfigCreator::~SshTunnelConfigCreator() {
delete _sshConfig;
}
}
+31 -15
View File
@@ -1,6 +1,7 @@
#pragma once
#include <QObject>
#include <robomongo/ssh/ssh.h>
#include "robomongo/core/events/MongoEvents.h"
@@ -17,6 +18,34 @@ namespace Robomongo
class EstablishSshConnectionRequest;
class ListenSshConnectionRequest;
/*
* Helper class for creating rbm_ssh_tunnel_config from ConnectionSettings
* Automatically deletes allocated structure
*/
class SshTunnelConfigCreator {
public:
explicit SshTunnelConfigCreator(ConnectionSettings *settings);
~SshTunnelConfigCreator();
rbm_ssh_tunnel_config *config() { return _sshConfig; }
private:
std::string _sshhost;
int _sshport;
std::string _remotehost;
int _remoteport;
std::string _localip;
int _localport;
std::string _userName;
std::string _userPassword;
std::string _privateKeyFile;
std::string _publicKeyFile;
std::string _passphrase;
std::string _authMethod; // "password" or "publickey"
rbm_ssh_tunnel_config* _sshConfig;
};
class SshTunnelWorker : public QObject
{
Q_OBJECT
@@ -31,7 +60,6 @@ namespace Robomongo
void stopAndDelete();
protected Q_SLOTS: // handlers:
void init();
void handle(EstablishSshConnectionRequest *event);
void handle(ListenSshConnectionRequest *event);
@@ -42,21 +70,9 @@ namespace Robomongo
QThread *_thread;
QAtomicInteger<int> _isQuiting;
ConnectionSettings* _settings;
rbm_ssh_tunnel_config* _sshConfig;
rbm_ssh_session* _sshSession;
std::string _sshhost;
int _sshport;
std::string _remotehost;
int _remoteport;
std::string _localip;
int _localport;
std::string _userName;
std::string _userPassword;
std::string _privateKeyFile;
std::string _publicKeyFile;
std::string _passphrase;
std::string _authMethod; // "password" or "publickey"
SshTunnelConfigCreator _configCreator;
};
}
@@ -11,6 +11,8 @@ namespace
const unsigned port = 27017;
const char *defaultServerHost = "localhost";
const char *defaultNameConnection = "New Connection";
const int maxLength = 300;
}
namespace Robomongo
@@ -27,12 +29,12 @@ namespace Robomongo
void ConnectionSettings::fromVariant(const QVariantMap &map) {
setConnectionName(QtUtils::toStdString(map.value("connectionName").toString()));
setServerHost(QtUtils::toStdString(map.value("serverHost").toString()));
setServerHost(QtUtils::toStdString(map.value("serverHost").toString().left(maxLength)));
setServerPort(map.value("serverPort").toInt());
setDefaultDatabase(QtUtils::toStdString(map.value("defaultDatabase").toString()));
QVariantList list = map.value("credentials").toList();
for(QVariantList::const_iterator it = list.begin(); it != list.end(); ++it) {
for (QVariantList::const_iterator it = list.begin(); it != list.end(); ++it) {
QVariant var = *it;
CredentialSettings *credential = new CredentialSettings(var.toMap());
addCredential(credential);
@@ -106,7 +108,7 @@ namespace Robomongo
map.insert("sslPemKeyFile", QtUtils::toQString(infl._sslPEMKeyFile));
#endif
QVariantList list;
for(QList<CredentialSettings *>::const_iterator it = _credentials.begin(); it != _credentials.end(); ++it) {
for (QList<CredentialSettings *>::const_iterator it = _credentials.begin(); it != _credentials.end(); ++it) {
CredentialSettings *credential = *it;
list.append(credential->toVariant());
}
@@ -120,7 +122,7 @@ namespace Robomongo
CredentialSettings *ConnectionSettings::findCredential(const std::string &databaseName) const
{
CredentialSettings *result = NULL;
for(QList<CredentialSettings *>::const_iterator it = _credentials.begin(); it != _credentials.end(); ++it) {
for (QList<CredentialSettings *>::const_iterator it = _credentials.begin(); it != _credentials.end(); ++it) {
CredentialSettings *cred = *it;
if (cred->databaseName() == databaseName) {
result = cred;
@@ -48,7 +48,9 @@ namespace Robomongo
_textFontFamily(""),
_textFontPointSize(-1),
_lineNumbers(false),
_loadMongoRcJs(false)
_loadMongoRcJs(false),
_mongoTimeoutSec(10),
_shellTimeoutSec(15)
{
load();
LOG_MSG("SettingsManager initialized in " + _configPath, mongo::logger::LogSeverity::Info(), false);
@@ -56,7 +58,7 @@ namespace Robomongo
SettingsManager::~SettingsManager()
{
std::for_each(_connections.begin() ,_connections.end(), stdutils::default_delete<ConnectionSettings *>());
std::for_each(_connections.begin(), _connections.end(), stdutils::default_delete<ConnectionSettings *>());
}
/**
@@ -179,6 +181,14 @@ namespace Robomongo
_textFontFamily = map.value("textFontFamily").toString();
_textFontPointSize = map.value("textFontPointSize").toInt();
if (map.contains("mongoTimeoutSec")) {
_mongoTimeoutSec = map.value("mongoTimeoutSec").toInt();
}
if (map.contains("shellTimeoutSec")) {
_shellTimeoutSec = map.value("shellTimeoutSec").toInt();
}
// 5. Load connections
_connections.clear();
@@ -239,6 +249,8 @@ namespace Robomongo
// 8. Save batchSize
map.insert("batchSize", _batchSize);
map.insert("mongoTimeoutSec", _mongoTimeoutSec);
map.insert("shellTimeoutSec", _shellTimeoutSec);
// 9. Save style
map.insert("style", _currentStyle);
@@ -250,7 +262,7 @@ namespace Robomongo
// 11. Save connections
QVariantList list;
for (ConnectionSettingsContainerType::const_iterator it = _connections.begin(); it!=_connections.end(); ++it) {
for (ConnectionSettingsContainerType::const_iterator it = _connections.begin(); it != _connections.end(); ++it) {
QVariantMap rm = (*it)->toVariant().toMap();
list.append(rm);
}
@@ -277,8 +289,8 @@ namespace Robomongo
*/
void SettingsManager::removeConnection(ConnectionSettings *connection)
{
ConnectionSettingsContainerType::iterator it = std::find(_connections.begin(),_connections.end(),connection);
if (it!=_connections.end()) {
ConnectionSettingsContainerType::iterator it = std::find(_connections.begin(), _connections.end(), connection);
if (it != _connections.end()) {
_connections.erase(it);
delete connection;
}
@@ -72,7 +72,7 @@ namespace Robomongo
UUIDEncoding uuidEncoding() const { return _uuidEncoding; }
void setTimeZone(SupportedTimes timeZ) { _timeZone = timeZ; }
SupportedTimes timeZone() const { return _timeZone;}
SupportedTimes timeZone() const { return _timeZone; }
void setViewMode(ViewMode viewMode) { _viewMode = viewMode; }
ViewMode viewMode() const { return _viewMode; }
@@ -98,7 +98,7 @@ namespace Robomongo
void setBatchSize(int batchSize) { _batchSize = batchSize; }
int batchSize() const { return _batchSize; }
QString currentStyle() const {return _currentStyle; }
QString currentStyle() const { return _currentStyle; }
void setCurrentStyle(const QString& style);
QString textFontFamily() const { return _textFontFamily; }
@@ -107,6 +107,9 @@ namespace Robomongo
int textFontPointSize() const { return _textFontPointSize; }
void setTextFontPointSize(int pointSize);
int mongoTimeoutSec() const { return _mongoTimeoutSec; }
int shellTimeoutSec() const { return _shellTimeoutSec; }
private:
@@ -125,14 +128,8 @@ namespace Robomongo
*/
QString _version;
/**
* @brief UUID encoding
*/
UUIDEncoding _uuidEncoding;
SupportedTimes _timeZone;
/**
* @brief view mode
*/
ViewMode _viewMode;
AutocompletionMode _autocompletionMode;
bool _loadMongoRcJs;
@@ -144,6 +141,10 @@ namespace Robomongo
QString _currentStyle;
QString _textFontFamily;
int _textFontPointSize;
int _mongoTimeoutSec;
int _shellTimeoutSec;
/**
* @brief List of connections
*/
+5 -1
View File
@@ -7,7 +7,9 @@ namespace Robomongo
SshSettings::SshSettings() :
_port(22),
_authMethod("publickey"),
_enabled(false) {
_enabled(false),
_askPassword(false),
_logLevel(1) {
}
@@ -27,6 +29,7 @@ namespace Robomongo
map.insert("passphrase", QtUtils::toQString(passphrase()));
map.insert("method", QtUtils::toQString(authMethod()));
map.insert("enabled", enabled());
map.insert("askPassword", askPassword());
return map;
}
@@ -40,5 +43,6 @@ namespace Robomongo
setPassphrase(QtUtils::toStdString(map.value("passphrase").toString()));
setAuthMethod(QtUtils::toStdString(map.value("method").toString()));
setEnabled(map.value("enabled").toBool());
setAskPassword(map.value("askPassword").toBool());
}
}
+16 -2
View File
@@ -22,6 +22,9 @@ namespace Robomongo
QVariant toVariant() const;
void fromVariant(const QVariantMap &map);
/*
* Domain or IPv4 or IPv6 address
*/
std::string host() const { return _host; }
void setHost(const std::string &host) { _host = host; }
@@ -53,11 +56,17 @@ namespace Robomongo
bool enabled() const { return _enabled; }
void setEnabled(bool enabled) { _enabled = enabled; }
bool askPassword() const { return _askPassword; }
void setAskPassword(bool ask) { _askPassword = ask; }
std::string askedPassword() const { return _askedPassword; }
void setAskedPassword(const std::string &asked) { _askedPassword = asked; }
int logLevel() const { return _logLevel; }
void setLogLevel(const int logLevel) { _logLevel = logLevel; }
private:
std::string _host;
std::string _host; // domain or IPv4/v6
int _port;
std::string _userName;
std::string _userPassword;
@@ -66,11 +75,16 @@ namespace Robomongo
std::string _passphrase;
std::string _authMethod; // "password" or "publickey"
// Should we ask user about password or passphrase
// each time when we try to connect
bool _askPassword;
/**
* Flag, indicating whether we should use
* this SSH tunnel or not.
*/
bool _enabled;
int _logLevel; // this property is not persisted
int _logLevel; // this property is not persisted
std::string _askedPassword; // this property is not persisted
};
}
+36 -25
View File
@@ -80,23 +80,23 @@ namespace Robomongo
s << (isArray ? "[" : "{");
BSONObjIterator i(obj);
BSONElement e = i.next();
if ( !e.eoo() ){
if ( !e.eoo() ) {
while ( 1 ) {
if ( pretty ) {
s << '\n';
for( int x = 0; x < pretty; x++ ){
for( int x = 0; x < pretty; x++ ) {
s << " ";
}
}
else {
s << " ";
}
s << jsonString(e, format, true, pretty?pretty+1:0, uuidEncoding, timeFormat, isArray);
s << jsonString(e, format, true, pretty ? pretty + 1 : 0, uuidEncoding, timeFormat, isArray);
e = i.next();
if (e.eoo()) {
s << '\n';
for( int x = 0; x < pretty - 1; x++ ){
for( int x = 0; x < pretty - 1; x++ ) {
s << " ";
}
s << (isArray ? "]" : "}");
@@ -130,15 +130,21 @@ namespace Robomongo
s << "NumberLong(" << elem._numberLong() << ")";
break;
case NumberInt:
s << elem._numberInt();
break;
case NumberDouble:
{
int sign=0;
int sign = 0;
if ( elem.number() >= -std::numeric_limits< double >::max() &&
elem.number() <= std::numeric_limits< double >::max() ) {
// was 16
s.precision(std::numeric_limits<double>::digits10);
s << elem.number();
// Leave trailing zero if needed
if (elem.number() == (long long)elem.number())
s << ".0";
}
else if (std::isnan(elem.number()) ) {
s << "NaN";
@@ -166,7 +172,7 @@ namespace Robomongo
break;
case Object: {
BSONObj obj = elem.embeddedObject();
s << jsonString(obj, format, pretty, uuidEncoding,timeFormat);
s << jsonString(obj, format, pretty, uuidEncoding, timeFormat);
}
break;
case mongo::Array: {
@@ -180,7 +186,7 @@ namespace Robomongo
if ( !e.eoo() ) {
int count = 0;
while ( 1 ) {
if( pretty ) {
if ( pretty ) {
s << '\n';
for( int x = 0; x < pretty; x++ )
s << " ";
@@ -190,7 +196,7 @@ namespace Robomongo
s << "undefined";
}
else {
s << jsonString(e, format, false, pretty?pretty+1:0, uuidEncoding, timeFormat, true);
s << jsonString(e, format, false, pretty ? pretty + 1 : 0, uuidEncoding, timeFormat, true);
e = i.next();
}
count++;
@@ -260,13 +266,13 @@ namespace Robomongo
case mongo::Date:
{
Date_t d = elem.date();
long long ms = d.toMillisSinceEpoch();//static_cast<long long>(d.millis);
long long ms = d.toMillisSinceEpoch(); //static_cast<long long>(d.millis);
bool isSupportedDate = miutil::minDate < ms && ms < miutil::maxDate;
if ( format == Strict )
s << "{ \"$date\" : ";
else{
if(isSupportedDate){
if (isSupportedDate) {
s << "ISODate(";
}
else{
@@ -275,7 +281,7 @@ namespace Robomongo
}
if ( pretty && isSupportedDate) {
boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
boost::posix_time::time_duration diff = boost::posix_time::millisec(ms);
boost::posix_time::ptime time = epoch + diff;
std::string timestr = miutil::isotimeString(time, true, timeFormat == LocalTime);
@@ -563,13 +569,13 @@ namespace Robomongo
con.append(e.fieldName());
con.append("\"");
con.append(" : ");
buildJsonString(e,con,uuid,tz);
buildJsonString(e, con, uuid, tz);
con.append(", \n");
}
con.append("\n}\n\n");
}
void buildJsonString(const mongo::BSONElement &elem,std::string &con, UUIDEncoding uuid, SupportedTimes tz)
void buildJsonString(const mongo::BSONElement &elem, std::string &con, UUIDEncoding uuid, SupportedTimes tz)
{
switch (elem.type())
{
@@ -578,6 +584,11 @@ namespace Robomongo
std::stringstream s;
s.precision(std::numeric_limits<double>::digits10);
s << elem.Double();
// Leave trailing zero if needed
if (elem.Double() == (long long)elem.Double())
s << ".0";
con.append(s.str());
}
break;
@@ -626,13 +637,13 @@ namespace Robomongo
long long ms = (long long) elem.Date().toMillisSinceEpoch();
bool isSupportedDate = miutil::minDate < ms && ms < miutil::maxDate;
boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
boost::posix_time::time_duration diff = boost::posix_time::millisec(ms);
boost::posix_time::ptime time = epoch + diff;
std::string date;
if(isSupportedDate)
date = miutil::isotimeString(time,false,tz==LocalTime);
if (isSupportedDate)
date = miutil::isotimeString(time, false, tz == LocalTime);
else
date = boost::lexical_cast<std::string>(ms);
@@ -652,7 +663,7 @@ namespace Robomongo
case 'g':
case 'i':
case 'm':
con+=*f;
con += *f;
default:
break;
}
@@ -678,15 +689,15 @@ namespace Robomongo
break;
case NumberInt:
{
char num[16]={0};
sprintf(num,"%d",elem.Int());
char num[16] = {0};
sprintf(num, "%d", elem.Int());
con.append(num);
break;
}
case bsonTimestamp:
{
Date_t date = elem.timestampTime();
unsigned long long millis = date.toMillisSinceEpoch();// millis;
unsigned long long millis = date.toMillisSinceEpoch(); // millis;
if ((long long)millis >= 0 &&
((long long)millis/1000) < (std::numeric_limits<time_t>::max)()) {
con.append(date.toString());
@@ -695,8 +706,8 @@ namespace Robomongo
}
case NumberLong:
{
char num[32]={0};
sprintf(num,"%lld",elem.Long());
char num[32] = {0};
sprintf(num, "%lld", elem.Long());
con.append(num);
break;
}
@@ -706,13 +717,13 @@ namespace Robomongo
}
}
mongo::BSONElement indexOf(const mongo::BSONObj &doc,int index)
mongo::BSONElement indexOf(const mongo::BSONObj &doc, int index)
{
mongo::BSONObjIterator iterator(doc);
for (int i = 0; iterator.more(); ++i)
{
mongo::BSONElement element = iterator.next();
if(i==index){
if (i == index) {
return element;
}
}
@@ -722,7 +733,7 @@ namespace Robomongo
int elementsCount(const mongo::BSONObj &doc)
{
mongo::BSONObjIterator iterator(doc);
int i=0;
int i = 0;
for (; iterator.more(); ++i)
{
iterator.next();
+2 -2
View File
@@ -100,8 +100,8 @@ namespace Robomongo
const char* BSONTypeToString(mongo::BSONType type, mongo::BinDataType binDataType, UUIDEncoding uuidEncoding);
void buildJsonString(const mongo::BSONObj &obj,std::string &con, UUIDEncoding uuid, SupportedTimes tz);
void buildJsonString(const mongo::BSONElement &elem,std::string &con, UUIDEncoding uuid, SupportedTimes tz);
void buildJsonString(const mongo::BSONObj &obj, std::string &con, UUIDEncoding uuid, SupportedTimes tz);
void buildJsonString(const mongo::BSONElement &elem, std::string &con, UUIDEncoding uuid, SupportedTimes tz);
mongo::BSONElement indexOf(const mongo::BSONObj &doc, int index);
int elementsCount(const mongo::BSONObj &doc);
+1 -1
View File
@@ -38,7 +38,7 @@ namespace Robomongo
void cleanUpThread(QThread *const thread)
{
if (thread&&thread->isRunning()) {
if (thread && thread->isRunning()) {
//thread->stop();
thread->wait();
}
+1 -1
View File
@@ -20,6 +20,6 @@ namespace Robomongo
static const QString StyleName;
virtual void drawControl(ControlElement element, const QStyleOption * option, QPainter * painter, const QWidget * widget) const;
virtual void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const;
virtual QRect subElementRect( SubElement element, const QStyleOption * option, const QWidget * widget=0 ) const;
virtual QRect subElementRect( SubElement element, const QStyleOption * option, const QWidget * widget = 0 ) const;
};
}
+15 -3
View File
@@ -223,16 +223,28 @@ namespace Robomongo
const QIcon &GuiRegistry::noMarkIcon() const
{
static const QIcon noMarkIc = QIcon(":/robomongo/icons/no_mark_16x16.png");
static const QIcon noMarkIc = QIcon(":/robomongo/icons/no_mark_24x24.png");
return noMarkIc;
}
const QIcon &GuiRegistry::yesMarkIcon() const
{
static const QIcon yesMarkIc = QIcon(":/robomongo/icons/yes_mark_16x16.png");
static const QIcon yesMarkIc = QIcon(":/robomongo/icons/yes_mark_24x24.png");
return yesMarkIc;
}
const QIcon &GuiRegistry::skipMarkIcon() const
{
static const QIcon skipMarkIc = QIcon(":/robomongo/icons/skip_mark_24x24.png");
return skipMarkIc;
}
const QIcon &GuiRegistry::questionMarkIcon() const
{
static const QIcon questionMarkIc = QIcon(":/robomongo/icons/question_mark_24x24.png");
return questionMarkIc;
}
const QIcon &GuiRegistry::timeIcon() const
{
static const QIcon timeIc = QIcon(":/robomongo/icons/time_16x16.png");
@@ -247,7 +259,7 @@ namespace Robomongo
const QBrush &GuiRegistry::typeBrush() const
{
static const QBrush typeBrush = QBrush(QColor(150,150, 150));
static const QBrush typeBrush = QBrush(QColor(150, 150, 150));
return typeBrush;
}
+2
View File
@@ -68,6 +68,8 @@ namespace Robomongo
const QIcon &bsonBooleanIcon() const;
const QIcon &noMarkIcon() const;
const QIcon &yesMarkIcon() const;
const QIcon &skipMarkIcon() const;
const QIcon &questionMarkIcon() const;
const QIcon &timeIcon() const;
const QIcon &keyIcon() const;
+24 -12
View File
@@ -323,17 +323,17 @@ namespace Robomongo
AutocompletionMode autocompletionMode = AppRegistry::instance().settingsManager()->autocompletionMode();
// Autocompletion
QAction *autocompletionAllAction = new QAction("All",this);
QAction *autocompletionAllAction = new QAction("All", this);
autocompletionAllAction->setCheckable(true);
autocompletionAllAction->setChecked(autocompletionMode == AutocompleteAll);
VERIFY(connect(autocompletionAllAction, SIGNAL(triggered()), this, SLOT(setShellAutocompletionAll())));
QAction *autocompletionNoCollectionNamesAction = new QAction("All (Except Collection Names)",this);
QAction *autocompletionNoCollectionNamesAction = new QAction("All (Except Collection Names)", this);
autocompletionNoCollectionNamesAction->setCheckable(true);
autocompletionNoCollectionNamesAction->setChecked(autocompletionMode == AutocompleteNoCollectionNames);
VERIFY(connect(autocompletionNoCollectionNamesAction, SIGNAL(triggered()), this, SLOT(setShellAutocompletionNoCollectionNames())));
QAction *autocompletionNoneAction = new QAction("None",this);
QAction *autocompletionNoneAction = new QAction("None", this);
autocompletionNoneAction->setCheckable(true);
autocompletionNoneAction->setChecked(autocompletionMode == AutocompleteNone);
VERIFY(connect(autocompletionNoneAction, SIGNAL(triggered()), this, SLOT(setShellAutocompletionNone())));
@@ -348,7 +348,7 @@ namespace Robomongo
autocompletionGroup->addAction(autocompletionNoCollectionNamesAction);
autocompletionGroup->addAction(autocompletionNoneAction);
QAction *loadMongoRcJs = new QAction("Load .mongorc.js",this);
QAction *loadMongoRcJs = new QAction("Load .mongorc.js", this);
loadMongoRcJs->setCheckable(true);
loadMongoRcJs->setChecked(AppRegistry::instance().settingsManager()->loadMongoRcJs());
VERIFY(connect(loadMongoRcJs, SIGNAL(triggered()), this, SLOT(setLoadMongoRcJs())));
@@ -369,19 +369,19 @@ namespace Robomongo
VERIFY(connect(showLineNumbers, SIGNAL(triggered()), this, SLOT(toggleLineNumbers())));
optionsMenu->addAction(showLineNumbers);
QAction *disabelConnectionShortcuts = new QAction("Disable Connection Shortcuts",this);
QAction *disabelConnectionShortcuts = new QAction("Disable Connection Shortcuts", this);
disabelConnectionShortcuts->setCheckable(true);
disabelConnectionShortcuts->setChecked(AppRegistry::instance().settingsManager()->disableConnectionShortcuts());
VERIFY(connect(disabelConnectionShortcuts, SIGNAL(triggered()), this, SLOT(setDisableConnectionShortcuts())));
optionsMenu->addAction(disabelConnectionShortcuts);
QAction *autoExec = new QAction(tr("Automatically execute code in new tab"),this);
QAction *autoExec = new QAction(tr("Automatically execute code in new tab"), this);
autoExec->setCheckable(true);
autoExec->setChecked(AppRegistry::instance().settingsManager()->autoExec());
VERIFY(connect(autoExec, SIGNAL(triggered()), this, SLOT(toggleAutoExec())));
optionsMenu->addAction(autoExec);
QAction *preferencesAction = new QAction("Preferences",this);
QAction *preferencesAction = new QAction("Preferences", this);
VERIFY(connect(preferencesAction, SIGNAL(triggered()), this, SLOT(openPreferences())));
preferencesAction->setVisible(false);
optionsMenu->addAction(preferencesAction);
@@ -516,7 +516,7 @@ namespace Robomongo
const QString &currentStyle = AppRegistry::instance().settingsManager()->currentStyle();
for (QStringList::const_iterator it = supportedStyles.begin(); it != supportedStyles.end(); ++it) {
const QString &style = *it;
QAction *styleAction = new QAction(style,this);
QAction *styleAction = new QAction(style, this);
styleAction->setCheckable(true);
styleAction->setChecked(style == currentStyle);
styleGroup->addAction(styleAction);
@@ -614,7 +614,7 @@ namespace Robomongo
int number = 1;
// Populate list with connections
SettingsManager::ConnectionSettingsContainerType connections = AppRegistry::instance().settingsManager()->connections();
for(SettingsManager::ConnectionSettingsContainerType::const_iterator it = connections.begin(); it!= connections.end(); ++it) {
for (SettingsManager::ConnectionSettingsContainerType::const_iterator it = connections.begin(); it != connections.end(); ++it) {
ConnectionSettings *connection = *it;
QAction *action = new QAction(QtUtils::toQString(connection->getReadableName()), this);
action->setData(QVariant::fromValue(connection));
@@ -663,7 +663,7 @@ namespace Robomongo
}
try {
_app->openServer(selected, true);
_app->openServer(selected, ConnectionPrimary);
} catch(const std::exception &) {
QString message = QString("Cannot connect to MongoDB (%1)").arg(QtUtils::toQString(selected->getFullAddress()));
QMessageBox::information(this, "Error", message);
@@ -788,7 +788,7 @@ namespace Robomongo
void MainWindow::refreshConnections()
{
QToolTip::showText(QPoint(0,0),
QToolTip::showText(QPoint(0, 0),
QString("Refresh not working yet... : <br/> <b>Ctrl+D</b> : push Button"));
}
@@ -883,7 +883,7 @@ namespace Robomongo
QVariant data = connectionAction->data();
ConnectionSettings *ptr = data.value<ConnectionSettings *>();
try {
_app->openServer(ptr, true);
_app->openServer(ptr, ConnectionPrimary);
}
catch(const std::exception &) {
QString message = QString("Cannot connect to the MongoDB at %1.")
@@ -894,6 +894,18 @@ namespace Robomongo
void MainWindow::handle(ConnectionFailedEvent *event)
{
// Handle only Primary connections
if (event->connectionType != ConnectionPrimary)
return;
// Very temporary solution to prevent multiple connection error messages
// from both SshTunnelWorker and MongoWorker
static int lastServerHandle = -1;
if (event->serverHandle <= lastServerHandle)
return;
lastServerHandle = event->serverHandle;
QMessageBox::information(this, "Error", QtUtils::toQString(event->message));
}
+14 -17
View File
@@ -57,23 +57,20 @@ namespace Robomongo
_mechanismComboBox->setCurrentText(QtUtils::toQString(primaryCredential->mechanism()));
}
QGridLayout *_authLayout = new QGridLayout;
_authLayout->addWidget(_useAuth, 0, 0, 1, 3);
_authLayout->addWidget(_databaseNameLabel, 1, 0);
_authLayout->addWidget(_databaseName, 1, 1, 1, 2);
_authLayout->addWidget(_databaseNameDescriptionLabel, 2, 1, 1, 2);
_authLayout->addWidget(_userNameLabel, 3, 0);
_authLayout->addWidget(_userName, 3, 1, 1, 2);
_authLayout->addWidget(_userPasswordLabel, 4, 0);
_authLayout->addWidget(_userPassword, 4, 1);
_authLayout->addWidget(_echoModeButton, 4, 2);
_authLayout->addWidget(_mechanismLabel, 5, 0);
_authLayout->addWidget(_mechanismComboBox, 5, 1, 1, 2);
_authLayout->setAlignment(Qt::AlignTop);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(_authLayout);
setLayout(mainLayout);
QGridLayout *authLayout = new QGridLayout;
authLayout->addWidget(_useAuth, 0, 0, 1, 3);
authLayout->addWidget(_databaseNameLabel, 1, 0);
authLayout->addWidget(_databaseName, 1, 1, 1, 2);
authLayout->addWidget(_databaseNameDescriptionLabel, 2, 1, 1, 2);
authLayout->addWidget(_userNameLabel, 3, 0);
authLayout->addWidget(_userName, 3, 1, 1, 2);
authLayout->addWidget(_userPasswordLabel, 4, 0);
authLayout->addWidget(_userPassword, 4, 1);
authLayout->addWidget(_echoModeButton, 4, 2);
authLayout->addWidget(_mechanismLabel, 5, 0);
authLayout->addWidget(_mechanismComboBox, 5, 1, 1, 2);
authLayout->setAlignment(Qt::AlignTop);
setLayout(authLayout);
}
void ConnectionAuthTab::accept()
@@ -30,7 +30,7 @@ namespace Robomongo
_serverAddress = new QLineEdit(QtUtils::toQString(_settings->serverHost()));
_serverPort = new QLineEdit(QString::number(_settings->serverPort()));
_serverPort->setFixedWidth(80);
QRegExp rx("\\d+");//(0-65554)
QRegExp rx("\\d+"); //(0-65554)
_serverPort->setValidator(new QRegExpValidator(rx, this));
QGridLayout *connectionLayout = new QGridLayout;
@@ -5,169 +5,261 @@
#include <QLabel>
#include <QPushButton>
#include <QMovie>
#include <QMessageBox>
#include <boost/scoped_ptr.hpp>
#include <mongo/client/dbclientinterface.h>
#include "robomongo/core/settings/ConnectionSettings.h"
#include "robomongo/core/settings/CredentialSettings.h"
#include "robomongo/core/settings/SshSettings.h"
#include "robomongo/gui/GuiRegistry.h"
#include "robomongo/core/AppRegistry.h"
#include "robomongo/core/domain/App.h"
#include "robomongo/core/domain/MongoServer.h"
#include "robomongo/core/EventBus.h"
#include "robomongo/core/utils/QtUtils.h"
#include "robomongo/core/mongodb/SshTunnelWorker.h"
namespace Robomongo
{
const QSize ConnectionDiagnosticDialog::dialogSize = QSize(300,200);
ConnectionDiagnosticDialog::ConnectionDiagnosticDialog(ConnectionSettings *connection, QWidget *parent) :
BaseClass(parent),
_connection(connection),
_connectionStatusReceived(false),
_authStatusReceived(false)
QDialog(parent),
_connection(NULL),
_server(NULL),
_serverHandle(0),
_continueExec(true)
{
_connection = connection->clone();
AppRegistry::instance().bus()->subscribe(this, ConnectionEstablishedEvent::Type);
AppRegistry::instance().bus()->subscribe(this, ConnectionFailedEvent::Type);
setWindowTitle("Diagnostic");
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); // Remove help button (?)
//setFixedSize(dialogSize);
_yesIcon = GuiRegistry::instance().yesMarkIcon();
_noIcon = GuiRegistry::instance().noMarkIcon();
_yesPixmap = _yesIcon.pixmap(24, 24);
_noPixmap = _noIcon.pixmap(24, 24);
_questionIcon = GuiRegistry::instance().questionMarkIcon();
_yesPixmap = _yesIcon.pixmap(20, 20);
_noPixmap = _noIcon.pixmap(20, 20);
_questionPixmap = _questionIcon.pixmap(20, 20);
QPushButton *closeButton = new QPushButton("&Close");
VERIFY(connect(closeButton, SIGNAL(clicked()), this, SLOT(accept())));
_connectionIconLabel = new QLabel;
_authIconLabel = new QLabel;
_connectionLabel = new QLabel;
_authIconLabel = new QLabel;
_authLabel = new QLabel;
_sshIconLabel = new QLabel;
_sshLabel = new QLabel;
_listIconLabel = new QLabel;
_listLabel = new QLabel;
_loadingMovie = new QMovie(":robomongo/icons/loading.gif", QByteArray(), this);
_viewErrorLink = new QLabel("<a href='error' style='color: #777777;'>Show error details</a>");
VERIFY(connect(_viewErrorLink, SIGNAL(linkActivated(QString)), this, SLOT(errorLinkActivated(QString))));
_loadingMovie = new QMovie(":robomongo/icons/loading_ticks_40x40.gif", QByteArray(), this);
_loadingMovie->setScaledSize(QSize(20, 20));
_loadingMovie->start();
_connectionIconLabel->setMovie(_loadingMovie);
_sshIconLabel->setMovie(_loadingMovie);
_authIconLabel->setMovie(_loadingMovie);
_connectionLabel->setText(QString("Connecting to <b>%1</b>...").arg(QtUtils::toQString(_connection->getFullAddress())));
if (_connection->hasEnabledPrimaryCredential()) {
_authLabel->setText(QString("Authorizing on <b>%1</b> database as <b>%2</b>...")
.arg(QtUtils::toQString(_connection->primaryCredential()->databaseName()))
.arg(QtUtils::toQString(_connection->primaryCredential()->userName())));
} else {
_authLabel->setText("Authorization skipped by you");
}
_listIconLabel->setMovie(_loadingMovie);
QGridLayout *layout = new QGridLayout();
layout->setContentsMargins(20, 20, 20, 10);
layout->addWidget(_connectionIconLabel, 0, 0);
layout->addWidget(_connectionLabel, 0, 1, Qt::AlignLeft);
layout->addWidget(_authIconLabel, 1, 0);
layout->addWidget(_authLabel, 1, 1, Qt::AlignLeft);
layout->setSizeConstraint(QLayout::SetFixedSize);
layout->addWidget(_sshIconLabel, 0, 0);
layout->addWidget(_sshLabel, 0, 1, Qt::AlignLeft);
layout->addWidget(_connectionIconLabel, 1, 0);
layout->addWidget(_connectionLabel, 1, 1, Qt::AlignLeft);
layout->addWidget(_authIconLabel, 2, 0);
layout->addWidget(_authLabel, 2, 1, Qt::AlignLeft);
layout->addWidget(_listIconLabel, 3, 0);
layout->addWidget(_listLabel, 3, 1, Qt::AlignLeft);
layout->setColumnStretch(0, 0) ; // Give column 0 no stretch ability
layout->setColumnStretch(1, 1) ; // Give column 1 stretch ability of ratio 1
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addSpacing(21);
hbox->addWidget(_viewErrorLink, 1, Qt::AlignLeft);
hbox->addWidget(closeButton, 0, Qt::AlignRight);
QVBoxLayout *box = new QVBoxLayout;
box->addLayout(layout);
box->addSpacing(10);
box->addWidget(closeButton, 0, Qt::AlignRight);
box->addLayout(hbox);
setLayout(box);
ConnectionDiagnosticThread *thread = new ConnectionDiagnosticThread(_connection);
VERIFY(connect(thread, SIGNAL(connectionStatus(QString, bool)), this, SLOT(connectionStatus(QString, bool))));
VERIFY(connect(thread, SIGNAL(authStatus(QString, bool)), this, SLOT(authStatus(QString, bool))));
VERIFY(connect(thread, SIGNAL(completed()), this, SLOT(completed())));
VERIFY(connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())));
thread->start();
}
sshStatus(InitialState);
connectionStatus(InitialState);
authStatus(InitialState);
listStatus(InitialState);
void ConnectionDiagnosticDialog::connectionStatus(QString error, bool connected)
{
_connectionStatusReceived = true;
_viewErrorLink->hide();
if (connected) {
_connectionIconLabel->setPixmap(_yesPixmap);
_connectionLabel->setText(QString("Connected to <b>%1</b>").arg(QtUtils::toQString(_connection->getFullAddress())));
} else {
_connectionIconLabel->setPixmap(_noPixmap);
_connectionLabel->setText(QString("Unable to connect to <b>%1</b>").arg(QtUtils::toQString(_connection->getFullAddress())));
}
layout()->activate();
setFixedSize(minimumSizeHint());
}
void ConnectionDiagnosticDialog::authStatus(QString error, bool authed)
{
_authStatusReceived = true;
if (authed) {
_authIconLabel->setPixmap(_yesPixmap);
_authLabel->setText(QString("Authorized as <b>%1</b>").arg(QtUtils::toQString(_connection->primaryCredential()->userName())));
} else {
_authIconLabel->setPixmap(_noPixmap);
if (_connection->hasEnabledPrimaryCredential())
_authLabel->setText(QString("Authorization failed"));
else
_authLabel->setText(QString("Authorization skipped by you"));
}
layout()->activate();
setFixedSize(minimumSizeHint());
}
void ConnectionDiagnosticDialog::completed()
{
if (!_connectionStatusReceived)
connectionStatus("", false);
if (!_authStatusReceived)
authStatus("", false);
// seems that it is wrong to call any method on thread,
// because thread already can be disposed.
// QThread *thread = static_cast<QThread *>(sender());
// thread->quit();
}
ConnectionDiagnosticThread::ConnectionDiagnosticThread(ConnectionSettings *connection) :
_connection(connection) { }
void ConnectionDiagnosticThread::run()
{
boost::scoped_ptr<mongo::DBClientConnection> connection;
try {
connection.reset(new mongo::DBClientConnection);
connection->connect(_connection->info());
emit connectionStatus("", true);
}
catch(const mongo::UserException &ex) {
const char *what = ex.what();
emit connectionStatus(QString(what), false);
emit completed();
if (!AppRegistry::instance().app()->openServer(_connection, ConnectionTest)) {
_continueExec = false;
return;
}
try {
if (_connection->hasEnabledPrimaryCredential())
{
CredentialSettings *credentials = _connection->primaryCredential();
_serverHandle = AppRegistry::instance().app()->getLastServerHandle();
}
// Building BSON object:
mongo::BSONObj authParams(mongo::BSONObjBuilder()
.append("user", credentials->userName())
.append("db", credentials->databaseName())
.append("pwd", credentials->userPassword())
.append("mechanism", credentials->mechanism())
.obj());
ConnectionDiagnosticDialog::~ConnectionDiagnosticDialog() {
if (_server)
AppRegistry::instance().app()->closeServer(_server);
}
connection->auth(authParams);
emit authStatus("", true);
}
} catch (const mongo::UserException &ex) {
emit authStatus("", false);
void ConnectionDiagnosticDialog::errorLinkActivated(const QString &link) {
if (_lastErrorMessage.empty())
return;
QMessageBox::information(this, "Error details", QtUtils::toQString(_lastErrorMessage));
}
void ConnectionDiagnosticDialog::sshStatus(State state)
{
if (!_connection->sshSettings()->enabled()) {
_sshIconLabel->setVisible(false);
_sshLabel->setVisible(false);
return;
}
emit completed();
if (state == InitialState) {
_sshIconLabel->setMovie(_loadingMovie);
_sshLabel->setText(QString("Connecting to SSH server at <b>%1:%2</b>...")
.arg(QtUtils::toQString(_connection->sshSettings()->host()))
.arg(_connection->sshSettings()->port()));
} else if (state == CompletedState) {
_sshIconLabel->setPixmap(_yesPixmap);
_sshLabel->setText(QString("Connected to SSH server at <b>%1:%2</b>")
.arg(QtUtils::toQString(_connection->sshSettings()->host()))
.arg(_connection->sshSettings()->port()));
} else if (state == FailedState) {
_sshIconLabel->setPixmap(_noPixmap);
_sshLabel->setText(QString("Unable to connect to SSH server at <b>%1:%2</b>")
.arg(QtUtils::toQString(_connection->sshSettings()->host()))
.arg(_connection->sshSettings()->port()));
}
}
void ConnectionDiagnosticDialog::connectionStatus(State state)
{
if (state == InitialState) {
_connectionIconLabel->setMovie(_loadingMovie);
QString tunnelNote = _connection->sshSettings()->enabled() ? " via SSH tunnel" : "";
_connectionLabel->setText(QString("Connecting to <b>%1</b>%2...").arg(QtUtils::toQString(_connection->getFullAddress()), tunnelNote));
} else if (state == CompletedState) {
_connectionIconLabel->setPixmap(_yesPixmap);
QString tunnelNote = _connection->sshSettings()->enabled() ? " via SSH tunnel" : "";
_connectionLabel->setText(QString("Connected to <b>%1</b>%2").arg(QtUtils::toQString(_connection->getFullAddress()), tunnelNote));
} else if (state == FailedState) {
_connectionIconLabel->setPixmap(_noPixmap);
QString tunnelNote = _connection->sshSettings()->enabled() ? " via tunnel" : "";
_connectionLabel->setText(QString("Failed to connect to <b>%1</b>%2").arg(QtUtils::toQString(_connection->getFullAddress()), tunnelNote));
} else if (state == NotPerformedState) {
_connectionIconLabel->setPixmap(_questionPixmap);
QString tunnelNote = _connection->sshSettings()->enabled() ? " via SSH tunnel" : "";
_connectionLabel->setText(QString("No chance to try connection to <b>%1</b>%2").arg(QtUtils::toQString(_connection->getFullAddress()), tunnelNote));
}
}
void ConnectionDiagnosticDialog::authStatus(State state)
{
if (!_connection->hasEnabledPrimaryCredential()) {
_authIconLabel->setVisible(false);
_authLabel->setVisible(false);
return;
}
if (state == InitialState) {
_authIconLabel->setMovie(_loadingMovie);
_authLabel->setText(QString("Authorizing on <b>%1</b> database as <b>%2</b>...")
.arg(QtUtils::toQString(_connection->primaryCredential()->databaseName()))
.arg(QtUtils::toQString(_connection->primaryCredential()->userName())));
} else if (state == CompletedState) {
_authIconLabel->setPixmap(_yesPixmap);
_authLabel->setText(QString("Authorized on <b>%1</b> database as <b>%2</b>")
.arg(QtUtils::toQString(_connection->primaryCredential()->databaseName()))
.arg(QtUtils::toQString(_connection->primaryCredential()->userName())));
} else if (state == FailedState) {
_authIconLabel->setPixmap(_noPixmap);
_authLabel->setText(QString("Authorization failed on <b>%1</b> database as <b>%2</b>")
.arg(QtUtils::toQString(_connection->primaryCredential()->databaseName()))
.arg(QtUtils::toQString(_connection->primaryCredential()->userName())));
} else if (state == NotPerformedState) {
_authIconLabel->setPixmap(_questionPixmap);
_authLabel->setText(QString("No chance to authorize"));
}
}
void ConnectionDiagnosticDialog::listStatus(State state)
{
if (_connection->hasEnabledPrimaryCredential()) {
_listIconLabel->setVisible(false);
_listLabel->setVisible(false);
return;
}
if (state == InitialState) {
_listIconLabel->setMovie(_loadingMovie);
_listLabel->setText(QString("Loading list of databases..."));
} else if (state == CompletedState) {
_listIconLabel->setPixmap(_yesPixmap);
_listLabel->setText(QString("Access to databases is available"));
} else if (state == FailedState) {
_listIconLabel->setPixmap(_noPixmap);
_listLabel->setText(QString("Failed to load list of databases"));
} else if (state == NotPerformedState) {
_listIconLabel->setPixmap(_questionPixmap);
_listLabel->setText(QString("No chance to load list of databases"));
}
}
void ConnectionDiagnosticDialog::handle(ConnectionEstablishedEvent *event) {
if (event->connectionType != ConnectionTest)
return;
sshStatus(CompletedState);
connectionStatus(CompletedState);
authStatus(CompletedState);
listStatus(CompletedState);
// Remember in order to delete on dialog close
_server = static_cast<MongoServer*>(event->sender());
}
void ConnectionDiagnosticDialog::handle(ConnectionFailedEvent *event) {
if (event->connectionType != ConnectionTest || event->serverHandle != _serverHandle)
return;
sshStatus(CompletedState);
connectionStatus(CompletedState);
authStatus(CompletedState);
listStatus(CompletedState);
switch (event->reason) {
case ConnectionFailedEvent::SshConnection:
sshStatus(FailedState);
connectionStatus(NotPerformedState);
authStatus(NotPerformedState);
listStatus(NotPerformedState);
break;
case ConnectionFailedEvent::SshChannel:
case ConnectionFailedEvent::MongoConnection:
connectionStatus(FailedState);
authStatus(NotPerformedState);
listStatus(NotPerformedState);
break;
case ConnectionFailedEvent::MongoAuth:
authStatus(FailedState);
listStatus(FailedState);
break;
}
// Show link for additional error details
if (!event->message.empty()) {
_lastErrorMessage = event->message;
_viewErrorLink->show();
}
}
}
@@ -2,63 +2,69 @@
#include <QDialog>
#include <QIcon>
#include <QThread>
QT_BEGIN_NAMESPACE
class QLabel;
class QMovie;
QT_END_NAMESPACE
namespace Robomongo
{
class ConnectionEstablishedEvent;
class ConnectionFailedEvent;
class ConnectionSettings;
class MongoServer;
class ConnectionDiagnosticDialog : public QDialog
{
Q_OBJECT
public:
typedef QDialog BaseClass;
static const QSize dialogSize;
ConnectionDiagnosticDialog(ConnectionSettings *connection, QWidget *parent = 0);
~ConnectionDiagnosticDialog();
bool continueExec() const { return _continueExec; }
protected Q_SLOTS:
void connectionStatus(QString error, bool connected);
void authStatus(QString error, bool authed);
void completed();
void handle(ConnectionEstablishedEvent *event);
void handle(ConnectionFailedEvent *event);
void errorLinkActivated(const QString &link);
private:
enum State {
InitialState,
CompletedState,
FailedState,
NotPerformedState
};
void sshStatus(State state);
void connectionStatus(State state);
void authStatus(State state);
void listStatus(State state);
ConnectionSettings *_connection;
QIcon _yesIcon;
QIcon _noIcon;
QIcon _waitIcon;
QIcon _questionIcon;
QMovie *_loadingMovie;
QPixmap _yesPixmap;
QPixmap _noPixmap;
QPixmap _questionPixmap;
QLabel *_sshIconLabel;
QLabel *_sshLabel;
QLabel *_connectionIconLabel;
QLabel *_connectionLabel;
QLabel *_authIconLabel;
QLabel *_authLabel;
QLabel *_listIconLabel; // List database names
QLabel *_listLabel;
bool _connectionStatusReceived;
bool _authStatusReceived;
};
QLabel *_viewErrorLink;
std::string _lastErrorMessage;
class ConnectionDiagnosticThread : public QThread
{
Q_OBJECT
public:
ConnectionDiagnosticThread(ConnectionSettings *connection);
Q_SIGNALS:
void connectionStatus(QString error, bool connected);
void authStatus(QString error, bool authed);
void completed();
protected:
void run();
private:
ConnectionSettings *_connection;
MongoServer *_server;
int _serverHandle;
bool _continueExec;
};
}
+13 -7
View File
@@ -57,8 +57,8 @@ namespace Robomongo
tabWidget->addTab(_basicTab, "Connection");
tabWidget->addTab(_authTab, "Authentication");
tabWidget->addTab(_advancedTab, "Advanced");
tabWidget->addTab(_sshTab, "SSH");
tabWidget->addTab(_advancedTab, "Advanced");
// v0.9
//tabWidget->addTab(_sslTab, "SSL");
@@ -76,7 +76,7 @@ namespace Robomongo
*/
void ConnectionDialog::accept()
{
if (validateAndApply()){
if (validateAndApply()) {
QDialog::accept();
}
}
@@ -93,7 +93,9 @@ namespace Robomongo
_basicTab->accept();
_authTab->accept();
_advancedTab->accept();
_sshTab->accept();
if (!_sshTab->accept())
return false;
// v0.9
// _sslTab->accept();
@@ -105,9 +107,13 @@ namespace Robomongo
*/
void ConnectionDialog::testConnection()
{
if(validateAndApply()){
ConnectionDiagnosticDialog diag(_connection,this);
diag.exec();
}
if (!validateAndApply())
return;
ConnectionDiagnosticDialog diag(_connection, this);
if (!diag.continueExec())
return;
diag.exec();
}
}
@@ -36,7 +36,7 @@ namespace Robomongo
_sslSupport->setChecked(_settings->sslInfo()._sslSupport);
_selectPemFileButton = new QPushButton("...");
_selectPemFileButton->setFixedSize(20,20);
_selectPemFileButton->setFixedSize(20, 20);
VERIFY(connect(_selectPemFileButton, SIGNAL(clicked()), this, SLOT(setSslPEMKeyFile())));
_sslPemLabel = new QLabel("SSL Certificate:");
@@ -233,7 +233,7 @@ namespace Robomongo
activateWindow();
int size = _connectionItems.size();
for (int i=0; i<size; ++i)
for (int i = 0; i<size; ++i)
{
ConnectionListWidgetItem *item = _connectionItems[i];
if (_connectionItems[i]->connection() == connection) {
@@ -281,7 +281,7 @@ namespace Robomongo
// Clone connection
ConnectionSettings *connection = currentItem->connection()->clone();
std::string newConnectionName="Copy of "+connection->connectionName();
std::string newConnectionName = "Copy of "+connection->connectionName();
connection->setConnectionName(newConnectionName);
@@ -307,7 +307,7 @@ namespace Robomongo
// Make childrens toplevel again. This is a bad, but quickiest item reordering
// implementation.
for(int i = 0; i < count; i++)
for (int i = 0; i < count; i++)
{
ConnectionListWidgetItem * item = (ConnectionListWidgetItem *) _listWidget->topLevelItem(i);
if (item->childCount() > 0) {
@@ -321,7 +321,7 @@ namespace Robomongo
count = _listWidget->topLevelItemCount();
SettingsManager::ConnectionSettingsContainerType items;
for(int i = 0; i < count; i++)
for (int i = 0; i < count; i++)
{
ConnectionListWidgetItem * item = (ConnectionListWidgetItem *) _listWidget->topLevelItem(i);
items.push_back(item->connection());
@@ -18,7 +18,7 @@
namespace Robomongo
{
const QSize CopyCollection::minimumSize = QSize(300,150);
const QSize CopyCollection::minimumSize = QSize(300, 150);
CopyCollection::CopyCollection(const QString &serverName, const QString &database,
const QString &collection, QWidget *parent) :
@@ -28,9 +28,9 @@ namespace Robomongo
{
App::MongoServersContainerType servers = AppRegistry::instance().app()->getServers();
QSet<QString> uniqueConnectionsNames;
for(App::MongoServersContainerType::const_iterator it = servers.begin(); it != servers.end(); ++it){
for (App::MongoServersContainerType::const_iterator it = servers.begin(); it != servers.end(); ++it) {
MongoServer *server = *it;
if (server->isConnected() ){
if (server->isConnected()) {
_servers.push_back(server);
uniqueConnectionsNames.insert(QtUtils::toQString(server->connectionRecord()->connectionName()));
}
@@ -109,7 +109,7 @@ namespace Robomongo
}
}
_databaseComboBox->addItems(server->getDatabasesNames());
if (_currentServerName==QtUtils::toQString(server->connectionRecord()->getFullAddress())) {
if (_currentServerName == QtUtils::toQString(server->connectionRecord()->getFullAddress())) {
_databaseComboBox->removeItem(_databaseComboBox->findText(_currentDatabase));
}
}
@@ -13,7 +13,7 @@
namespace Robomongo
{
const QSize CreateDatabaseDialog::dialogSize = QSize(300,150);
const QSize CreateDatabaseDialog::dialogSize = QSize(300, 150);
CreateDatabaseDialog::CreateDatabaseDialog(const QString &serverName, const QString &database,
const QString &collection, QWidget *parent) :
@@ -31,7 +31,7 @@ namespace Robomongo
hline->setFrameShadow(QFrame::Sunken);
_inputEdit = new QLineEdit();
_inputLabel= new QLabel("Database Name:");
_inputLabel = new QLabel("Database Name:");
_inputEdit->setMaxLength(maxLenghtName);
_buttonBox = new QDialogButtonBox(this);
+23 -15
View File
@@ -17,8 +17,19 @@
namespace Robomongo
{
const char * rolesText[CreateUserDialog::RolesCount] = {"read","readWrite","dbAdmin","userAdmin","clusterAdmin","readAnyDatabase","readWriteAnyDatabase","userAdminAnyDatabase","dbAdminAnyDatabase"};
const QSize CreateUserDialog::minimumSize = QSize(400,200);
const char * rolesText[CreateUserDialog::RolesCount] = {
"read",
"readWrite",
"dbAdmin",
"userAdmin",
"clusterAdmin",
"readAnyDatabase",
"readWriteAnyDatabase",
"userAdminAnyDatabase",
"dbAdminAnyDatabase"
};
const QSize CreateUserDialog::minimumSize = QSize(400, 200);
bool containsWord(const std::string& sentence, const std::string& word)
{
@@ -31,7 +42,7 @@ namespace Robomongo
if (pos) {
isFirstAlpha = isalpha(sentence[pos - 1]);
}
if (!isFirstAlpha&&!isLastAlpha)
if (!isFirstAlpha && !isLastAlpha)
return true;
}
pos++;
@@ -39,13 +50,11 @@ namespace Robomongo
return false;
}
CreateUserDialog::CreateUserDialog(const QStringList &databases,const QString &serverName,
CreateUserDialog::CreateUserDialog(const QStringList &databases, const QString &serverName,
const QString &database, const MongoUser &user,
QWidget *parent) : QDialog(parent),
_user(user)
{
VERIFY(!user.version() < MongoUser::minimumSupportedVersion);
setWindowTitle("Add User");
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); // Remove help button (?)
setMinimumSize(minimumSize);
@@ -57,10 +66,10 @@ namespace Robomongo
hline->setFrameShape(QFrame::HLine);
hline->setFrameShadow(QFrame::Sunken);
_userNameLabel= new QLabel("Name:");
_userNameLabel = new QLabel("Name:");
_userNameEdit = new QLineEdit();
_userNameEdit->setText(QtUtils::toQString(user.name()));
_userPassLabel= new QLabel("Password:");
_userPassLabel = new QLabel("Password:");
_userPassEdit = new QLineEdit();
_userPassEdit->setEchoMode(QLineEdit::Password);
_userSourceLabel = new QLabel("UserSource:");
@@ -70,14 +79,14 @@ namespace Robomongo
QGridLayout *gridRoles = new QGridLayout();
MongoUser::RoleType userRoles = user.role();
for (unsigned i=0; i<RolesCount; ++i)
for (unsigned i = 0; i<RolesCount; ++i)
{
int row = i%3;
int col = i/3;
_rolesArray[i] = new QCheckBox(rolesText[i],this);
MongoUser::RoleType::const_iterator it = std::find(userRoles.begin(),userRoles.end(),rolesText[i]);
_rolesArray[i]->setChecked(it!=userRoles.end());
gridRoles->addWidget(_rolesArray[i],row,col);
_rolesArray[i] = new QCheckBox(rolesText[i], this);
MongoUser::RoleType::const_iterator it = std::find(userRoles.begin(), userRoles.end(), rolesText[i]);
_rolesArray[i]->setChecked(it!= userRoles.end());
gridRoles->addWidget(_rolesArray[i], row, col);
}
QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
@@ -120,7 +129,6 @@ namespace Robomongo
QWidget *parent) : QDialog(parent),
_user(user)
{
VERIFY(user.version() < MongoUser::minimumSupportedVersion);
setWindowTitle("Add User");
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); // Remove help button (?)
setMinimumSize(minimumSize);
@@ -132,7 +140,7 @@ namespace Robomongo
hline->setFrameShape(QFrame::HLine);
hline->setFrameShadow(QFrame::Sunken);
_userNameLabel= new QLabel("Name:");
_userNameLabel = new QLabel("Name:");
_userNameEdit = new QLineEdit();
_userNameEdit->setText(QtUtils::toQString(user.name()));
_userPassLabel= new QLabel("Password:");
@@ -36,10 +36,6 @@ namespace Robomongo
resize(size);
int x = (screenGeometry.width() - width()) / 2;
int y = (screenGeometry.height() - height()) / 2;
move(x, y);
setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
Indicator *collectionIndicator = new Indicator(GuiRegistry::instance().collectionIcon(), QtUtils::toQString(_info._ns.collectionName()));
@@ -144,18 +140,18 @@ namespace Robomongo
int jsonLen = textString.length();
int offset = 0;
_obj.clear();
while(offset!=jsonLen)
while (offset != jsonLen)
{
mongo::BSONObj doc = mongo::Robomongo::fromjson(json+offset,&len);
mongo::BSONObj doc = mongo::Robomongo::fromjson(json+offset, &len);
_obj.push_back(doc);
offset+=len;
offset += len;
}
} catch (const mongo::Robomongo::ParseMsgAssertionException &ex) {
// v0.9
QString message = QtUtils::toQString(ex.reason());
int offset = ex.offset();
int line=0, pos=0;
int line = 0, pos = 0;
_queryText->sciScintilla()->lineIndexFromPosition(offset, &line, &pos);
_queryText->sciScintilla()->setCursorPosition(line, pos);
@@ -198,7 +194,7 @@ namespace Robomongo
QsciLexerJavaScript *javaScriptLexer = new JSLexer(this);
QFont font = GuiRegistry::instance().font();
javaScriptLexer->setFont(font);
_queryText->sciScintilla()->setBraceMatching(QsciScintilla::StrictBraceMatch);
_queryText->sciScintilla()->setAppropriateBraceMatching();
_queryText->sciScintilla()->setFont(font);
_queryText->sciScintilla()->setPaper(QColor(255, 0, 0, 127));
_queryText->sciScintilla()->setLexer(javaScriptLexer);
@@ -97,7 +97,7 @@ namespace Robomongo
const QFont &textFont = GuiRegistry::instance().font();
QsciLexerJavaScript *javaScriptLexer = new JSLexer(this);
javaScriptLexer->setFont(textFont);
_queryText->sciScintilla()->setBraceMatching(QsciScintilla::StrictBraceMatch);
_queryText->sciScintilla()->setAppropriateBraceMatching();
_queryText->sciScintilla()->setFont(textFont);
_queryText->sciScintilla()->setPaper(QColor(255, 0, 0, 127));
_queryText->sciScintilla()->setLexer(javaScriptLexer);
@@ -24,7 +24,7 @@ namespace Robomongo
setWindowTitle("Preferences " PROJECT_NAME_TITLE);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setFixedSize(height,width);
setFixedSize(height, width);
QVBoxLayout *layout = new QVBoxLayout(this);
@@ -33,7 +33,7 @@ namespace Robomongo
defLayout->addWidget(defDisplayModeLabel);
_defDisplayModeComboBox = new QComboBox();
QStringList modes;
for (int i = Text;i<=Custom;++i)
for (int i = Text; i <= Custom; ++i)
{
modes.append(convertViewModeToString(static_cast<ViewMode>(i)));
}
@@ -46,7 +46,7 @@ namespace Robomongo
timeZoneLayout->addWidget(timeZoneLabel);
_timeZoneComboBox = new QComboBox();
QStringList times;
for (int i = Utc;i<=LocalTime;++i)
for (int i = Utc; i <= LocalTime; ++i)
{
times.append(convertTimesToString(static_cast<SupportedTimes>(i)));
}
@@ -59,7 +59,7 @@ namespace Robomongo
uuidEncodingLayout->addWidget(uuidEncodingLabel);
_uuidEncodingComboBox = new QComboBox();
QStringList uuids;
for (int i = DefaultEncoding;i<=PythonLegacy;++i)
for (int i = DefaultEncoding; i <= PythonLegacy; ++i)
{
uuids.append(convertUUIDEncodingToString(static_cast<UUIDEncoding>(i)));
}
+87 -28
View File
@@ -9,6 +9,8 @@
#include <QPushButton>
#include <QFileDialog>
#include <QComboBox>
#include <QMessageBox>
#include <QFileInfo>
#include <QFrame>
#include "robomongo/core/utils/QtUtils.h"
@@ -16,6 +18,15 @@
#include "robomongo/core/settings/ConnectionSettings.h"
#include "robomongo/core/settings/SshSettings.h"
namespace {
const QString askPasswordText = "Ask for password each time";
const QString askPassphraseText = "Ask for passphrase each time";
bool isFileExists(const QString &path) {
QFileInfo fileInfo(path);
return fileInfo.exists() && fileInfo.isFile();
}
}
namespace Robomongo
{
SshTunnelTab::SshTunnelTab(ConnectionSettings *settings) :
@@ -26,12 +37,16 @@ namespace Robomongo
_sshSupport->setStyleSheet("margin-bottom: 7px");
_sshSupport->setChecked(info->enabled());
_askForPassword = new QCheckBox(askPasswordText);
_askForPassword->setChecked(info->askPassword());
VERIFY(connect(_askForPassword, SIGNAL(stateChanged(int)), this, SLOT(askForPasswordStateChanged(int))));
_sshHostName = new QLineEdit(QtUtils::toQString(info->host()));
_userName = new QLineEdit(QtUtils::toQString(info->userName()));
_sshPort = new QLineEdit(QString::number(info->port()));
_sshPort->setFixedWidth(80);
QRegExp rx("\\d+");//(0-65554)
_sshPort->setFixedWidth(40);
QRegExp rx("\\d+"); //(0-65554)
_sshPort->setValidator(new QRegExpValidator(rx, this));
_security = new QComboBox();
@@ -103,6 +118,7 @@ namespace Robomongo
connectionLayout->addWidget(_sshPassphraseLabel, 8, 0);
connectionLayout->addWidget(_passphraseBox, 8, 1);
connectionLayout->addWidget(_passphraseEchoModeButton, 8, 2);
connectionLayout->addWidget(_askForPassword, 9, 1, 1, 2);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(_sshSupport);
@@ -129,25 +145,48 @@ namespace Robomongo
return _sshSupport->isChecked();
}
void SshTunnelTab::sshSupportStateChange(int value)
void SshTunnelTab::setPasswordFieldsEnabled(bool enabled)
{
_sshHostName->setEnabled(value);
_userName->setEnabled(value);
_sshPort->setEnabled(value);
_security->setEnabled(value);
_sshPassphraseLabel->setEnabled(enabled);
_passphraseBox->setEnabled(enabled);
_passwordBox->setEnabled(enabled);
_passwordLabel->setEnabled(enabled);
_passphraseEchoModeButton->setEnabled(enabled);
_passwordEchoModeButton->setEnabled(enabled);
}
_sshPrivateKeyLabel->setEnabled(value);
_privateKeyBox->setEnabled(value);
_selectPrivateFileButton->setEnabled(value);
_sshAddressLabel->setEnabled(value);
_sshUserNameLabel->setEnabled(value);
_sshAuthMethodLabel->setEnabled(value);
void SshTunnelTab::askForPasswordStateChanged(int state)
{
bool checked = state == Qt::Checked;
if (checked) {
_passphraseBox->setText("");
_passwordBox->setText("");
}
_sshPassphraseLabel->setEnabled(value);
_passphraseBox->setEnabled(value);
setPasswordFieldsEnabled(!checked && _sshSupport->isChecked());
}
_passwordBox->setEnabled(value);
_passwordLabel->setEnabled(value);
void SshTunnelTab::sshSupportStateChange(int state)
{
bool checked = state == Qt::Checked;
_sshHostName->setEnabled(checked);
_userName->setEnabled(checked);
_sshPort->setEnabled(checked);
_security->setEnabled(checked);
_sshPrivateKeyLabel->setEnabled(checked);
_privateKeyBox->setEnabled(checked);
_selectPrivateFileButton->setEnabled(checked);
_sshAddressLabel->setEnabled(checked);
_sshUserNameLabel->setEnabled(checked);
_sshAuthMethodLabel->setEnabled(checked);
_askForPassword->setEnabled(checked);
askForPasswordStateChanged(_askForPassword->checkState());
if (checked)
_sshHostName->setFocus();
}
void SshTunnelTab::securityChange(const QString& method)
@@ -165,6 +204,7 @@ namespace Robomongo
_passwordBox->setVisible(!isKey);
_passwordLabel->setVisible(!isKey);
_passwordEchoModeButton->setVisible(!isKey);
_askForPassword->setText(isKey ? askPassphraseText : askPasswordText);
}
void SshTunnelTab::setPrivateFile()
@@ -196,24 +236,43 @@ namespace Robomongo
// return SSHInfo::PASSWORD;
// }
void SshTunnelTab::accept()
bool SshTunnelTab::accept()
{
bool sshEnabled = _sshSupport->isChecked();
QString authMethod = _security->currentText() == "Private Key" ? "publickey" : "password";
// Check for existence of the private key file name
// and try to expand "~" character when needed
QString privateKey = _privateKeyBox->text();
if (sshEnabled && authMethod == "publickey" && !isFileExists(privateKey)) {
bool failed = true;
// Try to expand "~" if available
if (privateKey.startsWith ("~/")) {
privateKey.replace (0, 1, QDir::homePath());
if (isFileExists(privateKey)) {
failed = false;
}
}
if (failed) {
QString message = QString("Private key file \"%1\" doesn't exist").arg(privateKey);
QMessageBox::information(this, "Settings are incomplete", message);
return false;
}
}
SshSettings *info = _settings->sshSettings();
info->setHost(QtUtils::toStdString(_sshHostName->text()));
info->setPort(_sshPort->text().toInt());
info->setUserName(QtUtils::toStdString(_userName->text()));
info->setUserPassword(QtUtils::toStdString(_passwordBox->text()));
// info->setPublicKeyFile("");
info->setPrivateKeyFile(QtUtils::toStdString(_privateKeyBox->text()));
info->setAskPassword(_askForPassword->isChecked());
info->setPrivateKeyFile(QtUtils::toStdString(privateKey));
info->setPassphrase(QtUtils::toStdString(_passphraseBox->text()));
if (_security->currentText() == "Private Key") {
info->setAuthMethod("publickey");
} else {
info->setAuthMethod("password");
}
info->setEnabled(_sshSupport->isChecked());
info->setAuthMethod(QtUtils::toStdString(authMethod));
info->setEnabled(sshEnabled);
return true;
}
void SshTunnelTab::togglePasswordEchoMode()
+6 -4
View File
@@ -23,21 +23,23 @@ namespace Robomongo
public:
SshTunnelTab(ConnectionSettings *settings);
void accept();
bool accept();
bool isSshSupported() const;
private Q_SLOTS:
void sshSupportStateChange(int val);
void sshSupportStateChange(int checked);
void askForPasswordStateChanged(int checked);
void securityChange(const QString& val);
void setPrivateFile();
void togglePasswordEchoMode();
void togglePassphraseEchoMode();
private:
// SSHInfo::SupportedAuthenticationMetods selectedAuthMethod();
void setPasswordFieldsEnabled(bool enabled);
private:
QCheckBox *_sshSupport;
QCheckBox *_askForPassword;
QLineEdit *_sshHostName;
QLineEdit *_userName;
QLineEdit *_sshPort;
+11 -7
View File
@@ -33,12 +33,13 @@ namespace Robomongo
_close->setIcon(QIcon(":/robomongo/icons/close_2_16x16.png"));
_close->setToolButtonStyle(Qt::ToolButtonIconOnly);
_close->setIconSize(QSize(16, 16));
_close->hide(); // We do not need close button because ESC works
_findLine->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute);
QHBoxLayout *layout = new QHBoxLayout();
layout->setContentsMargins(6, 0, 6, 0);
layout->setSpacing(4);
layout->addWidget(_close);
layout->setContentsMargins(2, 0, 6, 0);
layout->setSpacing(7);
layout->addWidget(_findLine);
layout->addWidget(_next);
layout->addWidget(_prev);
@@ -50,8 +51,8 @@ namespace Robomongo
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
mainLayout->addWidget(_scin);
mainLayout->addWidget(_findPanel);
mainLayout->addWidget(_scin, 1);
mainLayout->addWidget(_findPanel, 0, Qt::AlignBottom);
setLayout(mainLayout);
_findPanel->hide();
@@ -71,14 +72,17 @@ namespace Robomongo
bool isFocusScin = _scin->isActiveWindow();
bool isShowFind = _findPanel->isVisible();
if (Qt::Key_Escape == keyEvent->key() && isFocusScin && isShowFind) {
// Hide & Show of Scintilla widget solves problem of UI blinking
_scin->hide();
_findPanel->hide();
_scin->setFocus();
_scin->show();
return keyEvent->accept();
} else if (Qt::Key_Return == keyEvent->key() && (keyEvent->modifiers() & Qt::ShiftModifier) && isFocusScin && isShowFind) {
goToPrevElement();
} else if (Qt::Key_Return == keyEvent->key() && isFocusScin && isShowFind) {
goToNextElement();
} else if (((keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key()==Qt::Key_F) && isFocusScin) {
} else if (((keyEvent->modifiers() & Qt::ControlModifier) && keyEvent->key() == Qt::Key_F) && isFocusScin) {
_findPanel->show();
_findLine->setFocus();
_findLine->selectAll();
@@ -122,7 +126,7 @@ namespace Robomongo
_scin->ensureCursorVisible();
}
else {
QMessageBox::warning(this, tr("Search"),tr("The specified text was not found."));
QMessageBox::warning(this, tr("Search"), tr("The specified text was not found."));
}
}
}
+1 -1
View File
@@ -21,7 +21,7 @@ namespace Robomongo
public:
enum
{
HeightFindPanel = 40
HeightFindPanel = 38
};
typedef QFrame BaseClass;
explicit FindFrame(QWidget *parent);
@@ -155,13 +155,13 @@ namespace Robomongo
}
if (((keyEvent->modifiers() & Qt::ControlModifier) &&
(keyEvent->key()==Qt::Key_F4 || keyEvent->key()==Qt::Key_W ||
keyEvent->key()==Qt::Key_T || keyEvent->key()==Qt::Key_Space ||
keyEvent->key()==Qt::Key_F || keyEvent->key()==Qt::Key_Slash))
(keyEvent->key() == Qt::Key_F4 || keyEvent->key() == Qt::Key_W ||
keyEvent->key() == Qt::Key_T || keyEvent->key() == Qt::Key_Space ||
keyEvent->key() == Qt::Key_F || keyEvent->key() == Qt::Key_Slash))
|| keyEvent->key() == Qt::Key_Escape /*|| keyEvent->key() == Qt::Key_Return*/
|| ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->modifiers() & Qt::AltModifier) && keyEvent->key()==Qt::Key_Left)
|| ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->modifiers() & Qt::AltModifier) && keyEvent->key()==Qt::Key_Right)
|| ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->modifiers() & Qt::ShiftModifier) && keyEvent->key()==Qt::Key_C)
|| ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->modifiers() & Qt::AltModifier) && keyEvent->key() == Qt::Key_Left)
|| ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->modifiers() & Qt::AltModifier) && keyEvent->key() == Qt::Key_Right)
|| ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->modifiers() & Qt::ShiftModifier) && keyEvent->key() == Qt::Key_C)
)
{
keyEvent->ignore();
@@ -182,4 +182,18 @@ namespace Robomongo
setMarginWidth(0, _lineNumberMarginWidth);
}
}
void RoboScintilla::setAppropriateBraceMatching() {
#ifdef Q_OS_MAC
// On Mac OS when brace matching is enabled, text
// will blink when you move cursor to some brace or
// when inside braces. This behaviour is not fully fixed
// in QScintilla 2.9.1 and 2.8.4
setBraceMatching(QsciScintilla::NoBraceMatch);
#else
setBraceMatching(QsciScintilla::StrictBraceMatch);
#endif
}
}
@@ -19,6 +19,7 @@ namespace Robomongo
void setIgnoreTabKey(bool ignore) { _ignoreTabKey = ignore; }
int lineNumberMarginWidth() const;
int textWidth(int style, const QString &text);
void setAppropriateBraceMatching();
protected:
void wheelEvent(QWheelEvent *e);
+9 -2
View File
@@ -16,6 +16,7 @@
<file>icons/bson_object_16x16.png</file>
<file>icons/database_16x16.png</file>
<file>icons/loading.gif</file>
<file>icons/loading_ticks_40x40.gif</file>
<file>scripts/esprima.js</file>
<file>icons/maximize.gif</file>
<file>icons/text_16x16.png</file>
@@ -38,8 +39,14 @@
<file>icons/maximize_highlighted_16x16.png</file>
<file>icons/table_16x16.png</file>
<file>icons/table_highlighted_16x16.png</file>
<file>icons/no_mark_16x16.png</file>
<file>icons/yes_mark_16x16.png</file>
<file>icons/no_mark_24x24.png</file>
<file>icons/no_mark_24x24@2x.png</file>
<file>icons/yes_mark_24x24.png</file>
<file>icons/yes_mark_24x24@2x.png</file>
<file>icons/skip_mark_24x24.png</file>
<file>icons/skip_mark_24x24@2x.png</file>
<file>icons/question_mark_24x24.png</file>
<file>icons/question_mark_24x24@2x.png</file>
<file>icons/time_16x16.png</file>
<file>icons/key_16x16.png</file>
<file>icons/progress_bar.gif</file>
Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

+2 -2
View File
@@ -12,12 +12,12 @@ namespace Robomongo
int questionDialog(QWidget *parent, const QString &actionText, const QString &itemText, const QString& valueText)
{
return questionDialog(parent,actionText,itemText,textTemaple,valueText);
return questionDialog(parent, actionText, itemText, textTemaple, valueText);
}
int questionDialog(QWidget *parent, const QString &actionText, const QString &itemText, const QString &templateText, const QString &valueText)
{
return QMessageBox::question(parent,titleTemaple.arg(actionText).arg(itemText),templateText.arg(actionText).arg(itemText.toLower()).arg(valueText), QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);
return QMessageBox::question(parent, titleTemaple.arg(actionText).arg(itemText), templateText.arg(actionText).arg(itemText.toLower()).arg(valueText), QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);
}
}
}
+3 -3
View File
@@ -15,12 +15,12 @@ namespace Robomongo
{
_logTextEdit->setReadOnly(true);
_logTextEdit->setContextMenuPolicy(Qt::CustomContextMenu);
VERIFY(connect(_logTextEdit,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(showContextMenu(const QPoint &))));
VERIFY(connect(_logTextEdit, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint &))));
QHBoxLayout *hlayout = new QHBoxLayout;
hlayout->setContentsMargins(0,0,0,0);
hlayout->setContentsMargins(0, 0, 0, 0);
hlayout->addWidget(_logTextEdit);
_clear = new QAction("Clear All", this);
VERIFY(connect(_clear, SIGNAL(triggered()),_logTextEdit, SLOT(clear())));
VERIFY(connect(_clear, SIGNAL(triggered()), _logTextEdit, SLOT(clear())));
setLayout(hlayout);
}
@@ -62,7 +62,7 @@ namespace
Robomongo::FindFrame *findFrame = new Robomongo::FindFrame(parent);
findFrame->sciScintilla()->setLexer(javaScriptLexer);
findFrame->sciScintilla()->setTabWidth(4);
findFrame->sciScintilla()->setBraceMatching(QsciScintilla::StrictBraceMatch);
findFrame->sciScintilla()->setAppropriateBraceMatching();
findFrame->sciScintilla()->setFont(textFont);
findFrame->sciScintilla()->setStyleSheet("QFrame {background-color: rgb(73, 76, 78); border: 1px solid #c7c5c4; border-radius: 4px; margin: 0px; padding: 0px;}");
findFrame->sciScintilla()->setText(text);
@@ -74,11 +74,11 @@ namespace
namespace Robomongo
{
EditIndexDialog::EditIndexDialog(const EnsureIndexInfo &info, const QString &databaseName, const QString &serverAdress, QWidget *parent)
:BaseClass(parent),_info(info)
:BaseClass(parent), _info(info)
{
setWindowTitle("Index Properties");
Indicator *serverIndicator = new Indicator(GuiRegistry::instance().serverIcon(), serverAdress);
Indicator *collectionIndicator = new Indicator(GuiRegistry::instance().collectionIcon(),QtUtils::toQString(_info._collection.name()));
Indicator *collectionIndicator = new Indicator(GuiRegistry::instance().collectionIcon(), QtUtils::toQString(_info._collection.name()));
Indicator *databaseIndicator = new Indicator(GuiRegistry::instance().databaseIcon(), databaseName);
QHBoxLayout *hlayout = new QHBoxLayout;
@@ -156,7 +156,7 @@ namespace Robomongo
layout->addWidget(dropDupsHelpLabel, 7, 0, 1, 2);
layout->setAlignment(Qt::AlignTop);
basicTab->setLayout(layout);
VERIFY(connect(_uniqueCheckBox,SIGNAL(stateChanged(int)),this,SLOT(uniqueStateChanged(int))));
VERIFY(connect(_uniqueCheckBox, SIGNAL(stateChanged(int)), this, SLOT(uniqueStateChanged(int))));
return basicTab;
}
@@ -203,7 +203,7 @@ namespace Robomongo
_expireAfterLineEdit->setText(QString("%1").arg(_info._ttl));
}
expireStateChanged(expireCheckBox->checkState());
VERIFY(connect(expireCheckBox,SIGNAL(stateChanged(int)),this,SLOT(expireStateChanged(int))));
VERIFY(connect(expireCheckBox, SIGNAL(stateChanged(int)), this, SLOT(expireStateChanged(int))));
QLabel *sparseHelpLabel = createHelpLabel(
"If set, the index only references documents with the specified field. "
@@ -20,7 +20,7 @@ namespace Robomongo
HeightWidget = 320,
WidthWidget = 480
};
explicit EditIndexDialog(const EnsureIndexInfo &info, const QString &databaseName, const QString &serverAdress, QWidget *parent=0);
explicit EditIndexDialog(const EnsureIndexInfo &info, const QString &databaseName, const QString &serverAdress, QWidget *parent = 0);
EnsureIndexInfo info() const;
public Q_SLOTS:
@@ -116,8 +116,8 @@ namespace Robomongo
ExplorerCollectionTreeItem *par = dynamic_cast<ExplorerCollectionTreeItem *const>(parent());
if (!par)
return;
EnsureIndexInfo fakeInfo(par->collection()->info(),"");
EditIndexDialog dlg(fakeInfo , QtUtils::toQString(par->databaseItem()->database()->name()),QtUtils::toQString(par->databaseItem()->database()->server()->connectionRecord()->getFullAddress()), treeWidget());
EnsureIndexInfo fakeInfo(par->collection()->info(), "");
EditIndexDialog dlg(fakeInfo , QtUtils::toQString(par->databaseItem()->database()->name()), QtUtils::toQString(par->databaseItem()->database()->server()->connectionRecord()->getFullAddress()), treeWidget());
int result = dlg.exec();
if (result != QDialog::Accepted)
return;
@@ -126,7 +126,7 @@ namespace Robomongo
if (!databaseTreeItem)
return;
databaseTreeItem->enshureIndex(par,fakeInfo, dlg.info());
databaseTreeItem->enshureIndex(par, fakeInfo, dlg.info());
}
void ExplorerCollectionDirIndexesTreeItem::ui_reIndex()
@@ -145,8 +145,8 @@ namespace Robomongo
}
}
ExplorerCollectionIndexesTreeItem::ExplorerCollectionIndexesTreeItem(ExplorerCollectionDirIndexesTreeItem *parent,const EnsureIndexInfo &info)
: BaseClass(parent),_info(info)
ExplorerCollectionIndexesTreeItem::ExplorerCollectionIndexesTreeItem(ExplorerCollectionDirIndexesTreeItem *parent, const EnsureIndexInfo &info)
: BaseClass(parent), _info(info)
{
QAction *deleteIndex = new QAction("Drop Index...", this);
connect(deleteIndex, SIGNAL(triggered()), SLOT(ui_dropIndex()));
@@ -163,7 +163,7 @@ namespace Robomongo
void ExplorerCollectionIndexesTreeItem::ui_dropIndex()
{
// Ask user
int answer = utils::questionDialog(treeWidget(),"Drop","Index",text(0));
int answer = utils::questionDialog(treeWidget(), "Drop", "Index", text(0));
if (answer != QMessageBox::Yes)
return;
@@ -300,10 +300,10 @@ namespace Robomongo
if (indexes.size() == 0)
_indexDir->setExpanded(false);
for (std::vector<EnsureIndexInfo>::const_iterator it = indexes.begin(); it!=indexes.end(); ++it) {
_indexDir->addChild(new ExplorerCollectionIndexesTreeItem(_indexDir,*it));
for (std::vector<EnsureIndexInfo>::const_iterator it = indexes.begin(); it != indexes.end(); ++it) {
_indexDir->addChild(new ExplorerCollectionIndexesTreeItem(_indexDir, *it));
}
_indexDir->setText(0, detail::buildName(ExplorerCollectionDirIndexesTreeItem::labelText,_indexDir->childCount()));
_indexDir->setText(0, detail::buildName(ExplorerCollectionDirIndexesTreeItem::labelText, _indexDir->childCount()));
}
void ExplorerCollectionTreeItem::handle(DeleteCollectionIndexResponse *event)
@@ -351,7 +351,7 @@ namespace Robomongo
QString ExplorerCollectionTreeItem::buildToolTip(MongoCollection *collection)
{
// This function does not used now
char buff[2048]={0};
char buff[2048] = {0};
// sprintf(buff,tooltipTemplate,collection->name().c_str(),collection->info().count(),collection->sizeString().c_str());
return buff;
}
@@ -429,7 +429,7 @@ namespace Robomongo
void ExplorerCollectionTreeItem::ui_dropCollection()
{
// Ask user
int answer = utils::questionDialog(treeWidget(),"Drop","collection",QtUtils::toQString(_collection->name()));
int answer = utils::questionDialog(treeWidget(), "Drop", "collection", QtUtils::toQString(_collection->name()));
if (answer == QMessageBox::Yes) {
MongoDatabase *database = _collection->database();
@@ -530,7 +530,7 @@ namespace Robomongo
openCurrentCollectionShell("getShardDistribution()");
}
void ExplorerCollectionTreeItem::openCurrentCollectionShell(const QString &script, bool execute,const CursorPosition &cursor)
void ExplorerCollectionTreeItem::openCurrentCollectionShell(const QString &script, bool execute, const CursorPosition &cursor)
{
QString query = detail::buildCollectionQuery(_collection->name(), script);
AppRegistry::instance().app()->openShell(_collection->database(), query, execute, QtUtils::toQString(_collection->name()), cursor);
@@ -24,7 +24,7 @@ namespace Robomongo
Q_OBJECT
public:
typedef ExplorerTreeItem BaseClass;
ExplorerCollectionTreeItem(QTreeWidgetItem *parent,ExplorerDatabaseTreeItem *databaseItem,MongoCollection *collection);
ExplorerCollectionTreeItem(QTreeWidgetItem *parent, ExplorerDatabaseTreeItem *databaseItem, MongoCollection *collection);
MongoCollection *collection() const { return _collection; }
void expand();
void dropIndex(const QTreeWidgetItem * const ind);
@@ -83,7 +83,7 @@ namespace Robomongo
Q_OBJECT
public:
typedef ExplorerTreeItem BaseClass;
explicit ExplorerCollectionIndexesTreeItem(ExplorerCollectionDirIndexesTreeItem *parent,const EnsureIndexInfo &info);
explicit ExplorerCollectionIndexesTreeItem(ExplorerCollectionDirIndexesTreeItem *parent, const EnsureIndexInfo &info);
private Q_SLOTS:
void ui_dropIndex();
@@ -26,8 +26,8 @@ namespace
namespace Robomongo
{
ExplorerDatabaseCategoryTreeItem::ExplorerDatabaseCategoryTreeItem(ExplorerDatabaseTreeItem *databaseItem,ExplorerDatabaseCategory category) :
BaseClass(databaseItem) ,_category(category)
ExplorerDatabaseCategoryTreeItem::ExplorerDatabaseCategoryTreeItem(ExplorerDatabaseTreeItem *databaseItem, ExplorerDatabaseCategory category) :
BaseClass(databaseItem), _category(category)
{
if (_category == Collections) {
QAction *createCollection = new QAction("Create Collection...", this);
@@ -22,7 +22,7 @@ namespace Robomongo
Q_OBJECT
public:
typedef ExplorerTreeItem BaseClass;
ExplorerDatabaseCategoryTreeItem(ExplorerDatabaseTreeItem *databaseItem,ExplorerDatabaseCategory category);
ExplorerDatabaseCategoryTreeItem(ExplorerDatabaseTreeItem *databaseItem, ExplorerDatabaseCategory category);
void expand();
private Q_SLOTS:
@@ -24,7 +24,7 @@
namespace
{
void openCurrentDatabaseShell(Robomongo::MongoDatabase *database,const QString &script, bool execute = true, const Robomongo::CursorPosition &cursor = Robomongo::CursorPosition())
void openCurrentDatabaseShell(Robomongo::MongoDatabase *database, const QString &script, bool execute = true, const Robomongo::CursorPosition &cursor = Robomongo::CursorPosition())
{
Robomongo::AppRegistry::instance().app()->openShell(database, script, execute, Robomongo::QtUtils::toQString(database->name()), cursor);
}
@@ -34,7 +34,7 @@ namespace Robomongo
{
namespace detail
{
QString buildName(const QString& text,int count)
QString buildName(const QString& text, int count)
{
if (count == -1)
return QString("%1 ...").arg(text);
@@ -42,7 +42,7 @@ namespace Robomongo
return QString("%1 (%2)").arg(text).arg(count);
}
}
ExplorerDatabaseTreeItem::ExplorerDatabaseTreeItem(QTreeWidgetItem *parent,MongoDatabase *const database) :
ExplorerDatabaseTreeItem::ExplorerDatabaseTreeItem(QTreeWidgetItem *parent, MongoDatabase *const database) :
BaseClass(parent),
_database(database),
_bus(AppRegistry::instance().bus()),
@@ -84,17 +84,17 @@ namespace Robomongo
setExpanded(false);
setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
_collectionFolderItem = new ExplorerDatabaseCategoryTreeItem(this,Collections);
_collectionFolderItem = new ExplorerDatabaseCategoryTreeItem(this, Collections);
_collectionFolderItem->setText(0, "Collections");
_collectionFolderItem->setIcon(0, GuiRegistry::instance().folderIcon());
addChild(_collectionFolderItem);
_javascriptFolderItem = new ExplorerDatabaseCategoryTreeItem(this,Functions);
_javascriptFolderItem = new ExplorerDatabaseCategoryTreeItem(this, Functions);
_javascriptFolderItem->setText(0, "Functions");
_javascriptFolderItem->setIcon(0, GuiRegistry::instance().folderIcon());
addChild(_javascriptFolderItem);
_usersFolderItem = new ExplorerDatabaseCategoryTreeItem(this,Users);
_usersFolderItem = new ExplorerDatabaseCategoryTreeItem(this, Users);
_usersFolderItem->setText(0, "Users");
_usersFolderItem->setIcon(0, GuiRegistry::instance().folderIcon());
addChild(_usersFolderItem);
@@ -122,12 +122,12 @@ namespace Robomongo
void ExplorerDatabaseTreeItem::enshureIndex(ExplorerCollectionTreeItem *const item, const EnsureIndexInfo &oldInfo, const EnsureIndexInfo &newInfo)
{
_bus->send(_database->server()->client(), new EnsureIndexRequest(item,oldInfo ,newInfo));
_bus->send(_database->server()->client(), new EnsureIndexRequest(item, oldInfo, newInfo));
}
void ExplorerDatabaseTreeItem::editIndexFromCollection(ExplorerCollectionTreeItem *const item,const std::string &oldIndexText,const std::string &newIndexText)
void ExplorerDatabaseTreeItem::editIndexFromCollection(ExplorerCollectionTreeItem *const item, const std::string &oldIndexText, const std::string &newIndexText)
{
_bus->send(_database->server()->client(), new EditIndexRequest(item, item->collection()->info(),oldIndexText,newIndexText));
_bus->send(_database->server()->client(), new EditIndexRequest(item, item->collection()->info(), oldIndexText, newIndexText));
}
void ExplorerDatabaseTreeItem::expandFunctions()
@@ -150,7 +150,7 @@ namespace Robomongo
std::vector<MongoCollection *> collections = event->collections;
int count = collections.size();
_collectionFolderItem->setText(0, detail::buildName("Collections",count));
_collectionFolderItem->setText(0, detail::buildName("Collections", count));
QtUtils::clearChildItems(_collectionFolderItem);
// Do not expand, when we do not have collections
@@ -192,7 +192,7 @@ namespace Robomongo
std::vector<MongoUser> users = event->users();
int count = users.size();
_usersFolderItem->setText(0, detail::buildName("Users",count));
_usersFolderItem->setText(0, detail::buildName("Users", count));
// Do not expand, when we do not have users
if (count == 0)
@@ -221,7 +221,7 @@ namespace Robomongo
std::vector<MongoFunction> functions = event->functions();
int count = functions.size();
_javascriptFolderItem->setText(0, detail::buildName("Functions",count));
_javascriptFolderItem->setText(0, detail::buildName("Functions", count));
// Do not expand, when we do not have functions
if (count == 0)
@@ -237,22 +237,22 @@ namespace Robomongo
void ExplorerDatabaseTreeItem::handle(MongoDatabaseCollectionsLoadingEvent *event)
{
_collectionFolderItem->setText(0, detail::buildName("Collections",-1));
_collectionFolderItem->setText(0, detail::buildName("Collections", -1));
}
void ExplorerDatabaseTreeItem::handle(MongoDatabaseFunctionsLoadingEvent *event)
{
_javascriptFolderItem->setText(0, detail::buildName("Functions",-1));
_javascriptFolderItem->setText(0, detail::buildName("Functions", -1));
}
void ExplorerDatabaseTreeItem::handle(MongoDatabaseUsersLoadingEvent *event)
{
_usersFolderItem->setText(0, detail::buildName("Users",-1));
_usersFolderItem->setText(0, detail::buildName("Users", -1));
}
void ExplorerDatabaseTreeItem::addCollectionItem(MongoCollection *collection)
{
ExplorerCollectionTreeItem *collectionItem = new ExplorerCollectionTreeItem(_collectionFolderItem,this,collection);
ExplorerCollectionTreeItem *collectionItem = new ExplorerCollectionTreeItem(_collectionFolderItem, this, collection);
_collectionFolderItem->addChild(collectionItem);
}
@@ -286,7 +286,7 @@ namespace Robomongo
void ExplorerDatabaseTreeItem::ui_dbStatistics()
{
openCurrentDatabaseShell(_database,"db.stats()");
openCurrentDatabaseShell(_database, "db.stats()");
}
void ExplorerDatabaseTreeItem::ui_dbDrop()
@@ -294,7 +294,7 @@ namespace Robomongo
// Ask user
QString buff = QString("Drop <b>%1</b> database?").arg(QtUtils::toQString(_database->name()));
int answer = QMessageBox::question(treeWidget(),
"Drop Database",buff,
"Drop Database", buff,
QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);
if (answer != QMessageBox::Yes)
return;
@@ -6,7 +6,7 @@ namespace Robomongo
{
namespace detail
{
QString buildName(const QString& text,int count);
QString buildName(const QString& text, int count);
}
class ExplorerCollectionTreeItem;
@@ -30,7 +30,7 @@ namespace Robomongo
public:
typedef ExplorerTreeItem BaseClass;
ExplorerDatabaseTreeItem(QTreeWidgetItem *parent,MongoDatabase *const database);
ExplorerDatabaseTreeItem(QTreeWidgetItem *parent, MongoDatabase *const database);
MongoDatabase *database() const { return _database; }
void expandCollections();
@@ -39,7 +39,7 @@ namespace Robomongo
void expandColection(ExplorerCollectionTreeItem *const item);
void dropIndexFromCollection(ExplorerCollectionTreeItem *const item, const std::string &indexName);
void enshureIndex(ExplorerCollectionTreeItem *const item, const EnsureIndexInfo &oldInfo, const EnsureIndexInfo &newInfo);
void editIndexFromCollection(ExplorerCollectionTreeItem *const item,const std::string& oldIndexText,const std::string& newIndexText);
void editIndexFromCollection(ExplorerCollectionTreeItem *const item, const std::string& oldIndexText, const std::string& newIndexText);
public Q_SLOTS:
void handle(MongoDatabaseCollectionListLoadedEvent *event);
@@ -15,7 +15,7 @@
namespace Robomongo
{
ExplorerFunctionTreeItem::ExplorerFunctionTreeItem(QTreeWidgetItem *parent,MongoDatabase *database, const MongoFunction &function) :
ExplorerFunctionTreeItem::ExplorerFunctionTreeItem(QTreeWidgetItem *parent, MongoDatabase *database, const MongoFunction &function) :
BaseClass(parent),
_function(function),
_database(database)
@@ -64,7 +64,7 @@ namespace Robomongo
void ExplorerFunctionTreeItem::ui_dropFunction()
{
// Ask user
int answer = utils::questionDialog(treeWidget(),"Drop","Function",QtUtils::toQString(_function.name()));
int answer = utils::questionDialog(treeWidget(), "Drop", "Function", QtUtils::toQString(_function.name()));
if (answer != QMessageBox::Yes)
return;
@@ -12,7 +12,7 @@ namespace Robomongo
Q_OBJECT
public:
typedef ExplorerTreeItem BaseClass;
ExplorerFunctionTreeItem(QTreeWidgetItem *parent,MongoDatabase *database, const MongoFunction &function);
ExplorerFunctionTreeItem(QTreeWidgetItem *parent, MongoDatabase *database, const MongoFunction &function);
MongoFunction function() const { return _function; }
MongoDatabase *database() const { return _database; }
@@ -19,7 +19,7 @@
namespace
{
void openCurrentServerShell(Robomongo::MongoServer *const server,const QString &script, bool execute = true, const Robomongo::CursorPosition &cursor = Robomongo::CursorPosition())
void openCurrentServerShell(Robomongo::MongoServer *const server, const QString &script, bool execute = true, const Robomongo::CursorPosition &cursor = Robomongo::CursorPosition())
{
Robomongo::AppRegistry::instance().app()->openShell(server, script, std::string(), execute, Robomongo::QtUtils::toQString(server->connectionRecord()->getReadableName()), cursor);
}
@@ -27,7 +27,7 @@ namespace
namespace Robomongo
{
ExplorerServerTreeItem::ExplorerServerTreeItem(QTreeWidget *view,MongoServer *const server) : BaseClass(view),
ExplorerServerTreeItem::ExplorerServerTreeItem(QTreeWidget *view, MongoServer *const server) : BaseClass(view),
_server(server),
_bus(AppRegistry::instance().bus())
{
@@ -102,12 +102,12 @@ namespace Robomongo
MongoDatabase *database = dbs.at(i);
if (database->isSystem()) {
ExplorerDatabaseTreeItem *dbItem = new ExplorerDatabaseTreeItem(systemFolder,database);
ExplorerDatabaseTreeItem *dbItem = new ExplorerDatabaseTreeItem(systemFolder, database);
systemFolder->addChild(dbItem);
continue;
}
ExplorerDatabaseTreeItem *dbItem = new ExplorerDatabaseTreeItem(this,database);
ExplorerDatabaseTreeItem *dbItem = new ExplorerDatabaseTreeItem(this, database);
addChild(dbItem);
}
@@ -160,27 +160,27 @@ namespace Robomongo
void ExplorerServerTreeItem::ui_serverHostInfo()
{
openCurrentServerShell(_server,"db.hostInfo()");
openCurrentServerShell(_server, "db.hostInfo()");
}
void ExplorerServerTreeItem::ui_serverStatus()
{
openCurrentServerShell(_server,"db.serverStatus()");
openCurrentServerShell(_server, "db.serverStatus()");
}
void ExplorerServerTreeItem::ui_serverVersion()
{
openCurrentServerShell(_server,"db.version()");
openCurrentServerShell(_server, "db.version()");
}
void ExplorerServerTreeItem::ui_showLog()
{
openCurrentServerShell(_server,"show log");
openCurrentServerShell(_server, "show log");
}
void ExplorerServerTreeItem::ui_openShell()
{
openCurrentServerShell(_server,"");
openCurrentServerShell(_server, "");
}
void ExplorerServerTreeItem::ui_disconnectServer()
@@ -18,7 +18,7 @@ namespace Robomongo
/*
** Constructs ExplorerServerTreeItem
*/
ExplorerServerTreeItem(QTreeWidget *view,MongoServer *const server);
ExplorerServerTreeItem(QTreeWidget *view, MongoServer *const server);
/*
** Expand server tree item;
@@ -7,13 +7,13 @@
namespace Robomongo
{
ExplorerTreeItem::ExplorerTreeItem(QTreeWidgetItem *parent)
:QObject(),BaseClass(parent),_contextMenu(new QMenu(treeWidget()) )
:QObject(), BaseClass(parent), _contextMenu(new QMenu(treeWidget()) )
{
}
ExplorerTreeItem::ExplorerTreeItem(QTreeWidget *view)
:QObject(view),BaseClass(view),_contextMenu(new QMenu(view) )
:QObject(view), BaseClass(view), _contextMenu(new QMenu(view) )
{
}
@@ -22,16 +22,16 @@ namespace
std::string buildToolTip(const Robomongo::MongoUser &user)
{
char buff[2048]={0};
sprintf(buff,tooltipTemplate,user.name().c_str(),user.id().toString().c_str());
char buff[2048] = {0};
sprintf(buff, tooltipTemplate, user.name().c_str(), user.id().toString().c_str());
return buff;
}
}
namespace Robomongo
{
ExplorerUserTreeItem::ExplorerUserTreeItem(QTreeWidgetItem *parent,MongoDatabase *const database, const MongoUser &user) :
BaseClass(parent),_user(user),_database(database)
ExplorerUserTreeItem::ExplorerUserTreeItem(QTreeWidgetItem *parent, MongoDatabase *const database, const MongoUser &user) :
BaseClass(parent), _user(user), _database(database)
{
QAction *dropUser = new QAction("Drop User", this);
VERIFY(connect(dropUser, SIGNAL(triggered()), SLOT(ui_dropUser())));
@@ -52,7 +52,7 @@ namespace Robomongo
void ExplorerUserTreeItem::ui_dropUser()
{
// Ask user
int answer = utils::questionDialog(treeWidget(),"Drop","User",QtUtils::toQString(_user.name()));
int answer = utils::questionDialog(treeWidget(), "Drop", "User", QtUtils::toQString(_user.name()));
if (answer == QMessageBox::Yes) {
_database->dropUser(_user.id());
@@ -12,7 +12,7 @@ namespace Robomongo
Q_OBJECT
public:
typedef ExplorerTreeItem BaseClass;
ExplorerUserTreeItem(QTreeWidgetItem *parent,MongoDatabase *const database, const MongoUser &user);
ExplorerUserTreeItem(QTreeWidgetItem *parent, MongoDatabase *const database, const MongoUser &user);
private Q_SLOTS:
void ui_dropUser();
@@ -89,9 +89,13 @@ namespace Robomongo
void ExplorerWidget::handle(ConnectionEstablishedEvent *event)
{
// Do not make UI changes for non PRIMARY connections
if (event->connectionType != ConnectionPrimary)
return;
decreaseProgress();
ExplorerServerTreeItem *item = new ExplorerServerTreeItem(_treeWidget,event->server);
ExplorerServerTreeItem *item = new ExplorerServerTreeItem(_treeWidget, event->server);
_treeWidget->addTopLevelItem(item);
_treeWidget->setCurrentItem(item);
_treeWidget->setFocus();
@@ -48,12 +48,12 @@ namespace Robomongo
QModelIndex BsonTableModelProxy::sibling(int row, int column, const QModelIndex &idx) const
{
return BaseClass::sibling(row,0,idx);
return BaseClass::sibling(row, 0, idx);
}
QModelIndex BsonTableModelProxy::index( int row, int col, const QModelIndex& parent ) const
{
BsonTreeItem *node = QtUtils::item<BsonTreeItem *>(sourceModel()->index(row,0,parent));
BsonTreeItem *node = QtUtils::item<BsonTreeItem *>(sourceModel()->index(row, 0, parent));
if (!node || _columns.size() <= col)
return QModelIndex();
@@ -85,12 +85,12 @@ namespace Robomongo
void BsonTableModelProxy::setSourceModel( QAbstractItemModel* model )
{
if (model) {
BsonTreeItem *child = QtUtils::item<BsonTreeItem *>(model->index(0,0));
BsonTreeItem *child = QtUtils::item<BsonTreeItem *>(model->index(0, 0));
if (child) {
_root = qobject_cast<BsonTreeItem *>(child->parent());
if (_root) {
int count = _root->childrenCount();
for (int i=0; i < count; ++i) {
for (int i = 0; i < count; ++i) {
BsonTreeItem *child = _root->child(i);
int countc = child->childrenCount();
for (int j = 0; j < countc; ++j) {
@@ -121,7 +121,7 @@ namespace Robomongo
if (role == Qt::DisplayRole || role == Qt::ToolTipRole) {
bool isCut = node->type() == mongo::String || node->type() == mongo::Code || node->type() == mongo::CodeWScope;
if (role == Qt::ToolTipRole){
if (role == Qt::ToolTipRole) {
result = isCut ? node->value() : node->value().left(500);
}
else{
@@ -18,10 +18,10 @@ namespace Robomongo
explicit BsonTableModelProxy(QObject *parent = 0);
QVariant data(const QModelIndex &index, int role) const;
int rowCount(const QModelIndex &parent=QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent) const;
QVariant headerData(int section,Qt::Orientation orientation, int role=Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
QModelIndex index( int row, int col, const QModelIndex& index ) const;
virtual QModelIndex mapFromSource( const QModelIndex & sourceIndex ) const;
virtual QModelIndex mapToSource( const QModelIndex &proxyIndex ) const;
@@ -12,7 +12,7 @@
namespace Robomongo
{
BsonTableView::BsonTableView(MongoShell *shell, const MongoQueryInfo &queryInfo, QWidget *parent)
:BaseClass(parent),_notifier(this,shell,queryInfo)
:BaseClass(parent), _notifier(this, shell, queryInfo)
{
#if defined(Q_OS_MAC)
setAttribute(Qt::WA_MacShowFocusRect, false);
@@ -68,7 +68,7 @@ namespace Robomongo
QModelIndex selectedInd = selectedIndex();
BsonTreeItem *documentItem = QtUtils::item<BsonTreeItem*>(selectedInd);
QMenu menu(this);
_notifier.initMenu(&menu,documentItem);
_notifier.initMenu(&menu, documentItem);
menu.exec(menuPoint);
}
}
@@ -21,9 +21,9 @@ namespace
const Robomongo::BsonTreeItem *findSuperRoot(const Robomongo::BsonTreeItem *const item)
{
Robomongo::BsonTreeItem *parent = qobject_cast<Robomongo::BsonTreeItem *>(item->parent());
if(parent){
if (parent) {
Robomongo::BsonTreeItem *grParent = qobject_cast<Robomongo::BsonTreeItem *>(parent->parent());
if(grParent){
if (grParent) {
return findSuperRoot(parent);
}
}
@@ -77,7 +77,7 @@ namespace Robomongo
BsonTreeItem* BsonTreeItem::childByKey(const QString &val)
{
for (unsigned i=0; i < _items.size(); ++i) {
for (unsigned i = 0; i < _items.size(); ++i) {
if (_items[i]->key() == val) {
return _items[i];
}
@@ -102,7 +102,7 @@ namespace Robomongo
int BsonTreeItem::indexOf(BsonTreeItem *item) const
{
for (unsigned i=0; i < _items.size(); ++i) {
for (unsigned i = 0; i < _items.size(); ++i) {
if (item == _items[i]) {
return i;
}
@@ -152,6 +152,6 @@ namespace Robomongo
void BsonTreeItem::removeChild(BsonTreeItem *item)
{
_items.erase(std::remove_if(_items.begin(), _items.end(), removeIfFound(item)),_items.end());
_items.erase(std::remove_if(_items.begin(), _items.end(), removeIfFound(item)), _items.end());
}
}
@@ -49,6 +49,9 @@ namespace Robomongo
mongo::BSONObj root() const;
mongo::BSONObj superRoot() const;
std::string fieldName() const { return _fieldName; };
void setFieldName(const std::string &fieldName) { _fieldName = fieldName; };
QString key() const;
void setKey(const QString &key);
@@ -66,5 +69,6 @@ namespace Robomongo
const mongo::BSONObj _root;
ChildContainerType _items;
BsonItemFields _fields;
std::string _fieldName;
};
}
@@ -30,13 +30,16 @@ namespace
{
mongo::BSONElement element = iterator.next();
BsonTreeItem *childItemInner = new BsonTreeItem(doc, root);
QString fieldName = QtUtils::toQString(std::string(element.fieldName()));
childItemInner->setKey(fieldName);
std::string fieldName = std::string(element.fieldName());
childItemInner->setFieldName(fieldName);
QString uiFieldName = QtUtils::toQString(fieldName);
childItemInner->setKey(uiFieldName);
if (isArray) {
// When we iterate array, show field names in square brackets
// In this case field names are numeric, starting from 0.
childItemInner->setKey("[" + fieldName + "]");
childItemInner->setKey("[" + uiFieldName + "]");
}
if (BsonUtils::isArray(element)) {
@@ -98,7 +101,7 @@ namespace Robomongo
{
BsonTreeItem *node = QtUtils::item<BsonTreeItem*>(parent);
if (node) {
mongo::BSONElement elem = BsonUtils::indexOf(node->root(),parent.row());
mongo::BSONElement elem = BsonUtils::indexOf(node->root(), parent.row());
if (!elem.isNull() && elem.isABSONObj()) {
parseDocument(node, elem.Obj(), elem.type() == mongo::Array);
}
@@ -162,11 +165,11 @@ namespace Robomongo
int col = index.column();
if(role == Qt::DecorationRole && col == BsonTreeItem::eKey ){
if (role == Qt::DecorationRole && col == BsonTreeItem::eKey ) {
return getIcon(node);
}
if(role == Qt::TextColorRole && col == BsonTreeItem::eType){
if (role == Qt::TextColorRole && col == BsonTreeItem::eType) {
return QColor(Qt::gray);
}
@@ -178,7 +181,7 @@ namespace Robomongo
}
else if (col == BsonTreeItem::eValue) {
bool isCut = node->type() == mongo::String || node->type() == mongo::Code || node->type() == mongo::CodeWScope;
if (role == Qt::ToolTipRole){
if (role == Qt::ToolTipRole) {
result = isCut ? node->value().left(500) : node->value();
}
else{
@@ -186,7 +189,7 @@ namespace Robomongo
}
}
else if (col == BsonTreeItem::eType) {
result = BsonUtils::BSONTypeToString(node->type(),node->binType(),AppRegistry::instance().settingsManager()->uuidEncoding());
result = BsonUtils::BSONTypeToString(node->type(), node->binType(), AppRegistry::instance().settingsManager()->uuidEncoding());
}
}
@@ -204,7 +207,7 @@ namespace Robomongo
int BsonTreeModel::rowCount(const QModelIndex &parent) const
{
const BsonTreeItem *parentItem=NULL;
const BsonTreeItem *parentItem = NULL;
if (parent.isValid())
parentItem = QtUtils::item<BsonTreeItem*>(parent);
else
@@ -235,7 +238,7 @@ namespace Robomongo
}
}
return BaseClass::headerData(section,orientation,role);
return BaseClass::headerData(section, orientation, role);
}
QModelIndex BsonTreeModel::parent(const QModelIndex& index) const
@@ -244,10 +247,10 @@ namespace Robomongo
if (index.isValid()) {
BsonTreeItem *const childItem = QtUtils::item<BsonTreeItem*const>(index);
BsonTreeItem *const parentItem = static_cast<BsonTreeItem*const>(childItem->parent());
if (parentItem && parentItem!=_root) {
if (parentItem && parentItem != _root) {
BsonTreeItem *const grandParent = static_cast<BsonTreeItem*const>(parentItem->parent());
int row = grandParent->indexOf(parentItem);
result= createIndex(row, 0, parentItem);
result = createIndex(row, 0, parentItem);
}
}
return result;
@@ -257,7 +260,7 @@ namespace Robomongo
{
QModelIndex index;
if (hasIndex(row, column, parent)) {
const BsonTreeItem * parentItem=NULL;
const BsonTreeItem * parentItem = NULL;
if (!parent.isValid()) {
parentItem = _root;
} else {
@@ -274,9 +277,9 @@ namespace Robomongo
void BsonTreeModel::insertItem(BsonTreeItem *parent, BsonTreeItem *children)
{
QModelIndex index = createIndex(0,0,parent);
QModelIndex index = createIndex(0, 0, parent);
unsigned child_count = parent->childrenCount();
beginInsertRows(index,child_count,child_count);
beginInsertRows(index, child_count, child_count);
parent->addChild(children);
endInsertRows();
}
@@ -14,15 +14,15 @@ namespace Robomongo
public:
typedef QAbstractItemModel BaseClass;
static const QIcon &getIcon(BsonTreeItem *item);
explicit BsonTreeModel(const std::vector<MongoDocumentPtr> &documents,QObject *parent = 0);
explicit BsonTreeModel(const std::vector<MongoDocumentPtr> &documents, QObject *parent = 0);
QVariant data(const QModelIndex &index, int role) const;
int rowCount(const QModelIndex &parent=QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent) const;
QVariant headerData(int section,Qt::Orientation orientation, int role=Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
virtual QModelIndex index(int row, int column, const QModelIndex &parent= QModelIndex()) const;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
virtual QModelIndex parent(const QModelIndex& index) const;
void insertItem(BsonTreeItem *parent, BsonTreeItem *children);
@@ -13,7 +13,7 @@
namespace Robomongo
{
BsonTreeView::BsonTreeView(MongoShell *shell, const MongoQueryInfo &queryInfo, QWidget *parent)
: BaseClass(parent),_notifier(this,shell,queryInfo)
: BaseClass(parent), _notifier(this, shell, queryInfo)
{
#if defined(Q_OS_MAC)
setAttribute(Qt::WA_MacShowFocusRect, false);
@@ -70,7 +70,7 @@ namespace Robomongo
}
}
_notifier.initMenu(&menu,documentItem);
_notifier.initMenu(&menu, documentItem);
menu.exec(menuPoint);
}
}
@@ -137,7 +137,7 @@ namespace Robomongo
{
QModelIndexList indexes = selectedIndexes();
if (detail::isMultiSelection(indexes)) {
for (int i=0; i<indexes.count(); ++i)
for (int i = 0; i<indexes.count(); ++i)
expandNode(indexes[i]);
} else {
expandNode(selectedIndex());
@@ -148,7 +148,7 @@ namespace Robomongo
{
QModelIndexList indexes = selectedIndexes();
if (detail::isMultiSelection(indexes)) {
for (int i=0; i<indexes.count(); ++i)
for (int i = 0; i<indexes.count(); ++i)
collapseNode(indexes[i]);
} else {
collapseNode(selectedIndex());

Some files were not shown because too many files have changed in this diff Show More