Skip to content

Commit

Permalink
Some small URI tweaks.
Browse files Browse the repository at this point in the history
Based on suggestions from Greg K., made so the "Enter URL" entry is more forgiving of text preceding the actual URI path; e.g., instead now "https://interspec.example.com/?_=/G0/3000/eNrVj..." will read in okay.  The URL used will now start with {"/G0/", "/drf/", "/specsum/", "/flux/", ...}.
Added checking the "internal" URL on page load to see if it contains the beginning of a recognized URI, and if so handle it.
Switched email QR code to use lowest error correction.
  • Loading branch information
wcjohns committed Aug 29, 2023
1 parent 1e0ca26 commit 6c6f9cf
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/AppUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ namespace AppUtils
const string host_path = url.substr( 0, path_end );
const string::size_type host_end = host_path.find( '/' );

// If "host/path" is only one compnent (i.e., no slash), then populate host,
// If "host/path" is only one component (i.e., no slash), then populate host,
// and have path be empty
host = (host_end == string::npos) ? host_path : host_path.substr(0,host_end);
path = (host_end == string::npos) ? string("") : host_path.substr(host_end+1);
Expand Down
10 changes: 9 additions & 1 deletion src/ExportSpecFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,19 @@ std::string clean_uuid( string uuid )
if( urls.size() > 1 )
seqnum += ", " + to_string(index + 1) + " of " + to_string( urls.size() );

string desc = seqnum;
string title = "Spectrum File " + seqnum;
if( urls.size() == 1 )
{
title = "";

// If a single URL, and on a phone, save screen space by skipping the description
InterSpec *viewer = InterSpec::instance();
if( viewer && viewer->isPhone() )
desc = "";
}//if( urls.size() == 1 )


string desc = seqnum;
SimpleDialog *dialog = QrCode::displayTxtAsQrCode( urls[index].m_url, title, desc );

if( (index + 1) < urls.size() )
Expand Down
50 changes: 44 additions & 6 deletions src/InterSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,17 @@ namespace

return false;
}//try_update_hint_peak(...)

template<typename charT>
struct char_iequal
{
char_iequal( const std::locale &loc ) : m_loc(loc) {}
bool operator()(charT ch1, charT ch2) {
return std::toupper(ch1, m_loc) == std::toupper(ch2, m_loc);
}
private:
const std::locale &m_loc;
};
}//namespace


Expand Down Expand Up @@ -11058,6 +11069,7 @@ void InterSpec::handleAppUrl( const std::string &url_encoded_url )

