Skip to content

Commit

Permalink
Merge branch 'master' of github.com:sandialabs/InterSpec
Browse files Browse the repository at this point in the history
  • Loading branch information
wcjohns committed Jan 24, 2024
2 parents df808ed + 03d0636 commit b82c700
Show file tree
Hide file tree
Showing 17 changed files with 533 additions and 154 deletions.
40 changes: 34 additions & 6 deletions InterSpec/SearchMode3DChart.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,27 @@

#include "InterSpec_config.h"

#include <set>
#include <memory>
#include <string>
#include <vector>

#include <Wt/WContainerWidget>

//Some forward declarations
class SpecMeas;
class InterSpec;
class NativeFloatSpinBox;
class SearchMode3DDataModel;

namespace SpecUtils{ enum class SpectrumType : int; }

namespace Wt
{
class WText;
namespace Chart
{
class WSpinBox;
class WGridData;
class WGridLayout;
class WDoubleSpinBox;
Expand Down Expand Up @@ -100,8 +112,14 @@ class SearchMode3DChart : public Wt::WContainerWidget
void setEnergyLimits();

/** Function that gets called when the user loads a new spectrum. */
void newSpectralDataSet();
void newSpectralDataSet( const SpecUtils::SpectrumType type,
const std::shared_ptr<SpecMeas> &meas,
const std::set<int> &sample_numbers,
const std::vector<std::string> &detectors );

void setBinningLimits();
void handleNumTimeDivsChanged();
void handleNumEnergyDivsChanged();

protected:
InterSpec *m_viewer;
Expand All @@ -115,11 +133,21 @@ class SearchMode3DChart : public Wt::WContainerWidget
SearchMode3DDataModel *m_model;
Wt::Chart::WGridData *m_data;
Wt::Chart::WCartesian3DChart *m_chart;
Wt::WDoubleSpinBox *m_inputMinEnergy;
Wt::WDoubleSpinBox *m_inputMaxEnergy;
Wt::WDoubleSpinBox *m_inputMinTime;
Wt::WDoubleSpinBox *m_inputMaxTime;


NativeFloatSpinBox *m_inputMinEnergy;
NativeFloatSpinBox *m_inputMaxEnergy;
NativeFloatSpinBox *m_inputMinTime;
NativeFloatSpinBox *m_inputMaxTime;

Wt::WSpinBox *m_timeDivisions;
Wt::WSpinBox *m_energyDivisions;

Wt::WText *m_loadingTxt;

/** Some absolute limits on min and max number of divisions to display in the 3D chart. */
static const int sm_maxTimeDivs;
static const int sm_maxEnergyDivs;
static const int sm_minTimeOrEnergyDivs;
};//class SearchMode3DChart


Expand Down
30 changes: 27 additions & 3 deletions InterSpec/SpecMeasManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <string>

#include <boost/any.hpp>
#include <boost/asio/deadline_timer.hpp>

#include <Wt/WString>
#include <Wt/WResource>
Expand All @@ -47,10 +48,10 @@
#include "InterSpec/AuxWindow.h"
#include "InterSpec/SpectraFileModel.h"

// Some forward declarations
namespace SpecUtils{ enum class ParserType : int; }
namespace SpecUtils{ enum class SpectrumType : int; }

// Some forward declarations
namespace Wt
{
class JSlot;
Expand Down Expand Up @@ -396,6 +397,10 @@ class SpecMeasManager : public Wt::WObject
AuxWindow *window,
Wt::WModelIndex index );

/** Called by FileDragUploadResource, as files are being uploaded; if file is larger than `sm_minNumBytesShowUploadProgressDialog`,
then will create a status message dialog, `m_processingUploadDialog`.
*/
void handleDataRecievedStatus( uint64_t num_bytes_recieved, uint64_t num_bytes_total, SpecUtils::SpectrumType type );

//Handles a file dropped onto the application, or finishes opening files from
// filesystem URL.
Expand Down Expand Up @@ -449,6 +454,8 @@ class SpecMeasManager : public Wt::WObject
const bool checkIfPreviouslyOpened,
const bool doPreviousEnergyRangeCheck );

/** Deletes the dialog, but only if the passed in dialog is the same as `m_processingUploadDialog` */
void checkCloseUploadDialog( SimpleDialog *dialog, Wt::WApplication *app );

private:
Wt::WContainerWidget *createButtonBar();
Expand Down Expand Up @@ -489,16 +496,33 @@ class SpecMeasManager : public Wt::WObject
//m_sql same as m_viewer->sql();
std::shared_ptr<DataBaseUtils::DbSession> m_sql;

std::shared_ptr< std::mutex > m_destructMutex;
std::shared_ptr< bool > m_destructed;
std::shared_ptr<std::mutex> m_destructMutex;
std::shared_ptr<bool> m_destructed;

