From 58fc9c0bcdd76a977445837673ea507772c00ac8 Mon Sep 17 00:00:00 2001 From: kwrodarmer Date: Mon, 6 Mar 2017 14:28:20 -0500 Subject: [PATCH 01/23] change log for 2.8.2 --- CHANGES.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index e30b7837..9f02e9e3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,36 @@ # NCBI External Developer Release: +## SRA Toolkit 2.8.2 +**March 6, 2017** + + **blast**: Updated blast library to be able to process runs having empty rows + **blast, build**: removed library dependencies that were preventing users from launching these tools + **blast, sra-tools**: Prepared completely static build of blast tools for windows with HTTPS support + **build**: **bam-load**: changed memcpy to memmove when regions overlap - seems to corrupt data on centos7 + **build**: Added ability to specify ncbi-vdb/configure --with-magic-prefix. Look for libraries in (lib lib64) when running "configure --with-...-prefix" + **build**: configure detects location of ngs libraries + **build**: configure was fixed to skip options unrecognized by gcc 4.4.7 + **build**: created sra-toolkit Debian package + **build**: fixed a bug in 'configure' when in could not find source files in repository saved with non-standard name + **build, ncbi-vdb, sra-tools**: installation will back up old configuration files if they differ from the ones being installed + **cg-load**: added loading of CG File format v2.4 + **kns**: SRA tools respect standard set of environment variables for proxy specification + **kns**: updated mbedtls library to version 2.4.1 + **ncbi-vdb, ngs, ngs-tools, sra-tools**: eliminated memcpy from sources due to potential for overlap + **ngs, sra-search**: now supports search on reference + **ngs-tools**: updated the NCBI download page to incorporate ngs versions into 3rd party package names + **prefetch**: Fixed error message "path excessive while opening directory" when prefetch is trying to get vdbcache + **prefetch**: Fixed regression in prefetch-2.8.1 when downloading dbGaP files via HTTP + **prefetch**: Fixed regression in prefetch-2.8.1 when downloading vdbcache files from dbGaP via HTTP + **sam-dump**: consistency of sam-dump in fastq-mod improved + **sam-dump**: consistency of sam-dump in fastq-mode improved + **sra-stat**: sra-stat does XML-escaping when printing spot-groups + **test-sra**: extended test-sra to debug user problems with https connections to NCBI + **test-sra**: test-sra print amount of available disk space in user repositories + **vdb-config**: vdb-config correctly works when there is non-canonical path in configuration + + ## SRA Toolkit 2.8.1-2 **January 19, 2017** From fdd9971703d61e64fc78ba946ed984d6d9796b94 Mon Sep 17 00:00:00 2001 From: "durbrowk@ncbi.nlm.nih.gov" Date: Tue, 7 Mar 2017 14:43:57 -0500 Subject: [PATCH 02/23] initialized variable --- tools/bam-loader/loader-imp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/bam-loader/loader-imp.c b/tools/bam-loader/loader-imp.c index f81ea7ce..b78a6358 100644 --- a/tools/bam-loader/loader-imp.c +++ b/tools/bam-loader/loader-imp.c @@ -1650,7 +1650,7 @@ static rc_t ProcessBAM(char const bamFile[], context_t *ctx, VDatabase *db, uint16_t flags; int64_t rpos=0; char *seqDNA; - const BAMRefSeq *refSeq; + const BAMRefSeq *refSeq = NULL; ctx_value_t *value; bool wasInserted; int32_t refSeqId=-1; From c79570e7fedb15bbd88ddd8031bf2dd8a9329e95 Mon Sep 17 00:00:00 2001 From: klymenko Date: Fri, 10 Mar 2017 10:17:51 -0500 Subject: [PATCH 03/23] VDB-3272: do not return error when KConfig_Get_Default_User_Path fails --- tools/vdb-config/vdb-config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/vdb-config/vdb-config.c b/tools/vdb-config/vdb-config.c index f4b9e562..cec49c0e 100644 --- a/tools/vdb-config/vdb-config.c +++ b/tools/vdb-config/vdb-config.c @@ -1672,6 +1672,8 @@ rc_t CC KMain(int argc, char* argv[]) { } } } + else + rc = 0; } RELEASE ( KDirectory, d ); From bf6c6caba20427d0bffdbef4fad4a2dbd8bf7705 Mon Sep 17 00:00:00 2001 From: klymenko Date: Fri, 10 Mar 2017 10:17:51 -0500 Subject: [PATCH 04/23] VDB-3272, VDB-3327: do not return error when KConfig_Get_Default_User_Path fails --- tools/vdb-config/vdb-config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/vdb-config/vdb-config.c b/tools/vdb-config/vdb-config.c index f4b9e562..cec49c0e 100644 --- a/tools/vdb-config/vdb-config.c +++ b/tools/vdb-config/vdb-config.c @@ -1672,6 +1672,8 @@ rc_t CC KMain(int argc, char* argv[]) { } } } + else + rc = 0; } RELEASE ( KDirectory, d ); From a5490719365bea9c74424192596f4c4a1069f6fc Mon Sep 17 00:00:00 2001 From: klymenko Date: Fri, 10 Mar 2017 12:10:49 -0500 Subject: [PATCH 05/23] VDB-3327: added test to check vdb-config failure when /repository/user/default-path is not found --- test/Makefile | 1 + test/vdb-config/Makefile | 35 +++++++++++++++++++++++++++++++++++ test/vdb-config/test-vdb-config.pl | 12 ++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 test/vdb-config/Makefile create mode 100755 test/vdb-config/test-vdb-config.pl diff --git a/test/Makefile b/test/Makefile index 9f6464b2..ae67bbea 100644 --- a/test/Makefile +++ b/test/Makefile @@ -35,6 +35,7 @@ include $(TOP)/build/Makefile.config # default # SUBDIRS = \ + vdb-config \ fastq-loader \ vcf-loader \ kget \ diff --git a/test/vdb-config/Makefile b/test/vdb-config/Makefile new file mode 100644 index 00000000..7813982a --- /dev/null +++ b/test/vdb-config/Makefile @@ -0,0 +1,35 @@ +# =========================================================================== +# +# PUBLIC DOMAIN NOTICE +# National Center for Biotechnology Information +# +# This software/database is a "United States Government Work" under the +# terms of the United States Copyright Act. It was written as part of +# the author's official duties as a United States Government employee and +# thus cannot be copyrighted. This software/database is freely available +# to the public for use. The National Library of Medicine and the U.S. +# Government have not placed any restriction on its use or reproduction. +# +# Although all reasonable efforts have been taken to ensure the accuracy +# and reliability of the software and data, the NLM and the U.S. +# Government do not and cannot warrant the performance or results that +# may be obtained by using this software or data. The NLM and the U.S. +# Government disclaim all warranties, express or implied, including +# warranties of performance, merchantability or fitness for any particular +# purpose. +# +# Please cite the author in any work or product based on this material. +# +# =========================================================================== + +default: runtests + +TOP ?= $(abspath ../..) +include $(TOP)/build/Makefile.env # BINDIR + +runtests: test-vdb-config + +test-vdb-config: + @ printf "Testing exit code vdb-config of vdb-config... " + @ PATH=$(BINDIR):$(PATH) ; ./test-vdb-config.pl + @ echo OK diff --git a/test/vdb-config/test-vdb-config.pl b/test/vdb-config/test-vdb-config.pl new file mode 100755 index 00000000..542a5b02 --- /dev/null +++ b/test/vdb-config/test-vdb-config.pl @@ -0,0 +1,12 @@ +#!/usr/bin/perl -w + +use strict; + +use File::Temp "tempdir"; + +my $tmp = tempdir ( "phgvXXXX", CLEANUP => 1 ); +$ENV{VDB_CONFIG}=$tmp; +$ENV{NCBI_SETTINGS}="$tmp/u.mkfg"; + +`vdb-config -s foo=bar`; +die "vdb-config exited with " . ( $? >> 8 ) if ( $? ); From 46953fc35d2da0e831f10db0dd852f50cbb2ad58 Mon Sep 17 00:00:00 2001 From: "durbrowk@ncbi.nlm.nih.gov" Date: Mon, 13 Mar 2017 10:50:58 -0400 Subject: [PATCH 06/23] previously uninitialized variable hid a scope bug --- tools/bam-loader/loader-imp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/bam-loader/loader-imp.c b/tools/bam-loader/loader-imp.c index b78a6358..dc5cdba1 100644 --- a/tools/bam-loader/loader-imp.c +++ b/tools/bam-loader/loader-imp.c @@ -1548,6 +1548,7 @@ static rc_t ProcessBAM(char const bamFile[], context_t *ctx, VDatabase *db, KDataBuffer fragBuf; KDataBuffer cigBuf; rc_t rc; + const BAMRefSeq *refSeq = NULL; int32_t lastRefSeqId = -1; bool wasRenamed = false; size_t rsize; @@ -1650,7 +1651,6 @@ static rc_t ProcessBAM(char const bamFile[], context_t *ctx, VDatabase *db, uint16_t flags; int64_t rpos=0; char *seqDNA; - const BAMRefSeq *refSeq = NULL; ctx_value_t *value; bool wasInserted; int32_t refSeqId=-1; From 6650c16c550f4c96c389b0fb88026cbad58d5b52 Mon Sep 17 00:00:00 2001 From: "durbrowk@ncbi.nlm.nih.gov" Date: Mon, 13 Mar 2017 11:30:01 -0400 Subject: [PATCH 07/23] changed text --- tools/sra-dump/fastq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/sra-dump/fastq.c b/tools/sra-dump/fastq.c index 868443f9..0ee34956 100644 --- a/tools/sra-dump/fastq.c +++ b/tools/sra-dump/fastq.c @@ -3694,7 +3694,7 @@ rc_t SRADumper_Init( SRADumperFmt* fmt ) /* DO NOT ADD IN THE MIDDLE ORDER IS IMPORTANT IN USAGE FUNCTION ABOVE!!! */ {NULL, "split-spot", NULL, {"Split spots into individual reads", NULL}}, /* H_splip_sot = 0 */ - {"W", "clip", NULL, {"Clip adapter sequences", NULL}}, /* H_clip = 1 */ + {"W", "clip", NULL, {"Remove adapter sequences from reads", NULL}}, /* H_clip = 1 */ {"M", "minReadLen", "len", {"Filter by sequence length >= ", NULL}}, /* H_minReadLen = 2 */ {"E", "qual-filter", NULL, {"Filter used in early 1000 Genomes data:", /* H_qual_filter = 3 */ From 1363078ccf17ade2437cbc122b90ef7267d3eedd Mon Sep 17 00:00:00 2001 From: aboshkin Date: Tue, 14 Mar 2017 13:34:20 -0400 Subject: [PATCH 08/23] VDB-3314 make targets runtests/slowtests now depend on 'all' --- build/Makefile.env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/Makefile.env b/build/Makefile.env index 46cc5f53..9b5f2064 100644 --- a/build/Makefile.env +++ b/build/Makefile.env @@ -200,7 +200,7 @@ endif .PHONY: stdclean removelinks makedirs vers-includes rebuild-dirlinks .PHONY: stdjclean makejdirs -# configuration targets +# configuration targets out: @ echo $(OUTDIR) > $(TOP)/build/OUTDIR.$(BUILD_OS) @ $(MAKE) TOP=$(TOP) -f $(TOP)/build/Makefile.env rebuild-dirlinks @@ -362,11 +362,11 @@ LDFLAGS = $(DBG) $(PROF) $(CARCH) $(MIN_DEPLOY_OS_OPT) $(LDPATHS) #------------------------------------------------------------------------------- # runtests -# +# # MallocScribble=1 is for catching allocation problems on Mac # ifeq ($(RUNTESTS_OVERRIDE),) -runtests: std $(TEST_TOOLS) +runtests: all $(TEST_TOOLS) @ export VDB_CONFIG=$(VDB_CONFIG);export LD_LIBRARY_PATH=$(LIBDIR):$$LD_LIBRARY_PATH;export MallocScribble=1;\ for i in $(TEST_TOOLS);\ do\ @@ -380,11 +380,11 @@ endif #------------------------------------------------------------------------------- # slowtests -# +# # $(SLOWTESTSDATADIR) should be used to create temporary test files SLOWTESTSDATADIR ?= /panfs/pan1.be-md.ncbi.nlm.nih.gov/sra-test/slowtests/$(shell whoami) -slowtests: std $(SLOW_TEST_TOOLS) +slowtests: all $(SLOW_TEST_TOOLS) @ export LD_LIBRARY_PATH=$(LIBDIR):$$LD_LIBRARY_PATH;\ for i in $(SLOW_TEST_TOOLS);\ do\ From 53f931c2ee317d9ef6377ad915d77e5fc342269f Mon Sep 17 00:00:00 2001 From: aboshkin Date: Tue, 14 Mar 2017 14:19:48 -0400 Subject: [PATCH 09/23] VDB-3314 make targets runtests/slowtests now depend on 'all', additional fix --- test/vdb-dump/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/vdb-dump/Makefile b/test/vdb-dump/Makefile index 5449f2c5..9bcca8b5 100644 --- a/test/vdb-dump/Makefile +++ b/test/vdb-dump/Makefile @@ -53,6 +53,14 @@ $(ALL_TOOLS): makedirs .PHONY: all std $(ALL_TOOLS) #------------------------------------------------------------------------------- +# all +# +$(TARGDIR)/all: \ + $(addprefix $(BINDIR)/,$(ALL_TOOLS)) + +.PHONY: $(TARGDIR)/all + +#------------------------------------------------------------------------------- # std # $(TARGDIR)/std: \ From 5bc31d8615d51b30e3318e09f009ad004da7ed6d Mon Sep 17 00:00:00 2001 From: klymenko Date: Thu, 16 Mar 2017 11:26:52 -0400 Subject: [PATCH 10/23] VDB-3175: print free disk space as long unsigned --- tools/util/test-sra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/util/test-sra.c b/tools/util/test-sra.c index c61ea626..09f2bd57 100644 --- a/tools/util/test-sra.c +++ b/tools/util/test-sra.c @@ -3438,11 +3438,11 @@ static rc_t MainFreeSpace ( const Main * self, const KDirectory * dir ) { if ( self -> xml ) OUTMSG ( ( - " \n", + " \n", free_bytes_available, total_number_of_bytes ) ); else OUTMSG ( ( - " Space free=\"%d\" total=\"%d\" units=\"KBytes\"\n", + " Space free=\"%lu\" total=\"%lu\" units=\"KBytes\"\n", free_bytes_available, total_number_of_bytes ) ); return rc; From 028b8109a0a3861a903d38e4f5d986bed23e3510 Mon Sep 17 00:00:00 2001 From: ksrodarmer Date: Wed, 22 Mar 2017 12:56:29 -0400 Subject: [PATCH 11/23] Initial commit --- tools/vdb-config/sra-config/main.cpp | 44 ++++++++ tools/vdb-config/sra-config/sra-config.pro | 29 +++++ tools/vdb-config/sra-config/sraconfig.cpp | 172 +++++++++++++++++++++++++++++ tools/vdb-config/sra-config/sraconfig.h | 72 ++++++++++++ 4 files changed, 317 insertions(+) create mode 100644 tools/vdb-config/sra-config/main.cpp create mode 100644 tools/vdb-config/sra-config/sra-config.pro create mode 100644 tools/vdb-config/sra-config/sraconfig.cpp create mode 100644 tools/vdb-config/sra-config/sraconfig.h diff --git a/tools/vdb-config/sra-config/main.cpp b/tools/vdb-config/sra-config/main.cpp new file mode 100644 index 00000000..0a552642 --- /dev/null +++ b/tools/vdb-config/sra-config/main.cpp @@ -0,0 +1,44 @@ +/*=========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +*/ + +#include "sraconfig.h" + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication app ( argc, argv ); + + const QRect avail_geometry = QApplication :: desktop () -> availableGeometry ( QPoint ( 0, 0 ) ); + + SRAConfig config_window ( avail_geometry ); + + config_window . show (); + + return app . exec (); +} diff --git a/tools/vdb-config/sra-config/sra-config.pro b/tools/vdb-config/sra-config/sra-config.pro new file mode 100644 index 00000000..b3b7f9c9 --- /dev/null +++ b/tools/vdb-config/sra-config/sra-config.pro @@ -0,0 +1,29 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2017-03-22T11:17:53 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = sra-config +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + + +SOURCES += main.cpp\ + sraconfig.cpp + +HEADERS += sraconfig.h diff --git a/tools/vdb-config/sra-config/sraconfig.cpp b/tools/vdb-config/sra-config/sraconfig.cpp new file mode 100644 index 00000000..e051b719 --- /dev/null +++ b/tools/vdb-config/sra-config/sraconfig.cpp @@ -0,0 +1,172 @@ +/*=========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +*/ + +#include "sraconfig.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +SRAConfig :: SRAConfig ( const QRect &avail_geometry, QWidget *parent ) + : QMainWindow ( parent ) + , screen_geometry ( avail_geometry ) + , main_layout ( new QVBoxLayout () ) +{ + main_layout -> setSpacing ( 20 ); + main_layout -> setAlignment ( Qt::AlignTop ); + main_layout -> addWidget ( setupOptionGroup () ); + main_layout -> addWidget ( setupRepositoriesGroup () ); + + setupButtonLayout (); + + QWidget *main_widget = new QWidget (); + main_widget -> setLayout ( main_layout ); + + setCentralWidget ( main_widget ); + + move ( ( screen_geometry . width () - ( this -> width () / 2 ) ) / 2, + ( screen_geometry . height () - this -> height () ) / 2 ); +} + +SRAConfig :: ~SRAConfig () +{ + +} + +QGroupBox * SRAConfig::setupOptionGroup () +{ + QGroupBox *group = new QGroupBox ( "Options" ); + group -> setFixedHeight ( 170 ); + + QGridLayout *layout = new QGridLayout (); + layout -> setAlignment ( Qt :: AlignTop ); + layout -> setSpacing ( 15 ); + + //1 + QCheckBox *c_box = new QCheckBox ( "Enable Remote Access" ); + c_box -> setAutoExclusive ( false ); + c_box -> setChecked ( true ); + layout -> addWidget ( c_box, 0, 0 ); + + //2 + c_box = new QCheckBox ( "Enable Local File Caching" ); + c_box -> setAutoExclusive ( false ); + layout -> addWidget ( c_box, 1, 0 ); + + //3 + c_box = new QCheckBox ( "Use Site Installation" ); + c_box -> setAutoExclusive ( false ); + layout -> addWidget ( c_box, 2, 0 ); + + //4 + c_box = new QCheckBox ( "Use Proxy" ); + c_box -> setAutoExclusive ( false ); + + proxy_path = new QLabel ( "proxy.ncbi.nlm.nih.gov:XXXX" ); + + QPalette p = proxy_path -> palette (); + p . setColor ( QPalette::Background, Qt::white ); + + proxy_path -> setPalette ( p ); + proxy_path -> setAutoFillBackground ( true ); + proxy_path -> setTextInteractionFlags ( Qt::TextEditorInteraction ); + proxy_path -> setFixedHeight ( 20 ); + + layout -> addWidget ( c_box, 3, 0 ); + layout -> addWidget ( proxy_path, 3, 1, 1, 2 ); + + //5 + c_box = new QCheckBox ( "Prioritize Environment Variable 'http-proxy'" ); + c_box -> setAutoExclusive ( false ); + layout -> addWidget ( c_box, 4, 0, 1, 2 ); + + group -> setLayout ( layout ); + + return group; +} + +QGroupBox * SRAConfig :: setupRepositoriesGroup () +{ + QGroupBox *group = new QGroupBox ( "Repositories" ); + + QGridLayout *layout = new QGridLayout (); + layout -> setAlignment ( Qt :: AlignTop ); + layout -> setSpacing ( 15 ); + + //1 + QLabel *label = new QLabel ( "Import Path" ); + layout -> addWidget ( label, 0, 0 ); + + import_path = new QLabel ( "/home/rodarme1/ncbi" ); + layout -> addWidget ( import_path, 0, 1, 1, 3 ); + + //2 + label = new QLabel ( "Public" ); + layout -> addWidget ( label, 1, 0 ); + + public_path = new QLabel ( "/home/rodarme1/ncbi/public" ); + + QPalette p = public_path -> palette (); + p . setColor ( QPalette::Background, Qt::white ); + + public_path -> setPalette ( p ); + public_path -> setAutoFillBackground ( true ); + public_path -> setTextInteractionFlags ( Qt::TextEditorInteraction ); + public_path -> setFixedHeight ( 20 ); + + layout -> addWidget ( public_path, 1, 1, 1, 3 ); + + //3 + QPushButton *import = new QPushButton ( "Import" ); + layout -> addWidget ( import, 2, 0 ); + + group -> setLayout ( layout ); + + return group; +} + +void SRAConfig :: setupButtonLayout () +{ + QHBoxLayout *layout = new QHBoxLayout (); + layout -> setAlignment ( Qt::AlignBottom | Qt::AlignRight ); + layout -> setSpacing ( 5 ); + + apply = new QPushButton ( "Apply" ); + cancel = new QPushButton ( "Cancel" ); + ok = new QPushButton ( "OK" ); + + layout -> addWidget ( apply ); + layout -> addWidget ( cancel ); + layout -> addWidget ( ok ); + + main_layout -> addLayout ( layout ); +} diff --git a/tools/vdb-config/sra-config/sraconfig.h b/tools/vdb-config/sra-config/sraconfig.h new file mode 100644 index 00000000..066aae16 --- /dev/null +++ b/tools/vdb-config/sra-config/sraconfig.h @@ -0,0 +1,72 @@ +/*=========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +*/ + +#ifndef SRACONFIG_H +#define SRACONFIG_H + +#include + +QT_BEGIN_NAMESPACE +class QHBoxLayout; +class QVBoxLayout; +class QGroupBox; +class QLabel; +class QPushButton; +QT_END_NAMESPACE + +class SRAConfig : public QMainWindow +{ + Q_OBJECT + +public: + SRAConfig ( const QRect &avail_geometry, QWidget *parent = 0 ); + ~SRAConfig (); + +private slots: + + //void openFileDialog (); + +private: + + QGroupBox* setupOptionGroup (); + QGroupBox* setupRepositoriesGroup (); + void setupButtonLayout (); + + QRect screen_geometry; + + QVBoxLayout *main_layout; + + QLabel *import_path; + QLabel *public_path; + QLabel *proxy_path; + + QPushButton *ok; + QPushButton *apply; + QPushButton *cancel; + +}; + +#endif // SRACONFIG_H From c166a6db7fcadd06cf8e316878310601be4ef4ef Mon Sep 17 00:00:00 2001 From: wraetz Date: Tue, 4 Apr 2017 16:46:17 -0400 Subject: [PATCH 12/23] added enumeration of static columns --- tools/vdb-dump/vdb-dump-coldefs.c | 74 +++++++++++++++++++++++++++++++++++++++ tools/vdb-dump/vdb-dump-coldefs.h | 2 ++ tools/vdb-dump/vdb-dump-context.c | 1 + tools/vdb-dump/vdb-dump-context.h | 2 ++ tools/vdb-dump/vdb-dump.c | 28 +++++++++++++++ 5 files changed, 107 insertions(+) diff --git a/tools/vdb-dump/vdb-dump-coldefs.c b/tools/vdb-dump/vdb-dump-coldefs.c index af221650..a6169f7e 100644 --- a/tools/vdb-dump/vdb-dump-coldefs.c +++ b/tools/vdb-dump/vdb-dump-coldefs.c @@ -844,3 +844,77 @@ rc_t vdcd_collect_spread( const struct num_gen * row_set, col_defs * cols, const } return rc; } + +static uint32_t same_values( const VCursor * curs, uint32_t col_idx, int64_t first, uint32_t test_rows ) +{ + uint32_t res = 0; + const void * base; + uint32_t elem_bits, boff, row_len; + rc_t rc = VCursorCellDataDirect( curs, first, col_idx, &elem_bits, &base, &boff, &row_len ); + while ( rc == 0 && res < test_rows && rc == 0 ) + { + const void * base_1; + uint32_t elem_bits_1, boff_1, row_len_1; + rc = VCursorCellDataDirect( curs, first + res + 1, col_idx, &elem_bits_1, &base_1, &boff_1, &row_len_1 ); + if ( rc == 0 ) + { + if ( elem_bits != elem_bits_1 ) return res; + if ( boff != boff_1 ) return res; + if ( row_len != row_len_1 ) return res; + if ( base != base_1 ) return res; + } + res += 1; + } + return res; +} + +static bool vdcd_is_static_column( const VTable *my_table, col_def * col ) +{ + bool res = false; + const VCursor * curs; + rc_t rc = VTableCreateCursorRead( my_table, &curs ); + if ( rc == 0 ) + { + uint32_t idx; + rc = VCursorAddColumn( curs, &idx, "%s", col->name ); + if ( rc == 0 ) + { + rc = VCursorOpen( curs ); + if ( rc == 0 ) + { + int64_t first; + uint64_t count; + rc = VCursorIdRange( curs, idx, &first, &count ); + if ( rc == 0 && count == 0 ) + { + res = ( same_values( curs, idx, first, 100 ) == 100 ); + } + } + } + VCursorRelease( curs ); + } + return res; +} + + +bool vdcd_extract_static_columns( col_defs* defs, const VTable *my_table, const size_t str_limit ) +{ + col_defs * temp_defs; + bool res = vdcd_init( &temp_defs, str_limit ); + if ( res ) + { + uint32_t count = vdcd_extract_from_table( temp_defs, my_table ); + uint32_t idx; + for ( idx = 0; idx < count; ++idx ) + { + col_def * col = VectorGet( &(temp_defs->cols), idx ); + if ( col != NULL ) + { + if ( vdcd_is_static_column( my_table, col ) ) + vdcd_append_col( defs, col->name ); + } + } + vdcd_destroy( temp_defs ); + } + return res; +} \ No newline at end of file diff --git a/tools/vdb-dump/vdb-dump-coldefs.h b/tools/vdb-dump/vdb-dump-coldefs.h index fb81d044..5c19bcf8 100644 --- a/tools/vdb-dump/vdb-dump-coldefs.h +++ b/tools/vdb-dump/vdb-dump-coldefs.h @@ -101,6 +101,8 @@ void vdcd_ins_trans_fkt( col_defs* defs, const VSchema *my_schema ); void vdcd_exclude_these_columns( col_defs* defs, const char* column_names ); bool vdcd_get_first_none_static_column_idx( col_defs* defs, const VCursor * cur, uint32_t * idx ); +bool vdcd_extract_static_columns( col_defs* defs, const VTable *my_table, const size_t str_limit ); + rc_t vdcd_collect_spread( const struct num_gen * row_set, col_defs * cols, const VCursor * cursor ); #ifdef __cplusplus diff --git a/tools/vdb-dump/vdb-dump-context.c b/tools/vdb-dump/vdb-dump-context.c index e3ac2d7b..bb0c0a1a 100644 --- a/tools/vdb-dump/vdb-dump-context.c +++ b/tools/vdb-dump/vdb-dump-context.c @@ -597,6 +597,7 @@ static void vdco_evaluate_options( const Args *my_args, ctx->show_blobbing = vdco_get_bool_option( my_args, OPTION_SHOW_BLOBBING, false ); ctx->enum_phys = vdco_get_bool_option( my_args, OPTION_ENUM_PHYS, false ); ctx->enum_readable = vdco_get_bool_option( my_args, OPTION_ENUM_READABLE, false ); + ctx->enum_static = vdco_get_bool_option( my_args, OPTION_ENUM_STATIC, false ); ctx->idx_enum_requested = vdco_get_bool_option( my_args, OPTION_IDX_ENUM, false ); ctx->disable_multithreading = vdco_get_bool_option( my_args, OPTION_NO_MULTITHREAD, false ); ctx->print_info = vdco_get_bool_option( my_args, OPTION_INFO, false ); diff --git a/tools/vdb-dump/vdb-dump-context.h b/tools/vdb-dump/vdb-dump-context.h index 2bd5d545..8edd9358 100644 --- a/tools/vdb-dump/vdb-dump-context.h +++ b/tools/vdb-dump/vdb-dump-context.h @@ -68,6 +68,7 @@ extern "C" { #define OPTION_SHOW_BLOBBING "blobbing" #define OPTION_ENUM_PHYS "phys" #define OPTION_ENUM_READABLE "readable" +#define OPTION_ENUM_STATIC "static" #define OPTION_IDX_ENUM "idx-report" #define OPTION_IDX_RANGE "idx-range" #define OPTION_CUR_CACHE "cur-cache" @@ -186,6 +187,7 @@ typedef struct dump_context bool show_blobbing; bool enum_phys; bool enum_readable; + bool enum_static; bool idx_enum_requested; bool idx_range_requested; bool disable_multithreading; diff --git a/tools/vdb-dump/vdb-dump.c b/tools/vdb-dump/vdb-dump.c index fe5eff4e..abac29fa 100644 --- a/tools/vdb-dump/vdb-dump.c +++ b/tools/vdb-dump/vdb-dump.c @@ -104,6 +104,7 @@ static const char * numelemsum_usage[] = { "sum element-count", static const char * show_blobbing_usage[] = { "show blobbing", NULL }; static const char * enum_phys_usage[] = { "enumerate physical columns", NULL }; static const char * enum_readable_usage[] = { "enumerate readable columns", NULL }; +static const char * enum_static_usage[] = { "enumerate static columns", NULL }; static const char * objtype_usage[] = { "report type of object", NULL }; static const char * idx_enum_usage[] = { "enumerate all available index", NULL }; static const char * idx_range_usage[] = { "enumerate values and row-ranges of one index", NULL }; @@ -149,6 +150,7 @@ OptDef DumpOptions[] = { OPTION_SHOW_BLOBBING, NULL, NULL, show_blobbing_usage, 1, false, false }, { OPTION_ENUM_PHYS, NULL, NULL, enum_phys_usage, 1, false, false }, { OPTION_ENUM_READABLE, NULL, NULL, enum_readable_usage, 1, false, false }, + { OPTION_ENUM_STATIC, NULL, NULL, enum_static_usage, 1, false, false }, { OPTION_OBJVER, ALIAS_OBJVER, NULL, objver_usage, 1, false, false }, { OPTION_OBJTS, NULL, NULL, objts_usage, 1, false, false }, { OPTION_OBJTYPE, ALIAS_OBJTYPE, NULL, objtype_usage, 1, false, false }, @@ -558,6 +560,24 @@ static bool vdm_extract_or_parse_phys_columns( const p_dump_context ctx, return res; } + +static bool vdm_extract_or_parse_static_columns( const p_dump_context ctx, + const VTable *my_table, + p_col_defs my_col_defs ) +{ + bool res = false; + if ( ctx != NULL && my_col_defs != NULL ) + { + /* the user does not know the column-names or wants all of them */ + res = vdcd_extract_static_columns( my_col_defs, my_table, ctx->max_line_len ); + + if ( ctx->excluded_columns != NULL ) + vdcd_exclude_these_columns( my_col_defs, ctx->excluded_columns ); + } + return res; + +} + /************************************************************************************* dump_tab_table: * called by "dump_db_table()" and "dump_tab()" as a fkt-pointer @@ -1299,6 +1319,7 @@ static rc_t vdm_enum_readable_columns( const VTable *my_table ) return rc; } + /************************************************************************************* enum_tab_columns: * called by "enum_db_columns()" and "dump_table()" as fkt-pointer @@ -1344,6 +1365,13 @@ static rc_t vdm_enum_tab_columns( const p_dump_context ctx, const VTable *my_tab rc = VTableOpenKTableRead( my_table, &ci_ctx.my_ktable ); DISP_RC( rc, "VTableOpenKTableRead() failed" ); } + if ( ctx->enum_static ) + { + extracted = vdm_extract_or_parse_static_columns( ctx, my_table, my_col_defs ); + rc = VTableOpenKTableRead( my_table, &ci_ctx.my_ktable ); + DISP_RC( rc, "VTableOpenKTableRead() failed" ); + + } else { extracted = vdm_extract_or_parse_columns( ctx, my_table, my_col_defs ); From cdbd3dbff239fffbb47d75b737cd4a967ec29fdb Mon Sep 17 00:00:00 2001 From: ksrodarmer Date: Wed, 5 Apr 2017 13:46:10 -0400 Subject: [PATCH 13/23] Adding a lot of code that will require a real ngc file to work. --- .../vdb-config/sra-config/images/general_icon.png | Bin 0 -> 28473 bytes tools/vdb-config/sra-config/main.cpp | 36 +- tools/vdb-config/sra-config/resources.qrc | 5 + tools/vdb-config/sra-config/sra-config.pro | 20 +- tools/vdb-config/sra-config/sraconfig.cpp | 661 +++++++++++++++++++-- tools/vdb-config/sra-config/sraconfig.h | 57 +- .../sra-tools-gui/interfaces/ktoolbaritem.h | 41 ++ .../vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp | 56 ++ tools/vdb-config/util.cpp | 2 +- tools/vdb-config/vdb-config-model.cpp | 1 + tools/vdb-config/vdb-config-model.hpp | 9 +- 11 files changed, 803 insertions(+), 85 deletions(-) create mode 100644 tools/vdb-config/sra-config/images/general_icon.png create mode 100644 tools/vdb-config/sra-config/resources.qrc create mode 100644 tools/vdb-config/sra-tools-gui/interfaces/ktoolbaritem.h create mode 100644 tools/vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp diff --git a/tools/vdb-config/sra-config/images/general_icon.png b/tools/vdb-config/sra-config/images/general_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ebc0dbc3e7f08e32c44205816db78a53a4d83783 GIT binary patch literal 28473 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
    |(HIV%tJq%~h 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 qmj + #include #include #include +#include -int main(int argc, char *argv[]) -{ - QApplication app ( argc, argv ); - - const QRect avail_geometry = QApplication :: desktop () -> availableGeometry ( QPoint ( 0, 0 ) ); +#include - SRAConfig config_window ( avail_geometry ); +static QApplication * app; +extern "C" +{ + rc_t run_interactive ( vdbconf_model &m ) + { + const QRect avail_geometry = QApplication :: desktop () -> availableGeometry ( QPoint ( 0, 0 ) ); + SRAConfig config_window ( m, avail_geometry ); + config_window . show (); + int status = app -> exec (); + if ( status != 0 ) + exit ( status ); + return 0; + } + } - config_window . show (); +int main(int argc, char *argv[]) +{ + QApplication a ( argc, argv ); + app = & a; - return app . exec (); + rc_t rc = configure ( eCfgModeVisual ); + return ( rc == 0 ) ? 0 : 3; } diff --git a/tools/vdb-config/sra-config/resources.qrc b/tools/vdb-config/sra-config/resources.qrc new file mode 100644 index 00000000..996cc2ea --- /dev/null +++ b/tools/vdb-config/sra-config/resources.qrc @@ -0,0 +1,5 @@ + + + images/general_icon.png + + diff --git a/tools/vdb-config/sra-config/sra-config.pro b/tools/vdb-config/sra-config/sra-config.pro index b3b7f9c9..089fa5d8 100644 --- a/tools/vdb-config/sra-config/sra-config.pro +++ b/tools/vdb-config/sra-config/sra-config.pro @@ -21,9 +21,25 @@ DEFINES += QT_DEPRECATED_WARNINGS # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +LIBS += -L/Users/rodarme1/ncbi-outdir/ncbi-vdb/mac/clang/x86_64/dbg/lib -lncbi-vdb +INCLUDEPATH += ../../../../ncbi-vdb/interfaces \ + ../../../../ncbi-vdb/interfaces/os/mac \ + ../../../../ncbi-vdb/interfaces/os/unix \ + ../../../../ncbi-vdb/interfaces/cc/gcc \ + ../../../../ncbi-vdb/interfaces/cc/gcc/x86_64 SOURCES += main.cpp\ - sraconfig.cpp + sraconfig.cpp \ + ../configure.cpp \ + ../vdb-config-model.cpp \ + ../util.cpp \ + ../sra-tools-gui/libs/ktoolbaritem.cpp + + +HEADERS += sraconfig.h \ + ../sra-tools-gui/interfaces/ktoolbaritem.h + +RESOURCES += \ + resources.qrc -HEADERS += sraconfig.h diff --git a/tools/vdb-config/sra-config/sraconfig.cpp b/tools/vdb-config/sra-config/sraconfig.cpp index e051b719..1b0093c8 100644 --- a/tools/vdb-config/sra-config/sraconfig.cpp +++ b/tools/vdb-config/sra-config/sraconfig.cpp @@ -25,35 +25,65 @@ */ #include "sraconfig.h" +#include "../vdb-config-model.hpp" +#include "../sra-tools-gui/interfaces/ktoolbaritem.h" + +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include #include +#include #include +#include #include -SRAConfig :: SRAConfig ( const QRect &avail_geometry, QWidget *parent ) +const QString rsrc_path = ":/images"; + +/* static functions */ + + + + +SRAConfig :: SRAConfig ( vdbconf_model &config_model, const QRect &avail_geometry, QWidget *parent ) : QMainWindow ( parent ) + , model ( config_model ) , screen_geometry ( avail_geometry ) , main_layout ( new QVBoxLayout () ) { + setup_toolbar (); + main_layout -> setSpacing ( 20 ); main_layout -> setAlignment ( Qt::AlignTop ); - main_layout -> addWidget ( setupOptionGroup () ); - main_layout -> addWidget ( setupRepositoriesGroup () ); + main_layout -> addSpacing ( 10 ); + main_layout -> addWidget ( setup_option_group () ); + main_layout -> addWidget ( setup_workspace_group () ); + main_layout -> addStretch ( 1 ); + main_layout -> addLayout ( setup_button_layout () ); - setupButtonLayout (); + populate (); + + connect ( this, SIGNAL ( dirty_config () ), this, SLOT ( modified_config () ) ); QWidget *main_widget = new QWidget (); main_widget -> setLayout ( main_layout ); setCentralWidget ( main_widget ); - move ( ( screen_geometry . width () - ( this -> width () / 2 ) ) / 2, + resize ( ( screen_geometry . width () ) / 3, this -> height () ); + + move ( ( screen_geometry . width () - this -> width () ) / 2, ( screen_geometry . height () - this -> height () ) / 2 ); } @@ -62,7 +92,45 @@ SRAConfig :: ~SRAConfig () } -QGroupBox * SRAConfig::setupOptionGroup () +void SRAConfig :: setup_toolbar () +{ +#ifdef Q_OS_OSX + setUnifiedTitleAndToolBarOnMac ( true ); +#endif + + QToolBar *bar = new QToolBar ( this ); + + KToolbarItem *item = new KToolbarItem ( "General", rsrc_path + "/general_icon" ); + bar -> addWidget ( item ); + + item = new KToolbarItem ( "AWS", rsrc_path + "/aws_icon" ); + bar -> addWidget ( item ); + + item = new KToolbarItem ( "Network", rsrc_path + "/network_icon" ); + bar -> addWidget ( item ); + + addToolBar ( bar ); + +} + +void SRAConfig :: populate () +{ + remote_enabled_cb -> setChecked ( model . is_remote_enabled () ); + + local_caching_cb -> setChecked ( model . is_global_cache_enabled () ); + + if ( model . does_site_repo_exist () ) + site_cb -> setChecked ( model . is_site_enabled () ); + else + site_cb -> setDisabled ( true ); + + proxy_cb -> setChecked ( model . is_http_proxy_enabled () ); + proxy_label -> setText ( model . get_http_proxy_path () . c_str () ); + + http_priority_cb -> setChecked ( model . has_http_proxy_env_higher_priority () ); +} + +QGroupBox * SRAConfig::setup_option_group () { QGroupBox *group = new QGroupBox ( "Options" ); group -> setFixedHeight ( 170 ); @@ -72,101 +140,568 @@ QGroupBox * SRAConfig::setupOptionGroup () layout -> setSpacing ( 15 ); //1 - QCheckBox *c_box = new QCheckBox ( "Enable Remote Access" ); - c_box -> setAutoExclusive ( false ); - c_box -> setChecked ( true ); - layout -> addWidget ( c_box, 0, 0 ); + remote_enabled_cb = new QCheckBox ( "Enable Remote Access" ); + remote_enabled_cb -> setAutoExclusive ( false ); + layout -> addWidget ( remote_enabled_cb, 0, 0 ); + connect ( remote_enabled_cb, SIGNAL ( clicked ( bool ) ), this, SLOT ( toggle_remote_enabled ( bool ) ) ); //2 - c_box = new QCheckBox ( "Enable Local File Caching" ); - c_box -> setAutoExclusive ( false ); - layout -> addWidget ( c_box, 1, 0 ); + local_caching_cb = new QCheckBox ( "Enable Local File Caching" ); + local_caching_cb -> setAutoExclusive ( false ); + layout -> addWidget ( local_caching_cb, 1, 0 ); + connect ( local_caching_cb, SIGNAL ( clicked ( bool ) ), this, SLOT ( toggle_local_caching ( bool ) ) ); //3 - c_box = new QCheckBox ( "Use Site Installation" ); - c_box -> setAutoExclusive ( false ); - layout -> addWidget ( c_box, 2, 0 ); + site_cb = new QCheckBox ( "Use Site Installation" ); + site_cb -> setAutoExclusive ( false ); + layout -> addWidget ( site_cb, 2, 0 ); + connect ( site_cb, SIGNAL ( clicked ( bool ) ), this, SLOT ( toggle_use_site ( bool ) ) ); //4 - c_box = new QCheckBox ( "Use Proxy" ); - c_box -> setAutoExclusive ( false ); + proxy_cb = new QCheckBox ( "Use Proxy" ); + proxy_cb -> setAutoExclusive ( false ); + layout -> addWidget ( proxy_cb, 3, 0 ); + connect ( proxy_cb, SIGNAL ( clicked ( bool ) ), this, SLOT ( toggle_use_proxy ( bool ) ) ); + + proxy_label = new QLabel (); + proxy_label -> setMargin ( 0 ); + proxy_label -> setFrameShape ( QFrame::Panel ); + proxy_label -> setFrameShadow ( QFrame::Sunken ); + proxy_label -> setFixedHeight ( 20 ); + layout -> addWidget ( proxy_label, 3, 1 ); + + QPushButton *edit = new QPushButton ( "Edit" ); + edit -> setFixedSize ( 30, 20 ); + layout -> addWidget ( edit, 3, 2 ); + connect ( edit, SIGNAL ( clicked () ), this, SLOT ( edit_proxy_path () ) ); - proxy_path = new QLabel ( "proxy.ncbi.nlm.nih.gov:XXXX" ); + //5 + http_priority_cb = new QCheckBox ( "Prioritize Environment Variable 'http-proxy'" ); + http_priority_cb -> setAutoExclusive ( false ); + layout -> addWidget ( http_priority_cb, 4, 0 ); + connect ( http_priority_cb, SIGNAL ( clicked ( bool ) ), this, SLOT ( toggle_prioritize_http ( bool ) ) ); - QPalette p = proxy_path -> palette (); - p . setColor ( QPalette::Background, Qt::white ); + group -> setLayout ( layout ); - proxy_path -> setPalette ( p ); - proxy_path -> setAutoFillBackground ( true ); - proxy_path -> setTextInteractionFlags ( Qt::TextEditorInteraction ); - proxy_path -> setFixedHeight ( 20 ); + return group; +} - layout -> addWidget ( c_box, 3, 0 ); - layout -> addWidget ( proxy_path, 3, 1, 1, 2 ); - //5 - c_box = new QCheckBox ( "Prioritize Environment Variable 'http-proxy'" ); - c_box -> setAutoExclusive ( false ); - layout -> addWidget ( c_box, 4, 0, 1, 2 ); +void SRAConfig :: add_workspace ( QString name, QString val, bool insert ) +{ + QHBoxLayout *layout = new QHBoxLayout (); - group -> setLayout ( layout ); +qDebug () << name; + QLabel *label = new QLabel ( name . append ( ':' ) ); + label -> setFixedWidth ( 150 ); + label -> setAlignment ( Qt::AlignRight ); + layout -> addWidget ( label); + +qDebug () << val; + QLabel *path = new QLabel ( val ); + path -> setFrameShape ( QFrame::Panel ); + path -> setFrameShadow ( QFrame::Sunken ); + layout -> addWidget ( path ); + + QPushButton *edit = new QPushButton ( "Edit" ); + edit -> setFixedSize ( 30, 20 ); + layout -> addWidget ( edit ); + + if ( insert ) + { + qDebug () << "inserting"; + workspace_layout -> insertLayout ( workspace_layout -> count () - 1, layout ); + } + else + workspace_layout -> addLayout ( layout ); +} - return group; +static +bool location_error ( ESetRootState state, QWidget *p ) +{ + QString msg; + + switch ( state ) + { + case eSetRootState_NotChanged : return true; + case eSetRootState_NotUnique : msg = QString ( "location not unique, select a different one" ); break; + case eSetRootState_MkdirFail : msg = QString ( "could not created directory, maybe permisson problem" ); break; + case eSetRootState_NewPathEmpty : msg = QString ( "you gave me an empty path" ); break; + case eSetRootState_NewDirNotEmpty : msg = QString ( "the given location is not empty" ); break; + case eSetRootState_NewNotDir : msg = QString ( "new location is not a directory" ); break; + case eSetRootState_Error : msg = QString ( "error changing location" ); break; + default : msg = QString ( "unknown enum" ); break; + } + + QMessageBox msgBox ( QMessageBox::Warning, "Error", msg , 0, p ); + msgBox . exec (); + return false; } -QGroupBox * SRAConfig :: setupRepositoriesGroup () + +static +std :: string protected_location_start_dir ( vdbconf_model &model, uint32_t id ) { - QGroupBox *group = new QGroupBox ( "Repositories" ); + std :: string s = model . get_repo_location ( id ); - QGridLayout *layout = new QGridLayout (); - layout -> setAlignment ( Qt :: AlignTop ); - layout -> setSpacing ( 15 ); + if ( ! model . does_path_exist ( s ) ) + s = model . get_user_default_dir (); - //1 - QLabel *label = new QLabel ( "Import Path" ); - layout -> addWidget ( label, 0, 0 ); + if ( ! model.does_path_exist( s ) ) + s = model.get_home_dir () + "/ncbi"; - import_path = new QLabel ( "/home/rodarme1/ncbi" ); - layout -> addWidget ( import_path, 0, 1, 1, 3 ); + if ( ! model.does_path_exist( s ) ) + s = model.get_home_dir (); - //2 - label = new QLabel ( "Public" ); - layout -> addWidget ( label, 1, 0 ); + if ( ! model.does_path_exist( s ) ) + s = model.get_current_dir (); + + return s; +} + +bool SRAConfig :: select_protected_location ( uint32_t id ) +{ + QString path = protected_location_start_dir ( model, id ) . c_str (); + + if ( model . does_path_exist ( path . toStdString () ) ) + { + path = QFileDialog :: getOpenFileName ( this + , "Import Workspace" + , path ); + } + else + { + path = QInputDialog::getText ( this + , "" + , tr ( "Location of dbGaP project" ) + , QLineEdit::Normal ); + } + + if ( path . length () > 0 ) + { + QString repo_name = model . get_repo_name ( id ) . c_str (); + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( this + , "" + , "Change the location of '" + repo_name + "' to '" + path + "'?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + bool flush_old = false; + bool reuse_new = false; + + ESetRootState state = model . set_repo_location ( id, flush_old, path . toStdString (), reuse_new ); + + switch ( state ) + { + case eSetRootState_OK: + return true; + case eSetRootState_OldNotEmpty: + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( this + , tr ( "Directory not empty") + , tr ( "Previous location is not empty, flush it?" ) + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + flush_old = true; + state = model . set_repo_location ( id, flush_old, path . toStdString (), reuse_new ); + if ( state == eSetRootState_OK ) + return true; + else + return location_error ( state, this ); + } + } + default: + return location_error ( state, this ); + } + } + } + + return false; +} + +bool SRAConfig :: import_ngc ( const KNgcObj *ngc, std :: string location ) +{ + uint32_t result_flags = 0; + + if ( model . import_ngc ( location, ngc, INP_CREATE_REPOSITORY, &result_flags ) ) + { + /* we have it imported or it exists and no changes made */ + bool modified = false; + if ( result_flags & INP_CREATE_REPOSITORY ) + { + /* success is the most common outcome, the repository was created */ + QMessageBox::StandardButton reply; + reply = QMessageBox::information ( this + , tr ( "Import Successful") + , "project successfully imported" ); + if (reply == QMessageBox::Ok) + modified = true; + } + else + { + /* repository did exist and is completely identical to the given ngc-obj */ + QMessageBox::StandardButton reply; + reply = QMessageBox::information ( this + , "" + , "this project exists already, no changes made" ); + } + + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( this + , "" + , tr ( "Do you want to change the location?" ) + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + uint32_t id; + if ( model . get_id_of_ngc_obj ( ngc, &id ) ) + modified |= select_protected_location ( id ); + else + { + QMessageBox::StandardButton reply; + reply = QMessageBox::information ( this + , "" + , "Cannot find the imported Workspace" ); + } + } + + if ( modified ) + { + model . commit (); + model . mkdir ( ngc ); + return true; + } + } + else if ( result_flags == 0 ) + { + QMessageBox::critical ( this + , "Error" + , "Internal Error: Failed to impport the ngc-object" + , QMessageBox::Ok ); + } + else + { + QMessageBox::information ( this, "", "the repository does already exist!" ); + + if ( result_flags & INP_UPDATE_ENC_KEY ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( this + , "" + , "Encryption key would change, continue?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes && ( result_flags & INP_UPDATE_DNLD_TICKET ) ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( this + , "" + , "Download ticket would change, continue?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes && ( result_flags & INP_UPDATE_DESC ) ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( this + , "" + , "Description would change, continue?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + uint32_t result_flags2 = 0; + if ( model . import_ngc ( location, ngc, result_flags, &result_flags2 ) ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( this + , "" + , tr ( "Project successfully updated!\nDo you want to change the location? " ) + , QMessageBox::Yes | QMessageBox::No ); + + if ( reply == QMessageBox::Yes ) + { + uint32_t id; /* we have to find out the id of the imported/existing repository */ + if ( model . get_id_of_ngc_obj ( ngc, &id ) ) + select_protected_location ( id ); + else + QMessageBox::information ( this, "", "the repository does already exist!" ); + } + + model . commit (); + + return true; + } + else + { + QMessageBox::critical ( this + , "Error" + , "Internal Error: Failed to impport the ngc-object" + , QMessageBox::Ok ); + } + } + else + QMessageBox::information ( this, "", "The import was canceled" ); + } + } + } + } + + return false; + +} + +bool SRAConfig:: prepare_ngc ( const KNgcObj *ngc ) +{ + std :: string location_base = model . get_user_default_dir (); + std :: string location = model . get_ngc_root ( location_base, ngc ); + + ESetRootState state = model . prepare_repo_directory ( location ); + + switch ( state ) + { + case eSetRootState_OK: + return import_ngc ( ngc, location ); + case eSetRootState_OldNotEmpty: + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( this + , tr ( "Directory not empty") + , tr ( "Workspace location is not empty. Use it anyway?" ) + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + state = model . prepare_repo_directory ( location, true ); + if ( state == eSetRootState_OK ) + return import_ngc ( ngc, location ); + else + return location_error ( state, this ); + } + } + default: + return location_error ( state, this ); + } + + return false; +} + +static +bool make_ngc_obj ( const KNgcObj ** ngc, std::string &path ) +{ + KDirectory * dir; + rc_t rc = KDirectoryNativeDir( &dir ); + if ( rc == 0 ) + { + qDebug () << "got native dir"; + qDebug () << "opening: " << QString ( path . c_str () ); + const KFile * src; + rc = KDirectoryOpenFileRead ( dir, &src, "%s", path.c_str() ); + if ( rc == 0 ) + { + qDebug () << "opened file for read"; + rc = KNgcObjMakeFromFile ( ngc, src ); // wont make it past here until I have a real ngs file to work with. + KFileRelease( src ); + } + KDirectoryRelease( dir ); + } + + return ( rc == 0 ); +} + +void SRAConfig :: import_workspace () +{ + // open a file dialog to browse for the repository + QString dir = model . get_home_dir () . c_str (); + if ( ! model . does_path_exist ( dir . toStdString () ) ) + dir = model . get_current_dir () . c_str (); + + QString filter = tr ("NGS (*.ngc)" ); + QString file = QFileDialog :: getOpenFileName ( this + , "Import Workspace" + , dir + , tr ("NGC files (*.ngc)" ) ); + + + if ( ! file . isEmpty () ) + { + QStringList list = file . split ( '/' ); + QString ext = list . last (); + + QString input = QInputDialog::getText ( this + , tr ( "Name Workspace" ) + , tr ( "Choose a name for your workspace" ) + , QLineEdit::Normal + , ext.split ( '.' ) . first () ); + qDebug () << "got input"; + if ( input . isEmpty () ) + return; +#if 0 + const KNgcObj *ngc; + std :: string s = file . toStdString (); + if ( make_ngc_obj ( &ngc, s ) ) + { + qDebug () << "made ngc object"; + if ( prepare_ngc ( ngc ) ) + { + qDebug () << "prepared ngc object"; + add_workspace ( input , file, true ); + emit dirty_config (); + } + qDebug () << "failed to prepare ngc object"; + } + qDebug () << "failed to make ngc object"; +#endif + add_workspace ( input , file, true ); + emit dirty_config (); + } +} - public_path = new QLabel ( "/home/rodarme1/ncbi/public" ); - QPalette p = public_path -> palette (); - p . setColor ( QPalette::Background, Qt::white ); +QGroupBox * SRAConfig :: setup_workspace_group () +{ + QGroupBox *group = new QGroupBox ( "Workspaces: " ); + group -> setTitle ( group -> title () . append ( model . get_user_default_dir () . c_str ( ) ) ); + + workspace_layout = new QVBoxLayout (); + workspace_layout -> setAlignment ( Qt :: AlignTop ); + workspace_layout -> setSpacing ( 15 ); - public_path -> setPalette ( p ); - public_path -> setAutoFillBackground ( true ); - public_path -> setTextInteractionFlags ( Qt::TextEditorInteraction ); - public_path -> setFixedHeight ( 20 ); + add_workspace ( "Public", model . get_public_location () . c_str() ); - layout -> addWidget ( public_path, 1, 1, 1, 3 ); + int repo_count = model . get_repo_count (); + for ( int i = 0; i < repo_count; ++ i ) + { + add_workspace ( model . get_repo_name ( i ) . c_str (), + model . get_repo_location ( i ) . c_str () ); + } //3 - QPushButton *import = new QPushButton ( "Import" ); - layout -> addWidget ( import, 2, 0 ); + QHBoxLayout *i_layout = new QHBoxLayout (); - group -> setLayout ( layout ); + i_layout -> addSpacing ( 125 ); + + QPushButton *import = new QPushButton ( "+" ); + import -> setFixedSize ( 30, 25 ); + connect ( import, SIGNAL ( clicked () ), this, SLOT ( import_workspace () ) ); + i_layout -> addWidget ( import ); + + i_layout -> addSpacing ( 5 ); + + QLabel *label = new QLabel (); + label -> setFrameShape ( QFrame::Panel ); + label -> setFrameShadow ( QFrame::Sunken ); + + i_layout -> addWidget ( label ); + + workspace_layout -> addLayout ( i_layout ); + + group -> setLayout ( workspace_layout ); return group; } -void SRAConfig :: setupButtonLayout () +QHBoxLayout * SRAConfig::setup_button_layout () { QHBoxLayout *layout = new QHBoxLayout (); layout -> setAlignment ( Qt::AlignBottom | Qt::AlignRight ); layout -> setSpacing ( 5 ); apply = new QPushButton ( "Apply" ); - cancel = new QPushButton ( "Cancel" ); - ok = new QPushButton ( "OK" ); + apply -> setDisabled ( true ); + connect ( apply, SIGNAL ( clicked () ), this, SLOT ( commit_config () ) ); + revert = new QPushButton ( "Revert" ); + revert -> setDisabled ( true ); + connect ( revert, SIGNAL ( clicked () ), this, SLOT ( reload_config () ) ); + + layout -> addWidget ( revert ); layout -> addWidget ( apply ); - layout -> addWidget ( cancel ); - layout -> addWidget ( ok ); + //layout -> addWidget ( ok ); + + return layout; +} + +void SRAConfig :: commit_config () +{ + model . commit (); - main_layout -> addLayout ( layout ); + apply -> setDisabled ( true ); + revert -> setDisabled ( true ); +} + +void SRAConfig :: reload_config () +{ + model . reload (); + populate (); + + if ( ! model . get_config_changed () ) + { + apply -> setDisabled ( true ); + revert -> setDisabled ( true ); + } +} + +void SRAConfig :: modified_config () +{ + if ( model . get_config_changed () ) // this wont trigger on workspace addition yet + { + apply -> setDisabled ( false ); + revert -> setDisabled ( false ); + } } + +// TBD - still needs a menu item to be triggered. +void SRAConfig :: default_config () +{ + model . set_remote_enabled ( true ); + model . set_global_cache_enabled ( true ); + model . set_site_enabled ( true ); +} + +void SRAConfig :: toggle_remote_enabled ( bool toggled ) +{ + model . set_remote_enabled ( toggled ); + emit dirty_config (); +} + +void SRAConfig :: toggle_local_caching ( bool toggled ) +{ + model . set_global_cache_enabled ( toggled ); + emit dirty_config (); +} + +void SRAConfig :: toggle_use_site ( bool toggled ) +{ + model . set_site_enabled ( toggled ); + emit dirty_config (); +} + +void SRAConfig :: toggle_use_proxy ( bool toggled ) +{ + model . set_http_proxy_enabled ( toggled ); + emit dirty_config (); +} + +void SRAConfig :: toggle_prioritize_http ( bool toggled ) +{ + model . set_http_proxy_env_higher_priority ( toggled ); + emit dirty_config (); +} + +void SRAConfig :: edit_proxy_path () +{ + QString input = QInputDialog::getText ( this + , tr ( "Proxy Path" ) + , tr ( "Enter a proxy path" ) + , QLineEdit::Normal + , proxy_label -> text () ); + + if ( input . isEmpty () ) + return; + + proxy_label -> setText ( input ); + model . set_http_proxy_path ( input . toStdString () ); + + emit dirty_config (); +} + + diff --git a/tools/vdb-config/sra-config/sraconfig.h b/tools/vdb-config/sra-config/sraconfig.h index 066aae16..2bf14026 100644 --- a/tools/vdb-config/sra-config/sraconfig.h +++ b/tools/vdb-config/sra-config/sraconfig.h @@ -32,41 +32,80 @@ QT_BEGIN_NAMESPACE class QHBoxLayout; class QVBoxLayout; +class QCheckBox; class QGroupBox; class QLabel; class QPushButton; QT_END_NAMESPACE +class vdbconf_model; +struct KNgcObj; + class SRAConfig : public QMainWindow { Q_OBJECT public: - SRAConfig ( const QRect &avail_geometry, QWidget *parent = 0 ); + SRAConfig ( vdbconf_model &config_model, const QRect &avail_geometry, QWidget *parent = 0 ); ~SRAConfig (); +signals: + + void dirty_config (); + private slots: - //void openFileDialog (); + void commit_config (); + void reload_config (); + void default_config (); + void modified_config (); + + void import_workspace (); + + void edit_proxy_path (); + + void toggle_remote_enabled ( bool toggled ); + void toggle_local_caching ( bool toggled ); + void toggle_use_site ( bool toggled ); + void toggle_use_proxy ( bool toggled ); + void toggle_prioritize_http ( bool toggled ); + + private: - QGroupBox* setupOptionGroup (); - QGroupBox* setupRepositoriesGroup (); - void setupButtonLayout (); + vdbconf_model &model; QRect screen_geometry; QVBoxLayout *main_layout; + QVBoxLayout *workspace_layout; + + QCheckBox *remote_enabled_cb; + QCheckBox *local_caching_cb; + QCheckBox *site_cb; + QCheckBox *proxy_cb; + QCheckBox *http_priority_cb; - QLabel *import_path; - QLabel *public_path; - QLabel *proxy_path; + QLabel *proxy_label; QPushButton *ok; QPushButton *apply; - QPushButton *cancel; + QPushButton *revert; + + void populate (); + + bool select_protected_location ( uint32_t id ); + bool import_ngc ( const KNgcObj *ngc, std :: string location ); + bool prepare_ngc ( const KNgcObj *ngc ); + + void add_workspace ( QString name, QString val, bool insert = false ); + + void setup_toolbar (); + QGroupBox* setup_option_group (); + QGroupBox* setup_workspace_group (); + QHBoxLayout* setup_button_layout (); }; #endif // SRACONFIG_H diff --git a/tools/vdb-config/sra-tools-gui/interfaces/ktoolbaritem.h b/tools/vdb-config/sra-tools-gui/interfaces/ktoolbaritem.h new file mode 100644 index 00000000..72d2a661 --- /dev/null +++ b/tools/vdb-config/sra-tools-gui/interfaces/ktoolbaritem.h @@ -0,0 +1,41 @@ +/*=========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +*/ + +#ifndef KTOOLBARITEM_H +#define KTOOLBARITEM_H + +#include + +class KToolbarItem : public QWidget +{ + +public: + KToolbarItem ( const QString &name, const QString &icon, QWidget *parent = 0 ); + ~KToolbarItem (); + +}; + +#endif // KTOOLBARITEM_H diff --git a/tools/vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp b/tools/vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp new file mode 100644 index 00000000..492ba5e8 --- /dev/null +++ b/tools/vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp @@ -0,0 +1,56 @@ +/*=========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +*/ + +#include "../../sra-tools-gui/interfaces/ktoolbaritem.h" + +#include +#include +#include + +KToolbarItem :: KToolbarItem ( const QString &name, const QString &icon_name, QWidget *parent ) + : QWidget ( parent ) +{ + QPalette p = palette (); + p . setColor ( QPalette::Background, Qt::gray ); + setAutoFillBackground ( true ); + setPalette ( p ); + + QVBoxLayout *layout = new QVBoxLayout (); + + //QLabel *icon = new QLabel (); + + QLabel *label = new QLabel ( name ); + + //layout -> addWidget ( icon ); + layout -> addWidget ( label ); + + setLayout ( layout ); + +} + +KToolbarItem :: ~KToolbarItem () +{ +} diff --git a/tools/vdb-config/util.cpp b/tools/vdb-config/util.cpp index fdbbb334..f5e41728 100644 --- a/tools/vdb-config/util.cpp +++ b/tools/vdb-config/util.cpp @@ -480,7 +480,7 @@ void CKConfig::Reload(bool verbose) { m_Self = NULL; if (rc == 0) { - rc = KConfigMake(&m_Self, NULL); + rc = KConfigMakeLocal (&m_Self, NULL); } if (rc == 0) { diff --git a/tools/vdb-config/vdb-config-model.cpp b/tools/vdb-config/vdb-config-model.cpp index 184ff2b5..44e7999f 100644 --- a/tools/vdb-config/vdb-config-model.cpp +++ b/tools/vdb-config/vdb-config-model.cpp @@ -407,6 +407,7 @@ ESetRootState vdbconf_model::prepare_repo_directory return res; } + #if TDB bool check_locations_unique(KRepositoryVector *nonUniqueRepos, const string &newRootPath) diff --git a/tools/vdb-config/vdb-config-model.hpp b/tools/vdb-config/vdb-config-model.hpp index f294a429..bbc2d167 100644 --- a/tools/vdb-config/vdb-config-model.hpp +++ b/tools/vdb-config/vdb-config-model.hpp @@ -28,6 +28,7 @@ #define _h_vdb_config_model_ #include +#include #include #include #include @@ -226,6 +227,7 @@ class vdbconf_model } void set_user_enabled( bool enabled ) { + ( void ) enabled; #ifdef ALLOW_USER_REPOSITORY_DISABLING if ( _config_valid ) KConfig_Set_User_Access_Enabled( _config, enabled ); #endif @@ -268,6 +270,7 @@ class vdbconf_model bool is_protected_repo_enabled( uint32_t id ) const { + ( void ) id; bool res = true; #ifdef ALLOW_USER_REPOSITORY_DISABLING if ( _config_valid ) KConfigGetProtectedRepositoryEnabledById( _config, id, &res ); @@ -276,6 +279,8 @@ class vdbconf_model } void set_protected_repo_enabled( uint32_t id, bool enabled ) { + ( void ) id; + ( void ) enabled; #ifdef ALLOW_USER_REPOSITORY_DISABLING if ( _config_valid ) KConfigSetProtectedRepositoryEnabledById( _config, id, enabled ); #endif @@ -428,7 +433,7 @@ class vdbconf_model kcmCreate | kcmParents, root.c_str()) == 0; } - bool does_path_exist( std::string &path ) + bool does_path_exist( const std::string &path ) { bool res = false; if ( _dir != NULL ) @@ -447,7 +452,7 @@ class vdbconf_model _mgr = NULL; KConfigRelease ( _config ); - _config_valid = ( KConfigMake ( &_config, NULL ) == 0 ); + _config_valid = ( KConfigMakeLocal ( &_config, NULL ) == 0 ); if ( _config_valid ) KConfigMakeRepositoryMgrRead( _config, &_mgr ); From a1ab7be03430c911299e0ea0650b8d4cc87e170d Mon Sep 17 00:00:00 2001 From: ksrodarmer Date: Wed, 5 Apr 2017 14:19:41 -0400 Subject: [PATCH 14/23] Re-org --- tools/vdb-config/sra-config/sraconfig.cpp | 620 +++++++++++++++--------------- tools/vdb-config/sra-config/sraconfig.h | 4 - 2 files changed, 319 insertions(+), 305 deletions(-) diff --git a/tools/vdb-config/sra-config/sraconfig.cpp b/tools/vdb-config/sra-config/sraconfig.cpp index 1b0093c8..e1420e81 100644 --- a/tools/vdb-config/sra-config/sraconfig.cpp +++ b/tools/vdb-config/sra-config/sraconfig.cpp @@ -52,9 +52,324 @@ const QString rsrc_path = ":/images"; /* static functions */ +static +bool location_error ( ESetRootState state, QWidget *w ) +{ + QString msg; + + switch ( state ) + { + case eSetRootState_NotChanged : return true; + case eSetRootState_NotUnique : msg = QString ( "location not unique, select a different one" ); break; + case eSetRootState_MkdirFail : msg = QString ( "could not created directory, maybe permisson problem" ); break; + case eSetRootState_NewPathEmpty : msg = QString ( "you gave me an empty path" ); break; + case eSetRootState_NewDirNotEmpty : msg = QString ( "the given location is not empty" ); break; + case eSetRootState_NewNotDir : msg = QString ( "new location is not a directory" ); break; + case eSetRootState_Error : msg = QString ( "error changing location" ); break; + default : msg = QString ( "unknown enum" ); break; + } + + QMessageBox::critical ( w + , "Error" + , msg + , QMessageBox::Ok ); + return false; +} + +static +std :: string protected_location_start_dir ( vdbconf_model &model, uint32_t id ) +{ + std :: string s = model . get_repo_location ( id ); + + if ( ! model . does_path_exist ( s ) ) + s = model . get_user_default_dir (); + + if ( ! model.does_path_exist( s ) ) + s = model.get_home_dir () + "/ncbi"; + + if ( ! model.does_path_exist( s ) ) + s = model.get_home_dir (); + + if ( ! model.does_path_exist( s ) ) + s = model.get_current_dir (); + + return s; +} + +static +bool select_protected_location ( vdbconf_model &model, uint32_t id, QWidget *w ) +{ + QString path = protected_location_start_dir ( model, id ) . c_str (); + + if ( model . does_path_exist ( path . toStdString () ) ) + { + path = QFileDialog :: getOpenFileName ( w + , "Import Workspace" + , path ); + } + else + { + path = QInputDialog::getText ( w + , "" + , "Location of dbGaP project" + , QLineEdit::Normal ); + } + + if ( path . length () > 0 ) + { + QString repo_name = model . get_repo_name ( id ) . c_str (); + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "" + , "Change the location of '" + repo_name + "' to '" + path + "'?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + bool flush_old = false; + bool reuse_new = false; + + ESetRootState state = model . set_repo_location ( id, flush_old, path . toStdString (), reuse_new ); + + switch ( state ) + { + case eSetRootState_OK: + return true; + case eSetRootState_OldNotEmpty: + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "Directory not empty" + , "Previous location is not empty, flush it?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + flush_old = true; + state = model . set_repo_location ( id, flush_old, path . toStdString (), reuse_new ); + if ( state == eSetRootState_OK ) + return true; + else + return location_error ( state, w ); + } + } + default: + return location_error ( state, w ); + } + } + } + + return false; +} + + +static +bool make_ngc_obj ( const KNgcObj ** ngc, std::string &path ) +{ + KDirectory * dir; + rc_t rc = KDirectoryNativeDir( &dir ); + if ( rc == 0 ) + { + qDebug () << "got native dir"; + qDebug () << "opening: " << QString ( path . c_str () ); + const KFile * src; + rc = KDirectoryOpenFileRead ( dir, &src, "%s", path.c_str() ); + if ( rc == 0 ) + { + qDebug () << "opened file for read"; + rc = KNgcObjMakeFromFile ( ngc, src ); // wont make it past here until I have a real ngs file to work with. + KFileRelease( src ); + } + KDirectoryRelease( dir ); + } + return ( rc == 0 ); +} +static +bool prepare_ngc ( vdbconf_model &model, const KNgcObj *ngc, QString *loc, QWidget *w ) +{ + std :: string location_base = model . get_user_default_dir (); + std :: string location = model . get_ngc_root ( location_base, ngc ); + ESetRootState state = model . prepare_repo_directory ( location ); + + switch ( state ) + { + case eSetRootState_OK: + { + *loc = location . c_str (); + return true; + } + case eSetRootState_OldNotEmpty: + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "Directory not empty" + , "Workspace location is not empty. Use it anyway?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + state = model . prepare_repo_directory ( location, true ); + if ( state == eSetRootState_OK ) + { + *loc = location . c_str (); + return true; + } + else + return location_error ( state, w ); + } + } + default: + return location_error ( state, w ); + } + + return false; +} + +static +bool import_ngc ( vdbconf_model &model, std :: string file, QWidget *w ) +{ + const KNgcObj *ngc; + if ( make_ngc_obj ( &ngc, file ) ) + { + qDebug () << "made ngc object"; + + QString location; + if ( prepare_ngc ( model, ngc, &location, w ) ) + { + qDebug () << "prepared ngc object"; + + uint32_t result_flags = 0; + + if ( model . import_ngc ( location . toStdString (), ngc, INP_CREATE_REPOSITORY, &result_flags ) ) + { + /* we have it imported or it exists and no changes made */ + bool modified = false; + if ( result_flags & INP_CREATE_REPOSITORY ) + { + /* success is the most common outcome, the repository was created */ + QMessageBox::StandardButton reply; + reply = QMessageBox::information ( w + , "Import Successful" + , "project successfully imported" ); + if ( reply == QMessageBox::Ok ) + modified = true; + } + else + { + /* repository did exist and is completely identical to the given ngc-obj */ + QMessageBox::StandardButton reply; + reply = QMessageBox::information ( w + , "" + , "this project exists already, no changes made" ); + } + + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "" + , "Do you want to change the location?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + uint32_t id; + if ( model . get_id_of_ngc_obj ( ngc, &id ) ) + modified |= select_protected_location ( model, id, w ); + else + { + QMessageBox::StandardButton reply; + reply = QMessageBox::information ( w + , "" + , "Cannot find the imported Workspace" ); + } + } + + if ( modified ) + { + model . commit (); + model . mkdir ( ngc ); + return true; + } + } + else if ( result_flags == 0 ) + { + QMessageBox::critical ( w + , "Error" + , "Internal Error: Failed to impport the ngc-object" + , QMessageBox::Ok ); + } + else + { + QMessageBox::information ( w, "", "the repository does already exist!" ); + + if ( result_flags & INP_UPDATE_ENC_KEY ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "" + , "Encryption key would change, continue?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes && ( result_flags & INP_UPDATE_DNLD_TICKET ) ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "" + , "Download ticket would change, continue?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes && ( result_flags & INP_UPDATE_DESC ) ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "" + , "Description would change, continue?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + uint32_t result_flags2 = 0; + if ( model . import_ngc ( location . toStdString () , ngc, result_flags, &result_flags2 ) ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "" + , "Project successfully updated!\nDo you want to change the location? " + , QMessageBox::Yes | QMessageBox::No ); + + if ( reply == QMessageBox::Yes ) + { + uint32_t id; /* we have to find out the id of the imported/existing repository */ + if ( model . get_id_of_ngc_obj ( ngc, &id ) ) + select_protected_location ( model, id, w ); + else + QMessageBox::information ( w, "", "the repository does already exist!" ); + } + + model . commit (); + + return true; + } + else + { + QMessageBox::critical ( w + , "Error" + , "Internal Error: Failed to impport the ngc-object" + , QMessageBox::Ok ); + } + } + else + QMessageBox::information ( w, "", "The import was canceled" ); + } + } + } + } + } + qDebug () << "failed to prepare ngc object"; + } + qDebug () << "failed to make ngc object"; + + return false; +} + + + +/* Class methods */ SRAConfig :: SRAConfig ( vdbconf_model &config_model, const QRect &avail_geometry, QWidget *parent ) : QMainWindow ( parent ) @@ -216,296 +531,6 @@ qDebug () << val; workspace_layout -> addLayout ( layout ); } -static -bool location_error ( ESetRootState state, QWidget *p ) -{ - QString msg; - - switch ( state ) - { - case eSetRootState_NotChanged : return true; - case eSetRootState_NotUnique : msg = QString ( "location not unique, select a different one" ); break; - case eSetRootState_MkdirFail : msg = QString ( "could not created directory, maybe permisson problem" ); break; - case eSetRootState_NewPathEmpty : msg = QString ( "you gave me an empty path" ); break; - case eSetRootState_NewDirNotEmpty : msg = QString ( "the given location is not empty" ); break; - case eSetRootState_NewNotDir : msg = QString ( "new location is not a directory" ); break; - case eSetRootState_Error : msg = QString ( "error changing location" ); break; - default : msg = QString ( "unknown enum" ); break; - } - - QMessageBox msgBox ( QMessageBox::Warning, "Error", msg , 0, p ); - msgBox . exec (); - return false; -} - - -static -std :: string protected_location_start_dir ( vdbconf_model &model, uint32_t id ) -{ - std :: string s = model . get_repo_location ( id ); - - if ( ! model . does_path_exist ( s ) ) - s = model . get_user_default_dir (); - - if ( ! model.does_path_exist( s ) ) - s = model.get_home_dir () + "/ncbi"; - - if ( ! model.does_path_exist( s ) ) - s = model.get_home_dir (); - - if ( ! model.does_path_exist( s ) ) - s = model.get_current_dir (); - - return s; -} - -bool SRAConfig :: select_protected_location ( uint32_t id ) -{ - QString path = protected_location_start_dir ( model, id ) . c_str (); - - if ( model . does_path_exist ( path . toStdString () ) ) - { - path = QFileDialog :: getOpenFileName ( this - , "Import Workspace" - , path ); - } - else - { - path = QInputDialog::getText ( this - , "" - , tr ( "Location of dbGaP project" ) - , QLineEdit::Normal ); - } - - if ( path . length () > 0 ) - { - QString repo_name = model . get_repo_name ( id ) . c_str (); - QMessageBox::StandardButton reply; - reply = QMessageBox::question ( this - , "" - , "Change the location of '" + repo_name + "' to '" + path + "'?" - , QMessageBox::Yes | QMessageBox::No ); - if ( reply == QMessageBox::Yes ) - { - bool flush_old = false; - bool reuse_new = false; - - ESetRootState state = model . set_repo_location ( id, flush_old, path . toStdString (), reuse_new ); - - switch ( state ) - { - case eSetRootState_OK: - return true; - case eSetRootState_OldNotEmpty: - { - QMessageBox::StandardButton reply; - reply = QMessageBox::question ( this - , tr ( "Directory not empty") - , tr ( "Previous location is not empty, flush it?" ) - , QMessageBox::Yes | QMessageBox::No ); - if ( reply == QMessageBox::Yes ) - { - flush_old = true; - state = model . set_repo_location ( id, flush_old, path . toStdString (), reuse_new ); - if ( state == eSetRootState_OK ) - return true; - else - return location_error ( state, this ); - } - } - default: - return location_error ( state, this ); - } - } - } - - return false; -} - -bool SRAConfig :: import_ngc ( const KNgcObj *ngc, std :: string location ) -{ - uint32_t result_flags = 0; - - if ( model . import_ngc ( location, ngc, INP_CREATE_REPOSITORY, &result_flags ) ) - { - /* we have it imported or it exists and no changes made */ - bool modified = false; - if ( result_flags & INP_CREATE_REPOSITORY ) - { - /* success is the most common outcome, the repository was created */ - QMessageBox::StandardButton reply; - reply = QMessageBox::information ( this - , tr ( "Import Successful") - , "project successfully imported" ); - if (reply == QMessageBox::Ok) - modified = true; - } - else - { - /* repository did exist and is completely identical to the given ngc-obj */ - QMessageBox::StandardButton reply; - reply = QMessageBox::information ( this - , "" - , "this project exists already, no changes made" ); - } - - QMessageBox::StandardButton reply; - reply = QMessageBox::question ( this - , "" - , tr ( "Do you want to change the location?" ) - , QMessageBox::Yes | QMessageBox::No ); - if ( reply == QMessageBox::Yes ) - { - uint32_t id; - if ( model . get_id_of_ngc_obj ( ngc, &id ) ) - modified |= select_protected_location ( id ); - else - { - QMessageBox::StandardButton reply; - reply = QMessageBox::information ( this - , "" - , "Cannot find the imported Workspace" ); - } - } - - if ( modified ) - { - model . commit (); - model . mkdir ( ngc ); - return true; - } - } - else if ( result_flags == 0 ) - { - QMessageBox::critical ( this - , "Error" - , "Internal Error: Failed to impport the ngc-object" - , QMessageBox::Ok ); - } - else - { - QMessageBox::information ( this, "", "the repository does already exist!" ); - - if ( result_flags & INP_UPDATE_ENC_KEY ) - { - QMessageBox::StandardButton reply; - reply = QMessageBox::question ( this - , "" - , "Encryption key would change, continue?" - , QMessageBox::Yes | QMessageBox::No ); - if ( reply == QMessageBox::Yes && ( result_flags & INP_UPDATE_DNLD_TICKET ) ) - { - QMessageBox::StandardButton reply; - reply = QMessageBox::question ( this - , "" - , "Download ticket would change, continue?" - , QMessageBox::Yes | QMessageBox::No ); - if ( reply == QMessageBox::Yes && ( result_flags & INP_UPDATE_DESC ) ) - { - QMessageBox::StandardButton reply; - reply = QMessageBox::question ( this - , "" - , "Description would change, continue?" - , QMessageBox::Yes | QMessageBox::No ); - if ( reply == QMessageBox::Yes ) - { - uint32_t result_flags2 = 0; - if ( model . import_ngc ( location, ngc, result_flags, &result_flags2 ) ) - { - QMessageBox::StandardButton reply; - reply = QMessageBox::question ( this - , "" - , tr ( "Project successfully updated!\nDo you want to change the location? " ) - , QMessageBox::Yes | QMessageBox::No ); - - if ( reply == QMessageBox::Yes ) - { - uint32_t id; /* we have to find out the id of the imported/existing repository */ - if ( model . get_id_of_ngc_obj ( ngc, &id ) ) - select_protected_location ( id ); - else - QMessageBox::information ( this, "", "the repository does already exist!" ); - } - - model . commit (); - - return true; - } - else - { - QMessageBox::critical ( this - , "Error" - , "Internal Error: Failed to impport the ngc-object" - , QMessageBox::Ok ); - } - } - else - QMessageBox::information ( this, "", "The import was canceled" ); - } - } - } - } - - return false; - -} - -bool SRAConfig:: prepare_ngc ( const KNgcObj *ngc ) -{ - std :: string location_base = model . get_user_default_dir (); - std :: string location = model . get_ngc_root ( location_base, ngc ); - - ESetRootState state = model . prepare_repo_directory ( location ); - - switch ( state ) - { - case eSetRootState_OK: - return import_ngc ( ngc, location ); - case eSetRootState_OldNotEmpty: - { - QMessageBox::StandardButton reply; - reply = QMessageBox::question ( this - , tr ( "Directory not empty") - , tr ( "Workspace location is not empty. Use it anyway?" ) - , QMessageBox::Yes | QMessageBox::No ); - if ( reply == QMessageBox::Yes ) - { - state = model . prepare_repo_directory ( location, true ); - if ( state == eSetRootState_OK ) - return import_ngc ( ngc, location ); - else - return location_error ( state, this ); - } - } - default: - return location_error ( state, this ); - } - - return false; -} - -static -bool make_ngc_obj ( const KNgcObj ** ngc, std::string &path ) -{ - KDirectory * dir; - rc_t rc = KDirectoryNativeDir( &dir ); - if ( rc == 0 ) - { - qDebug () << "got native dir"; - qDebug () << "opening: " << QString ( path . c_str () ); - const KFile * src; - rc = KDirectoryOpenFileRead ( dir, &src, "%s", path.c_str() ); - if ( rc == 0 ) - { - qDebug () << "opened file for read"; - rc = KNgcObjMakeFromFile ( ngc, src ); // wont make it past here until I have a real ngs file to work with. - KFileRelease( src ); - } - KDirectoryRelease( dir ); - } - - return ( rc == 0 ); -} void SRAConfig :: import_workspace () { @@ -534,21 +559,14 @@ void SRAConfig :: import_workspace () qDebug () << "got input"; if ( input . isEmpty () ) return; + #if 0 - const KNgcObj *ngc; std :: string s = file . toStdString (); - if ( make_ngc_obj ( &ngc, s ) ) + if ( import_ngc ( model, s ) ) { - qDebug () << "made ngc object"; - if ( prepare_ngc ( ngc ) ) - { - qDebug () << "prepared ngc object"; - add_workspace ( input , file, true ); - emit dirty_config (); - } - qDebug () << "failed to prepare ngc object"; + add_workspace ( input , file, true ); + emit dirty_config (); } - qDebug () << "failed to make ngc object"; #endif add_workspace ( input , file, true ); emit dirty_config (); diff --git a/tools/vdb-config/sra-config/sraconfig.h b/tools/vdb-config/sra-config/sraconfig.h index 2bf14026..890d19bc 100644 --- a/tools/vdb-config/sra-config/sraconfig.h +++ b/tools/vdb-config/sra-config/sraconfig.h @@ -95,10 +95,6 @@ private slots: void populate (); - bool select_protected_location ( uint32_t id ); - bool import_ngc ( const KNgcObj *ngc, std :: string location ); - bool prepare_ngc ( const KNgcObj *ngc ); - void add_workspace ( QString name, QString val, bool insert = false ); void setup_toolbar (); From e9b02656f417c0d0464dbb2738f900cf439c4a9f Mon Sep 17 00:00:00 2001 From: wraetz Date: Mon, 10 Apr 2017 12:26:23 -0400 Subject: [PATCH 15/23] function added to just enumerate or print static columns --- tools/vdb-dump/vdb-dump-coldefs.c | 22 +++++++++++++++------- tools/vdb-dump/vdb-dump-coldefs.h | 2 +- tools/vdb-dump/vdb-dump.c | 29 ++++++++++++++++++++++++++--- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/tools/vdb-dump/vdb-dump-coldefs.c b/tools/vdb-dump/vdb-dump-coldefs.c index a6169f7e..5fd1c4d7 100644 --- a/tools/vdb-dump/vdb-dump-coldefs.c +++ b/tools/vdb-dump/vdb-dump-coldefs.c @@ -868,7 +868,7 @@ static uint32_t same_values( const VCursor * curs, uint32_t col_idx, int64_t fir return res; } -static bool vdcd_is_static_column( const VTable *my_table, col_def * col ) +static bool vdcd_is_static_column( const VTable *my_table, col_def * col, uint32_t test_rows ) { bool res = false; const VCursor * curs; @@ -887,7 +887,7 @@ static bool vdcd_is_static_column( const VTable *my_table, col_def * col ) rc = VCursorIdRange( curs, idx, &first, &count ); if ( rc == 0 && count == 0 ) { - res = ( same_values( curs, idx, first, 100 ) == 100 ); + res = ( same_values( curs, idx, first, test_rows ) == test_rows ); } } } @@ -897,11 +897,13 @@ static bool vdcd_is_static_column( const VTable *my_table, col_def * col ) } -bool vdcd_extract_static_columns( col_defs* defs, const VTable *my_table, const size_t str_limit ) +#define TEST_ROWS 20 + +uint32_t vdcd_extract_static_columns( col_defs* defs, const VTable *my_table, const size_t str_limit ) { col_defs * temp_defs; - bool res = vdcd_init( &temp_defs, str_limit ); - if ( res ) + uint32_t res = 0; + if ( vdcd_init( &temp_defs, str_limit ) ) { uint32_t count = vdcd_extract_from_table( temp_defs, my_table ); uint32_t idx; @@ -910,8 +912,14 @@ bool vdcd_extract_static_columns( col_defs* defs, const VTable *my_table, const col_def * col = VectorGet( &(temp_defs->cols), idx ); if ( col != NULL ) { - if ( vdcd_is_static_column( my_table, col ) ) - vdcd_append_col( defs, col->name ); + if ( vdcd_is_static_column( my_table, col, TEST_ROWS ) ) + { + p_col_def c = vdcd_append_col( defs, col->name ); + if ( c != NULL ) + { + res++; + } + } } } vdcd_destroy( temp_defs ); diff --git a/tools/vdb-dump/vdb-dump-coldefs.h b/tools/vdb-dump/vdb-dump-coldefs.h index 5c19bcf8..c0c48416 100644 --- a/tools/vdb-dump/vdb-dump-coldefs.h +++ b/tools/vdb-dump/vdb-dump-coldefs.h @@ -101,7 +101,7 @@ void vdcd_ins_trans_fkt( col_defs* defs, const VSchema *my_schema ); void vdcd_exclude_these_columns( col_defs* defs, const char* column_names ); bool vdcd_get_first_none_static_column_idx( col_defs* defs, const VCursor * cur, uint32_t * idx ); -bool vdcd_extract_static_columns( col_defs* defs, const VTable *my_table, const size_t str_limit ); +uint32_t vdcd_extract_static_columns( col_defs* defs, const VTable *my_table, const size_t str_limit ); rc_t vdcd_collect_spread( const struct num_gen * row_set, col_defs * cols, const VCursor * cursor ); diff --git a/tools/vdb-dump/vdb-dump.c b/tools/vdb-dump/vdb-dump.c index abac29fa..a058c4c2 100644 --- a/tools/vdb-dump/vdb-dump.c +++ b/tools/vdb-dump/vdb-dump.c @@ -524,8 +524,29 @@ static uint32_t vdm_extract_or_parse_columns( const p_dump_context ctx, { bool cols_unknown = ( ( ctx->columns == NULL ) || ( string_cmp( ctx->columns, 1, "*", 1, 1 ) == 0 ) ); if ( cols_unknown ) - /* the user does not know the column-names or wants all of them */ - count = vdcd_extract_from_table( my_col_defs, my_table ); + { + if ( ctx->enum_static ) + { + /* the user wants to see only the static columns */ + count = vdcd_extract_static_columns( my_col_defs, my_table, ctx->max_line_len ); + if ( count > 0 ) + { + /* if we found some static columns, let's restrict the row-count + if the user did not give a specific row-set to just show row #1 */ + if ( ctx->rows == NULL ) + { + rc_t rc = num_gen_make_from_range( &ctx->rows, 1, 1 ); + DISP_RC( rc, "num_gen_make_from_range() failed" ); + } + + } + } + else + { + /* the user does not know the column-names or wants all of them */ + count = vdcd_extract_from_table( my_col_defs, my_table ); + } + } else /* the user knows the names of the wanted columns... */ count = vdcd_parse_string( my_col_defs, ctx->columns, my_table ); @@ -547,8 +568,10 @@ static bool vdm_extract_or_parse_phys_columns( const p_dump_context ctx, { bool cols_unknown = ( ( ctx->columns == NULL ) || ( string_cmp( ctx->columns, 1, "*", 1, 1 ) == 0 ) ); if ( cols_unknown ) + { /* the user does not know the column-names or wants all of them */ res = vdcd_extract_from_phys_table( my_col_defs, my_table ); + } else /* the user knows the names of the wanted columns... */ res = vdcd_parse_string( my_col_defs, ctx->columns, my_table ); @@ -569,7 +592,7 @@ static bool vdm_extract_or_parse_static_columns( const p_dump_context ctx, if ( ctx != NULL && my_col_defs != NULL ) { /* the user does not know the column-names or wants all of them */ - res = vdcd_extract_static_columns( my_col_defs, my_table, ctx->max_line_len ); + res = ( vdcd_extract_static_columns( my_col_defs, my_table, ctx->max_line_len ) > 0 ); if ( ctx->excluded_columns != NULL ) vdcd_exclude_these_columns( my_col_defs, ctx->excluded_columns ); From 1017a588696ebcd5f8c11fe51e88c475a9814542 Mon Sep 17 00:00:00 2001 From: wraetz Date: Wed, 12 Apr 2017 15:40:28 -0400 Subject: [PATCH 16/23] fastq-option fixed --- tools/vdb-dump/vdb-dump-coldefs.c | 24 ++++++++++++++++++++++-- tools/vdb-dump/vdb-dump-fastq.c | 17 ++++++++++------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/tools/vdb-dump/vdb-dump-coldefs.c b/tools/vdb-dump/vdb-dump-coldefs.c index 5fd1c4d7..af888703 100644 --- a/tools/vdb-dump/vdb-dump-coldefs.c +++ b/tools/vdb-dump/vdb-dump-coldefs.c @@ -868,7 +868,7 @@ static uint32_t same_values( const VCursor * curs, uint32_t col_idx, int64_t fir return res; } -static bool vdcd_is_static_column( const VTable *my_table, col_def * col, uint32_t test_rows ) +static bool vdcd_is_static_column1( const VTable *my_table, col_def * col, uint32_t test_rows ) { bool res = false; const VCursor * curs; @@ -896,6 +896,26 @@ static bool vdcd_is_static_column( const VTable *my_table, col_def * col, uint32 return res; } +static bool vdcd_is_static_column2( const VTable *my_table, col_def * col ) +{ + bool res = false; + const VCursor * curs; + rc_t rc = VTableCreateCursorRead( my_table, &curs ); + if ( rc == 0 ) + { + uint32_t idx; + rc = VCursorAddColumn( curs, &idx, "%s", col->name ); + if ( rc == 0 ) + { + rc = VCursorOpen( curs ); + if ( rc == 0 ) + rc = VCursorIsStaticColumn( curs, idx, &res ); + } + VCursorRelease( curs ); + } + return res; +} + #define TEST_ROWS 20 @@ -912,7 +932,7 @@ uint32_t vdcd_extract_static_columns( col_defs* defs, const VTable *my_table, co col_def * col = VectorGet( &(temp_defs->cols), idx ); if ( col != NULL ) { - if ( vdcd_is_static_column( my_table, col, TEST_ROWS ) ) + if ( vdcd_is_static_column1( my_table, col ) ) { p_col_def c = vdcd_append_col( defs, col->name ); if ( c != NULL ) diff --git a/tools/vdb-dump/vdb-dump-fastq.c b/tools/vdb-dump/vdb-dump-fastq.c index d02fef3b..9bc6f8e6 100644 --- a/tools/vdb-dump/vdb-dump-fastq.c +++ b/tools/vdb-dump/vdb-dump-fastq.c @@ -464,15 +464,18 @@ static rc_t print_qual( const char * qual, uint32_t count, uint32_t max_line_len rc = KOutMsg( "%s", buffer ); on_line = num_writ; } - if ( ( on_line + num_writ + 1 ) < max_line_len ) - { - rc = KOutMsg( " %s", buffer ); - on_line += ( num_writ + 1 ); - } else { - rc = KOutMsg( "\n%s", buffer ); - on_line = num_writ; + if ( ( on_line + num_writ + 1 ) < max_line_len ) + { + rc = KOutMsg( " %s", buffer ); + on_line += ( num_writ + 1 ); + } + else + { + rc = KOutMsg( "\n%s", buffer ); + on_line = num_writ; + } } i++; } From 88f574e1b2f721986a64734597915ac16db4493f Mon Sep 17 00:00:00 2001 From: wraetz Date: Wed, 12 Apr 2017 16:37:33 -0400 Subject: [PATCH 17/23] test function needed one more argument --- tools/vdb-dump/vdb-dump-coldefs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/vdb-dump/vdb-dump-coldefs.c b/tools/vdb-dump/vdb-dump-coldefs.c index af888703..1e13a2a5 100644 --- a/tools/vdb-dump/vdb-dump-coldefs.c +++ b/tools/vdb-dump/vdb-dump-coldefs.c @@ -932,7 +932,7 @@ uint32_t vdcd_extract_static_columns( col_defs* defs, const VTable *my_table, co col_def * col = VectorGet( &(temp_defs->cols), idx ); if ( col != NULL ) { - if ( vdcd_is_static_column1( my_table, col ) ) + if ( vdcd_is_static_column1( my_table, col, TEST_ROWS ) ) { p_col_def c = vdcd_append_col( defs, col->name ); if ( c != NULL ) From c4e297671671a4408d4325ea947639351eb1e6a4 Mon Sep 17 00:00:00 2001 From: ksrodarmer Date: Thu, 13 Apr 2017 15:48:27 -0400 Subject: [PATCH 18/23] SRAConfig should now be interchangeable with vdb-config - i --- tools/vdb-config/sra-config/images/aws_icon.png | Bin 0 -> 13761 bytes .../vdb-config/sra-config/images/network_icon.png | Bin 0 -> 32471 bytes tools/vdb-config/sra-config/sra-config.pro.user | 339 ++++++++++++++ tools/vdb-config/sra-config/sraconfig.cpp | 501 ++++++++++++++++----- tools/vdb-config/sra-config/sraconfig.h | 36 +- tools/vdb-config/vdb-config-model.cpp | 4 +- tools/vdb-config/vdb-config-model.hpp | 2 +- 7 files changed, 765 insertions(+), 117 deletions(-) create mode 100644 tools/vdb-config/sra-config/images/aws_icon.png create mode 100644 tools/vdb-config/sra-config/images/network_icon.png create mode 100644 tools/vdb-config/sra-config/sra-config.pro.user diff --git a/tools/vdb-config/sra-config/images/aws_icon.png b/tools/vdb-config/sra-config/images/aws_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b0b4ed67d7efa4d5f72108da4706ccec82076411 GIT binary patch literal 13761 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 + + + + + EnvironmentId + {8a39ecd7-5faa-47c8-8a45-2fb59818cecd} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + false + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 1 + true + true + 1 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop Qt 5.8.0 clang 64bit + Desktop Qt 5.8.0 clang 64bit + qt.58.clang_64_kit + 0 + 0 + 0 + + /net/snowman/vol/export4/rodarme1/devel/sra-tools/tools/vdb-config/build-sra-config-Desktop_Qt_5_8_0_clang_64bit-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /net/snowman/vol/export4/rodarme1/devel/sra-tools/tools/vdb-config/build-sra-config-Desktop_Qt_5_8_0_clang_64bit-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + /net/snowman/vol/export4/rodarme1/devel/sra-tools/tools/vdb-config/build-sra-config-Desktop_Qt_5_8_0_clang_64bit-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 1 + + VDB_CONFIG=/net/traces01.be-md.ncbi.nlm.nih.gov/trace_software/vdb/config:/net/traces01.be-md.ncbi.nlm.nih.gov/trace_software/vdb/mac/config + + sra-config + + Qt4ProjectManager.Qt4RunConfiguration:/net/snowman/vol/export4/rodarme1/devel/sra-tools/tools/vdb-config/sra-config/sra-config.pro + true + + sra-config.pro + false + false + + /net/snowman/vol/export4/rodarme1/devel/sra-tools/tools/vdb-config/build-sra-config-Desktop_Qt_5_8_0_clang_64bit-Debug/sra-config.app/Contents/MacOS + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/tools/vdb-config/sra-config/sraconfig.cpp b/tools/vdb-config/sra-config/sraconfig.cpp index e1420e81..1e146a15 100644 --- a/tools/vdb-config/sra-config/sraconfig.cpp +++ b/tools/vdb-config/sra-config/sraconfig.cpp @@ -36,13 +36,17 @@ #include #include +#include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include @@ -51,6 +55,38 @@ const QString rsrc_path = ":/images"; +struct WorkspaceItem +{ + WorkspaceItem ( QString name, QString path, uint32_t id ) + : name_label ( new QLabel ( name ) ) + , path_label ( new QLabel ( path ) ) + , edit_button ( new QPushButton ( "Edit" ) ) + , ngc_id ( id ) + { + name_label -> setFixedWidth ( 150 ); + name_label -> setAlignment ( Qt::AlignRight ); + + path_label -> setFrameShape ( QFrame::Panel ); + path_label -> setFrameShadow ( QFrame::Sunken ); + + edit_button -> setFixedSize ( 30, 20 ); + } + + WorkspaceItem () + : name_label ( nullptr ) + , path_label ( nullptr ) + , edit_button ( nullptr ) + , ngc_id ( -1 ) + {} + + QLabel *name_label; + QLabel *path_label; + QPushButton *edit_button; + + int ngc_id; +}; + + /* static functions */ static bool location_error ( ESetRootState state, QWidget *w ) @@ -77,6 +113,89 @@ bool location_error ( ESetRootState state, QWidget *w ) } static +std :: string public_location_start_dir ( vdbconf_model &model ) +{ + std :: string s = model . get_public_location (); + + if ( ! model . does_path_exist ( s ) ) + s = model . get_user_default_dir (); + + if ( ! model.does_path_exist( s ) ) + s = model.get_home_dir () + "/ncbi"; + + if ( ! model.does_path_exist( s ) ) + s = model.get_home_dir (); + + if ( ! model.does_path_exist( s ) ) + s = model.get_current_dir (); + + return s; +} + +static +bool select_public_location ( vdbconf_model &model, QWidget *w ) +{ + QString path = public_location_start_dir ( model ) . c_str (); + + if ( model . does_path_exist ( path . toStdString () ) ) + { + path = QFileDialog :: getOpenFileName ( w + , "Import Workspace" + , path ); + } + else + { + path = QInputDialog::getText ( w + , "" + , "Location of public cache" + , QLineEdit::Normal ); + } + + if ( path . length () > 0 ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "" + , "Change the location to '" + path + "'?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + bool flush_old = false; + bool reuse_new = false; + + ESetRootState state = model . set_public_location ( flush_old, path . toStdString (), reuse_new ); + + switch ( state ) + { + case eSetRootState_OK: + return true; + case eSetRootState_OldNotEmpty: + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "Directory not empty" + , "Previous location is not empty, flush it?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) + { + flush_old = true; + state = model . set_public_location ( flush_old, path . toStdString () . c_str (), reuse_new ); + if ( state == eSetRootState_OK ) + return true; + else + return location_error ( state, w ); + } + } + default: + return location_error ( state, w ); + } + } + } + + return false; +} + +static std :: string protected_location_start_dir ( vdbconf_model &model, uint32_t id ) { std :: string s = model . get_repo_location ( id ); @@ -97,9 +216,11 @@ std :: string protected_location_start_dir ( vdbconf_model &model, uint32_t id ) } static -bool select_protected_location ( vdbconf_model &model, uint32_t id, QWidget *w ) +bool select_protected_location ( vdbconf_model &model, int id, QWidget *w ) { + QString path = protected_location_start_dir ( model, id ) . c_str (); + qDebug () << "Protect location path: " << path << " [" << id << "]"; if ( model . does_path_exist ( path . toStdString () ) ) { @@ -149,7 +270,7 @@ bool select_protected_location ( vdbconf_model &model, uint32_t id, QWidget *w ) return true; else return location_error ( state, w ); - } + } } default: return location_error ( state, w ); @@ -160,7 +281,6 @@ bool select_protected_location ( vdbconf_model &model, uint32_t id, QWidget *w ) return false; } - static bool make_ngc_obj ( const KNgcObj ** ngc, std::string &path ) { @@ -168,14 +288,11 @@ bool make_ngc_obj ( const KNgcObj ** ngc, std::string &path ) rc_t rc = KDirectoryNativeDir( &dir ); if ( rc == 0 ) { - qDebug () << "got native dir"; - qDebug () << "opening: " << QString ( path . c_str () ); const KFile * src; rc = KDirectoryOpenFileRead ( dir, &src, "%s", path.c_str() ); if ( rc == 0 ) { - qDebug () << "opened file for read"; - rc = KNgcObjMakeFromFile ( ngc, src ); // wont make it past here until I have a real ngs file to work with. + rc = KNgcObjMakeFromFile ( ngc, src ); KFileRelease( src ); } KDirectoryRelease( dir ); @@ -189,13 +306,14 @@ bool prepare_ngc ( vdbconf_model &model, const KNgcObj *ngc, QString *loc, QWidg { std :: string location_base = model . get_user_default_dir (); std :: string location = model . get_ngc_root ( location_base, ngc ); - + qDebug () << "model changed 2: " << model . get_config_changed (); ESetRootState state = model . prepare_repo_directory ( location ); - + qDebug () << "model changed 2.1: " << model . get_config_changed (); switch ( state ) { case eSetRootState_OK: { + qDebug () << "model changed 3: " << model . get_config_changed (); *loc = location . c_str (); return true; } @@ -211,6 +329,7 @@ bool prepare_ngc ( vdbconf_model &model, const KNgcObj *ngc, QString *loc, QWidg state = model . prepare_repo_directory ( location, true ); if ( state == eSetRootState_OK ) { + qDebug () << "model changed 4: " << model . get_config_changed (); *loc = location . c_str (); return true; } @@ -221,20 +340,26 @@ bool prepare_ngc ( vdbconf_model &model, const KNgcObj *ngc, QString *loc, QWidg default: return location_error ( state, w ); } - + qDebug () << "model changed 5: " << model . get_config_changed (); return false; } static -bool import_ngc ( vdbconf_model &model, std :: string file, QWidget *w ) +bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QWidget *w ) { const KNgcObj *ngc; - if ( make_ngc_obj ( &ngc, file ) ) + if ( ! make_ngc_obj ( &ngc, file ) ) + { + QMessageBox::information ( w + , "Import Error" + , "Unable to import NGC file" ); + } + else { - qDebug () << "made ngc object"; - QString location; - if ( prepare_ngc ( model, ngc, &location, w ) ) + if ( ! prepare_ngc ( model, ngc, &location, w ) ) + qDebug () << "failed to prepare ngc object"; + else { qDebug () << "prepared ngc object"; @@ -247,44 +372,47 @@ bool import_ngc ( vdbconf_model &model, std :: string file, QWidget *w ) if ( result_flags & INP_CREATE_REPOSITORY ) { /* success is the most common outcome, the repository was created */ - QMessageBox::StandardButton reply; - reply = QMessageBox::information ( w - , "Import Successful" - , "project successfully imported" ); - if ( reply == QMessageBox::Ok ) - modified = true; + QMessageBox::information ( w + , "Import Successful" + , "project successfully imported" ); + + modified = true; } else { + qDebug () << "model changed 4: " << model . get_config_changed (); /* repository did exist and is completely identical to the given ngc-obj */ - QMessageBox::StandardButton reply; - reply = QMessageBox::information ( w - , "" - , "this project exists already, no changes made" ); + QMessageBox::information ( w + , "" + , "this project exists already, no changes made" ); + + modified = false; } - QMessageBox::StandardButton reply; - reply = QMessageBox::question ( w - , "" - , "Do you want to change the location?" - , QMessageBox::Yes | QMessageBox::No ); - if ( reply == QMessageBox::Yes ) + if ( model . get_id_of_ngc_obj ( ngc, &ngc_id ) ) { - uint32_t id; - if ( model . get_id_of_ngc_obj ( ngc, &id ) ) - modified |= select_protected_location ( model, id, w ); - else + qDebug () << "NGC ID: " << ngc_id; + + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( w + , "" + , "Do you want to change the location?" + , QMessageBox::Yes | QMessageBox::No ); + if ( reply == QMessageBox::Yes ) { - QMessageBox::StandardButton reply; - reply = QMessageBox::information ( w - , "" - , "Cannot find the imported Workspace" ); + modified |= select_protected_location ( model, ngc_id, w ); } } + else + { + QMessageBox::information ( w + , "" + , "Cannot find the imported Workspace" ); + } if ( modified ) { - model . commit (); + model . commit (); // TBD - on import of NGC files, do we automaically commit, or allow for revert and require apply button? model . mkdir ( ngc ); return true; } @@ -334,9 +462,12 @@ bool import_ngc ( vdbconf_model &model, std :: string file, QWidget *w ) if ( reply == QMessageBox::Yes ) { - uint32_t id; /* we have to find out the id of the imported/existing repository */ - if ( model . get_id_of_ngc_obj ( ngc, &id ) ) - select_protected_location ( model, id, w ); + /* we have to find out the id of the imported/existing repository */ + if ( model . get_id_of_ngc_obj ( ngc, &ngc_id ) ) + { + qDebug () << "NGC ID: " << ngc_id; + select_protected_location ( model, ngc_id, w ); + } else QMessageBox::information ( w, "", "the repository does already exist!" ); } @@ -360,9 +491,9 @@ bool import_ngc ( vdbconf_model &model, std :: string file, QWidget *w ) } } } - qDebug () << "failed to prepare ngc object"; + + KNgcObjRelease ( ngc ); } - qDebug () << "failed to make ngc object"; return false; } @@ -377,14 +508,16 @@ SRAConfig :: SRAConfig ( vdbconf_model &config_model, const QRect &avail_geometr , screen_geometry ( avail_geometry ) , main_layout ( new QVBoxLayout () ) { - setup_toolbar (); + + setWindowTitle ( "SRA Configuration Tool" ); + setup_menubar (); + //setup_toolbar (); main_layout -> setSpacing ( 20 ); main_layout -> setAlignment ( Qt::AlignTop ); main_layout -> addSpacing ( 10 ); main_layout -> addWidget ( setup_option_group () ); main_layout -> addWidget ( setup_workspace_group () ); - main_layout -> addStretch ( 1 ); main_layout -> addLayout ( setup_button_layout () ); populate (); @@ -407,6 +540,27 @@ SRAConfig :: ~SRAConfig () } +void SRAConfig :: setup_menubar () +{ + QMenu *file = menuBar () -> addMenu ( tr ( "&File" ) ); + + apply_action = file -> addAction ( tr ( "&Apply" ), this, SLOT ( commit_config () ) ); + apply_action -> setDisabled ( true ); + + file -> addSeparator (); + file -> addAction ( tr ( "&Import" ), this, SLOT ( import_workspace () ) ); + + QMenu *edit = menuBar () -> addMenu ( tr ( "\u200CEdit" ) ); // \u200C was added because OSX auto-adds some unwanted menu items + + discard_action = edit -> addAction ( tr ( "&Discard Changes" ), this, SLOT ( reload_config () ) ); + discard_action -> setDisabled ( true ); + + edit -> addSeparator (); + edit -> addAction ( tr ( "&Advanced" ), this, SLOT ( advanced_settings () ) ); + edit -> addSeparator (); + edit -> addAction ( tr ( "&Soft Factory Reset" ), this, SLOT ( default_config () ) ); +} + void SRAConfig :: setup_toolbar () { #ifdef Q_OS_OSX @@ -501,30 +655,29 @@ QGroupBox * SRAConfig::setup_option_group () return group; } - -void SRAConfig :: add_workspace ( QString name, QString val, bool insert ) +void SRAConfig :: add_workspace (QString name, QString val, int ngc_id, bool insert ) { QHBoxLayout *layout = new QHBoxLayout (); -qDebug () << name; - QLabel *label = new QLabel ( name . append ( ':' ) ); - label -> setFixedWidth ( 150 ); - label -> setAlignment ( Qt::AlignRight ); - layout -> addWidget ( label); + WorkspaceItem *ws = new WorkspaceItem ( name . append ( ':' ), val, ngc_id ); -qDebug () << val; - QLabel *path = new QLabel ( val ); - path -> setFrameShape ( QFrame::Panel ); - path -> setFrameShadow ( QFrame::Sunken ); - layout -> addWidget ( path ); + if ( ngc_id == -1 ) + { + public_workspace = ws; + connect ( ws -> edit_button, SIGNAL ( clicked () ), this, SLOT ( edit_public_path () ) ); + } + else + { + protected_workspaces . append ( ws ); + connect ( ws -> edit_button, SIGNAL ( clicked () ), this, SLOT ( edit_workspace_path () ) ); + } - QPushButton *edit = new QPushButton ( "Edit" ); - edit -> setFixedSize ( 30, 20 ); - layout -> addWidget ( edit ); + layout -> addWidget ( ws -> name_label ); + layout -> addWidget ( ws -> path_label ); + layout -> addWidget ( ws -> edit_button ); if ( insert ) { - qDebug () << "inserting"; workspace_layout -> insertLayout ( workspace_layout -> count () - 1, layout ); } else @@ -548,48 +701,44 @@ void SRAConfig :: import_workspace () if ( ! file . isEmpty () ) { - QStringList list = file . split ( '/' ); - QString ext = list . last (); - - QString input = QInputDialog::getText ( this - , tr ( "Name Workspace" ) - , tr ( "Choose a name for your workspace" ) - , QLineEdit::Normal - , ext.split ( '.' ) . first () ); - qDebug () << "got input"; - if ( input . isEmpty () ) - return; - -#if 0 std :: string s = file . toStdString (); - if ( import_ngc ( model, s ) ) + uint32_t ngc_id; + if ( import_ngc ( model, s, ngc_id, this ) ) { - add_workspace ( input , file, true ); - emit dirty_config (); + QString name = model . get_repo_name ( ngc_id ) . c_str (); + + name = QInputDialog::getText ( this + , tr ( "Name Workspace" ) + , tr ( "Choose a name for your workspace" ) + , QLineEdit::Normal + , name ); + + if ( name . isEmpty () ) + name = model . get_repo_name ( ngc_id ) . c_str (); + + add_workspace ( name, file, ngc_id, true ); } -#endif - add_workspace ( input , file, true ); - emit dirty_config (); } } QGroupBox * SRAConfig :: setup_workspace_group () { - QGroupBox *group = new QGroupBox ( "Workspaces: " ); - group -> setTitle ( group -> title () . append ( model . get_user_default_dir () . c_str ( ) ) ); + QGroupBox *group = new QGroupBox ( "Workspaces" ); workspace_layout = new QVBoxLayout (); workspace_layout -> setAlignment ( Qt :: AlignTop ); workspace_layout -> setSpacing ( 15 ); - add_workspace ( "Public", model . get_public_location () . c_str() ); + add_workspace ( "Public", model . get_public_location () . c_str(), -1 ); int repo_count = model . get_repo_count (); + qDebug () << "Setup workspace group: repo-count: " << repo_count; for ( int i = 0; i < repo_count; ++ i ) { add_workspace ( model . get_repo_name ( i ) . c_str (), - model . get_repo_location ( i ) . c_str () ); + model . get_repo_location ( i ) . c_str (), + model . get_repo_id ( model . get_repo_name ( i ) ) ); } //3 @@ -617,33 +766,111 @@ QGroupBox * SRAConfig :: setup_workspace_group () return group; } -QHBoxLayout * SRAConfig::setup_button_layout () +QVBoxLayout * SRAConfig::setup_button_layout () { + QVBoxLayout *v_layout = new QVBoxLayout (); + + // 1 QHBoxLayout *layout = new QHBoxLayout (); + layout -> setAlignment ( Qt::AlignTop | Qt::AlignRight ); + + QPushButton *advanced = new QPushButton ( "Advanced" ); + advanced -> setFixedWidth ( 150 ); + connect ( advanced, SIGNAL ( clicked () ), this, SLOT ( advanced_settings () ) ); + + layout -> addWidget ( advanced ); + v_layout -> addLayout ( layout ); + v_layout -> addStretch ( 1 ); + + // 2 + layout = new QHBoxLayout (); layout -> setAlignment ( Qt::AlignBottom | Qt::AlignRight ); layout -> setSpacing ( 5 ); - apply = new QPushButton ( "Apply" ); - apply -> setDisabled ( true ); - connect ( apply, SIGNAL ( clicked () ), this, SLOT ( commit_config () ) ); + apply_btn = new QPushButton ( "Apply" ); + apply_btn -> setDisabled ( true ); + connect ( apply_btn, SIGNAL ( clicked () ), this, SLOT ( commit_config () ) ); + + discard_btn = new QPushButton ( "Revert" ); + discard_btn -> setDisabled ( true ); + connect ( discard_btn, SIGNAL ( clicked () ), this, SLOT ( reload_config () ) ); + + layout -> addWidget ( discard_btn ); + layout -> addWidget ( apply_btn ); + + v_layout -> addLayout ( layout ); + + return v_layout; +} + +void SRAConfig :: closeEvent ( QCloseEvent *ev ) +{ + if ( model . get_config_changed () ) + { + QMessageBox::StandardButton reply; + reply = QMessageBox::question ( this + , "" + , "Save changes? " + , QMessageBox::No | QMessageBox::Yes ); + + if ( reply == QMessageBox::Yes ) + commit_config (); + } + + ev -> accept (); +} + +void SRAConfig :: advanced_settings () +{ + adv_setting_window = new QFrame (); + adv_setting_window -> resize ( this -> width () * .7, this -> height () / 2 ); + adv_setting_window -> setWindowTitle ( "Advanced Setting" ); + + QVBoxLayout *v_layout = new QVBoxLayout (); + + // 1 + QHBoxLayout *layout = new QHBoxLayout (); + + QLabel *label = new QLabel ( "Default import path:" ); + label -> setFixedWidth ( 150 ); + label -> setAlignment ( Qt::AlignRight ); + layout -> addWidget ( label); + + import_path_label = new QLabel ( model . get_user_default_dir () . c_str () ); + import_path_label -> setFrameShape ( QFrame::Panel ); + import_path_label -> setFrameShadow ( QFrame::Sunken ); + layout -> addWidget ( import_path_label ); + + QPushButton *edit = new QPushButton ( "Edit" ); + connect ( edit, SIGNAL ( clicked () ), this, SLOT ( edit_import_path () ) ); + edit -> setFixedSize ( 30, 20 ); + layout -> addWidget ( edit ); - revert = new QPushButton ( "Revert" ); - revert -> setDisabled ( true ); - connect ( revert, SIGNAL ( clicked () ), this, SLOT ( reload_config () ) ); + v_layout -> addLayout ( layout ); + v_layout -> addStretch ( 1 ); - layout -> addWidget ( revert ); - layout -> addWidget ( apply ); - //layout -> addWidget ( ok ); + // last + layout = new QHBoxLayout (); + layout -> setAlignment ( Qt::AlignBottom | Qt::AlignRight ); + + QPushButton *done = new QPushButton ( "Done" ); + connect ( done, SIGNAL ( clicked () ), adv_setting_window, SLOT ( close () ) ); + + layout -> addWidget ( done ); + v_layout -> addLayout ( layout ); + + adv_setting_window -> setLayout ( v_layout ); - return layout; + adv_setting_window -> show (); } void SRAConfig :: commit_config () { - model . commit (); + if ( ! model . commit () ) + QMessageBox::information ( this, "", "Error saving changes" ); - apply -> setDisabled ( true ); - revert -> setDisabled ( true ); + apply_btn -> setDisabled ( true ); + discard_btn -> setDisabled ( true ); } void SRAConfig :: reload_config () @@ -653,8 +880,10 @@ void SRAConfig :: reload_config () if ( ! model . get_config_changed () ) { - apply -> setDisabled ( true ); - revert -> setDisabled ( true ); + apply_btn -> setDisabled ( true ); + apply_action -> setDisabled ( true ); + discard_btn -> setDisabled ( true ); + discard_action -> setDisabled ( true ); } } @@ -662,17 +891,23 @@ void SRAConfig :: modified_config () { if ( model . get_config_changed () ) // this wont trigger on workspace addition yet { - apply -> setDisabled ( false ); - revert -> setDisabled ( false ); + apply_btn -> setDisabled ( false ); + apply_action -> setDisabled ( false ); + discard_btn -> setDisabled ( false ); + discard_action -> setDisabled ( false ); } } -// TBD - still needs a menu item to be triggered. +// TBD - still needs a menu item to be triggered. -- this is not a hard reset - it still keeps some user settings void SRAConfig :: default_config () { model . set_remote_enabled ( true ); model . set_global_cache_enabled ( true ); model . set_site_enabled ( true ); + + populate (); + + emit dirty_config (); } void SRAConfig :: toggle_remote_enabled ( bool toggled ) @@ -705,6 +940,30 @@ void SRAConfig :: toggle_prioritize_http ( bool toggled ) emit dirty_config (); } +void SRAConfig :: edit_import_path () +{ + QString path = model . get_user_default_dir () . c_str (); + + if ( ! model . does_path_exist ( path . toStdString () ) ) + path = model . get_home_dir () . c_str (); + + if ( ! model . does_path_exist ( path . toStdString () ) ) + path = model . get_current_dir () . c_str (); + + QString e_path = QFileDialog :: getOpenFileName ( adv_setting_window + , "" + , path ); + + + if ( e_path . isEmpty () ) + return; + + import_path_label -> setText ( e_path ); + model . set_user_default_dir ( e_path . toStdString () . c_str () ); + + emit dirty_config (); +} + void SRAConfig :: edit_proxy_path () { QString input = QInputDialog::getText ( this @@ -722,4 +981,36 @@ void SRAConfig :: edit_proxy_path () emit dirty_config (); } +void SRAConfig :: edit_public_path () +{ + qDebug () << public_workspace -> ngc_id; + if ( select_public_location ( model, this ) ) + { + public_workspace -> path_label -> setText ( model . get_public_location () . c_str () ); + + emit dirty_config (); + } +} + +void SRAConfig :: edit_workspace_path () +{ + foreach ( WorkspaceItem *item, protected_workspaces ) + { + if ( sender () == item -> edit_button ) + { + qDebug () << item -> ngc_id; + + if ( select_protected_location ( model, item -> ngc_id, this ) ) + { + item -> path_label -> setText ( model . get_repo_location ( item -> ngc_id ) . c_str () ); + import_path_label -> setText ( model . get_repo_location ( item -> ngc_id ) . c_str () ); + + emit dirty_config (); + } + + return; + } + } +} + diff --git a/tools/vdb-config/sra-config/sraconfig.h b/tools/vdb-config/sra-config/sraconfig.h index 890d19bc..af866116 100644 --- a/tools/vdb-config/sra-config/sraconfig.h +++ b/tools/vdb-config/sra-config/sraconfig.h @@ -33,6 +33,7 @@ QT_BEGIN_NAMESPACE class QHBoxLayout; class QVBoxLayout; class QCheckBox; +class QFrame; class QGroupBox; class QLabel; class QPushButton; @@ -40,6 +41,7 @@ QT_END_NAMESPACE class vdbconf_model; struct KNgcObj; +struct WorkspaceItem; class SRAConfig : public QMainWindow { @@ -55,6 +57,7 @@ class SRAConfig : public QMainWindow private slots: + void advanced_settings (); void commit_config (); void reload_config (); void default_config (); @@ -62,7 +65,10 @@ private slots: void import_workspace (); + void edit_import_path (); void edit_proxy_path (); + void edit_public_path (); + void edit_workspace_path (); void toggle_remote_enabled ( bool toggled ); void toggle_local_caching ( bool toggled ); @@ -74,8 +80,20 @@ private slots: private: + + void closeEvent ( QCloseEvent *event ); + void populate (); + + void add_workspace ( QString name, QString val, int ngc_id, bool insert = false ); + + void setup_menubar (); + void setup_toolbar (); + vdbconf_model &model; + QAction *discard_action; + QAction *apply_action; + QRect screen_geometry; QVBoxLayout *main_layout; @@ -88,20 +106,20 @@ private slots: QCheckBox *http_priority_cb; QLabel *proxy_label; + QLabel *import_path_label; - QPushButton *ok; - QPushButton *apply; - QPushButton *revert; + QFrame *adv_setting_window; - void populate (); - - void add_workspace ( QString name, QString val, bool insert = false ); - - void setup_toolbar (); + QPushButton *apply_btn; + QPushButton *discard_btn; QGroupBox* setup_option_group (); QGroupBox* setup_workspace_group (); - QHBoxLayout* setup_button_layout (); + QVBoxLayout *setup_button_layout(); + + WorkspaceItem *public_workspace; + QVector protected_workspaces; + }; #endif // SRACONFIG_H diff --git a/tools/vdb-config/vdb-config-model.cpp b/tools/vdb-config/vdb-config-model.cpp index 44e7999f..0e7e28e7 100644 --- a/tools/vdb-config/vdb-config-model.cpp +++ b/tools/vdb-config/vdb-config-model.cpp @@ -384,7 +384,7 @@ ESetRootState vdbconf_model::set_repo_location(uint32_t id, } ESetRootState vdbconf_model::set_public_location( - bool flushOld, string &path, bool reuseNew) + bool flushOld, const string &path, bool reuseNew) { ESetRootState res = x_ChangeRepoLocation( path, reuseNew, kPublicRepoId, flushOld ); _config_changed = true; @@ -403,7 +403,7 @@ ESetRootState vdbconf_model::prepare_repo_directory (const string &newPath, bool reuseNew) { ESetRootState res = x_ChangeRepoLocation( newPath, reuseNew, kInvalidRepoId ); - _config_changed = true; + /*_config_changed = true;*/ return res; } diff --git a/tools/vdb-config/vdb-config-model.hpp b/tools/vdb-config/vdb-config-model.hpp index bbc2d167..a7bf6577 100644 --- a/tools/vdb-config/vdb-config-model.hpp +++ b/tools/vdb-config/vdb-config-model.hpp @@ -329,7 +329,7 @@ class vdbconf_model std::string get_public_location( void ) const; - ESetRootState set_public_location( bool flushOld, std::string &path, bool reuseNew ); + ESetRootState set_public_location(bool flushOld, const std::string &path, bool reuseNew ); bool is_user_public_enabled( void ) const { From 30451549ad2de94b40e7b535ffe3890a1d5d7039 Mon Sep 17 00:00:00 2001 From: kwrodarmer Date: Wed, 26 Apr 2017 12:24:19 -0400 Subject: [PATCH 19/23] spelling modification --- tools/vdb-config/interactive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/vdb-config/interactive.cpp b/tools/vdb-config/interactive.cpp index 66af49f4..6bb0903e 100644 --- a/tools/vdb-config/interactive.cpp +++ b/tools/vdb-config/interactive.cpp @@ -883,7 +883,7 @@ bool vdbconf_controller::on_set_location_error( Dlg &dlg, ESetRootState s ) case eSetRootState_NewDirNotEmpty : vdbconf_msg( dlg, r, "the given location is not empty" ); break; case eSetRootState_NewNotDir : vdbconf_msg( dlg, r, "new location is not a directory" ); break; case eSetRootState_Error : vdbconf_msg( dlg, r, "error changing location" ); break; - default : vdbconf_msg( dlg, r, "unknow enum" ); break; + default : vdbconf_msg( dlg, r, "unknown enum" ); break; } return result; } From 3bc87c846010453a1e238bdff2661b9cf2a1a760 Mon Sep 17 00:00:00 2001 From: wraetz Date: Wed, 3 May 2017 13:54:14 -0400 Subject: [PATCH 20/23] new len-spread feature --- tools/vdb-dump/vdb-dump-context.c | 2 + tools/vdb-dump/vdb-dump-context.h | 2 + tools/vdb-dump/vdb-dump-fastq.c | 347 ++++++++++++++++++++++++++++++++++++-- tools/vdb-dump/vdb-dump-fastq.h | 2 + tools/vdb-dump/vdb-dump-str.c | 2 +- tools/vdb-dump/vdb-dump-tools.c | 109 ++++++++++++ tools/vdb-dump/vdb-dump-tools.h | 6 + tools/vdb-dump/vdb-dump.c | 138 ++------------- 8 files changed, 470 insertions(+), 138 deletions(-) diff --git a/tools/vdb-dump/vdb-dump-context.c b/tools/vdb-dump/vdb-dump-context.c index bb0c0a1a..17154920 100644 --- a/tools/vdb-dump/vdb-dump-context.c +++ b/tools/vdb-dump/vdb-dump-context.c @@ -138,6 +138,7 @@ static void vdco_init_values( p_dump_context ctx ) ctx->diff = false; ctx->show_spotgroups = false; ctx->show_spread = false; + ctx->len_spread = false; ctx->interactive = false; } @@ -606,6 +607,7 @@ static void vdco_evaluate_options( const Args *my_args, /*ctx->force_sra_schema = vdco_get_bool_option( my_args, OPTION_SRASCHEMA, false );*/ ctx->merge_ranges = vdco_get_bool_option( my_args, OPTION_MERGE_RANGES, false ); ctx->show_spread = vdco_get_bool_option( my_args, OPTION_SPREAD, false ); + ctx->len_spread = vdco_get_bool_option( my_args, OPTION_LEN_SPREAD, false ); ctx->interactive = vdco_get_bool_option( my_args, OPTION_INTERACTIVE, false ); ctx->slice_depth = vdco_get_uint16_option( my_args, OPTION_SLICE, 0 ); diff --git a/tools/vdb-dump/vdb-dump-context.h b/tools/vdb-dump/vdb-dump-context.h index 8edd9358..9d873c53 100644 --- a/tools/vdb-dump/vdb-dump-context.h +++ b/tools/vdb-dump/vdb-dump-context.h @@ -87,6 +87,7 @@ extern "C" { #define OPTION_SPREAD "spread" #define OPTION_SLICE "slice" #define OPTION_INTERACTIVE "interactive" +#define OPTION_LEN_SPREAD "len-spread" #define ALIAS_ROW_ID_ON "I" #define ALIAS_LINE_FEED "l" @@ -198,6 +199,7 @@ typedef struct dump_context bool merge_ranges; bool show_spread; bool interactive; + bool len_spread; } dump_context; typedef dump_context* p_dump_context; diff --git a/tools/vdb-dump/vdb-dump-fastq.c b/tools/vdb-dump/vdb-dump-fastq.c index 9bc6f8e6..a0a3733b 100644 --- a/tools/vdb-dump/vdb-dump-fastq.c +++ b/tools/vdb-dump/vdb-dump-fastq.c @@ -26,6 +26,7 @@ #include "vdb-dump-fastq.h" #include "vdb-dump-helper.h" +#include "vdb-dump-tools.h" #include @@ -991,7 +992,7 @@ static rc_t vdb_fastq_table( const p_dump_context ctx, const VDBManager *mgr, fastq_ctx * fctx ) { - VSchema * schema = NULL; + VSchema * schema = NULL; rc_t rc; vdh_parse_schema( mgr, &schema, &(ctx->schema_list), true /* ctx->force_sra_schema */ ); @@ -1025,25 +1026,42 @@ static rc_t vdb_fastq_database( const p_dump_context ctx, DISP_RC( rc, "VDBManagerOpenDBRead() failed" ); if ( rc == 0 ) { - bool table_defined = ( ctx->table != NULL ); - if ( !table_defined ) - table_defined = vdh_take_this_table_from_db( ctx, db, "SEQUENCE" ); - - if ( table_defined ) + KNamelist *tbl_names; + rc = VDatabaseListTbl( db, &tbl_names ); + if ( rc != 0 ) + ErrMsg( "VDatabaseListTbl( '%s' ) -> %R", ctx->path, rc ); + else + { + if ( ctx->table == NULL ) + { + /* the user DID NOT not specify a table: by default assume the SEQUENCE-table */ + bool table_found = vdh_take_this_table_from_list( ctx, tbl_names, "SEQUENCE" ); + /* if there is no SEQUENCE-table, just pick the first table available... */ + if ( !table_found ) + vdh_take_1st_table_from_db( ctx, tbl_names ); + } + else + { + /* the user DID specify a table: check if the database has a table with this name, + if not try with a sub-string */ + String value; + StringInitCString( &value, ctx->table ); + if ( !list_contains_value( tbl_names, &value ) ) + vdh_take_this_table_from_list( ctx, tbl_names, ctx->table ); + } + rc = KNamelistRelease( tbl_names ); + if ( rc != 0 ) + ErrMsg( "KNamelistRelease() -> %R", rc ); + } + if ( rc == 0 ) { - rc = VDatabaseOpenTableRead( db, &fctx->tbl, "%s", ctx->table ); - DISP_RC( rc, "VDatabaseOpenTableRead() failed" ); + rc = open_table_by_path( db, ctx->table, &fctx->tbl ); /* vdb-dump-tools.c */ if ( rc == 0 ) { rc = vdb_fastq_tbl( ctx, fctx ); VTableRelease( fctx->tbl ); } } - else - { - LOGMSG( klogInfo, "opened as vdb-database, but no table found/defined" ); - ctx->usage_requested = true; - } VDatabaseRelease( db ); } @@ -1106,10 +1124,6 @@ static rc_t vdb_fastq_by_probing( const p_dump_context ctx, PLOGERR( klogInt, ( klogInt, rc, "the path '$(p)' cannot be opened as vdb-database or vdb-table", "p=%s", ctx->path ) ); - if ( vdco_schema_count( ctx ) == 0 ) - { - LOGERR( klogInt, rc, "Maybe it is a legacy table. If so, specify a schema with the -S option" ); - } } return rc; } @@ -1133,3 +1147,302 @@ rc_t vdf_main( const p_dump_context ctx, const VDBManager * mgr, const char * ac return rc; } + +/* ---------------------------------------------------------------------------------------------------- */ + +#define NUM_COUNTERS 1024 + +static rc_t vdf_len_spread_loop( const p_dump_context ctx, + const VCursor * curs, + bool has_read_len, bool has_ref_len, + uint32_t read_len_idx, uint32_t ref_len_idx, + const char * path ) +{ + const struct num_gen_iter * row_iter; + rc_t rc = num_gen_iterator_make( ctx->rows, &row_iter ); + DISP_RC( rc, "num_gen_iterator_make() failed" ); + if ( rc == 0 ) + { + int64_t row_id; + uint64_t read_len_counters[ NUM_COUNTERS ]; + uint64_t ref_len_counters[ NUM_COUNTERS ]; + uint32_t idx; + + + for ( idx = 0; idx < NUM_COUNTERS; ++idx ) + { + read_len_counters[ idx ] = 0; + ref_len_counters[ idx ] = 0; + } + + while ( rc == 0 && num_gen_iterator_next( row_iter, &row_id, &rc ) ) + { + if ( rc == 0 ) + rc = Quitting(); + if ( rc == 0 ) + { + uint32_t elem_bits, boff, row_len; + uint32_t * ptr; + if ( has_read_len ) + { + rc = VCursorCellDataDirect( curs, row_id, read_len_idx, &elem_bits, (const void**)&ptr, &boff, &row_len ); + if ( rc == 0 && row_len > 0 ) + { + if ( *ptr < NUM_COUNTERS ) + read_len_counters[ *ptr ]++; + else + read_len_counters[ NUM_COUNTERS - 1 ]++; + } + } + if ( has_ref_len ) + { + rc = VCursorCellDataDirect( curs, row_id, ref_len_idx, &elem_bits, (const void**)&ptr, &boff, &row_len ); + if ( rc == 0 && row_len > 0 ) + { + if ( *ptr < NUM_COUNTERS ) + ref_len_counters[ *ptr ]++; + else + ref_len_counters[ NUM_COUNTERS - 1 ]++; + } + } + } + } + + num_gen_iterator_destroy( row_iter ); + + for ( idx = 0; idx < NUM_COUNTERS; ++idx ) + { + if ( read_len_counters[ idx ] > 0 ) + rc = KOutMsg( "READ_LEN[ %d ] = %,lu\n", idx, read_len_counters[ idx ] ); + } + for ( idx = 0; idx < NUM_COUNTERS; ++idx ) + { + if ( ref_len_counters[ idx ] > 0 ) + rc = KOutMsg( "REF_LEN[ %d ] = %,lu\n", idx, ref_len_counters[ idx ] ); + } + } + return rc; +} + +static rc_t vdf_len_spread_vdbtbl( const p_dump_context ctx, const VTable * tbl, const char * path ) +{ + KNamelist * col_names; + rc_t rc = VTableListCol( tbl, &col_names ); + DISP_RC( rc, "VTableListCol() failed" ); + if ( rc == 0 ) + { + const VCursor * curs; + rc = VTableCreateCachedCursorRead( tbl, &curs, 1024 * 1024 * 32 ); + DISP_RC( rc, "VTableCreateCursorRead( fasta/fastq ) failed" ); + if ( rc == 0 ) + { + bool has_read_len = is_name_in_list( col_names, "READ_LEN" ); + bool has_ref_len = is_name_in_list( col_names, "REF_LEN" ); + if ( has_read_len || has_ref_len ) + { + uint32_t read_len_idx, ref_len_idx; + if ( has_read_len ) + { + rc = VCursorAddColumn( curs, &read_len_idx, "READ_LEN" ); + if ( rc != 0 ) + { + PLOGERR( klogInt, ( klogInt, rc, "VCurosrAddColumn( '$(col)' ) failed", "col=%s", "READ_LEN" ) ); + } + } + if ( rc == 0 && has_ref_len ) + { + rc = VCursorAddColumn( curs, &ref_len_idx, "REF_LEN" ); + if ( rc != 0 ) + { + PLOGERR( klogInt, ( klogInt, rc, "VCurosrAddColumn( '$(col)' ) failed", "col=%s", "REF_LEN" ) ); + } + } + if ( rc == 0 ) + { + rc = VCursorOpen( curs ); + DISP_RC( rc, "VCursorOpen( len-spread ) failed" ); + } + if ( rc == 0 ) + { + int64_t first; + uint64_t count; + + if ( has_read_len ) + rc = VCursorIdRange( curs, read_len_idx, &first, &count ); + else + rc = VCursorIdRange( curs, ref_len_idx, &first, &count ); + DISP_RC( rc, "VCursorIdRange() failed" ); + if ( rc == 0 ) + { + if ( count == 0 ) + KOutMsg( "this table is empty\n" ); + else + { + /* if the user did not specify a row-range, take all rows */ + if ( ctx->rows == NULL ) + { + rc = num_gen_make_from_range( &ctx->rows, first, count ); + DISP_RC( rc, "num_gen_make_from_range() failed" ); + } + /* if the user did specify a row-range, check the boundaries */ + else + { + rc = num_gen_trim( ctx->rows, first, count ); + DISP_RC( rc, "num_gen_trim() failed" ); + } + } + } + } + if ( rc == 0 && !num_gen_empty( ctx->rows ) ) + rc = vdf_len_spread_loop( ctx, curs, has_read_len, has_ref_len, read_len_idx, ref_len_idx, path ); /* <=== the meat */ + } + else + { + rc = RC( rcVDB, rcNoTarg, rcConstructing, rcItem, rcNotFound ); + PLOGERR( klogInt, ( klogInt, rc, + "neither READ_LEN nor REF_LEN found in '$(p)'", "p=%s", path ) ); + } + VCursorRelease( curs ); + } + KNamelistRelease( col_names ); + } + return rc; + + return KOutMsg( "vdf_len_spread_vdbtbl\n" ); +} + + +static rc_t vdf_len_spread_db( const p_dump_context ctx, const VDBManager * mgr, const char * path ) +{ + const VDatabase * db; + VSchema *schema = NULL; + rc_t rc; + + vdh_parse_schema( mgr, &schema, &(ctx->schema_list), true /* ctx->force_sra_schema */ ); + + rc = VDBManagerOpenDBRead( mgr, &db, schema, "%s", path ); + DISP_RC( rc, "VDBManagerOpenDBRead() failed" ); + if ( rc == 0 ) + { + KNamelist *tbl_names; + rc = VDatabaseListTbl( db, &tbl_names ); + if ( rc != 0 ) + ErrMsg( "VDatabaseListTbl( '%s' ) -> %R", path, rc ); + else + { + if ( ctx->table == NULL ) + { + /* the user DID NOT not specify a table: by default assume the SEQUENCE-table */ + bool table_found = vdh_take_this_table_from_list( ctx, tbl_names, "SEQUENCE" ); + /* if there is no SEQUENCE-table, just pick the first table available... */ + if ( !table_found ) + vdh_take_1st_table_from_db( ctx, tbl_names ); + } + else + { + /* the user DID specify a table: check if the database has a table with this name, + if not try with a sub-string */ + String value; + StringInitCString( &value, ctx->table ); + if ( !list_contains_value( tbl_names, &value ) ) + vdh_take_this_table_from_list( ctx, tbl_names, ctx->table ); + } + rc = KNamelistRelease( tbl_names ); + if ( rc != 0 ) + ErrMsg( "KNamelistRelease() -> %R", rc ); + } + + if ( rc == 0 ) + { + const VTable * tbl; + rc = open_table_by_path( db, ctx->table, &tbl ); /* vdb-dump-tools.c */ + if ( rc == 0 ) + { + rc = vdf_len_spread_vdbtbl( ctx, tbl, path ); + VTableRelease( tbl ); + } + } + VDatabaseRelease( db ); + } + if ( schema != NULL ) + VSchemaRelease( schema ); + return rc; + +} + + +static rc_t vdf_len_spread_tbl( const p_dump_context ctx, const VDBManager * mgr, const char * path ) +{ + VSchema * schema = NULL; + const VTable * tbl; + rc_t rc; + + vdh_parse_schema( mgr, &schema, &(ctx->schema_list), true /* ctx->force_sra_schema */ ); + + rc = VDBManagerOpenTableRead( mgr, &tbl, schema, "%s", path ); + DISP_RC( rc, "VDBManagerOpenTableRead() failed" ); + if ( rc == 0 ) + { + rc = vdf_len_spread_vdbtbl( ctx, tbl, path ); + VTableRelease( tbl ); + } + if ( schema != NULL ) + VSchemaRelease( schema ); + return rc; + +} + + +static rc_t vdf_len_spread_by_pathtype( const p_dump_context ctx, const VDBManager * mgr, const char * path ) +{ + rc_t rc; + int path_type = ( VDBManagerPathType ( mgr, "%s", path ) & ~ kptAlias ); + /* types defined in */ + switch ( path_type ) + { + case kptDatabase : rc = vdf_len_spread_db( ctx, mgr, path ); break; + + case kptPrereleaseTbl: + case kptTable : rc = vdf_len_spread_tbl( ctx, mgr, path ); break; + + default : rc = RC( rcVDB, rcNoTarg, rcConstructing, rcItem, rcNotFound ); + PLOGERR( klogInt, ( klogInt, rc, + "the path '$(p)' cannot be opened as vdb-database or vdb-table", + "p=%s", ctx->path ) ); + break; + } + return rc; + +} + +static rc_t vdf_len_spread_by_probing( const p_dump_context ctx, const VDBManager * mgr, const char * path ) +{ + rc_t rc; + if ( vdh_is_path_database( mgr, path, &(ctx->schema_list) ) ) + { + rc = vdf_len_spread_db( ctx, mgr, path ); + } + else if ( vdh_is_path_table( mgr, path, &(ctx->schema_list) ) ) + { + rc = vdf_len_spread_tbl( ctx, mgr, path ); + } + else + { + rc = RC( rcVDB, rcNoTarg, rcConstructing, rcItem, rcNotFound ); + PLOGERR( klogInt, ( klogInt, rc, + "the path '$(p)' cannot be opened as vdb-database or vdb-table", + "p=%s", path ) ); + } + return rc; + +} + +rc_t vdf_len_spread( const p_dump_context ctx, const VDBManager * mgr, const char * path ) +{ + rc_t rc = 0; + if ( USE_PATHTYPE_TO_DETECT_DB_OR_TAB ) /* in vdb-dump-context.h */ + rc = vdf_len_spread_by_pathtype( ctx, mgr, path ); + else + rc = vdf_len_spread_by_probing( ctx, mgr, path ); + return rc; +} diff --git a/tools/vdb-dump/vdb-dump-fastq.h b/tools/vdb-dump/vdb-dump-fastq.h index 652718ca..e598e398 100644 --- a/tools/vdb-dump/vdb-dump-fastq.h +++ b/tools/vdb-dump/vdb-dump-fastq.h @@ -40,6 +40,8 @@ extern "C" { rc_t vdf_main( const p_dump_context ctx, const VDBManager * mgr, const char * acc_or_path ); +rc_t vdf_len_spread( const p_dump_context ctx, const VDBManager * mgr, const char * path ); + #ifdef __cplusplus } #endif diff --git a/tools/vdb-dump/vdb-dump-str.c b/tools/vdb-dump/vdb-dump-str.c index 8dac7e79..d96e6771 100644 --- a/tools/vdb-dump/vdb-dump-str.c +++ b/tools/vdb-dump/vdb-dump-str.c @@ -537,4 +537,4 @@ rc_t vds_diff( const char * f1, const char * f2 ) clear_recorded_errors(); return rc; -} \ No newline at end of file +} diff --git a/tools/vdb-dump/vdb-dump-tools.c b/tools/vdb-dump/vdb-dump-tools.c index bbcee5c9..f831578f 100644 --- a/tools/vdb-dump/vdb-dump-tools.c +++ b/tools/vdb-dump/vdb-dump-tools.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -526,3 +527,111 @@ rc_t vdt_dump_element( const p_dump_src src, const p_col_def def, bool bracket ) src->element_idx++; return rc; } + + +void vdm_clear_recorded_errors( void ) +{ + rc_t rc; + const char * filename; + const char * funcname; + uint32_t line_nr; + while ( GetUnreadRCInfo ( &rc, &filename, &funcname, &line_nr ) ) + { + } +} + + +static rc_t walk_sections( const VDatabase * base_db, const VDatabase ** sub_db, + const VNamelist * sections, uint32_t count ) +{ + rc_t rc = 0; + const VDatabase * parent_db = base_db; + if ( count == 0 ) + { + rc = VDatabaseAddRef ( parent_db ); + DISP_RC( rc, "VDatabaseAddRef() failed" ); + } + else + { + uint32_t idx; + for ( idx = 0; rc == 0 && idx < count; ++idx ) + { + const char * dbname; + rc = VNameListGet ( sections, idx, &dbname ); + DISP_RC( rc, "VNameListGet() failed" ); + if ( rc == 0 ) + { + const VDatabase * temp; + rc = VDatabaseOpenDBRead ( parent_db, &temp, "%s", dbname ); + DISP_RC( rc, "VDatabaseOpenDBRead() failed" ); + if ( rc == 0 && idx > 0 ) + { + rc = VDatabaseRelease ( parent_db ); + DISP_RC( rc, "VDatabaseRelease() failed" ); + } + if ( rc == 0 ) + parent_db = temp; + } + } + } + + if ( rc == 0 ) *sub_db = parent_db; + return rc; +} + + +rc_t check_table_empty( const VTable * tab ) +{ + bool empty; + rc_t rc = VTableIsEmpty( tab, &empty ); + DISP_RC( rc, "VTableIsEmpty() failed" ); + if ( rc == 0 && empty ) + { + vdm_clear_recorded_errors(); + KOutMsg( "the requested table is empty!\n" ); + rc = RC( rcVDB, rcNoTarg, rcConstructing, rcTable, rcEmpty ); + } + return rc; +} + + +rc_t open_table_by_path( const VDatabase * db, const char * inner_db_path, const VTable ** tab ) +{ + VNamelist * sections; + rc_t rc = vds_path_to_sections( inner_db_path, '.', §ions ); + DISP_RC( rc, "vds_path_to_sections() failed" ); + if ( rc == 0 ) + { + uint32_t count; + rc = VNameListCount ( sections, &count ); + DISP_RC( rc, "VNameListCount() failed" ); + if ( rc == 0 && count > 0 ) + { + const VDatabase * sub_db; + rc = walk_sections( db, &sub_db, sections, count - 1 ); + if ( rc == 0 ) + { + const char * tabname; + rc = VNameListGet ( sections, count - 1, &tabname ); + DISP_RC( rc, "VNameListGet() failed" ); + if ( rc == 0 ) + { + rc = VDatabaseOpenTableRead( sub_db, tab, "%s", tabname ); + DISP_RC( rc, "VDatabaseOpenTableRead() failed" ); + if ( rc == 0 ) + { + rc = check_table_empty( *tab ); + if ( rc != 0 ) + { + VTableRelease( *tab ); + tab = NULL; + } + } + } + VDatabaseRelease ( sub_db ); + } + } + VNamelistRelease ( sections ); + } + return rc; +} diff --git a/tools/vdb-dump/vdb-dump-tools.h b/tools/vdb-dump/vdb-dump-tools.h index d8b7ac71..64060c27 100644 --- a/tools/vdb-dump/vdb-dump-tools.h +++ b/tools/vdb-dump/vdb-dump-tools.h @@ -53,6 +53,12 @@ typedef dump_src* p_dump_src; rc_t vdt_dump_element( const p_dump_src src, const p_col_def def, bool bracket ); +void vdm_clear_recorded_errors( void ); + +rc_t check_table_empty( const VTable * tab ); + +rc_t open_table_by_path( const VDatabase * db, const char * inner_db_path, const VTable ** tab ); + #ifdef __cplusplus } #endif diff --git a/tools/vdb-dump/vdb-dump.c b/tools/vdb-dump/vdb-dump.c index a058c4c2..3ad4f5d7 100644 --- a/tools/vdb-dump/vdb-dump.c +++ b/tools/vdb-dump/vdb-dump.c @@ -119,6 +119,7 @@ static const char * info_usage[] = { "print info about run", static const char * spotgroup_usage[] = { "show spotgroups", NULL }; static const char * merge_ranges_usage[] = { "merge and sort row-ranges", NULL }; static const char * spread_usage[] = { "show spread of integer values", NULL }; +static const char * len_spread_usage[] = { "show spread of READ/REF_LEN values", NULL }; static const char * slice_usage[] = { "find a slice of given depth", NULL }; static const char * interactive_usage[] = { "interactive mode", NULL }; @@ -169,6 +170,7 @@ OptDef DumpOptions[] = { OPTION_SPOTGROUPS, NULL, NULL, spotgroup_usage, 1, false, false }, { OPTION_MERGE_RANGES, NULL, NULL, merge_ranges_usage, 1, false, false }, { OPTION_SPREAD, NULL, NULL, spread_usage, 1, false, false }, + { OPTION_LEN_SPREAD, NULL, NULL, len_spread_usage, 1, false, false }, { OPTION_INTERACTIVE, NULL, NULL, interactive_usage, 1, false, false }, { OPTION_SLICE, NULL, NULL, slice_usage, 1, true, false } }; @@ -726,117 +728,11 @@ static rc_t vdm_dump_opened_table( const p_dump_context ctx, const VTable *my_ta ctx [IN] ... contains path, tablename, columns, row-range etc. my_database [IN] ... open database needed for vdb-calls *************************************************************************************/ -static rc_t vdm_walk_sections( const VDatabase * base_db, const VDatabase ** sub_db, - const VNamelist * sections, uint32_t count ) -{ - rc_t rc = 0; - const VDatabase * parent_db = base_db; - if ( count == 0 ) - { - rc = VDatabaseAddRef ( parent_db ); - DISP_RC( rc, "VDatabaseAddRef() failed" ); - } - else - { - uint32_t idx; - for ( idx = 0; rc == 0 && idx < count; ++idx ) - { - const char * dbname; - rc = VNameListGet ( sections, idx, &dbname ); - DISP_RC( rc, "VNameListGet() failed" ); - if ( rc == 0 ) - { - const VDatabase * temp; - rc = VDatabaseOpenDBRead ( parent_db, &temp, "%s", dbname ); - DISP_RC( rc, "VDatabaseOpenDBRead() failed" ); - if ( rc == 0 && idx > 0 ) - { - rc = VDatabaseRelease ( parent_db ); - DISP_RC( rc, "VDatabaseRelease() failed" ); - } - if ( rc == 0 ) - parent_db = temp; - } - } - } - - if ( rc == 0 ) *sub_db = parent_db; - return rc; -} - - -static void vdm_clear_recorded_errors( void ) -{ - rc_t rc; - const char * filename; - const char * funcname; - uint32_t line_nr; - while ( GetUnreadRCInfo ( &rc, &filename, &funcname, &line_nr ) ) - { - } -} - - -static rc_t vdm_check_table_empty( const VTable * tab ) -{ - bool empty; - rc_t rc = VTableIsEmpty( tab, &empty ); - DISP_RC( rc, "VTableIsEmpty() failed" ); - if ( rc == 0 && empty ) - { - vdm_clear_recorded_errors(); - KOutMsg( "the requested table is empty!\n" ); - rc = RC( rcVDB, rcNoTarg, rcConstructing, rcTable, rcEmpty ); - } - return rc; -} - -static rc_t vdm_open_table_by_path( const VDatabase * db, const char * path, const VTable ** tab ) -{ - VNamelist * sections; - rc_t rc = vds_path_to_sections( path, '.', §ions ); - DISP_RC( rc, "vds_path_to_sections() failed" ); - if ( rc == 0 ) - { - uint32_t count; - rc = VNameListCount ( sections, &count ); - DISP_RC( rc, "VNameListCount() failed" ); - if ( rc == 0 && count > 0 ) - { - const VDatabase * sub_db; - rc = vdm_walk_sections( db, &sub_db, sections, count - 1 ); - if ( rc == 0 ) - { - const char * tabname; - rc = VNameListGet ( sections, count - 1, &tabname ); - DISP_RC( rc, "VNameListGet() failed" ); - if ( rc == 0 ) - { - rc = VDatabaseOpenTableRead( sub_db, tab, "%s", tabname ); - DISP_RC( rc, "VDatabaseOpenTableRead() failed" ); - if ( rc == 0 ) - { - rc = vdm_check_table_empty( *tab ); - if ( rc != 0 ) - { - VTableRelease( *tab ); - tab = NULL; - } - } - } - VDatabaseRelease ( sub_db ); - } - } - VNamelistRelease ( sections ); - } - return rc; -} - static rc_t vdm_dump_opened_database( const p_dump_context ctx, const VDatabase *my_database ) { const VTable *my_table; - rc_t rc = vdm_open_table_by_path( my_database, ctx->table, &my_table ); + rc_t rc = open_table_by_path( my_database, ctx->table, &my_table ); if ( rc == 0 ) { rc = vdm_dump_opened_table( ctx, my_table ); @@ -919,7 +815,7 @@ static rc_t vdm_show_db_spread( const p_dump_context ctx, const VDatabase *my_database ) { const VTable *my_table; - rc_t rc = vdm_open_table_by_path( my_database, ctx->table, &my_table ); + rc_t rc = open_table_by_path( my_database, ctx->table, &my_table ); if ( rc == 0 ) { rc = vdm_show_tab_spread( ctx, my_table ); @@ -999,7 +895,7 @@ static rc_t vdm_dump_db_schema( const p_dump_context ctx, { /* the user has given a database as object, but asks to inspect a given table */ const VTable *my_table; - rc = vdm_open_table_by_path( my_database, ctx->table, &my_table ); + rc = open_table_by_path( my_database, ctx->table, &my_table ); if ( rc == 0 ) { rc = vdm_dump_tab_schema( ctx, my_table ); @@ -1447,7 +1343,7 @@ my_database [IN] ... open database needed for vdb-calls static rc_t vdm_enum_db_columns( const p_dump_context ctx, const VDatabase *my_database ) { const VTable *my_table; - rc_t rc = vdm_open_table_by_path( my_database, ctx->table, &my_table ); + rc_t rc = open_table_by_path( my_database, ctx->table, &my_table ); if ( rc == 0 ) { rc = vdm_enum_tab_columns( ctx, my_table ); @@ -1520,7 +1416,7 @@ my_database [IN] ... open database needed for vdb-calls static rc_t vdm_print_db_id_range( const p_dump_context ctx, const VDatabase *my_database ) { const VTable *my_table; - rc_t rc = vdm_open_table_by_path( my_database, ctx->table, &my_table ); + rc_t rc = open_table_by_path( my_database, ctx->table, &my_table ); if ( rc == 0 ) { rc = vdm_print_tab_id_range( ctx, my_table ); @@ -1621,7 +1517,7 @@ static rc_t vdm_enum_tab_index( const p_dump_context ctx, const VTable *my_table static rc_t vdm_enum_db_index( const p_dump_context ctx, const VDatabase *my_database ) { const VTable *my_table; - rc_t rc = vdm_open_table_by_path( my_database, ctx->table, &my_table ); + rc_t rc = open_table_by_path( my_database, ctx->table, &my_table ); if ( rc == 0 ) { rc = vdm_enum_tab_index( ctx, my_table ); @@ -1670,7 +1566,7 @@ static rc_t vdm_range_tab_index( const p_dump_context ctx, const VTable *my_tabl static rc_t vdm_range_db_index( const p_dump_context ctx, const VDatabase *my_database ) { const VTable *my_table; - rc_t rc = vdm_open_table_by_path( my_database, ctx->table, &my_table ); + rc_t rc = open_table_by_path( my_database, ctx->table, &my_table ); if ( rc == 0 ) { rc = vdm_range_tab_index( ctx, my_table ); @@ -1766,7 +1662,7 @@ static rc_t vdm_show_tab_spotgroups( const p_dump_context ctx, const VTable *my_ static rc_t vdm_show_db_spotgroups( const p_dump_context ctx, const VDatabase *my_database ) { const VTable *my_table; - rc_t rc = vdm_open_table_by_path( my_database, ctx->table, &my_table ); + rc_t rc = open_table_by_path( my_database, ctx->table, &my_table ); if ( rc == 0 ) { rc = vdm_show_tab_spotgroups( ctx, my_table ); @@ -1808,7 +1704,7 @@ static rc_t vdm_dump_tab_fkt( const p_dump_context ctx, ErrMsg( "VDBManagerOpenTableRead( '%R' ) -> %R", ctx->path, rc ); else { - rc = vdm_check_table_empty( my_table ); + rc = check_table_empty( my_table ); if ( rc == 0 ) rc = tab_fkt( ctx, my_table ); /* fkt-pointer is called */ VTableRelease( my_table ); @@ -2264,6 +2160,8 @@ static rc_t vdm_main( const p_dump_context ctx, Args * args ) if ( ctx->print_info ) rc = vdb_info( &(ctx->schema_list), ctx->format, mgr, value, ctx->rows ); /* in vdb_info.c */ + else if ( ctx->len_spread ) + rc = vdf_len_spread( ctx, mgr, value ); /* in vdb-dump-fastq.c */ else switch( ctx->format ) { case df_fastq : ; @@ -2379,17 +2277,17 @@ rc_t CC KMain ( int argc, char *argv [] ) if ( rc == 0 ) { if ( ctx->phase > 0 ) - rc = vdi_bin_phase( ctx, args ); /* vdb-dump-bin.c */ + rc = vdi_bin_phase( ctx, args ); /* vdb-dump-bin.c */ else if ( ctx->diff ) - rc = diff_files( args ); /* above calls into vdb-dump-str.c */ + rc = diff_files( args ); /* code is above, calls into vdb-dump-str.c */ else if ( ctx->interactive ) - rc = vdi_main( ctx, args ); /* vdb-dump-interact.c */ + rc = vdi_main( ctx, args ); /* vdb-dump-interact.c */ else if ( ctx->slice_depth > 0 ) - rc = find_slice( ctx, args ); /* vdb-dump-str.c */ + rc = find_slice( ctx, args ); /* vdb-dump-str.c */ else rc = vdm_main( ctx, args ); - release_out_redir( &redir ); /* vdb-dump-redir.c */ + release_out_redir( &redir ); /* vdb-dump-redir.c */ } } vdco_destroy( ctx ); From e9efc1dd62c48ede8065e48817897a58ec5bbca1 Mon Sep 17 00:00:00 2001 From: ksrodarmer Date: Wed, 17 May 2017 16:02:14 -0400 Subject: [PATCH 21/23] beginning to break apart the all in one sraconfig class. started by adding an class that will act as the interface to the vdbconf-model --- tools/vdb-config/sra-config/images/aws_icon.png | Bin 13761 -> 13050 bytes tools/vdb-config/sra-config/images/images.ncbi.png | Bin 0 -> 71471 bytes .../sra-config/images/troubleshooting.png | Bin 0 -> 21965 bytes tools/vdb-config/sra-config/resources.qrc | 4 + tools/vdb-config/sra-config/sra-config.pro | 8 +- tools/vdb-config/sra-config/sra-config.pro.user | 2 +- tools/vdb-config/sra-config/sraconfig.cpp | 6 +- tools/vdb-config/sra-config/sraconfig.h | 1 + tools/vdb-config/sra-config/sraconfigmodel.cpp | 180 +++++++++++++++++++++ tools/vdb-config/sra-config/sraconfigmodel.h | 75 +++++++++ tools/vdb-config/sra-config/srapreferences.cpp | 6 + tools/vdb-config/sra-config/srapreferences.h | 12 ++ .../vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp | 20 ++- 13 files changed, 301 insertions(+), 13 deletions(-) create mode 100644 tools/vdb-config/sra-config/images/images.ncbi.png create mode 100644 tools/vdb-config/sra-config/images/troubleshooting.png create mode 100644 tools/vdb-config/sra-config/sraconfigmodel.cpp create mode 100644 tools/vdb-config/sra-config/sraconfigmodel.h create mode 100644 tools/vdb-config/sra-config/srapreferences.cpp create mode 100644 tools/vdb-config/sra-config/srapreferences.h diff --git a/tools/vdb-config/sra-config/images/aws_icon.png b/tools/vdb-config/sra-config/images/aws_icon.png index b0b4ed67d7efa4d5f72108da4706ccec82076411..46417fb241ce344212aebbab0e13f5c9ec977f91 100644 GIT binary patch delta 9993 zcmV+kC-&IEYx-p&iBL{Q4GJ0x0000DNk~Le0001!0000<2nGNE069PuT(Ke53j{Pb zJTH^r3l)IvoVnM}j)L5}2pcLr{h#;W!Ds5(%{{MZ~z30xE z;ZDKK`+WGw-F)ucbNAVMon3x=t+m%$`w*#AvQ$cqKqHJmS|iX%k$*^yfR8{5Oer8V z+6bh;)M!JQB9sDC3ImNc0_lxL>Hn0F_6U{b`czn@K9Pu;9f|4_`3_HoR)y1ZT4`}w z_FZUwhsS@9tL&v zSysB~Gb`V@TKT21E=STVEj!OL@`hMun*%MqSx-yLY$ZVC3J77zEn4MqS_P}EWXl{Y z-8kLKbzNB=(27`EPFv9$ELsOydea`F)iMdKMi}kyIf=asOn=Ue%Eg72S<&iu1)|wj zv1^kiewT@jxOjqJ!95}pPmyS*MKYUPdW*i6)p4|CwK>=fu?2TY(E7@XR=s1To9D)8 zm5EkmnTty&<(w!+D=n*qrMK)STB9s0|DY;bv4W|;^^Cw?1SWBjT^p@J+$T-qtD~*~EZVe-Wwah_87=x*T9fuJb}CA?T7TKLF9fJ!=R|<1QaTSHDHSJ! z^OOlJ>8dME^uuVt;GUMk@Tg07R?E0Z4hXe zNgU3zvMuvPYk)N$bfa*Uxer66;a%VB6!40Y?N+f#y3Ll)HHR&v&$N>s)72+7CdM*! zZ@v|;`+rD)SSr10omCcZ5vM5@qtPy{g?4=;iMbf9* z#90cLKIuTBjH^b8O;Yn${$ouJ>;4GIT&q3>$t`4KOh z5_6$JYT)HwC+3pQyE4Q1%z5w$`Wf7hB!75Rs7^J+1T~U>C+O}$o#d4Ez1+PFOj4^I z6#+Ct6Otq=bXS*hv3N#+0=|{w`~2!9ll}6#p=Zc89%qN4%w!c)d5IC&i@+3-E2EPP zi*4l<$r1(>ViJc(qP4YLL~!oP#e$zM+O(VecDP97VrkM={=2$q1yBhf2(5@L-hcS% zqRqOg3475H)zbgHCHp%l;2L&pHL}lCR>;4V#$<_%{9+BA{Ho4}XqC&gA(uz#vfcWVm8O^FcDU#{jDMuVCr{i%}UbNQ1S$`s@arw?~ z;viA@3ACDa68MISR$p;5(MreBn@W2+0`)t3Wp%C;*Qh93Z^eoQDp~)D{8*aUz$)#a z(FEt@J2%K`f0(5=?;V?vARHuU6`>#U)>jm+6|HHaHN_{mI<07omOS{G@}Ci_6iLs~ z^9Va3x-vr?QGPga3>SrnA%7P|fxrqL7XFR{7>-JR)DE~2;M{XsVY;d7U<4{E6aiaj za2&oZdFF|5EM7NJEBb3WRkvvZN;E045L(ToPbTq2X&Jc!LVFKd%kFfXbB5S`l@Vu) z(VAq%Yeh>ODWHW@6?$P>aJgu%xSj&woR&gEg8M-Sf^RxfR#s+Pw|{Q6EnBu&K|z6~ zrKMS`maQzmO}^#il`*==9hD3O%eUvSu@4I%n4B>uO zR+iD;?c29I4aOrs)b|=qNcyv0FqM5fUrH?zjM<8O+$vGA!AiF+QmBVwjO1mnEG=|y z5zXyv(N_IE{MBQNh*Xq5Q&zA_u||pqiZ+oL`$9U2lxxwdD1TNs2_j5ll28wiRYETk zAfqZz7)ho=X`$;;j{z-t{3DsIt96D>d@BIG@x~iAVZsF4uzrK>+Epa*M14T}_wQ$C zpL32495~R@HE<+=F?rG?uTxP`X)T&Jw;%uH$F^|cB76Def7+VWt2GIkcF3WJ*!kyQ zpn=V^ufO@mo_~4zX`3^9j#UWw?c2Avb42&>BP5bD6`~TKFeYnPaj{LBIMK$x{kAP# zs^B~aZG`}vV_my-wNp+x)s8;qXa_kH4WKt{*kI$Hddk+USyQcl)qg~+nE?6IpZ(N2 zcG9>i(H8*z>MO6RR^*Z%dItzEm;GBY#mz=IC5i!Qpz+O|`qg%)Ogsa`N`oAxW8Xd)R2kIiV= zUphu>fh$))+F_;Aozek_LOXDrR+K1CXy*#oamt92RJ?ZcVYh0B*50Q@yfSg~S--F3&E zHf4%px;2rN0tb^rVxm~Vty{IWTW`P3Mjv~ubCP0B_Fo@(z{WoQxYudXyoH^8?m70a zS6;PEnha?0h)jXx#1l^v(0*cf-*uNz{Gl?+^QA)89pl7TNFazT4)`Q9PG`l6aP$laZcbhaG;H-EiZL*0ZP71&s&5 zzJK+W-`X3mzwY#U^z5NUajrf5@I$t9=gvgmseAYlhua_i^e2C2n7et!8h>a@Jqozk zZ}E1;P0#e;v$X71F1n)4dstu2tj3sh0TUqgz!fbfi*V{j?0}IwW)_(}m+9XbtFZLDqEwzhipD%-Yoo0Sxo_^N;Y+2?H7@Zpx1m*)e{;FL7+4h`W1A$x-gxbGJAeA< zV>IART~xgD&O64l!s3S2j|hV6AWpb`>dB|<&_fTk!9#`!C<47WM|wuOrN=o4edPHi zB~mE_Ctn`1H6oB_c{^zD!w)@Vvt}tyzO>9a3gU@2(zaa^Ws@dNR-g0jrr(TlF&lub zq!hYl>({Th=bnAm3JVIW`mU#yYkv_;o;=w;{NMvS`IJ*!TzZ8%{?r2|YBG2V*HDa6 zdBIx$n79R?X{N0_ySl<9R6YnFQwq&!DzS=UPY@^;3CebnYbU@cxY8fHF9-`|?#=Gwvq3vB0(7*_!l)2B_hmaSUa&|$-D&8pP`>S})`ZTM>G zQgNeg5+%6~l4qZO##cCm0q!-|{?bMsa)@o*xY7RmPk**qGsS83ylv9&KK=Al8zAw^ zB4{UZa_ME4`Q%cUNr#J!dw*)2+JYVw=S_nz(pn257E6VuDsI6 z=5K#}Q1m~sVu}2B#*cTAcii#ELAqLklcHnx>(|fKg8B33+m7uDa~6=x1kkAxoyQ%2 zLgRobV6)x=W|j;+$OG6MJX)=aFLEFS_XD0BYBqzBEWyDLks2N6W`7RcDp)3~lE{NQ zb??#Las_}=DXuq-8Dj@Y)}tRFf{^=wi8dD&6&lKL6*v=Qe4vh!esSyVx4Rzm=p&EV z6OWIz!b0hUYIw8e&7AfRPCU`+-FU+dHh|O;v*5iqs-vD zo+s6M+hG{LD_XUYtC623bHIoL50paN%~v@S*}HddSAJR10H;W+(%Y=M=q_-uWC`5} z5TaY5V+|cT%$|MbnFN?nX5k3z_}XYU)>WL(!IWrIY+z8z@4fFn-wp2Axx-qw&T}rr z%7^o969)r4!GAci7=r!+T0|X_&2I5yZ6=ZIUZpad$i|&${m1)DZV>?E=2|K!%|M{{__~@g$N%^zHf9iN}<1tzy9>dAGaiWbeu76i;k;Vr<{*|a&*H|P9CAp{*Ogtps)+AMH zWCexmsuL(D8f1WG8h`nLMhTDCA_=Af*CT8lCsi7LR zT-F@PT8bsj_PVr?kJ-GrbM1u}UUc1v3GUdTqy6^QTYVP@7b%d^j5tY_;6k5kCx7*~ z2Oe~V867VxJIhY^!3j15^8p-5W%%Zk6BoMytpeG!irtJ5%PCjcfU}Xq_@JZ*^@Dn~ ze#g30>+NJW>NahPB_|zgWrio$hf{xo=U1;2FHB}oAk>m1S^iA&`2@6Lrh?#?c4uPq zb2WMFI!K5q41sVYbQ%V7`;P5?uYb-z$r?~+h3YrM)#u1?SfpJez`>}w|G)vhqeRbP z5>bZ3x?60rl_L>^e)r@PPr9z<`67(2#4hg>*?TaUu9x1$Jw#K-jvf6O3=lL63yU0t zLF;fW70bpJh&7CmDDN?Ac6=PejSnj7JDA&AZih-%zpRrpWwah7d(tKuE`O!S%IK(; z@u*k;Tl`5hEBH8RO)3u9NQPv1%l&2j?x1Vw9Bqb*4Qrs~N`aR9xMH9py(d0w&`)hfsO?pd0F ztx~W9Jtq8(J&N5WfCvBooP%kTC_ zWrAY6-K!;|PB1mu??O3QkC)Y2(E>75mhW6CADvdapVN=AYXxx#Jb!xe1FyG{qnA^& z8Ti)p5{YzKxOG$DDY0D9%ISQf5du=OQDGnjE0w(?MhoTFlUTUyDUpbFPMJ;JmzSaU z31qejq6e^b#AX;HWsGgd>#FBZjD5nby$r*HGTN<{<(l0XK*Lb@qC^n3BDhyLB^$Iv zUOj+H+*UtvEXNdiT7OV!3uIKqg50fpclU?QoGCD2S5qY>`Kx7LxsMS4+2Su2yD5Tt z-1l~?j4v2{ljzTK0WdGGwf)C`{->RN_Br;KzufO-uwcLX>Z>x?cF``c!hLl`;#MT= zWEWk0k#7P}@Eep89cxf&FH|R(aMnh1yIKyPE~mPuzf=y}5`X#K(sJZOqss~p$;cn# z=l|hE>72Ti@2`Y~@@BKYpZmKIJsYu|b0d$>cvtZjoZ&B~6<;)vmho3Qd&Bov_ixM24J}f!k!g z3~)0(`%D(y<9};V+rys>G#@?3r#U|GShF!#psxWI+$T4W`Hj0V)^Av^E=JtMP@swD z{`PI#Wmuf&8-`$)M;SyBJ~+1R^aZ0MVx2lA>MP=sa;Khlsw~t~q&vRvAe|zM`j-MF z+y^m7dF*BaVt4n0-XdXfrw$Lc9o<93~3s()5iudj(Jwg`V(R{NvXB5|Z> zj&lusbfgMJ6%?(0&)*Wu#>~@D*cKaix@DS;k zV_EGE*K2V`#(pbL7y2acIiC8HPd&vZO!&zCW^S?7bMQ$a7BDnkea$uY+4RpmIsn_z z<(L1|y?^LTR!sNM#8t{lqtQhak$4)DKpy4bG%?ZXw_|@)G^Tq{Rys`l*6<^oK}*ks}Yb!xV|oy<2w~ zDqA=((5Jp!yx2aJD4aicp0Pjx6Nb#IfB8#yE`Q@YWYOTLCegm^tZc(?c==B+cQHvF zKA1KF4yvD?f<7RAF|DM@=0+JetOkW*MQi=ra4<1sgs`Fyh29F{*AjDO+rQLXOy1V( zYL-e0%56bN2`t@WUh{|s9oI=Y`jP_UDiCu5QZ~SpXk)nmC`-QC*{uV(OaKfP=a*#D zVSgtD3&&80esIdEr^+JS%a|~@Mc;mXwUSTs)y~Srgn;1>2<3_c;8kY=7;KDqa4)v^ z4Dvw-A1u8?;#b$uA1MPOOBejLm17wtnR?tKoCAa5#E(Cg<9MqZLNR0>FM5X_c9=f{ zjglIjH<=Jnynit(umdBZZ1?Zq-`j-Wkl*xy_V$t0|DJpA zHT-llXUue9G50uk4?XNqg}a>M?ExGl7TUoAERJ5a##{aM8^>k;Vn331O`5w$BM%?Lt@Y{O2UzxE2%7X zxF!LlARdU{JP#d=6jj+EPRcX*qk20f$_fh${61FYaLg0+q0PkZX`lLYvGARS zUJC@f*1T^83;!V1>MQ+uebz(sT=Iuo(hzM3Wa01)q#EKw**Wzj~$ zK{tpqu>yAQd_$V!-JmC`o@@Y<(g?a9AMmkq?&8(|`4zvgzJ2>T5WHTJ34Z}FwcgW> z@UVK1lF^7!*rUG~Mz59lo;`cEjg|8jKmiC6&kUZ+7}Plq^|asnw+C$oOnbgGs&!oh zN=Qis?~N=LK-l$3IadH(dh`AKph31?=@(JtWyyxA0uOI(TOw|@N&u4$BpxjgiyEj# zc#nVh!0jmxYYf(+g$otdGJjv5^7Yn7qLLL}YpUy>D%ClWwGyrW2EggswVSs61unkB z&*3`!yH0BLw7<^2*FyN;1XGMEL(Z1A>Rm{3Lh2=?1i|@<51oZ8{OVbS=`Qt>!4$>n zQFqT1D*jAJN4( z{R%b@fga@dMH3n%Xi|pzTnG2V0to-z$g z49bidpV`w-J#FV-aDTol)95rGy#Kzo{xjUD*S&jp*9+cy>rDl_Ewl?2&+Lk^VzWPx z8)oB%jkcc@^fS*s%SA=th(#A7g!ZKu<)~e^&Y*MgB^O(N1lW=Wo6BmQ9;B z&FwsJvQtk#EkTPm62&DiU3otaN8s8 z_!EwIGt+pZ~JbS&Bn>6oNNb3xu)Ojgr_J59QPFQU#(@wI#wahhaG;n z2h0JghNMOT(|>NP1+>H#R72XZ$7LW5Cm>RhQy2peIKU$yCf>Ej#JtlY9ZN8JIk2vKv7!`|)M6oG;fw1zEUd zZvwOr|Lq|+j&|?SLx9heY2qRK`s)?$AO=hX#t}*kh}fwTpoe{mKH>L!TZ`iF4?nDD zwYHx7^?y{f!&>{ZqC$x;zec8qU=h_fQ4ND!Jyg`*>Z#`M>UaO`UrZ=l*p3}L7*=I= zHtS@N#1=yU8e3$z$2SVjU%O_lTnznf(HDz6ETm(nj&}Wx|7E{YNXL~|UFGhKhaUW! zM>fLl5nY6Q-16I7>_&m;+;h*fRV!Bsg#WSvqJJJ$2Hk49I1=WDF*pClqcDkpgsXiz z`4bm8PmdetU_bV_Fu;~1{| zihn?i&FZ&0RPpN@u2($xZ#-P*5k)w_eLwu*Ll0@WT8nCo?%j6B9X3E?Fjbrmmkx`p zA*pdVQ;jEqr8*zq2%L)uK|u2HgbB7t14beMjD!IXEA(=$U;@%c95}+`xUugLN{bnQ zVEhj9>bGy-POJE9_hq50G}lQL0_d>~v41T-@uU;&vBw_ua2GfoR%sGC)22khzA!3))Je1?)jw;5US`uLU^|m*qQ@}aU3(z+(;sJN}&2oM02Rey^9#N=ar|J^-z%W&CFA-b((;2Z2#c_xe)ZJe)9 zDH0%Cp(IQ)6NXKPc9e(~V1g5&y8&DPhusP~fb0`-IUK~C@uNPcYr+OZz`sroZ2*pl z^B^~s>nC%;9e3X8mhyMsdDox!hT^0+8%Kg`bK-`6?~tfGX4GhLvClmy4}U!nBWw@R zJNCF^-C&#U#_IYftx>=f%sK$B4@fkrW|{h%89brtn}O@!zn=h;k1b_f&3mteM!My-* zkT^Wrqepia?$r4;aGB!e;m>S; zs6tQj#in8B`0uJ#cKBg_?Ld=#L#~rFMFeE(RXF_5O8l-Bfx8jm5wXa@!Gj0;U3^WP zUPUqQAr?*O2CJF-hyhk0-~UpW2I0Plt-12p|KYyh`*}8w76EER6I*CbexM@(%Hm?3 zeCgZAISLQM?|*iiA}Akw^ieMZFgwV0 zV;^_jaHoKd9!0qGAAkRQ-}OCk|6gQwxXpDl=bQq2et#Q07BQO@;XG6#&&&I;un zMV$ix7k^!%2u<03;BHI+yS3}Cz1FwN1f1bCJxxy7AfO+egbBy&FkgU#7OQ`qc8;Si<_jc=n^v1u5&v-V9EX1 zyQw$?z|>W`($7xrlTRkQT?;?qg878CjFx$0fPZru%nj&YH~ji~cM}on%wdPCv;*zf zv6JG{yV`gyAdaU4VjSGFv?Im|e9Y+4t~-X?R@-&-cBR^GHYi_!axRnAO70VJnGVMY zC__C+4o7a5{_8FNlbo_by$quD0Bh3Y9Lw!>p@*^XZYKwlgRVhO+pSR3W=-AuKXBjy zc7N0{NBe5#RPOQ>%YD-D)WbP)rN8hZiVW#ka38o1TQL5V>{XX4BrOm@3CAY6=dXL#s;_KTmp0-G-Y4v~=(@NC|^#q}3X z3}1QGl{)kovsW#Yp2g|ogB68l<4AQ%|PjmYy#NLvWvx}a=!X~+UaLVOt$nsvIuvH17j+H7CY0c zWIEYjpa%5yB{bF=>>+dyeQrk!JT7&|%=9g{TC8 zQfo(Kz5J5kp4DH}PA7%I()R!av;%-JPJe7fFl+*T78x{omV;4!#v0C807BFPXaxOs;BRLj#++289C0890K1xq1 zA<%dOkm5{@H4L}M^jW?G2Jf;5+0tQ00000NkvXXu0mjf4bqA1 delta 10710 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 IM6N<$g5ZHe1poj5 diff --git a/tools/vdb-config/sra-config/images/images.ncbi.png b/tools/vdb-config/sra-config/images/images.ncbi.png new file mode 100644 index 0000000000000000000000000000000000000000..a40a148f5f95c82a216cd95599f4ec0733522aa8 GIT binary patch literal 71471 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%0DnAi+&kefDfyK@s-__Tee)(*0L?=<(Oo!T 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 z zLliZn{dsW`w$SvhD-`QKL4NkJE{c|*F9;4;8Ttn6H@_v)xUa+W+{cv#Bh_(T`QXn(v1;^kWv?4CD~z1>hFl6OX`>^JI7SbS4DwnK zUx9A1Sg)DP?Pvl5rky0YUjX$0BKAu)9;FAuOLY=xe0&6Rql@YQMJXGpuv6?&Q;-Wg zTEc|W=A5G-vmYRV7qXIMCotr}BDSHlYU5&-_2}#w+iT2D7Gnol`?B+(VJBn17xmd?NFa1fB#KX)e~g?+l}? zzV9`n9)<}!Vtwu1PB2#0omcX6;*%M10pO!ibVBzu~a*l$Z&iR={LjhV3b}U>Q z&ADl`edrW+C?ra{(*|>^Z6RI%c4XUY;JUIW^mO*R*=0D*U`Kesj}HhwqaT8?z@~G^CEaRvWaH6EYm#q&j<>`*edU*EQ zX_15``c2*_`()#nJNj;xar8|7#&;mUOourwh;u!0&x?-26(MoSH&AmNZ8S%x2u%g1 z6iJX!r0Ha!GShiWvVqnSyqKkVdq5J5tyWeYaQKz^U{`ASWto)L>3m9uuzxE z`c_f;72j3Fdjuz9w_xrLUN@eJ;Od3wjWSPwJPtDX7{E&Ib4UX!Ql)ZVd~lmB0>#;b zHwTyI#d{+u9pz+6^EN-sV%C3(go|2AfM4Js>`D5N5Arw$Ze*abw*Nq(C zr5UlcR|AVHU+aCV@l3uSRx84HX|3nDUwXJ89JT^bM^zADyY*mU>^8JiXZaukfnd9f zE8a<5vI^?1s*BHrwt!Uc9Hdpw=e>;xSg5nGhB=4uNMR$rAQ#F!!6y8)!>x{Y#YEum zDwhL*4aijmp3u708(&BRU>&;rasdpZG;zZsPK{-xD_O#Oz9pU<$RN=eWBgz5iND${ z27*s)iD>}7*aIpRu>6jWz{(FC_*>)Mz108P_df)-%)ozX`Lhx5k^WMh`$%E2ZBy8xV~_6qqA4`*b+ literal 0 HcmV?d00001 diff --git a/tools/vdb-config/sra-config/images/troubleshooting.png b/tools/vdb-config/sra-config/images/troubleshooting.png new file mode 100644 index 0000000000000000000000000000000000000000..96162131dc6510c959dedda14ca3e33e56d2bf7b GIT binary patch literal 21965 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 literal 0 HcmV?d00001 diff --git a/tools/vdb-config/sra-config/resources.qrc b/tools/vdb-config/sra-config/resources.qrc index 996cc2ea..a29f46d3 100644 --- a/tools/vdb-config/sra-config/resources.qrc +++ b/tools/vdb-config/sra-config/resources.qrc @@ -1,5 +1,9 @@ images/general_icon.png + images/aws_icon.png + images/images.ncbi.png + images/network_icon.png + images/troubleshooting.png diff --git a/tools/vdb-config/sra-config/sra-config.pro b/tools/vdb-config/sra-config/sra-config.pro index 089fa5d8..220c82f3 100644 --- a/tools/vdb-config/sra-config/sra-config.pro +++ b/tools/vdb-config/sra-config/sra-config.pro @@ -34,11 +34,15 @@ SOURCES += main.cpp\ ../configure.cpp \ ../vdb-config-model.cpp \ ../util.cpp \ - ../sra-tools-gui/libs/ktoolbaritem.cpp + ../sra-tools-gui/libs/ktoolbaritem.cpp \ + srapreferences.cpp \ + sraconfigmodel.cpp HEADERS += sraconfig.h \ - ../sra-tools-gui/interfaces/ktoolbaritem.h + ../sra-tools-gui/interfaces/ktoolbaritem.h \ + srapreferences.h \ + sraconfigmodel.h RESOURCES += \ resources.qrc diff --git a/tools/vdb-config/sra-config/sra-config.pro.user b/tools/vdb-config/sra-config/sra-config.pro.user index c6374c22..ee96d3fe 100644 --- a/tools/vdb-config/sra-config/sra-config.pro.user +++ b/tools/vdb-config/sra-config/sra-config.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/tools/vdb-config/sra-config/sraconfig.cpp b/tools/vdb-config/sra-config/sraconfig.cpp index 1e146a15..2dad1970 100644 --- a/tools/vdb-config/sra-config/sraconfig.cpp +++ b/tools/vdb-config/sra-config/sraconfig.cpp @@ -511,7 +511,7 @@ SRAConfig :: SRAConfig ( vdbconf_model &config_model, const QRect &avail_geometr setWindowTitle ( "SRA Configuration Tool" ); setup_menubar (); - //setup_toolbar (); + setup_toolbar (); main_layout -> setSpacing ( 20 ); main_layout -> setAlignment ( Qt::AlignTop ); @@ -578,6 +578,9 @@ void SRAConfig :: setup_toolbar () item = new KToolbarItem ( "Network", rsrc_path + "/network_icon" ); bar -> addWidget ( item ); + item = new KToolbarItem ( "Diagnostics", rsrc_path + "/troubleshooting" ); + bar -> addWidget ( item ); + addToolBar ( bar ); } @@ -698,7 +701,6 @@ void SRAConfig :: import_workspace () , dir , tr ("NGC files (*.ngc)" ) ); - if ( ! file . isEmpty () ) { std :: string s = file . toStdString (); diff --git a/tools/vdb-config/sra-config/sraconfig.h b/tools/vdb-config/sra-config/sraconfig.h index af866116..edaf297f 100644 --- a/tools/vdb-config/sra-config/sraconfig.h +++ b/tools/vdb-config/sra-config/sraconfig.h @@ -48,6 +48,7 @@ class SRAConfig : public QMainWindow Q_OBJECT public: + SRAConfig ( vdbconf_model &config_model, const QRect &avail_geometry, QWidget *parent = 0 ); ~SRAConfig (); diff --git a/tools/vdb-config/sra-config/sraconfigmodel.cpp b/tools/vdb-config/sra-config/sraconfigmodel.cpp new file mode 100644 index 00000000..9818c6f6 --- /dev/null +++ b/tools/vdb-config/sra-config/sraconfigmodel.cpp @@ -0,0 +1,180 @@ +#include "sraconfigmodel.h" +#include "../vdb-config-model.hpp" + +#include + +#include +#include + + +bool SRAConfigModel :: config_changed () +{ + return model . get_config_changed (); +} + +bool SRAConfigModel :: proxy_enabled () +{ + return model . is_http_proxy_enabled (); +} + +bool SRAConfigModel :: proxy_priority () +{ + return model . has_http_proxy_env_higher_priority (); +} + +bool SRAConfigModel :: remote_enabled () +{ + return model . is_remote_enabled (); +} + +bool SRAConfigModel :: site_enabled () +{ + return model . is_site_enabled (); +} + +bool SRAConfigModel :: import_ngc ( const std :: string path, KNgcObj *ngc, uint32_t permissions, uint32_t *rslt_flags ) +{ + return model . import_ngc ( path, ngc, permissions, rslt_flags ); +} + +bool SRAConfigModel :: path_exists ( const std :: string &path ) +{ + return model . does_path_exist ( path ); +} + +bool SRAConfigModel :: site_workspace_exists ( const std :: string &path ) +{ + return model . does_repo_exist ( path . c_str () ); +} + +void SRAConfigModel :: commit () +{ + model . commit (); +} + +void SRAConfigModel :: reload () +{ + model . reload (); +} + +void SRAConfigModel :: create_directory ( const KNgcObj *ngc ) +{ + model . mkdir ( ngc ); +} + +void SRAConfigModel :: set_cache_enabled ( bool enabled ) +{ + model . set_global_cache_enabled ( enabled ); +} + +void SRAConfigModel :: set_proxy_enabled ( bool enabled ) +{ + model . set_http_proxy_enabled ( enabled ); +} + +void SRAConfigModel :: set_remote_enabled ( bool enabled ) +{ + model . set_remote_enabled ( enabled ); +} + +void SRAConfigModel :: set_site_enabled ( bool enabled ) +{ + model . set_site_enabled ( enabled ); +} + +void SRAConfigModel :: set_proxy_priority ( bool priority ) +{ + model . set_http_proxy_env_higher_priority ( priority ); +} + +void SRAConfigModel :: set_public_path ( const std :: string &path, bool flushOld, bool reuseNew ) +{ + model . set_public_location ( flushOld, path, reuseNew ); +} + +void SRAConfigModel :: set_workspace_path ( const std :: string & path, uint32_t id, bool flushOld, bool reuseNew ) +{ + model . set_repo_location ( id, flushOld, path, reuseNew ); +} + +bool SRAConfigModel :: get_ngc_obj_id ( const KNgcObj *ngc, uint32_t *id ) +{ + return model . get_id_of_ngc_obj ( ngc, id ); +} + +int32_t SRAConfigModel :: get_workspace_id ( const std :: string &name ) +{ + return model . get_repo_id ( name ); +} + +std :: string SRAConfigModel :: get_current_path () +{ + return model . get_current_dir (); +} + +std :: string SRAConfigModel :: get_home_path () +{ + return model . get_home_dir (); +} + +std :: string SRAConfigModel :: get_proxy_path () +{ + return model . get_http_proxy_path (); +} + +std :: string SRAConfigModel :: get_public_path () +{ + return model . get_public_location (); +} + +std :: string SRAConfigModel :: get_user_default_path () +{ + return model . get_user_default_dir (); +} + +std :: string SRAConfigModel :: get_workspace_name ( uint32_t id ) +{ + return model . get_repo_name ( id ); +} + +std :: string SRAConfigModel :: get_workspace_path ( uint32_t id ) +{ + return model . get_repo_location ( id ); +} + +std :: string SRAConfigModel :: get_ngc_root ( std :: string &dir, KNgcObj *ngc ) +{ + return model . get_ngc_root ( dir, ngc ); +} + +SRAConfigModel::RootState SRAConfigModel :: configure_workspace ( const std :: string &path, bool reuseNew ) +{ + switch ( model . prepare_repo_directory ( path, reuseNew ) ) + { + case eSetRootState_OK: + return RootState_OK; // successfully changed repository root + case eSetRootState_NotChanged: + return RootState_NotChanged; // the new path is the same as the old one + case eSetRootState_NotUnique: + return RootState_NotUnique; // there is another repository with the same root + case eSetRootState_MkdirFail: + return RootState_MkdirFail; // failed to make new repository directory + case eSetRootState_NewPathEmpty: + return RootState_NewPathEmpty; // new repository directory path is not empty + case eSetRootState_NewDirNotEmpty: + return RootState_NewDirNotEmpty; // new repository directory is not empty + case eSetRootState_NewNotDir: + return RootState_NewNotDir; // new repository exists and is not a directory + case eSetRootState_OldNotEmpty: + return RootState_OldNotEmpty; // old repository is not empty + case eSetRootState_Error: + return RootState_Error; // some unusual error happened + } +} + +SRAConfigModel :: SRAConfigModel ( vdbconf_model &config_model, QObject *parent ) + : QObject ( parent ) + , model ( config_model ) +{ +} + diff --git a/tools/vdb-config/sra-config/sraconfigmodel.h b/tools/vdb-config/sra-config/sraconfigmodel.h new file mode 100644 index 00000000..0e7cce14 --- /dev/null +++ b/tools/vdb-config/sra-config/sraconfigmodel.h @@ -0,0 +1,75 @@ +#ifndef SRACONFIGCONTROLLER_H +#define SRACONFIGCONTROLLER_H + +#include + +class vdbconf_model; +struct KNgcObj; + +class SRAConfigModel : public QObject +{ + Q_OBJECT + +public: + + enum RootState + { + RootState_OK, // successfully changed repository root + RootState_NotChanged, // the new path is the same as the old one + RootState_NotUnique, // there is another repository with the same root + RootState_MkdirFail, // failed to make new repository directory + RootState_NewPathEmpty, // new repository directory path is not empty + RootState_NewDirNotEmpty,// new repository directory is not empty + RootState_NewNotDir, // new repository exists and is not a directory + RootState_OldNotEmpty, // old repository is not empty + RootState_Error, // some unusual error happened + }; + + bool config_changed (); + bool proxy_enabled (); + bool proxy_priority (); + bool remote_enabled (); + bool site_enabled (); + bool import_ngc ( const std :: string path, KNgcObj *ngc, uint32_t permissions, uint32_t *rslt_flags ); + bool path_exists ( const std :: string &path ); + bool site_workspace_exists ( const std :: string &path ); + + void commit (); + void reload (); + void create_directory ( const KNgcObj *ngc ); + + void set_cache_enabled ( bool enabled ); + void set_proxy_enabled ( bool enabled ); + void set_remote_enabled ( bool enabled ); + void set_site_enabled ( bool enabled ); + void set_proxy_priority ( bool priority ); + void set_public_path ( const std :: string &path, bool flushOld, bool reuseNew ); + void set_workspace_path ( const std :: string &path, uint32_t id, bool flushOld, bool reuseNew ); + + std :: string get_current_path (); + std :: string get_home_path (); + std :: string get_proxy_path (); + std :: string get_public_path (); + std :: string get_user_default_path (); + + bool get_ngc_obj_id ( const KNgcObj *ngc, uint32_t *id ); + int32_t get_workspace_id ( const std :: string &name ); + std :: string get_ngc_root ( std :: string &dir, KNgcObj *ngc ); + std :: string get_workspace_name ( uint32_t id ); + std :: string get_workspace_path ( uint32_t id ); + + RootState configure_workspace ( const std :: string &path, bool reuseNew = false ); + + SRAConfigModel ( vdbconf_model &config_model, QObject *parent = 0 ); + +signals: + + void dirty_config (); + +private: + + vdbconf_model &model; + +}; + +#endif // SRACONFIGCONTROLLER_H diff --git a/tools/vdb-config/sra-config/srapreferences.cpp b/tools/vdb-config/sra-config/srapreferences.cpp new file mode 100644 index 00000000..b3e301d0 --- /dev/null +++ b/tools/vdb-config/sra-config/srapreferences.cpp @@ -0,0 +1,6 @@ +#include "srapreferences.h" + +SRAPreferences :: SRAPreferences ( QWidget *parent ) +{ + +} diff --git a/tools/vdb-config/sra-config/srapreferences.h b/tools/vdb-config/sra-config/srapreferences.h new file mode 100644 index 00000000..881a28f6 --- /dev/null +++ b/tools/vdb-config/sra-config/srapreferences.h @@ -0,0 +1,12 @@ +#ifndef SRAPREFERENCES_H +#define SRAPREFERENCES_H + +#include + +class SRAPreferences +{ +public: + SRAPreferences ( QWidget *parent = 0 ); +}; + +#endif // SRAPREFERENCES_H diff --git a/tools/vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp b/tools/vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp index 492ba5e8..ee406dc7 100644 --- a/tools/vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp +++ b/tools/vdb-config/sra-tools-gui/libs/ktoolbaritem.cpp @@ -27,26 +27,30 @@ #include "../../sra-tools-gui/interfaces/ktoolbaritem.h" #include -#include +#include #include +#include KToolbarItem :: KToolbarItem ( const QString &name, const QString &icon_name, QWidget *parent ) : QWidget ( parent ) { - QPalette p = palette (); - p . setColor ( QPalette::Background, Qt::gray ); - setAutoFillBackground ( true ); - setPalette ( p ); - QVBoxLayout *layout = new QVBoxLayout (); + layout -> setMargin ( 10 ); + layout -> setSpacing ( 10 ); - //QLabel *icon = new QLabel (); + QPixmap pxmp = QPixmap :: fromImage ( QImage ( icon_name ) ); QLabel *label = new QLabel ( name ); + label -> setPixmap ( pxmp . scaled ( QSize ( 50, 50 ), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); + label -> setScaledContents ( true ); + label -> resize ( 50, 50 ); - //layout -> addWidget ( icon ); layout -> addWidget ( label ); + QLabel *txt = new QLabel ( name ); + txt -> setAlignment ( Qt::AlignHCenter ); + layout -> addWidget ( txt ); + setLayout ( layout ); } From 0e2900c4eac6ec6b9ea3485c175630fdbc28429e Mon Sep 17 00:00:00 2001 From: ksrodarmer Date: Thu, 18 May 2017 12:59:01 -0400 Subject: [PATCH 22/23] The model interface class has now replaced all direct calls to the vdbconf-model. --- tools/vdb-config/sra-config/sraconfig.cpp | 259 +++++++++++++------------ tools/vdb-config/sra-config/sraconfig.h | 3 +- tools/vdb-config/sra-config/sraconfigmodel.cpp | 181 ++++++++++------- tools/vdb-config/sra-config/sraconfigmodel.h | 85 +++++--- 4 files changed, 301 insertions(+), 227 deletions(-) diff --git a/tools/vdb-config/sra-config/sraconfig.cpp b/tools/vdb-config/sra-config/sraconfig.cpp index 2dad1970..5359a8c7 100644 --- a/tools/vdb-config/sra-config/sraconfig.cpp +++ b/tools/vdb-config/sra-config/sraconfig.cpp @@ -25,7 +25,7 @@ */ #include "sraconfig.h" -#include "../vdb-config-model.hpp" +#include "sraconfigmodel.h" #include "../sra-tools-gui/interfaces/ktoolbaritem.h" #include @@ -89,19 +89,19 @@ struct WorkspaceItem /* static functions */ static -bool location_error ( ESetRootState state, QWidget *w ) +bool location_error ( RootState state, QWidget *w ) { QString msg; switch ( state ) { - case eSetRootState_NotChanged : return true; - case eSetRootState_NotUnique : msg = QString ( "location not unique, select a different one" ); break; - case eSetRootState_MkdirFail : msg = QString ( "could not created directory, maybe permisson problem" ); break; - case eSetRootState_NewPathEmpty : msg = QString ( "you gave me an empty path" ); break; - case eSetRootState_NewDirNotEmpty : msg = QString ( "the given location is not empty" ); break; - case eSetRootState_NewNotDir : msg = QString ( "new location is not a directory" ); break; - case eSetRootState_Error : msg = QString ( "error changing location" ); break; + case RootState_NotChanged : return true; + case RootState_NotUnique : msg = QString ( "location not unique, select a different one" ); break; + case RootState_MkdirFail : msg = QString ( "could not created directory, maybe permisson problem" ); break; + case RootState_NewPathEmpty : msg = QString ( "you gave me an empty path" ); break; + case RootState_NewDirNotEmpty : msg = QString ( "the given location is not empty" ); break; + case RootState_NewNotDir : msg = QString ( "new location is not a directory" ); break; + case RootState_Error : msg = QString ( "error changing location" ); break; default : msg = QString ( "unknown enum" ); break; } @@ -113,63 +113,66 @@ bool location_error ( ESetRootState state, QWidget *w ) } static -std :: string public_location_start_dir ( vdbconf_model &model ) +std :: string public_location_start_dir ( SRAConfigModel *model ) { - std :: string s = model . get_public_location (); + std :: string s = model -> get_public_path (); - if ( ! model . does_path_exist ( s ) ) - s = model . get_user_default_dir (); + if ( ! model -> path_exists ( s ) ) + s = model -> get_user_default_path (); - if ( ! model.does_path_exist( s ) ) - s = model.get_home_dir () + "/ncbi"; + if ( ! model -> path_exists ( s ) ) + s = model -> get_home_path () + "/ncbi"; - if ( ! model.does_path_exist( s ) ) - s = model.get_home_dir (); + if ( ! model -> path_exists ( s ) ) + s = model -> get_home_path (); - if ( ! model.does_path_exist( s ) ) - s = model.get_current_dir (); + if ( ! model -> path_exists ( s ) ) + s = model -> get_current_path (); return s; } static -bool select_public_location ( vdbconf_model &model, QWidget *w ) +bool select_public_location ( SRAConfigModel *model, QWidget *w ) { - QString path = public_location_start_dir ( model ) . c_str (); + std ::string path = public_location_start_dir ( model ) . c_str (); - if ( model . does_path_exist ( path . toStdString () ) ) + if ( model -> path_exists ( path ) ) { - path = QFileDialog :: getOpenFileName ( w + QString p = QFileDialog :: getOpenFileName ( w , "Import Workspace" - , path ); + , path . c_str () ); + path = p . toStdString (); } else { - path = QInputDialog::getText ( w + QString p = QInputDialog::getText ( w , "" , "Location of public cache" , QLineEdit::Normal ); + path = p . toStdString (); } if ( path . length () > 0 ) { + QString p = path . c_str (); QMessageBox::StandardButton reply; reply = QMessageBox::question ( w , "" - , "Change the location to '" + path + "'?" + , "Change the location to '" + p + "'?" , QMessageBox::Yes | QMessageBox::No ); if ( reply == QMessageBox::Yes ) { bool flush_old = false; bool reuse_new = false; - ESetRootState state = model . set_public_location ( flush_old, path . toStdString (), reuse_new ); + RootState state = model -> set_public_path ( path, flush_old, reuse_new ); switch ( state ) { - case eSetRootState_OK: + case RootState_OK: return true; - case eSetRootState_OldNotEmpty: + case RootState_OldNotEmpty: { QMessageBox::StandardButton reply; reply = QMessageBox::question ( w @@ -179,8 +182,8 @@ bool select_public_location ( vdbconf_model &model, QWidget *w ) if ( reply == QMessageBox::Yes ) { flush_old = true; - state = model . set_public_location ( flush_old, path . toStdString () . c_str (), reuse_new ); - if ( state == eSetRootState_OK ) + state = model -> set_public_path ( path, flush_old, reuse_new ); + if ( state == RootState_OK ) return true; else return location_error ( state, w ); @@ -196,66 +199,67 @@ bool select_public_location ( vdbconf_model &model, QWidget *w ) } static -std :: string protected_location_start_dir ( vdbconf_model &model, uint32_t id ) +std :: string protected_location_start_dir ( SRAConfigModel *model, uint32_t id ) { - std :: string s = model . get_repo_location ( id ); + std :: string s = model -> get_workspace_path ( id ); - if ( ! model . does_path_exist ( s ) ) - s = model . get_user_default_dir (); + if ( ! model -> path_exists ( s ) ) + s = model -> get_user_default_path (); - if ( ! model.does_path_exist( s ) ) - s = model.get_home_dir () + "/ncbi"; + if ( ! model -> path_exists ( s ) ) + s = model -> get_home_path () + "/ncbi"; - if ( ! model.does_path_exist( s ) ) - s = model.get_home_dir (); + if ( ! model -> path_exists ( s ) ) + s = model -> get_home_path (); - if ( ! model.does_path_exist( s ) ) - s = model.get_current_dir (); + if ( ! model -> path_exists ( s ) ) + s = model -> get_current_path (); return s; } static -bool select_protected_location ( vdbconf_model &model, int id, QWidget *w ) +bool select_protected_location ( SRAConfigModel *model, int id, QWidget *w ) { + std :: string path = protected_location_start_dir ( model, id ); + qDebug () << "Protect location path: " << QString ( path . c_str () ) << " [" << id << "]"; - QString path = protected_location_start_dir ( model, id ) . c_str (); - qDebug () << "Protect location path: " << path << " [" << id << "]"; - - if ( model . does_path_exist ( path . toStdString () ) ) + if ( model -> path_exists ( path ) ) { - path = QFileDialog :: getOpenFileName ( w + QString p = QFileDialog :: getOpenFileName ( w , "Import Workspace" - , path ); + , path . c_str () ); + path = p . toStdString (); } else { - path = QInputDialog::getText ( w + QString p = QInputDialog::getText ( w , "" , "Location of dbGaP project" , QLineEdit::Normal ); + path = p . toStdString (); } if ( path . length () > 0 ) { - QString repo_name = model . get_repo_name ( id ) . c_str (); + QString repo_name = model -> get_workspace_name ( id ) . c_str (); QMessageBox::StandardButton reply; reply = QMessageBox::question ( w , "" - , "Change the location of '" + repo_name + "' to '" + path + "'?" + , "Change the location of '" + repo_name + "' to '" + QString ( path . c_str () ) + "'?" , QMessageBox::Yes | QMessageBox::No ); if ( reply == QMessageBox::Yes ) { bool flush_old = false; bool reuse_new = false; - ESetRootState state = model . set_repo_location ( id, flush_old, path . toStdString (), reuse_new ); + RootState state = model -> set_workspace_path ( path, id, flush_old, reuse_new ); switch ( state ) { - case eSetRootState_OK: + case RootState_OK: return true; - case eSetRootState_OldNotEmpty: + case RootState_OldNotEmpty: { QMessageBox::StandardButton reply; reply = QMessageBox::question ( w @@ -265,8 +269,8 @@ bool select_protected_location ( vdbconf_model &model, int id, QWidget *w ) if ( reply == QMessageBox::Yes ) { flush_old = true; - state = model . set_repo_location ( id, flush_old, path . toStdString (), reuse_new ); - if ( state == eSetRootState_OK ) + state = model -> set_workspace_path ( path, id, flush_old, reuse_new ); + if ( state == RootState_OK ) return true; else return location_error ( state, w ); @@ -302,22 +306,21 @@ bool make_ngc_obj ( const KNgcObj ** ngc, std::string &path ) } static -bool prepare_ngc ( vdbconf_model &model, const KNgcObj *ngc, QString *loc, QWidget *w ) +bool prepare_ngc ( SRAConfigModel *model, const KNgcObj *ngc, QString *loc, QWidget *w ) { - std :: string location_base = model . get_user_default_dir (); - std :: string location = model . get_ngc_root ( location_base, ngc ); - qDebug () << "model changed 2: " << model . get_config_changed (); - ESetRootState state = model . prepare_repo_directory ( location ); - qDebug () << "model changed 2.1: " << model . get_config_changed (); + std :: string base_path = model -> get_user_default_path (); + std :: string path = model -> get_ngc_root ( base_path, ngc ); + + RootState state = model -> configure_workspace ( path ); + switch ( state ) { - case eSetRootState_OK: + case RootState_OK: { - qDebug () << "model changed 3: " << model . get_config_changed (); - *loc = location . c_str (); + *loc = path . c_str (); return true; } - case eSetRootState_OldNotEmpty: + case RootState_OldNotEmpty: { QMessageBox::StandardButton reply; reply = QMessageBox::question ( w @@ -326,11 +329,10 @@ bool prepare_ngc ( vdbconf_model &model, const KNgcObj *ngc, QString *loc, QWidg , QMessageBox::Yes | QMessageBox::No ); if ( reply == QMessageBox::Yes ) { - state = model . prepare_repo_directory ( location, true ); - if ( state == eSetRootState_OK ) + state = model -> configure_workspace ( path, true ); + if ( state == RootState_OK ) { - qDebug () << "model changed 4: " << model . get_config_changed (); - *loc = location . c_str (); + *loc = path . c_str (); return true; } else @@ -340,12 +342,12 @@ bool prepare_ngc ( vdbconf_model &model, const KNgcObj *ngc, QString *loc, QWidg default: return location_error ( state, w ); } - qDebug () << "model changed 5: " << model . get_config_changed (); + return false; } static -bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QWidget *w ) +bool import_ngc ( SRAConfigModel *model, std :: string file, uint32_t &ngc_id, QWidget *w ) { const KNgcObj *ngc; if ( ! make_ngc_obj ( &ngc, file ) ) @@ -356,8 +358,8 @@ bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QW } else { - QString location; - if ( ! prepare_ngc ( model, ngc, &location, w ) ) + QString path; + if ( ! prepare_ngc ( model, ngc, &path, w ) ) qDebug () << "failed to prepare ngc object"; else { @@ -365,7 +367,7 @@ bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QW uint32_t result_flags = 0; - if ( model . import_ngc ( location . toStdString (), ngc, INP_CREATE_REPOSITORY, &result_flags ) ) + if ( model -> import_ngc ( path . toStdString (), ngc, INP_CREATE_REPOSITORY, &result_flags ) ) { /* we have it imported or it exists and no changes made */ bool modified = false; @@ -380,7 +382,6 @@ bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QW } else { - qDebug () << "model changed 4: " << model . get_config_changed (); /* repository did exist and is completely identical to the given ngc-obj */ QMessageBox::information ( w , "" @@ -389,7 +390,7 @@ bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QW modified = false; } - if ( model . get_id_of_ngc_obj ( ngc, &ngc_id ) ) + if ( model -> get_ngc_obj_id ( ngc, &ngc_id ) ) { qDebug () << "NGC ID: " << ngc_id; @@ -412,8 +413,8 @@ bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QW if ( modified ) { - model . commit (); // TBD - on import of NGC files, do we automaically commit, or allow for revert and require apply button? - model . mkdir ( ngc ); + model -> commit (); // TBD - on import of NGC files, do we automaically commit, or allow for revert and require apply button? + model -> create_directory ( ngc ); return true; } } @@ -452,7 +453,7 @@ bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QW if ( reply == QMessageBox::Yes ) { uint32_t result_flags2 = 0; - if ( model . import_ngc ( location . toStdString () , ngc, result_flags, &result_flags2 ) ) + if ( model -> import_ngc ( path . toStdString () , ngc, result_flags, &result_flags2 ) ) { QMessageBox::StandardButton reply; reply = QMessageBox::question ( w @@ -463,7 +464,7 @@ bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QW if ( reply == QMessageBox::Yes ) { /* we have to find out the id of the imported/existing repository */ - if ( model . get_id_of_ngc_obj ( ngc, &ngc_id ) ) + if ( model -> get_ngc_obj_id ( ngc, &ngc_id ) ) { qDebug () << "NGC ID: " << ngc_id; select_protected_location ( model, ngc_id, w ); @@ -472,7 +473,7 @@ bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QW QMessageBox::information ( w, "", "the repository does already exist!" ); } - model . commit (); + model -> commit (); return true; } @@ -504,7 +505,7 @@ bool import_ngc ( vdbconf_model &model, std :: string file, uint32_t &ngc_id, QW SRAConfig :: SRAConfig ( vdbconf_model &config_model, const QRect &avail_geometry, QWidget *parent ) : QMainWindow ( parent ) - , model ( config_model ) + , model ( new SRAConfigModel ( config_model ) ) , screen_geometry ( avail_geometry ) , main_layout ( new QVBoxLayout () ) { @@ -587,19 +588,19 @@ void SRAConfig :: setup_toolbar () void SRAConfig :: populate () { - remote_enabled_cb -> setChecked ( model . is_remote_enabled () ); + remote_enabled_cb -> setChecked ( model -> remote_enabled () ); - local_caching_cb -> setChecked ( model . is_global_cache_enabled () ); + local_caching_cb -> setChecked ( model -> global_cache_enabled () ); - if ( model . does_site_repo_exist () ) - site_cb -> setChecked ( model . is_site_enabled () ); + if ( model -> site_workspace_exists () ) + site_cb -> setChecked ( model -> site_enabled () ); else site_cb -> setDisabled ( true ); - proxy_cb -> setChecked ( model . is_http_proxy_enabled () ); - proxy_label -> setText ( model . get_http_proxy_path () . c_str () ); + proxy_cb -> setChecked ( model -> proxy_enabled () ); + proxy_label -> setText ( model -> get_proxy_path () . c_str () ); - http_priority_cb -> setChecked ( model . has_http_proxy_env_higher_priority () ); + http_priority_cb -> setChecked ( model -> proxy_priority () ); } QGroupBox * SRAConfig::setup_option_group () @@ -691,14 +692,14 @@ void SRAConfig :: add_workspace (QString name, QString val, int ngc_id, bool ins void SRAConfig :: import_workspace () { // open a file dialog to browse for the repository - QString dir = model . get_home_dir () . c_str (); - if ( ! model . does_path_exist ( dir . toStdString () ) ) - dir = model . get_current_dir () . c_str (); + std :: string path = model -> get_home_path (); + if ( ! model -> path_exists ( path ) ) + path = model -> get_current_path (); QString filter = tr ("NGS (*.ngc)" ); QString file = QFileDialog :: getOpenFileName ( this , "Import Workspace" - , dir + , path . c_str () , tr ("NGC files (*.ngc)" ) ); if ( ! file . isEmpty () ) @@ -707,7 +708,7 @@ void SRAConfig :: import_workspace () uint32_t ngc_id; if ( import_ngc ( model, s, ngc_id, this ) ) { - QString name = model . get_repo_name ( ngc_id ) . c_str (); + QString name = model -> get_workspace_name ( ngc_id ) . c_str (); name = QInputDialog::getText ( this , tr ( "Name Workspace" ) @@ -716,7 +717,7 @@ void SRAConfig :: import_workspace () , name ); if ( name . isEmpty () ) - name = model . get_repo_name ( ngc_id ) . c_str (); + name = model -> get_workspace_name ( ngc_id ) . c_str (); add_workspace ( name, file, ngc_id, true ); } @@ -732,15 +733,16 @@ QGroupBox * SRAConfig :: setup_workspace_group () workspace_layout -> setAlignment ( Qt :: AlignTop ); workspace_layout -> setSpacing ( 15 ); - add_workspace ( "Public", model . get_public_location () . c_str(), -1 ); + add_workspace ( "Public", model -> get_public_path () . c_str(), -1 ); - int repo_count = model . get_repo_count (); - qDebug () << "Setup workspace group: repo-count: " << repo_count; - for ( int i = 0; i < repo_count; ++ i ) + int ws_count = model -> workspace_count (); + qDebug () << "Setup workspace group: repo-count: " << ws_count; + for ( int i = 0; i < ws_count; ++ i ) { - add_workspace ( model . get_repo_name ( i ) . c_str (), - model . get_repo_location ( i ) . c_str (), - model . get_repo_id ( model . get_repo_name ( i ) ) ); + std :: string name = model -> get_workspace_name ( i ); + add_workspace ( name . c_str () , + model -> get_workspace_path ( i ) . c_str (), + model -> get_workspace_id ( name ) ); } //3 @@ -807,7 +809,7 @@ QVBoxLayout * SRAConfig::setup_button_layout () void SRAConfig :: closeEvent ( QCloseEvent *ev ) { - if ( model . get_config_changed () ) + if ( model -> config_changed () ) { QMessageBox::StandardButton reply; reply = QMessageBox::question ( this @@ -838,7 +840,7 @@ void SRAConfig :: advanced_settings () label -> setAlignment ( Qt::AlignRight ); layout -> addWidget ( label); - import_path_label = new QLabel ( model . get_user_default_dir () . c_str () ); + import_path_label = new QLabel ( model -> get_user_default_path () . c_str () ); import_path_label -> setFrameShape ( QFrame::Panel ); import_path_label -> setFrameShadow ( QFrame::Sunken ); layout -> addWidget ( import_path_label ); @@ -868,7 +870,7 @@ void SRAConfig :: advanced_settings () void SRAConfig :: commit_config () { - if ( ! model . commit () ) + if ( ! model -> commit () ) QMessageBox::information ( this, "", "Error saving changes" ); apply_btn -> setDisabled ( true ); @@ -877,10 +879,10 @@ void SRAConfig :: commit_config () void SRAConfig :: reload_config () { - model . reload (); + model -> reload (); populate (); - if ( ! model . get_config_changed () ) + if ( ! model -> config_changed () ) { apply_btn -> setDisabled ( true ); apply_action -> setDisabled ( true ); @@ -891,7 +893,7 @@ void SRAConfig :: reload_config () void SRAConfig :: modified_config () { - if ( model . get_config_changed () ) // this wont trigger on workspace addition yet + if ( model -> config_changed () ) // this wont trigger on workspace addition yet { apply_btn -> setDisabled ( false ); apply_action -> setDisabled ( false ); @@ -903,9 +905,9 @@ void SRAConfig :: modified_config () // TBD - still needs a menu item to be triggered. -- this is not a hard reset - it still keeps some user settings void SRAConfig :: default_config () { - model . set_remote_enabled ( true ); - model . set_global_cache_enabled ( true ); - model . set_site_enabled ( true ); + model -> set_remote_enabled ( true ); + model -> set_global_cache_enabled ( true ); + model -> set_site_enabled ( true ); populate (); @@ -914,54 +916,54 @@ void SRAConfig :: default_config () void SRAConfig :: toggle_remote_enabled ( bool toggled ) { - model . set_remote_enabled ( toggled ); + model -> set_remote_enabled ( toggled ); emit dirty_config (); } void SRAConfig :: toggle_local_caching ( bool toggled ) { - model . set_global_cache_enabled ( toggled ); + model -> set_global_cache_enabled ( toggled ); emit dirty_config (); } void SRAConfig :: toggle_use_site ( bool toggled ) { - model . set_site_enabled ( toggled ); + model -> set_site_enabled ( toggled ); emit dirty_config (); } void SRAConfig :: toggle_use_proxy ( bool toggled ) { - model . set_http_proxy_enabled ( toggled ); + model -> set_proxy_enabled ( toggled ); emit dirty_config (); } void SRAConfig :: toggle_prioritize_http ( bool toggled ) { - model . set_http_proxy_env_higher_priority ( toggled ); + model -> set_proxy_priority ( toggled ); emit dirty_config (); } void SRAConfig :: edit_import_path () { - QString path = model . get_user_default_dir () . c_str (); + std :: string path = model -> get_user_default_path () . c_str (); - if ( ! model . does_path_exist ( path . toStdString () ) ) - path = model . get_home_dir () . c_str (); + if ( ! model -> path_exists ( path ) ) + path = model -> get_home_path (); - if ( ! model . does_path_exist ( path . toStdString () ) ) - path = model . get_current_dir () . c_str (); + if ( ! model -> path_exists ( path ) ) + path = model -> get_current_path (); QString e_path = QFileDialog :: getOpenFileName ( adv_setting_window , "" - , path ); + , path . c_str () ); if ( e_path . isEmpty () ) return; import_path_label -> setText ( e_path ); - model . set_user_default_dir ( e_path . toStdString () . c_str () ); + model -> set_user_default_path ( e_path . toStdString () . c_str () ); emit dirty_config (); } @@ -978,7 +980,7 @@ void SRAConfig :: edit_proxy_path () return; proxy_label -> setText ( input ); - model . set_http_proxy_path ( input . toStdString () ); + model -> set_proxy_path ( input . toStdString () ); emit dirty_config (); } @@ -988,7 +990,7 @@ void SRAConfig :: edit_public_path () qDebug () << public_workspace -> ngc_id; if ( select_public_location ( model, this ) ) { - public_workspace -> path_label -> setText ( model . get_public_location () . c_str () ); + public_workspace -> path_label -> setText ( model -> get_public_path () . c_str () ); emit dirty_config (); } @@ -1004,8 +1006,9 @@ void SRAConfig :: edit_workspace_path () if ( select_protected_location ( model, item -> ngc_id, this ) ) { - item -> path_label -> setText ( model . get_repo_location ( item -> ngc_id ) . c_str () ); - import_path_label -> setText ( model . get_repo_location ( item -> ngc_id ) . c_str () ); + QString path = model -> get_workspace_path ( item -> ngc_id ) . c_str (); + item -> path_label -> setText ( path ); + import_path_label -> setText ( path ); emit dirty_config (); } diff --git a/tools/vdb-config/sra-config/sraconfig.h b/tools/vdb-config/sra-config/sraconfig.h index edaf297f..326eb109 100644 --- a/tools/vdb-config/sra-config/sraconfig.h +++ b/tools/vdb-config/sra-config/sraconfig.h @@ -39,6 +39,7 @@ class QLabel; class QPushButton; QT_END_NAMESPACE +class SRAConfigModel; class vdbconf_model; struct KNgcObj; struct WorkspaceItem; @@ -90,7 +91,7 @@ private slots: void setup_menubar (); void setup_toolbar (); - vdbconf_model &model; + SRAConfigModel *model; QAction *discard_action; QAction *apply_action; diff --git a/tools/vdb-config/sra-config/sraconfigmodel.cpp b/tools/vdb-config/sra-config/sraconfigmodel.cpp index 9818c6f6..f095a016 100644 --- a/tools/vdb-config/sra-config/sraconfigmodel.cpp +++ b/tools/vdb-config/sra-config/sraconfigmodel.cpp @@ -6,107 +6,148 @@ #include #include +static +RootState translate_state ( ESetRootState state ) +{ + switch ( state ) + { + case eSetRootState_OK: + return RootState_OK; // successfully changed repository root + case eSetRootState_NotChanged: + return RootState_NotChanged; // the new path is the same as the old one + case eSetRootState_NotUnique: + return RootState_NotUnique; // there is another repository with the same root + case eSetRootState_MkdirFail: + return RootState_MkdirFail; // failed to make new repository directory + case eSetRootState_NewPathEmpty: + return RootState_NewPathEmpty; // new repository directory path is not empty + case eSetRootState_NewDirNotEmpty: + return RootState_NewDirNotEmpty; // new repository directory is not empty + case eSetRootState_NewNotDir: + return RootState_NewNotDir; // new repository exists and is not a directory + case eSetRootState_OldNotEmpty: + return RootState_OldNotEmpty; // old repository is not empty + case eSetRootState_Error: + return RootState_Error; // some unusual error happened + } +} + +bool SRAConfigModel::commit() +{ + return model . commit (); +} bool SRAConfigModel :: config_changed () { return model . get_config_changed (); } -bool SRAConfigModel :: proxy_enabled () + +bool SRAConfigModel :: path_exists ( const std :: string &path ) { - return model . is_http_proxy_enabled (); + return model . does_path_exist ( path ); } -bool SRAConfigModel :: proxy_priority () +void SRAConfigModel :: create_directory ( const KNgcObj *ngc ) { - return model . has_http_proxy_env_higher_priority (); + model . mkdir ( ngc ); } -bool SRAConfigModel :: remote_enabled () +void SRAConfigModel :: reload () { - return model . is_remote_enabled (); + model . reload (); } -bool SRAConfigModel :: site_enabled () +// cache +bool SRAConfigModel :: global_cache_enabled () { - return model . is_site_enabled (); + return model . is_global_cache_enabled (); } -bool SRAConfigModel :: import_ngc ( const std :: string path, KNgcObj *ngc, uint32_t permissions, uint32_t *rslt_flags ) +bool SRAConfigModel :: user_cache_enabled () { - return model . import_ngc ( path, ngc, permissions, rslt_flags ); + return model . is_user_cache_enabled (); } -bool SRAConfigModel :: path_exists ( const std :: string &path ) +void SRAConfigModel :: set_global_cache_enabled ( bool enabled ) { - return model . does_path_exist ( path ); + model . set_global_cache_enabled ( enabled ); } -bool SRAConfigModel :: site_workspace_exists ( const std :: string &path ) +void SRAConfigModel :: set_user_cache_enabled ( bool enabled ) { - return model . does_repo_exist ( path . c_str () ); + model . set_user_cache_enabled ( enabled ); } -void SRAConfigModel :: commit () +// network +bool SRAConfigModel :: remote_enabled () { - model . commit (); + return model . is_remote_enabled (); } -void SRAConfigModel :: reload () +void SRAConfigModel :: set_remote_enabled ( bool enabled ) { - model . reload (); + model . set_remote_enabled ( enabled ); } -void SRAConfigModel :: create_directory ( const KNgcObj *ngc ) +bool SRAConfigModel :: site_enabled () { - model . mkdir ( ngc ); + return model . is_site_enabled (); } -void SRAConfigModel :: set_cache_enabled ( bool enabled ) +void SRAConfigModel :: set_site_enabled ( bool enabled ) { - model . set_global_cache_enabled ( enabled ); + model . set_site_enabled ( enabled ); } -void SRAConfigModel :: set_proxy_enabled ( bool enabled ) +// ngc +bool SRAConfigModel :: import_ngc ( const std :: string path, const KNgcObj *ngc, uint32_t permissions, uint32_t *rslt_flags ) { - model . set_http_proxy_enabled ( enabled ); + return model . import_ngc ( path, ngc, permissions, rslt_flags ); } -void SRAConfigModel :: set_remote_enabled ( bool enabled ) +bool SRAConfigModel :: get_ngc_obj_id ( const KNgcObj *ngc, uint32_t *id ) { - model . set_remote_enabled ( enabled ); + return model . get_id_of_ngc_obj ( ngc, id ); } -void SRAConfigModel :: set_site_enabled ( bool enabled ) +std :: string SRAConfigModel :: get_ngc_root ( std :: string &dir, const KNgcObj *ngc ) { - model . set_site_enabled ( enabled ); + return model . get_ngc_root ( dir, ngc ); } -void SRAConfigModel :: set_proxy_priority ( bool priority ) +// proxy +bool SRAConfigModel :: proxy_enabled () { - model . set_http_proxy_env_higher_priority ( priority ); + return model . is_http_proxy_enabled (); } -void SRAConfigModel :: set_public_path ( const std :: string &path, bool flushOld, bool reuseNew ) +void SRAConfigModel :: set_proxy_enabled ( bool enabled ) { - model . set_public_location ( flushOld, path, reuseNew ); + model . set_http_proxy_enabled ( enabled ); } -void SRAConfigModel :: set_workspace_path ( const std :: string & path, uint32_t id, bool flushOld, bool reuseNew ) +std :: string SRAConfigModel :: get_proxy_path () { - model . set_repo_location ( id, flushOld, path, reuseNew ); + return model . get_http_proxy_path (); } -bool SRAConfigModel :: get_ngc_obj_id ( const KNgcObj *ngc, uint32_t *id ) +void SRAConfigModel :: set_proxy_path ( const std :: string &path ) { - return model . get_id_of_ngc_obj ( ngc, id ); + model . set_http_proxy_path ( path ); } -int32_t SRAConfigModel :: get_workspace_id ( const std :: string &name ) +bool SRAConfigModel :: proxy_priority () { - return model . get_repo_id ( name ); + return model . has_http_proxy_env_higher_priority (); +} + +void SRAConfigModel :: set_proxy_priority ( bool priority ) +{ + model . set_http_proxy_env_higher_priority ( priority ); } +// settings std :: string SRAConfigModel :: get_current_path () { return model . get_current_dir (); @@ -117,14 +158,14 @@ std :: string SRAConfigModel :: get_home_path () return model . get_home_dir (); } -std :: string SRAConfigModel :: get_proxy_path () +std :: string SRAConfigModel :: get_public_path () { - return model . get_http_proxy_path (); + return model . get_public_location (); } -std :: string SRAConfigModel :: get_public_path () +RootState SRAConfigModel :: set_public_path ( const std :: string &path, bool flushOld, bool reuseNew ) { - return model . get_public_location (); + return translate_state ( model . set_public_location ( flushOld, path, reuseNew ) ); } std :: string SRAConfigModel :: get_user_default_path () @@ -132,6 +173,33 @@ std :: string SRAConfigModel :: get_user_default_path () return model . get_user_default_dir (); } +void SRAConfigModel :: set_user_default_path ( const char *path ) +{ + model . set_user_default_dir ( path ); +} + +// workspace + +bool SRAConfigModel :: site_workspace_exists () +{ + return model . does_site_repo_exist (); +} + +RootState SRAConfigModel :: configure_workspace ( const std :: string &path, bool reuseNew ) +{ + return translate_state ( model . prepare_repo_directory ( path, reuseNew ) ); +} + +uint32_t SRAConfigModel :: workspace_count () +{ + return model . get_repo_count (); +} + +int32_t SRAConfigModel :: get_workspace_id ( const std :: string &name ) +{ + return model . get_repo_id ( name ); +} + std :: string SRAConfigModel :: get_workspace_name ( uint32_t id ) { return model . get_repo_name ( id ); @@ -142,34 +210,9 @@ std :: string SRAConfigModel :: get_workspace_path ( uint32_t id ) return model . get_repo_location ( id ); } -std :: string SRAConfigModel :: get_ngc_root ( std :: string &dir, KNgcObj *ngc ) +RootState SRAConfigModel :: set_workspace_path ( const std :: string & path, uint32_t id, bool flushOld, bool reuseNew ) { - return model . get_ngc_root ( dir, ngc ); -} - -SRAConfigModel::RootState SRAConfigModel :: configure_workspace ( const std :: string &path, bool reuseNew ) -{ - switch ( model . prepare_repo_directory ( path, reuseNew ) ) - { - case eSetRootState_OK: - return RootState_OK; // successfully changed repository root - case eSetRootState_NotChanged: - return RootState_NotChanged; // the new path is the same as the old one - case eSetRootState_NotUnique: - return RootState_NotUnique; // there is another repository with the same root - case eSetRootState_MkdirFail: - return RootState_MkdirFail; // failed to make new repository directory - case eSetRootState_NewPathEmpty: - return RootState_NewPathEmpty; // new repository directory path is not empty - case eSetRootState_NewDirNotEmpty: - return RootState_NewDirNotEmpty; // new repository directory is not empty - case eSetRootState_NewNotDir: - return RootState_NewNotDir; // new repository exists and is not a directory - case eSetRootState_OldNotEmpty: - return RootState_OldNotEmpty; // old repository is not empty - case eSetRootState_Error: - return RootState_Error; // some unusual error happened - } + return translate_state ( model . set_repo_location ( id, flushOld, path, reuseNew ) ); } SRAConfigModel :: SRAConfigModel ( vdbconf_model &config_model, QObject *parent ) diff --git a/tools/vdb-config/sra-config/sraconfigmodel.h b/tools/vdb-config/sra-config/sraconfigmodel.h index 0e7cce14..9b0f887b 100644 --- a/tools/vdb-config/sra-config/sraconfigmodel.h +++ b/tools/vdb-config/sra-config/sraconfigmodel.h @@ -6,60 +6,87 @@ class vdbconf_model; struct KNgcObj; + +enum RootState +{ + RootState_OK, // successfully changed repository root + RootState_NotChanged, // the new path is the same as the old one + RootState_NotUnique, // there is another repository with the same root + RootState_MkdirFail, // failed to make new repository directory + RootState_NewPathEmpty, // new repository directory path is not empty + RootState_NewDirNotEmpty,// new repository directory is not empty + RootState_NewNotDir, // new repository exists and is not a directory + RootState_OldNotEmpty, // old repository is not empty + RootState_Error, // some unusual error happened +}; + class SRAConfigModel : public QObject { Q_OBJECT public: - enum RootState - { - RootState_OK, // successfully changed repository root - RootState_NotChanged, // the new path is the same as the old one - RootState_NotUnique, // there is another repository with the same root - RootState_MkdirFail, // failed to make new repository directory - RootState_NewPathEmpty, // new repository directory path is not empty - RootState_NewDirNotEmpty,// new repository directory is not empty - RootState_NewNotDir, // new repository exists and is not a directory - RootState_OldNotEmpty, // old repository is not empty - RootState_Error, // some unusual error happened - }; - + bool commit (); bool config_changed (); - bool proxy_enabled (); - bool proxy_priority (); - bool remote_enabled (); - bool site_enabled (); - bool import_ngc ( const std :: string path, KNgcObj *ngc, uint32_t permissions, uint32_t *rslt_flags ); bool path_exists ( const std :: string &path ); - bool site_workspace_exists ( const std :: string &path ); - void commit (); - void reload (); void create_directory ( const KNgcObj *ngc ); + void reload (); - void set_cache_enabled ( bool enabled ); - void set_proxy_enabled ( bool enabled ); + + // cache + bool global_cache_enabled (); + void set_global_cache_enabled ( bool enabled ); + + bool user_cache_enabled (); + void set_user_cache_enabled ( bool enabled ); + + // network + bool remote_enabled (); void set_remote_enabled ( bool enabled ); + + bool site_enabled (); void set_site_enabled ( bool enabled ); + + // ngc + bool import_ngc ( const std :: string path, const KNgcObj *ngc, uint32_t permissions, uint32_t *rslt_flags ); + bool get_ngc_obj_id ( const KNgcObj *ngc, uint32_t *id ); + std :: string get_ngc_root ( std :: string &dir, const KNgcObj *ngc ); + + // proxy + bool proxy_enabled (); + void set_proxy_enabled ( bool enabled ); + + std :: string get_proxy_path (); + void set_proxy_path ( const std :: string &path ); + + bool proxy_priority (); void set_proxy_priority ( bool priority ); - void set_public_path ( const std :: string &path, bool flushOld, bool reuseNew ); - void set_workspace_path ( const std :: string &path, uint32_t id, bool flushOld, bool reuseNew ); + // settings std :: string get_current_path (); std :: string get_home_path (); - std :: string get_proxy_path (); + std :: string get_public_path (); + RootState set_public_path ( const std :: string &path, bool flushOld, bool reuseNew ); + std :: string get_user_default_path (); + void set_user_default_path ( const char *path ); - bool get_ngc_obj_id ( const KNgcObj *ngc, uint32_t *id ); + // workspace + bool site_workspace_exists (); + + RootState configure_workspace ( const std :: string &path, bool reuseNew = false ); + + uint32_t workspace_count (); int32_t get_workspace_id ( const std :: string &name ); - std :: string get_ngc_root ( std :: string &dir, KNgcObj *ngc ); + std :: string get_workspace_name ( uint32_t id ); std :: string get_workspace_path ( uint32_t id ); - RootState configure_workspace ( const std :: string &path, bool reuseNew = false ); + RootState set_workspace_path ( const std :: string &path, uint32_t id, bool flushOld, bool reuseNew ); + // constructor SRAConfigModel ( vdbconf_model &config_model, QObject *parent = 0 ); signals: From 0eaf3fbcff3bf8c4795af79aa84ed1b30036406b Mon Sep 17 00:00:00 2001 From: ksrodarmer Date: Wed, 24 May 2017 13:53:19 -0400 Subject: [PATCH 23/23] Forgot to disable some unfinished features --- tools/vdb-config/sra-config/sraconfig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/vdb-config/sra-config/sraconfig.cpp b/tools/vdb-config/sra-config/sraconfig.cpp index 5359a8c7..9ab8f4ae 100644 --- a/tools/vdb-config/sra-config/sraconfig.cpp +++ b/tools/vdb-config/sra-config/sraconfig.cpp @@ -512,7 +512,7 @@ SRAConfig :: SRAConfig ( vdbconf_model &config_model, const QRect &avail_geometr setWindowTitle ( "SRA Configuration Tool" ); setup_menubar (); - setup_toolbar (); + //setup_toolbar (); main_layout -> setSpacing ( 20 ); main_layout -> setAlignment ( Qt::AlignTop ); @@ -828,7 +828,7 @@ void SRAConfig :: advanced_settings () { adv_setting_window = new QFrame (); adv_setting_window -> resize ( this -> width () * .7, this -> height () / 2 ); - adv_setting_window -> setWindowTitle ( "Advanced Setting" ); + adv_setting_window -> setWindowTitle ( "Advanced Settings" ); QVBoxLayout *v_layout = new QVBoxLayout ();