void InterSpec::makeEnterAppUrlWindow()
{
// TODO: could probably put this functions implementation into its own source file.
if( m_enterUri )
return;

Expand All @@ -11078,23 +11090,34 @@ void InterSpec::makeEnterAppUrlWindow()
WPushButton *cancel = m_enterUri->addButton( "Cancel" );
WPushButton *okay = m_enterUri->addButton( "Okay" );

const string acceptable_paths[] = {
"G0", "drf", "specsum", "flux", "specexport", "decay", "dose", "gammaxs", "1overr2", "unit"
};//acceptable_paths[]


// We will validate the URL starts with 'interspec://' or 'raddata://', end enable/disable the
// "Okay" button in javascript
const string jsokay = okay->jsRef();
const string validate_js = "function(textarea,event){ "
"const matches = /^((interspec:\\/\\/)|(raddata:)).+/i.test(textarea.value);"
string validate_js = "function(textarea,event){ "
"const matches = /^((interspec:\\/\\/)|(raddata:\\/\\/))";

for( const string &path : acceptable_paths )
validate_js += "|(.*\\/" + path + "\\/)";

validate_js += ".+/i.test(textarea.value);"
"$(" + jsokay + ").prop('disabled', !matches);"
" }";
text->keyWentUp().connect( validate_js );


// Dont disable okay button during undo/redo - would be better to validate after we might put text
// into the textarea - but not bothering to do it correctly, at the moment.
if( !m_undo || !m_undo->isInUndoOrRedo() )
okay->doJavaScript( "$(" + jsokay + ").prop('disabled', true);" );

// TODO: All this undo/redo stuff is still probably not quite right - could use a little more work

okay->clicked().connect( std::bind([this, text](){
okay->clicked().connect( std::bind([this, text, acceptable_paths](){
string uri = text->text().toUTF8();
SpecUtils::trim( uri );
m_enterUri = nullptr;
Expand Down Expand Up @@ -11137,9 +11160,24 @@ void InterSpec::makeEnterAppUrlWindow()
handleAppUrl( uri );
}else
{
throw runtime_error( "URL must start with 'interspec://' or 'raddata:'." );
}

bool found_sub = false;
for( const string &path : acceptable_paths )
{
const string key = "/" + path + "/";
const auto it = std::search( begin(uri), end(uri), begin(key), end(key),
char_iequal<char>(std::locale()) );
if( it != end(uri) )
{
const string sub_uri = "interspec:/" + string(it, end(uri));
handleAppUrl( sub_uri );
found_sub = true;
break;
}//if( it != end(uri) )
}//for( const string &path : acceptable_paths )

if( !found_sub )
throw runtime_error( "URL must start with 'interspec://', 'raddata://', or have a /G0/ component." );
}//
}catch( std::exception &e )
{
SimpleDialog *errdialog = new SimpleDialog( "Error with entered URL", e.what() );
Expand Down
23 changes: 23 additions & 0 deletions src/InterSpecApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,29 @@ void InterSpecApp::setupWidgets( const bool attemptStateLoad )
}//if( !m_externalToken.empty() )
#endif

#if( USE_QR_CODES && (BUILD_FOR_WEB_DEPLOYMENT || BUILD_AS_LOCAL_SERVER) )
// Allow having an "internal" path where URI data is represented as part of the URL, for
// example https://interspec.example.com/?_=/G0/3000/eNrV...
// It probably doesnt make sense to support "drf", "specsum", "flux", and "specexport" here.
const string &internal_path = environment().internalPath();
if( !loadedSpecFile
&& (SpecUtils::istarts_with(internal_path, "/G0/")
|| SpecUtils::istarts_with(internal_path, "/decay/")
|| SpecUtils::istarts_with(internal_path, "/dose/")
|| SpecUtils::istarts_with(internal_path, "/gammaxs/")
|| SpecUtils::istarts_with(internal_path, "/1overr2/")
|| SpecUtils::istarts_with(internal_path, "/unit/") ) )
{
try
{
m_viewer->handleAppUrl( "interspec:/" + internal_path );
loadedSpecFile = true;
}catch( std::exception & )
{
}
}//
#endif // #if( USE_QR_CODES && (BUILD_FOR_WEB_DEPLOYMENT || BUILD_AS_LOCAL_SERVER) )


#if( USE_DB_TO_STORE_SPECTRA )
//Check to see if we should load the apps last saved state
Expand Down
28 changes: 26 additions & 2 deletions src/QrCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "InterSpec_config.h"

#include <cctype>
#include <string>
#include <sstream>
#include <iostream>
Expand Down Expand Up @@ -106,6 +107,23 @@ WT_DECLARE_WT_MEMBER
}
);


bool starts_with( const std::string &line, const char *label )
{
const size_t len1 = line.size();
const size_t len2 = strlen(label);

if( len1 < len2 )
return false;

for( size_t i = 0; i < len2; ++i )
{
if( std::toupper( (int)line[i] ) != std::toupper( (int)label[i] ) )
return false;
}

return true;
}//bool starts_with( const std::string &line, const char *label )
}//namespace


Expand Down Expand Up @@ -236,8 +254,14 @@ SimpleDialog *displayTxtAsQrCode( const std::string &url,
{
try
{
const tuple<string,int,ErrorCorrLevel> qr_svg
= utf8_string_to_svg_qr( url, ErrorCorrLevel::About30Percent, 3 );
// If its a "mailto:" URI, then put error correction to lowest level, to make the QR code
// as small as possible, since user will most likely be directly reading the QR code onto
// their phone.
QrCode::ErrorCorrLevel wanted_ecl = ErrorCorrLevel::About30Percent;
if( starts_with( url, "mailto:") )
wanted_ecl = ErrorCorrLevel::About7Percent;

const tuple<string,int,ErrorCorrLevel> qr_svg = utf8_string_to_svg_qr( url, wanted_ecl, 3 );
const string &qr_svg_str = get<0>(qr_svg);
const int qr_size = get<1>(qr_svg); //A simple DRF is like 70, or so
const ErrorCorrLevel ecl = get<2>(qr_svg);
Expand Down

0 comments on commit 6c6f9cf

Please sign in to comment.