/** Dialog created when a file is uploading, from `handleDataRecievedStatus()`, letting the user know that something is going on.
On the client-side there is an upload status that is shown, but for large files the upload status in JS can be significantly off from what
the server is seeing, leading to a potentially long gap between the client-side status, and when the file actually finishes uploading and
is being parsed (which another dialog will be shown for parsing large files) - so this dialog covers this time gap to keep the user informed.
*/
SimpleDialog *m_processingUploadDialog;

/** Timer used to make sure the dialog is destroyed, even if upload stalls-out; reset in every call to `handleDataRecievedStatus()`,
with a timeout of 30 seconds.
Did not use a `Wt::WTimer` so we dont effect the DOM when creating and resetting timer, as the WTimer gets inserted into the DOM, and
maybe also added to the client-side JS (but I didnt check if creating/resetting a WTimer would cause a network request, but a quick glance at
the Wt source code did look like this might be the case, but also maybe not if its server-side only connection)
*/
std::unique_ptr<boost::asio::deadline_timer> m_processingUploadTimer;

#if( !defined(MAX_SPECTRUM_MEMMORY_SIZE_MB) || MAX_SPECTRUM_MEMMORY_SIZE_MB < 0 )
static const size_t sm_maxTempCacheSize = 0;
#else
static const size_t sm_maxTempCacheSize = 1024 * 1024 * MAX_SPECTRUM_MEMMORY_SIZE_MB;
#endif

const static size_t sm_minNumBytesShowUploadProgressDialog = 100 * 1024;

mutable std::deque< std::shared_ptr<const SpecMeas> > m_tempSpectrumInfoCache;
};//class SpecMeasManager

Expand Down
34 changes: 34 additions & 0 deletions InterSpec_resources/SearchMode3DChart.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,37 @@
{
}


.SearchMode3DChart div.SearchMode3DControls
{
display: grid;
grid-column-gap: 5px;
row-gap: 4px;
padding-top: 5px;

grid-template-columns: auto auto auto auto 1fr auto auto;
}


.SearchMode3DChart div.SearchMode3DControls label
{
margin-right: 5px;
align-self: center;
}


/* The input areas for min/max time/energy */
.SearchMode3DChart div.SearchMode3DControls input
{
align-self: center;
margin-right: 15px;
width: 5em;
}


/* The number of time and energy divisions input */
.SearchMode3DChart div.SearchMode3DControls .Wt-spinbox
{
margin-right: 0px;
width: 4em;
}
82 changes: 55 additions & 27 deletions js/InterSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ function()

if( !validin )
{
alert( 'You can only upload a single file at a time unless the name is'
+ ' prefixed with "i-", "b-", "k-" or has back/fore/item/calib'
+ ' in the file name, and there is at most one of each spectrum type.' );
const msg = 'showMsg-error-You can only upload a single file at a time unless the name is'
+ ' prefixed with "i-", "b-", "k-" or has back/fore/item/calib'
+ ' in the file name, and there is at most one of each spectrum type.';

Wt.emit( $('.specviewer').attr('id'), {name:'miscSignal'}, msg );
return;
}

Expand Down Expand Up @@ -102,36 +104,62 @@ function()
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
// Filename may have non-ISO-8859-1 code points, so we need to URI encode it
xhr.setRequestHeader("X-File-Name", encodeURIComponent(file.name));
const filename_uri = encodeURIComponent(file.name);
xhr.setRequestHeader("X-File-Name", filename_uri);


//#if( BUILD_AS_ELECTRON_APP ) //C++ preprocessors dont look to work here...
if( lookForPath && (typeof file.path === "string") && (file.path.length > 2) && !file.path.toLowerCase().includes('fake') ) {
// For Electron builds, file.path gives the full path (including filename), so we
// will just upload the path so we can read it in the c++ to avoid lots of copying and
// stuff. But we also need to fallback, JIC c++ fails for some unforeseen reason.
// See #FileDragUploadResource::handleRequest for the other part of this logic
xhr.setRequestHeader("Is-File-Path", "1" );
if( lookForPath && file.name && (file.name.length > 3) ){
let fspath = null;
if( (typeof file.path === "string") && file.path.length > 3 ){
fspath = file.path;
}else{
const fns = $(document).data('dragOverFilePaths');
if( fns && Array.isArray(fns.filenames) && fns.time && (Math.abs(fns.time - (new Date())) < 30000) ){
for( let i = 0; i < fns.filenames.length; ++i ) {
if( encodeURIComponent(fns.filenames[i]).endsWith(filename_uri) ){
fspath = fns.filenames[i];
//remove this filename from the array, incase there are multiple files with same leaf-name, but diff paths
fns.filenames = fns.filenames.splice(i,i);
console.log( "Matched filenames: ", file.name, " vs ", fspath );
console.log( "Remaining files: ", fns.filenames );
if( fns.filenames.length === 0 )
$(document).data('dragOverFilePaths', null);
break;
}//if( native fn ends with browsers fn )
}//for( loop over fns.filenames.length )
}//if( we have 'dragOverFilePaths' object, and its valid )
}//if( we have `file.path` available ) else if( we have 'dragOverFilePaths' avaiable )

if( (typeof fspath === "string") && (fspath.length > 2) && !fspath.toLowerCase().includes('fake') ) {
// For Electron and macOS builds, fspath gives the full path (including filename), so we
// will just upload the path so we can read it in the c++ to avoid lots of copying and
// stuff. But we also need to fallback, JIC c++ fails for some unforeseen reason.
// See #FileDragUploadResource::handleRequest for the other part of this logic
xhr.setRequestHeader("Is-File-Path", "1" );

console.log( 'Will send file path, instead of actual file; path: ', file.path );
console.log( 'Will send native file-system path, instead of actual file; path: ', fspath );

xhr.onload = function(){
removeUploading();
xhr.onload = function(){
removeUploading();

if( (xhr.readyState === 4) && (xhr.status !== 200) ){
console.log( 'Failed to upload via Electron path.' );
uploadFileToUrl( uploadURL, file, false );
}else if( xhr.readyState === 4 ) {
console.log( 'Successfully uploaded path to Electron.' );
}
};
if( (xhr.readyState === 4) && (xhr.status !== 200) ){
// Fallback to standard http upload, since reading in c++ failed
console.log( 'Failed to upload via native file-system path.' );
uploadFileToUrl( uploadURL, file, false );
}else if( xhr.readyState === 4 ) {
// Reading in c++ succeeded
console.log( 'Successfully uploaded native file-system path.' );
uploadNextFile();
}
};

xhr.onloadend = removeUploading;
xhr.onloadend = removeUploading;

const body = JSON.stringify( { fullpath: file.path} );
xhr.send(body);
return;
}//if( have full path on Electron build )
//#endif
const body = JSON.stringify( { fullpath: fspath} );
xhr.send(body);
return;
}//if( have full path on Electron or macOS build )
}

xhr.onerror = errfcn;
xhr.onload = function(){
Expand Down
2 changes: 1 addition & 1 deletion src/D3SpectrumDisplayDiv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ D3SpectrumDisplayDiv::D3SpectrumDisplayDiv( WContainerWidget *parent )
wApp->useStyleSheet( resource_base + "SpectrumChartD3.css" );
initChangeableCssRules();

wApp->require( resource_base + "d3.v3.min.js", "d3.v3.js" );
wApp->require( "InterSpec_resources/d3.v3.min.js", "d3.v3.js" );
wApp->require( resource_base + "SpectrumChartD3.js" );


Expand Down
10 changes: 0 additions & 10 deletions src/DecayChainChart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,17 +297,7 @@ DecayChainChart::DecayChainChart( WContainerWidget *parent )
m_showDecayParticles( this, "ShowDecayParticleInfo", true ),
m_showDecaysThrough( this, "ShowDecaysThrough", true )
{
//To keep Wt from loading d3.js again, if it loaded it fo D3SpectrumDisplay, then
// it looks like (for Wt 3.3.4 anyway) we need the same URL, not just the same
// second argument - so the loading here matches D3SpectrumDisplay.
#if( defined(NDEBUG) || IOS || ANDROID || BUILD_AS_ELECTRON_APP || BUILD_AS_OSX_APP || BUILD_AS_WX_WIDGETS_APP )
//THe NDEBUG should be enough, but just making sure
wApp->require( "InterSpec_resources/d3.v3.min.js", "d3.v3.js" );
#else
wApp->require( "external_libs/SpecUtils/d3_resources/d3.v3.min.js", "d3.v3.js" );
#endif

//wApp->require( "InterSpec_resources/d3.v3.min.js", "d3.v3.js" );
wApp->require( "InterSpec_resources/DecayChainChart.js" );
wApp->useStyleSheet( "InterSpec_resources/DecayChainChart.css" );
addStyleClass( "DecayChainChart" );
Expand Down
2 changes: 1 addition & 1 deletion src/DoseCalcWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ void DoseCalcWidget::init()
else
m_activityEnterUnits->setCurrentIndex( 6 ); //uci

m_activityAnswerUnits->addItem( "curries" );
m_activityAnswerUnits->addItem( "curies" );
m_activityAnswerUnits->addItem( "becquerels" );

if( useBq )
Expand Down
2 changes: 1 addition & 1 deletion src/FileDragUploadResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ void FileDragUploadResource::handleRequest( const Http::Request& request,
}//if( !app )


#if( BUILD_AS_ELECTRON_APP )
#if( BUILD_AS_ELECTRON_APP || BUILD_AS_OSX_APP )
// See FileUploadFcn in InterSpec.js
const string isFilePath = request.headerValue("Is-File-Path");

Expand Down
2 changes: 1 addition & 1 deletion src/FluxTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1183,7 +1183,7 @@ void FluxToolWidget::init()
m_copyBtn = new WPushButton( "Copy To Clipboard" );

// TODO: "upgrade" to using the InterSpecApp 'miscSignal' directly in CopyFluxDataTextToClipboard, and get rid of m_infoCopied signal handler
//"Wt.emit( '" + wApp->dom()->id() + "', {name:'miscSignal'}, 'showMsg-info-' );"
//"Wt.emit( $('.specviewer').attr('id'), {name:'miscSignal'}, 'showMsg-info-' );"

m_copyBtn->clicked().connect( "function(s,e){ "
"var success = Wt.WT.CopyFluxDataTextToClipboard(s,e,'" + m_copyBtn->id() + "'); "
Expand Down
15 changes: 10 additions & 5 deletions src/InterSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7374,7 +7374,7 @@ void InterSpec::addAboutMenu( Wt::WWidget *parent )
true, HelpSystem::ToolTipPosition::Right );

const string msg = "Changes will not take effect until app is restarted or refreshed."
"<div onclick=\"Wt.emit('" + wApp->root()->id() + "',{name:'miscSignal'}, 'clearSession');"
"<div onclick=\"Wt.emit( $('.specviewer').attr('id'), {name:'miscSignal'}, 'clearSession');"
"try{$(this.parentElement.parentElement).remove();}catch(e){}return false;\" "
"class=\"clearsession\"><span class=\"clearsessiontxt\">Refresh Session</span></div>";
const WString wmsg = WString::fromUTF8( msg );
Expand Down Expand Up @@ -8293,6 +8293,10 @@ void InterSpec::create3DSearchModeChart()
programmaticallyClose3DSearchModeChart();

m_3dViewWindow = new AuxWindow( "3D Data View" );
//set min size so setResizable call before setResizable so Wt/Resizable.js wont cause the initial
// size to be the min-size
m_3dViewWindow->setMinimumSize( 512, 420 );

m_3dViewWindow->disableCollapse();
m_3dViewWindow->Wt::WDialog::rejectWhenEscapePressed();

Expand All @@ -8308,8 +8312,9 @@ void InterSpec::create3DSearchModeChart()

m_3dViewWindow->show();
m_3dViewWindow->setClosable( true );
m_3dViewWindow->resizeScaledWindow( 0.95, 0.95 );
m_3dViewWindow->resizeScaledWindow( 0.7, 0.9 );
m_3dViewWindow->centerWindow();
m_3dViewWindow->setResizable( true );
m_3dViewWindow->finished().connect( this, &InterSpec::handle3DSearchModeChartClose );

if( m_undo && m_undo->canAddUndoRedoNow() )
Expand Down Expand Up @@ -10677,7 +10682,7 @@ void InterSpec::setSpectrum( std::shared_ptr<SpecMeas> meas,
WStringStream js;
js << "File contains GPS coordinates."
<< "<div onclick="
"\"Wt.emit('" << wApp->root()->id() << "',{name:'miscSignal'}, 'showMap-" << type << "');"
"\"Wt.emit( $('.specviewer').attr('id'),{name:'miscSignal'}, 'showMap-" << type << "');"
"try{$(this.parentElement.parentElement).remove();}catch(e){}"
"return false;\" "
"class=\"clearsession\">"
Expand Down Expand Up @@ -10807,7 +10812,7 @@ void InterSpec::setSpectrum( std::shared_ptr<SpecMeas> meas,
#endif
<< riidAnaSummary(meas)
<< "<div onclick="
"\"Wt.emit('" << wApp->root()->id() << "',{name:'miscSignal'}, 'showRiidAna-" << type << "');"
"\"Wt.emit( $('.specviewer').attr('id'),{name:'miscSignal'}, 'showRiidAna-" << type << "');"
//"$('.qtip.jgrowl:visible:last').remove();"
"try{$(this.parentElement.parentElement).remove();}catch(e){}"
"return false;\" "
Expand Down Expand Up @@ -10928,7 +10933,7 @@ void InterSpec::setSpectrum( std::shared_ptr<SpecMeas> meas,
WStringStream js;
js << "Spectrum file contained embedded images: "
<< "<div onclick="
"\"Wt.emit('" << wApp->root()->id() << "',{name:'miscSignal'}, 'showMultimedia-" << type << "');"
"\"Wt.emit( $('.specviewer').attr('id'),{name:'miscSignal'}, 'showMultimedia-" << type << "');"
//"$('.qtip.jgrowl:visible:last').remove();"
"try{$(this.parentElement.parentElement).remove();}catch(e){}"
"return false;\" "
Expand Down
Loading

0 comments on commit b82c700

Please sign in to comment.