diff --git a/CMake/Modules/Findhamlib.cmake b/CMake/Modules/Findhamlib.cmake
index 1590f051d..7eebf1066 100644
--- a/CMake/Modules/Findhamlib.cmake
+++ b/CMake/Modules/Findhamlib.cmake
@@ -16,7 +16,7 @@ set (hamlib_LIBRARY_DIRS)
# pkg-config?
find_path (__hamlib_pc_path NAMES hamlib.pc
- PATH_SUFFIXES lib/pkgconfig
+ PATH_SUFFIXES lib/pkgconfig lib64/pkgconfig
)
if (__hamlib_pc_path)
set (ENV{PKG_CONFIG_PATH} "${__hamlib_pc_path}" "$ENV{PKG_CONFIG_PATH}")
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c684ab4aa..e2afabd6a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -265,6 +265,7 @@ set (wsjt_qt_CXXSRCS
models/DecodeHighlightingModel.cpp
widgets/DecodeHighlightingListView.cpp
models/FoxLog.cpp
+ widgets/AbstractLogWindow.cpp
widgets/FoxLogWindow.cpp
widgets/CabrilloLogWindow.cpp
item_delegates/CallsignDelegate.cpp
@@ -382,7 +383,6 @@ set (wsjt_FSRCS
lib/badmsg.f90
lib/ft8/baseline.f90
lib/bpdecode40.f90
- lib/bpdecode144.f90
lib/bpdecode128_90.f90
lib/ft8/bpdecode174.f90
lib/ft8/bpdecode174_91.f90
@@ -414,7 +414,6 @@ set (wsjt_FSRCS
lib/encode232.f90
lib/encode4.f90
lib/encode_msk40.f90
- lib/encode_msk144.f90
lib/encode_128_90.f90
lib/ft8/encode174.f90
lib/ft8/encode174_91.f90
@@ -422,7 +421,6 @@ set (wsjt_FSRCS
lib/ephem.f90
lib/extract.f90
lib/extract4.f90
- lib/extractmessage144.f90
lib/extractmessage77.f90
lib/ft8/extractmessage174.f90
lib/ft8/extractmessage174_91.f90
@@ -497,10 +495,8 @@ set (wsjt_FSRCS
lib/moondopjpl.f90
lib/morse.f90
lib/move.f90
- lib/msk144d.f90
lib/msk40decodeframe.f90
lib/msk144decodeframe.f90
- lib/msk144sd.f90
lib/msk40spd.f90
lib/msk144spd.f90
lib/msk40sync.f90
@@ -519,6 +515,8 @@ set (wsjt_FSRCS
lib/peakdt9.f90
lib/peakup.f90
lib/plotsave.f90
+ lib/platanh.f90
+ lib/pltanh.f90
lib/polyfit.f90
lib/prog_args.f90
lib/ps4.f90
@@ -561,7 +559,6 @@ set (wsjt_FSRCS
lib/twkfreq.f90
lib/ft8/twkfreq1.f90
lib/twkfreq65.f90
- lib/unpackmsg144.f90
lib/update_recent_calls.f90
lib/update_hasharray.f90
lib/ft8/watterson.f90
@@ -1252,14 +1249,9 @@ target_link_libraries (ft8code wsjt_fort wsjt_cxx)
add_executable (ft8sim lib/ft8/ft8sim.f90 wsjtx.rc)
target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
-add_executable (msk144sd lib/msk144sd.f90 wsjtx.rc)
-target_link_libraries (msk144sd wsjt_fort wsjt_cxx)
-
add_executable (msk144sim lib/msk144sim.f90 wsjtx.rc)
target_link_libraries (msk144sim wsjt_fort wsjt_cxx)
-add_executable (msk144d lib/msk144d.f90 wsjtx.rc)
-target_link_libraries (msk144d wsjt_fort wsjt_cxx)
endif(WSJT_BUILD_UTILS)
# build the main application
@@ -1708,11 +1700,11 @@ endif ()
set (CPACK_DEBIAN_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}")
set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "${PROJECT_HOMEPAGE}")
-set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran3 (>=4.8.2), libqt5serialport5 (>=5.2), libqt5multimedia5-plugins (>=5.2), libqt5widgets5 (>=5.2), libusb-1.0-0, libudev1, libc6 (>=2.19)")
+set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran3 (>=4.8.2), libqt5serialport5 (>=5.5), libqt5multimedia5-plugins (>=5.5), libqt5widgets5 (>=5.5), libqt5sql5-sqlite (>=5.5), libusb-1.0-0, libudev1, libc6 (>=2.19)")
set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set (CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
-set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtserialport >= 5.2, qt5-qtmultimedia >= 5.2, qt5-qtsvg, libusb, systemd-udev, glibc >= 2, libgfortran >= 4.8.2")
+set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtserialport >= 5.5, qt5-qtmultimedia >= 5.5, qt5-qtsvg, libusb, systemd-udev, glibc >= 2, libgfortran >= 4.8.2")
set (CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/share/pixmaps /usr/share/applications /usr/share/man /usr/share/man1)
configure_file ("${PROJECT_SOURCE_DIR}/CMakeCPackOptions.cmake.in"
diff --git a/Configuration.cpp b/Configuration.cpp
index 03f5b2ac2..bf57206b2 100644
--- a/Configuration.cpp
+++ b/Configuration.cpp
@@ -1091,6 +1091,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
frequencies_.sort (FrequencyList_v2::frequency_column);
ui_->frequencies_table_view->setModel (&next_frequencies_);
+ ui_->frequencies_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
+ ui_->frequencies_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
ui_->frequencies_table_view->sortByColumn (FrequencyList_v2::frequency_column, Qt::AscendingOrder);
ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2::frequency_mhz_column, true);
@@ -1131,6 +1133,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
//
stations_.sort (StationList::band_column);
ui_->stations_table_view->setModel (&next_stations_);
+ ui_->stations_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
+ ui_->stations_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder);
// stations delegates
@@ -2275,10 +2279,10 @@ void Configuration::impl::delete_selected_macros (QModelIndexList selected_rows)
{
// sort in reverse row order so that we can delete without changing
// indices underneath us
- qSort (selected_rows.begin (), selected_rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs)
- {
- return rhs.row () < lhs.row (); // reverse row ordering
- });
+ std::sort (selected_rows.begin (), selected_rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs)
+ {
+ return rhs.row () < lhs.row (); // reverse row ordering
+ });
// now delete them
Q_FOREACH (auto index, selected_rows)
diff --git a/Configuration.ui b/Configuration.ui
index 1e8feae69..7a3ec96be 100644
--- a/Configuration.ui
+++ b/Configuration.ui
@@ -1712,24 +1712,24 @@ QListView::item:hover {
-
- Some logging programs will not accept JT-65 or JT9 as a recognized mode.
+ Some logging programs will not accept the type of reports
+saved by this program.
+Check this option to save the sent and received reports in the
+comments field.
- Con&vert mode to RTTY
+ d&B reports to comments
-
- <html><head/><body><p>The callsign of the operator, if different from the station callsign.</p></body></html>
+ Check this option to force the clearing of the DX Call
+and DX Grid fields when a 73 or free text message is sent.
-
-
- -
-
- Log automatically
+ Clear &DX call and grid after logging
diff --git a/Darwin/Info.plist.in b/Darwin/Info.plist.in
index b62e03682..830975da5 100644
--- a/Darwin/Info.plist.in
+++ b/Darwin/Info.plist.in
@@ -36,5 +36,7 @@
NSApplication
NSHighResolutionCapable
True
+ NSRequiresAquaSystemAppearance
+
diff --git a/Release_Notes.txt b/Release_Notes.txt
index 8c483f454..c2b2c711b 100644
--- a/Release_Notes.txt
+++ b/Release_Notes.txt
@@ -12,6 +12,31 @@
Copyright 2001 - 2018 by Joe Taylor, K1JT.
+ Release: WSJT-X 2.0-rc5
+ November 26, 2018
+ -----------------------
+
+Release Candidate 5 ("RC5") is stable, works well, and fixes the known
+problems in RC4. It is likely that the General Availability (GA)
+release of WSJT-X 2.0 will be nearly identical to RC5.
+
+Changes from WSJT-X 2.0-rc4 include the following:
+
+ - Make the "Auto Seq" checkbox sticky, again
+ - Remove the 5-minute mouse timer
+ - Correct the "worked before" logic for color highlighting
+ - Add "No own call decodes" checkbox in WSPR mode
+ - Display and log UTC (not local time) in contest operations
+ - Validate contest QSO details before allowing logging
+ - Force Aqua theme on macOS to avoid issues with Mojave dark theme
+ - Move Fox log Reset action to Fox log window context menu
+ - Improve layout of Working Frequencies and Station Information tables
+ - Allow deletes and editing in Fox and Contest log windows
+ - Add Tool Tips for Fox and Contest log windows
+ - Fix a bug causing false AP decodes in JT65 VHF+ operation
+ - Fix a bug that could switch unexpectedly from JT65 to JT9 mode
+
+
Release: WSJT-X 2.0-rc4
November 12, 2018
-----------------------
diff --git a/Versions.cmake b/Versions.cmake
index 6cb4d89c2..3ba5db895 100644
--- a/Versions.cmake
+++ b/Versions.cmake
@@ -1,6 +1,6 @@
# Version number components
set (WSJTX_VERSION_MAJOR 2)
set (WSJTX_VERSION_MINOR 0)
-set (WSJTX_VERSION_PATCH 1)
-#set (WSJTX_RC 1) # release candidate number, comment out or zero for development versions
+set (WSJTX_VERSION_PATCH 0)
+set (WSJTX_RC 5) # release candidate number, comment out or zero for development versions
set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build
diff --git a/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp b/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp
index 66d3b6769..5b7f76eb8 100644
--- a/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp
+++ b/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp
@@ -28,7 +28,7 @@ public:
static QDateTime to_date_time (QVariant const& value)
{
- return QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull);
+ return QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC);
}
QString displayText (QVariant const& value, QLocale const& locale) const override
diff --git a/item_delegates/ForeignKeyDelegate.cpp b/item_delegates/ForeignKeyDelegate.cpp
index 09df6a731..204738163 100644
--- a/item_delegates/ForeignKeyDelegate.cpp
+++ b/item_delegates/ForeignKeyDelegate.cpp
@@ -1,7 +1,10 @@
#include "ForeignKeyDelegate.hpp"
+#include
#include
-
+#include
+#include
+#include
#include "CandidateKeyFilter.hpp"
ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel const * referenced_model
@@ -40,3 +43,20 @@ QWidget * ForeignKeyDelegate::createEditor (QWidget * parent
editor->setSizeAdjustPolicy (QComboBox::AdjustToContents);
return editor;
}
+
+QSize ForeignKeyDelegate::sizeHint (QStyleOptionViewItem const& option, QModelIndex const& index) const
+{
+ auto size_hint = QStyledItemDelegate::sizeHint (option, index);
+ QFontMetrics metrics {option.font};
+ QStyleOptionComboBox combo_box_option;
+ combo_box_option.rect = option.rect;
+ combo_box_option.state = option.state | QStyle::State_Enabled;
+ for (auto row = 0; row < candidate_key_filter_->rowCount (); ++row)
+ {
+ size_hint = size_hint.expandedTo (qApp->style ()->sizeFromContents (QStyle::CT_ComboBox
+ , &combo_box_option
+ , {metrics.width (candidate_key_filter_->data (candidate_key_filter_->index (row, 0)).toString ())
+ , metrics.height ()}));
+ }
+ return size_hint;
+}
diff --git a/item_delegates/ForeignKeyDelegate.hpp b/item_delegates/ForeignKeyDelegate.hpp
index 01b03ee5b..4f58f4608 100644
--- a/item_delegates/ForeignKeyDelegate.hpp
+++ b/item_delegates/ForeignKeyDelegate.hpp
@@ -33,9 +33,10 @@ public:
, int referencing_key_role = Qt::EditRole);
~ForeignKeyDelegate ();
- QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
-
private:
+ QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
+ QSize sizeHint (QStyleOptionViewItem const&, QModelIndex const&) const override;
+
QScopedPointer candidate_key_filter_;
};
diff --git a/lib/77bit/77bit.txt b/lib/77bit/77bit.txt
index 0d6c4b733..ef370c111 100644
--- a/lib/77bit/77bit.txt
+++ b/lib/77bit/77bit.txt
@@ -10,12 +10,12 @@ subtypes.
i3.n3 Example message Bits Total Purpose
----------------------------------------------------------------------------------
0.0 FREE TEXT MSG 71 71 Free text
-0.1 K1ABC RR73; W9XYZ -11 28 28 10 5 71 DXpedition Mode
+0.1 K1ABC RR73; W9XYZ -12 28 28 10 5 71 DXpedition Mode
0.2 PA3XYZ/P R 590003 IO91NP 28 1 1 3 12 25 70 EU VHF contest
0.3 WA9XYZ KA1ABC R 16A EMA 28 28 1 4 3 7 71 ARRL Field Day
0.4 WA9XYZ KA1ABC R 32A EMA 28 28 1 4 3 7 71 ARRL Field Day
0.5 123456789ABCDEF012 71 71 Telemetry (18 hex)
-0.6 ... tbd
+0.6 K1ABC RR73; CQ W9XYZ EN37 28 28 15 71 Contesting
0.7 ... tbd
1 WA9XYZ/R KA1ABC/R R FN42 28 1 28 1 1 15 74 Standard msg
diff --git a/lib/Makefile.mskWin b/lib/Makefile.mskWin
deleted file mode 100644
index 9d5e6e62b..000000000
--- a/lib/Makefile.mskWin
+++ /dev/null
@@ -1,75 +0,0 @@
-
-# Set paths
-EXE_DIR = ..\\..\\wsjtx_install
-QT_DIR = C:/wsjt-env/Qt5/5.2.1/mingw48_32
-FFTW3_DIR = ..
-
-INCPATH = -I${QT_DIR}/include/QtCore -I${QT_DIR}/include
-
-# Compilers
-CC = gcc
-CXX = g++
-FC = gfortran
-AR = ar cr
-RANLIB = ranlib
-MKDIR = mkdir -p
-CP = cp
-RM = rm -f
-
-FFLAGS = -O2 -fbounds-check -Wall -Wno-conversion
-CFLAGS = -O2 -I.
-
-# Default rules
-%.o: %.c
- ${CC} ${CFLAGS} -c $<
-%.o: %.f
- ${FC} ${FFLAGS} -c $<
-%.o: %.F
- ${FC} ${FFLAGS} -c $<
-%.o: %.f90
- ${FC} ${FFLAGS} -c $<
-%.o: %.F90
- ${FC} ${FFLAGS} -c $<
-
-#all: jt9code JTMSKcode.exe
-all: jtmsk.exe JTMSKsim.exe JTMSKcode.exe fixwav.exe
-
-OBJS3 = JTMSKsim.o wavhdr.o gran.o four2a.o db.o
-JTMSKsim.exe: $(OBJS3)
- $(FC) -o JTMSKsim.exe $(OBJS3) C:\JTSDK\fftw3f\libfftw3f-3.dll
-
-OBJS4 = jt9code.o packjt.o fmtmsg.o gen9.o deg2grid.o grid2deg.o \
- entail.o encode232.o interleave9.o graycode.o igray.o
-jt9code: $(OBJS4)
- $(FC) -o jt9code $(OBJS4)
-
-OBJS5 = JTMSKcode.o packjt.o fmtmsg.o genmsk.o deg2grid.o grid2deg.o \
- entail.o tab.o vit213.o hashing.o nhash.o
-JTMSKcode.exe: $(OBJS5)
- $(FC) -o JTMSKcode.exe $(OBJS5)
-
-OBJS6 = jtmsk.o analytic.o four2a.o db.o pctile.o \
- shell.o tweak1.o syncmsk.o genmsk.o packjt.o fmtmsg.o indexx.o \
- deg2grid.o grid2deg.o entail.o hashing.o nhash.o tab.o vit213.o \
- mskdt.o rectify_msk.o timer.o jtmsk_decode.o genmsk_short.o \
- jtmsk_short.o golay24_table.o hash.o
-
-jtmsk.exe: $(OBJS6)
- $(FC) -o jtmsk.exe $(OBJS6) C:\JTSDK\fftw3f\libfftw3f-3.dll
-
-OBJS1 = fixwav.o wavhdr.o
-fixwav.exe: $(OBJS1)
- $(FC) -o fixwav.exe $(OBJS1)
-
-OBJS2 = t2.o four2a.o db.o
-t2: $(OBJS2)
- $(FC) -o t2 $(OBJS2) C:\JTSDK\fftw3f\libfftw3f-3.dll
-
-OBJS6 = t6.o four2a.o db.o
-t6: $(OBJS6)
- $(FC) -o t6 $(OBJS6) C:\JTSDK\fftw3f\libfftw3f-3.dll
-
-.PHONY : clean
-
-clean:
- $(RM) *.o JTMSKcode JTMSKcode.exe
diff --git a/lib/encode_msk144.f90 b/lib/encode_msk144.f90
deleted file mode 100644
index 4e4d8968e..000000000
--- a/lib/encode_msk144.f90
+++ /dev/null
@@ -1,111 +0,0 @@
-subroutine encode_msk144(message,codeword)
-! Encode an 80-bit message and return a 128-bit codeword.
-! The generator matrix has dimensions (48,80).
-! The code is a (128,80) regular ldpc code with column weight 3.
-! The code was generated using the PEG algorithm.
-! After creating the codeword, the columns are re-ordered according to
-! "colorder" to make the codeword compatible with the parity-check
-! matrix stored in Radford Neal's "pchk" format.
-!
-character*20 g(48)
-integer*1 codeword(128)
-integer*1 colorder(128)
-integer*1 gen144(48,80)
-integer*1 itmp(128)
-integer*1 message(80)
-integer*1 pchecks(48)
-logical first
-data first/.true./
-data g/ & !parity-check generator matrix for (128,80) code
- "24084000800020008000", &
- "b39678f7ccdb1baf5f4c", &
- "10001000400408012000", &
- "08104000100002010800", &
- "dc9c18f61ea0e4b7f05c", &
- "42c040160909ca002c00", &
- "cc50b52b9a80db0d7f9e", &
- "dde5ace80780bae74740", &
- "00800080020000890080", &
- "01020040010400400040", &
- "20008010020000100030", &
- "80400008004000040050", &
- "a4b397810915126f5604", &
- "04040100001040200008", &
- "00800006000888000800", &
- "00010c00000104040001", &
- "cc7cd7d953cdc204eba0", &
- "0094abe7dd146beb16ce", &
- "5af2aec8c7b051c7544a", &
- "14040508801840200088", &
- "7392f5e720f8f5a62c1e", &
- "503cc2a06bff4e684ec9", &
- "5a2efd46f1efbb513b80", &
- "ac06e9513fd411f1de03", &
- "16a31be3dd3082ca2bd6", &
- "28542e0daf62fe1d9332", &
- "00210c002001540c0401", &
- "0ed90d56f84298706a98", &
- "939670f7ecdf9baf4f4c", &
- "cfe41dec47a433e66240", &
- "16d2179c2d5888222630", &
- "408000160108ca002800", &
- "808000830a00018900a0", &
- "9ae2ed8ef3afbf8c3a52", &
- "5aaafd86f3efbfc83b02", &
- "f39658f68cdb0baf1f4c", &
- "9414bb6495106261366a", &
- "71ba18670c08411bf682", &
- "7298f1a7217cf5c62e5e", &
- "86d7a4864396a981369b", &
- "a8042c01ae22fe191362", &
- "9235ae108b2d60d0e306", &
- "dfe5ade807a03be74640", &
- "d2451588e6e27ccd9bc4", &
- "12b51ae39d20e2ea3bde", &
- "a49387810d95136fd604", &
- "467e7578e51d5b3b8a0e", &
- "f6ad1ac7cc3aaa3fe580"/
-
-data colorder/0,1,2,3,4,5,6,7,8,9, &
- 10,11,12,13,14,15,24,26,29,30, &
- 32,43,44,47,60,77,79,97,101,111, &
- 96,38,64,53,93,34,59,94,74,90, &
- 108,123,85,57,70,25,69,62,48,49, &
- 50,51,52,33,54,55,56,21,58,36, &
- 16,61,23,63,20,65,66,67,68,46, &
- 22,71,72,73,31,75,76,45,78,17, &
- 80,81,82,83,84,42,86,87,88,89, &
- 39,91,92,35,37,95,19,27,98,99, &
- 100,28,102,103,104,105,106,107,40,109, &
- 110,18,112,113,114,115,116,117,118,119, &
- 120,121,122,41,124,125,126,127/
-
-save first,gen144
-
-if( first ) then ! fill the generator matrix
- gen144=0
- do i=1,48
- do j=1,5
- read(g(i)( (j-1)*4+1:(j-1)*4+4 ),"(Z4)") istr
- do jj=1,16
- icol=(j-1)*16+jj
- if( btest(istr,16-jj) ) gen144(i,icol)=1
- enddo
- enddo
- enddo
-first=.false.
-endif
-
-do i=1,48
- nsum=0
- do j=1,80
- nsum=nsum+message(j)*gen144(i,j)
- enddo
- pchecks(i)=mod(nsum,2)
-enddo
-itmp(1:48)=pchecks
-itmp(49:128)=message(1:80)
-codeword(colorder+1)=itmp(1:128)
-
-return
-end subroutine encode_msk144
diff --git a/lib/extractmessage144.f90 b/lib/extractmessage144.f90
deleted file mode 100644
index a5dadb0b4..000000000
--- a/lib/extractmessage144.f90
+++ /dev/null
@@ -1,51 +0,0 @@
-subroutine extractmessage144(decoded,msgreceived,nhashflag,recent_calls,nrecent)
- use iso_c_binding, only: c_loc,c_size_t
- use packjt
- use hashing
-
- character*22 msgreceived
- character*12 call1,call2
- character*12 recent_calls(nrecent)
- integer*1 decoded(80)
- integer*1, target:: i1Dec8BitBytes(10)
- integer*1 i1hashdec
- integer*4 i4Dec6BitWords(12)
-
-! Collapse 80 decoded bits to 10 bytes. Bytes 1-9 are the message, byte 10 is the hash
- do ibyte=1,10
- itmp=0
- do ibit=1,8
- itmp=ishft(itmp,1)+iand(1,decoded((ibyte-1)*8+ibit))
- enddo
- i1Dec8BitBytes(ibyte)=itmp
- enddo
-
-! Calculate the hash using the first 9 bytes.
- ihashdec=nhash(c_loc(i1Dec8BitBytes),int(9,c_size_t),146)
- ihashdec=2*iand(ihashdec,255)
-
-! Compare calculated hash with received byte 10 - if they agree, keep the message.
- i1hashdec=ihashdec
- if( i1hashdec .eq. i1Dec8BitBytes(10) ) then
-! Good hash --- unpack 72-bit message
- do ibyte=1,12
- itmp=0
- do ibit=1,6
- itmp=ishft(itmp,1)+iand(1,decoded((ibyte-1)*6+ibit))
- enddo
- i4Dec6BitWords(ibyte)=itmp
- enddo
- call unpackmsg144(i4Dec6BitWords,msgreceived,call1,call2)
- nhashflag=1
- if( call1(1:2) .ne. 'CQ' .and. call1(1:2) .ne. ' ' ) then
- call update_recent_calls(call1,recent_calls,nrecent)
- endif
- if( call2(1:2) .ne. ' ' ) then
- call update_recent_calls(call2,recent_calls,nrecent)
- endif
- else
- msgreceived=' '
- nhashflag=-1
- endif
- return
- end subroutine extractmessage144
diff --git a/lib/genmsk144.f90 b/lib/genmsk144.f90
deleted file mode 100644
index f02344439..000000000
--- a/lib/genmsk144.f90
+++ /dev/null
@@ -1,146 +0,0 @@
-subroutine genmsk144(msg0,mygrid,ichk,msgsent,i4tone,itype)
-! s8 + 48bits + s8 + 80 bits = 144 bits (72ms message duration)
-!
-! Encode an MSK144 message
-! Input:
-! - msg0 requested message to be transmitted
-! - ichk if ichk=1, return only msgsent
-! if ichk.ge.10000, set imsg=ichk-10000 for short msg
-! - msgsent message as it will be decoded
-! - i4tone array of audio tone values, 0 or 1
-! - itype message type
-! 1 = standard message "Call_1 Call_2 Grid/Rpt"
-! 2 = type 1 prefix
-! 3 = type 1 suffix
-! 4 = type 2 prefix
-! 5 = type 2 suffix
-! 6 = free text (up to 13 characters)
-! 7 = short message " Rpt"
-
- use iso_c_binding, only: c_loc,c_size_t
- use packjt
- use hashing
- character*22 msg0
- character*22 message !Message to be generated
- character*22 msgsent !Message as it will be received
- character*6 mygrid
- integer*4 i4Msg6BitWords(13) !72-bit message as 6-bit words
- integer*4 i4tone(144) !
- integer*1, target:: i1Msg8BitBytes(10) !80 bits represented in 10 bytes
- integer*1 codeword(128) !Encoded bits before re-ordering
- integer*1 msgbits(80) !72-bit message + 8-bit hash
- integer*1 bitseq(144) !Tone #s, data and sync (values 0-1)
- integer*1 i1hash(4)
- integer*1 s8(8)
- real*8 pp(12)
- real*8 xi(864),xq(864),pi,twopi
- data s8/0,1,1,1,0,0,1,0/
- equivalence (ihash,i1hash)
- logical first
- data first/.true./
- save
-
- if(first) then
- first=.false.
- nsym=128
- pi=4.0*atan(1.0)
- twopi=8.*atan(1.0)
- do i=1,12
- pp(i)=sin((i-1)*pi/12)
- enddo
- endif
-
- if(msg0(1:1).eq.'@') then !Generate a fixed tone
- read(msg0(2:5),*,end=1,err=1) nfreq !at specified frequency
- go to 2
-1 nfreq=1000
-2 i4tone(1)=nfreq
- else
- message=msg0
- do i=1,22
- if(ichar(message(i:i)).eq.0) then
- message(i:)=' '
- exit
- endif
- enddo
-
- do i=1,22 !Strip leading blanks
- if(message(1:1).ne.' ') exit
- message=message(i+1:)
- enddo
-
- if(message(1:1).eq.'<') then
- call genmsk40(message,msgsent,ichk,i4tone,itype)
- if(itype.lt.0) go to 999
- i4tone(41)=-40
- go to 999
- endif
-
- call packmsg(message,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes
- call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent
-
- if(ichk.eq.1) go to 999
- i4=0
- ik=0
- im=0
- do i=1,12
- nn=i4Msg6BitWords(i)
- do j=1, 6
- ik=ik+1
- i4=i4+i4+iand(1,ishft(nn,j-6))
- i4=iand(i4,255)
- if(ik.eq.8) then
- im=im+1
- i1Msg8BitBytes(im)=i4
- ik=0
- endif
- enddo
- enddo
-
- ihash=nhash(c_loc(i1Msg8BitBytes),int(9,c_size_t),146)
- ihash=2*iand(ihash,32767) !Generate the 8-bit hash
- i1Msg8BitBytes(10)=i1hash(1) !Hash code to byte 10
-
- mbit=0
- do i=1, 10
- i1=i1Msg8BitBytes(i)
- do ibit=1,8
- mbit=mbit+1
- msgbits(mbit)=iand(1,ishft(i1,ibit-8))
- enddo
- enddo
-
- call encode_msk144(msgbits,codeword)
-
-!Create 144-bit channel vector:
-!8-bit sync word + 48 bits + 8-bit sync word + 80 bits
- bitseq=0
- bitseq(1:8)=s8
- bitseq(9:56)=codeword(1:48)
- bitseq(57:64)=s8
- bitseq(65:144)=codeword(49:128)
- bitseq=2*bitseq-1
-
- xq(1:6)=bitseq(1)*pp(7:12) !first bit is mapped to 1st half-symbol on q
- do i=1,71
- is=(i-1)*12+7
- xq(is:is+11)=bitseq(2*i+1)*pp
- enddo
- xq(864-5:864)=bitseq(1)*pp(1:6) !last half symbol
- do i=1,72
- is=(i-1)*12+1
- xi(is:is+11)=bitseq(2*i)*pp
- enddo
-! Map I and Q to tones.
- i4tone=0
- do i=1,72
- i4tone(2*i-1)=(bitseq(2*i)*bitseq(2*i-1)+1)/2;
- i4tone(2*i)=-(bitseq(2*i)*bitseq(mod(2*i,144)+1)-1)/2;
- enddo
- endif
-
-! Flip polarity
- i4tone=-i4tone+1
-
-999 return
-end subroutine genmsk144
diff --git a/lib/genmsk_short.f90 b/lib/genmsk_short.f90
deleted file mode 100644
index f1b555f34..000000000
--- a/lib/genmsk_short.f90
+++ /dev/null
@@ -1,66 +0,0 @@
-subroutine genmsk_short(msg,msgsent,ichk,itone,itype)
-
- use hashing
- character*22 msg,msgsent
- character*3 crpt,rpt(0:7)
- logical first
- integer itone(35)
- integer ig24(0:4096-1) !Codewords for Golay (24,12) code
- integer b11(11)
- data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 code
- data rpt /'26 ','27 ','28 ','R26','R27','R28','RRR','73 '/
- data first/.true./
- save first,ig24
-
- if(first) then
- call golay24_table(ig24) !Define the Golay(24,12) codewords
- first=.false.
- endif
-
- itype=-1
- msgsent='*** bad message ***'
- itone=0
- i1=index(msg,'>')
- if(i1.lt.9) go to 900
- call fmtmsg(msg,iz)
- crpt=msg(i1+2:i1+5)
- do i=0,7
- if(crpt.eq.rpt(i)) go to 10
- enddo
- go to 900
-
-10 irpt=i !Report index, 0-7
- if(ichk.lt.10000) then
- call hash(msg(2:i1-1),i1-2,ihash)
- ihash=iand(ihash,511) !9-bit hash for the two callsigns
- ig=8*ihash + irpt !12-bit message information
- else
- ig=ichk-10000
- endif
- ncodeword=ig24(ig)
- itone(1:11)=b11 !Insert the Barker-11 code
- n=2**24
- do i=12,35 !Insert codeword into itone array
- n=n/2
- itone(i)=0
- if(iand(ncodeword,n).ne.0) itone(i)=1
- enddo
- msgsent=msg
- itype=7
-
- n=count(itone(1:35).eq.0)
- if(mod(n,2).ne.0) stop 'Parity error in genmsk_short.'
-
-900 return
-end subroutine genmsk_short
-
-subroutine hash_calls(calls,ih9)
-
- use hashing
- character*(*) calls
- i1=index(calls,'>')
- call hash(calls(2:i1-1),i1-2,ih9)
- ih9=iand(ih9,511) !9-bit hash for the two callsigns
-
- return
-end subroutine hash_calls
diff --git a/lib/ldpcsim144.f90 b/lib/ldpcsim144.f90
deleted file mode 100644
index 3121ada2c..000000000
--- a/lib/ldpcsim144.f90
+++ /dev/null
@@ -1,175 +0,0 @@
-program ldpcsim
-
-use, intrinsic :: iso_c_binding
-use iso_c_binding, only: c_loc,c_size_t
-use hashing
-use packjt
-parameter(NRECENT=10)
-character*12 recent_calls(NRECENT)
-character*22 msg,msgsent,msgreceived
-character*8 arg
-integer*1, allocatable :: codeword(:), decoded(:), message(:)
-integer*1, target:: i1Msg8BitBytes(10)
-integer*1 i1hash(4)
-integer*1 msgbits(80)
-integer*4 i4Msg6BitWords(13)
-integer ihash
-integer nerrtot(0:128),nerrdec(0:128)
-real*8, allocatable :: lratio(:), rxdata(:), rxavgd(:)
-real, allocatable :: yy(:), llr(:)
-equivalence(ihash,i1hash)
-
-do i=1,NRECENT
- recent_calls(i)=' '
-enddo
-nerrtot=0
-nerrdec=0
-
-nargs=iargc()
-if(nargs.ne.4) then
- print*,'Usage: ldpcsim niter navg #trials s '
- print*,'eg: ldpcsim 10 1 1000 0.75'
- return
-endif
-call getarg(1,arg)
-read(arg,*) max_iterations
-call getarg(2,arg)
-read(arg,*) navg
-call getarg(3,arg)
-read(arg,*) ntrials
-call getarg(4,arg)
-read(arg,*) s
-
-! don't count hash bits as data bits
-K=72
-N=128
-rate=real(K)/real(N)
-
-write(*,*) "rate: ",rate
-
-write(*,*) "niter= ",max_iterations," navg= ",navg," s= ",s
-
-allocate ( codeword(N), decoded(K), message(K) )
-allocate ( lratio(N), rxdata(N), rxavgd(N), yy(N), llr(N) )
-
-msg="K9AN K1JT EN50"
- call packmsg(msg,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes
- call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent
- write(*,*) "message sent ",msgsent
-
- i4=0
- ik=0
- im=0
- do i=1,12
- nn=i4Msg6BitWords(i)
- do j=1, 6
- ik=ik+1
- i4=i4+i4+iand(1,ishft(nn,j-6))
- i4=iand(i4,255)
- if(ik.eq.8) then
- im=im+1
-! if(i4.gt.127) i4=i4-256
- i1Msg8BitBytes(im)=i4
- ik=0
- endif
- enddo
- enddo
-
- ihash=nhash(c_loc(i1Msg8BitBytes),int(9,c_size_t),146)
- ihash=2*iand(ihash,32767) !Generate the 8-bit hash
- i1Msg8BitBytes(10)=i1hash(1) !Hash code to byte 10
- mbit=0
- do i=1, 10
- i1=i1Msg8BitBytes(i)
- do ibit=1,8
- mbit=mbit+1
- msgbits(mbit)=iand(1,ishft(i1,ibit-8))
- enddo
- enddo
- call encode_msk144(msgbits,codeword)
- call init_random_seed()
-
-write(*,*) "Eb/N0 SNR2500 ngood nundetected nbadhash sigma"
-do idb = 14,-6,-1
- db=idb/2.0-1.0
- sigma=1/sqrt( 2*rate*(10**(db/10.0)) )
- ngood=0
- nue=0
- nbadhash=0
-
- do itrial=1, ntrials
- rxavgd=0d0
- do iav=1,navg
- call sgran()
-! Create a realization of a noisy received word
- do i=1,N
- rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran()
- enddo
- rxavgd=rxavgd+rxdata
- enddo
- rxdata=rxavgd
- nerr=0
- do i=1,N
- if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1
- enddo
- nerrtot(nerr)=nerrtot(nerr)+1
-
-! Correct signal normalization is important for this decoder.
- rxav=sum(rxdata)/N
- rx2av=sum(rxdata*rxdata)/N
- rxsig=sqrt(rx2av-rxav*rxav)
- rxdata=rxdata/rxsig
-! To match the metric to the channel, s should be set to the noise standard deviation.
-! For now, set s to the value that optimizes decode probability near threshold.
-! The s parameter can be tuned to trade a few tenth's dB of threshold for an order of
-! magnitude in UER
- if( s .lt. 0 ) then
- ss=sigma
- else
- ss=s
- endif
-
- llr=2.0*rxdata/(ss*ss)
- lratio=exp(llr)
- yy=rxdata
-
-! max_iterations is max number of belief propagation iterations
-! call ldpc_decode(lratio, decoded, max_iterations, niterations, max_dither, ndither)
-! call amsdecode(yy, max_iterations, decoded, niterations)
-! call bitflipmsk144(rxdata, decoded, niterations)
- call bpdecode144(llr, max_iterations, decoded, niterations)
-
-! If the decoder finds a valid codeword, niterations will be .ge. 0.
- if( niterations .ge. 0 ) then
- call extractmessage144(decoded,msgreceived,nhashflag,recent_calls,nrecent)
- if( nhashflag .ne. 1 ) then
- nbadhash=nbadhash+1
- endif
- nueflag=0
-
-! Check the message plus hash against what was sent.
- do i=1,K
- if( msgbits(i) .ne. decoded(i) ) then
- nueflag=1
- endif
- enddo
- if( nhashflag .eq. 1 .and. nueflag .eq. 0 ) then
- ngood=ngood+1
- nerrdec(nerr)=nerrdec(nerr)+1
- else if( nhashflag .eq. 1 .and. nueflag .eq. 1 ) then
- nue=nue+1;
- endif
- endif
- enddo
- snr2500=db-3.5
- write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2)") db,snr2500,ngood,nue,nbadhash,ss
-
-enddo
-
-open(unit=23,file='nerrhisto.dat',status='unknown')
-do i=0,128
- write(23,'(i4,2x,i10,i10,f10.2)') i,nerrdec(i),nerrtot(i),real(nerrdec(i))/real(nerrtot(i)+1e-10)
-enddo
-close(23)
-
-end program ldpcsim
diff --git a/lib/msk144d.f90 b/lib/msk144d.f90
deleted file mode 100644
index 60c8b0c1d..000000000
--- a/lib/msk144d.f90
+++ /dev/null
@@ -1,136 +0,0 @@
-program msk144d
-
- ! Test the msk144 decoder for WSJT-X
-
- use options
- use timer_module, only: timer
- use timer_impl, only: init_timer
- use readwav
-
- character c
- character*80 line
- character*512 datadir
- character*500 infile
- character*12 mycall,hiscall
- character*6 mygrid
- character(len=500) optarg
-
- logical :: display_help=.false.
- logical*1 bShMsgs
- logical*1 btrain
- logical*1 bswl
-
- type(wav_header) :: wav
-
- integer*2 id2(30*12000)
- integer*2 ichunk(7*1024)
-
- real*8 pcoeffs(5)
-
- type (option) :: long_options(9) = [ &
- option ('ndepth',.true.,'c','ndepth',''), &
- option ('dxcall',.true.,'d','hiscall',''), &
- option ('evemode',.true.,'e','Must be used with -s.',''), &
- option ('frequency',.true.,'f','rxfreq',''), &
- option ('help',.false.,'h','Display this help message',''), &
- option ('mycall',.true.,'m','mycall',''), &
- option ('nftol',.true.,'n','nftol',''), &
- option ('rxequalize',.false.,'r','Rx Equalize',''), &
- option ('short',.false.,'s','enable Sh','') &
- ]
- t0=0.0
- ndepth=3
- ntol=100
- nrxfreq=1500
- mycall=''
- mygrid='EN50WC'
- hiscall=''
- bShMsgs=.false.
- btrain=.false.
- bswl=.false.
- datadir='.'
- pcoeffs=0.d0
-
- do
- call getopt('c:d:ef:hm:n:rs',long_options,c,optarg,narglen,nstat,noffset,nremain,.true.)
- if( nstat .ne. 0 ) then
- exit
- end if
- select case (c)
- case ('c')
- read (optarg(:narglen), *) ndepth
- case ('d')
- read (optarg(:narglen), *) hiscall
- case ('e')
- bswl=.true.
- case ('f')
- read (optarg(:narglen), *) nrxfreq
- case ('h')
- display_help = .true.
- case ('m')
- read (optarg(:narglen), *) mycall
- case ('n')
- read (optarg(:narglen), *) ntol
- case ('r')
- btrain=.true.
- case ('s')
- bShMsgs=.true.
- end select
- end do
-
- if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then
- print *, ''
- print *, 'Usage: msk144d [OPTIONS] file1 [file2 ...]'
- print *, ''
- print *, ' msk144 decode pre-recorded .WAV file(s)'
- print *, ''
- print *, 'OPTIONS:'
- do i = 1, size (long_options)
- call long_options(i) % print (6)
- end do
- go to 999
- endif
-
- call init_timer ('timer.out')
- call timer('msk144 ',0)
- ndecoded=0
- do ifile=noffset+1,noffset+nremain
- call get_command_argument(ifile,optarg,narglen)
- infile=optarg(:narglen)
- call timer('read ',0)
- call wav%read (infile)
- i1=index(infile,'.wav')
- if( i1 .eq. 0 ) i1=index(infile,'.WAV')
- read(infile(i1-6:i1-1),*,err=998) nutc
- inquire(FILE=infile,SIZE=isize)
- npts=min((isize-216)/2,360000)
- read(unit=wav%lun) id2(1:npts)
- close(unit=wav%lun)
- call timer('read ',1)
-
- do i=1,npts-7*1024+1,7*512
- ichunk=id2(i:i+7*1024-1)
- tsec=(i-1)/12000.0
- tt=sum(float(abs(id2(i:i+7*512-1))))
- if( tt .ne. 0.0 ) then
- call mskrtd(ichunk,nutc,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall,bShMsgs, &
- btrain,pcoeffs,bswl,datadir,line)
- if( index(line,"&") .ne. 0 .or. &
- index(line,"^") .ne. 0 .or. &
- index(line,"!") .ne. 0 .or. &
- index(line,"@") .ne. 0 ) then
- write(*,*) line
- endif
- endif
- enddo
- enddo
-
- call timer('msk144 ',1)
- call timer('msk144 ',101)
- go to 999
-
-998 print*,'Cannot read from file:'
- print*,infile
-
-999 continue
-end program msk144d
diff --git a/lib/msk144sd.f90 b/lib/msk144sd.f90
deleted file mode 100644
index 267fff545..000000000
--- a/lib/msk144sd.f90
+++ /dev/null
@@ -1,197 +0,0 @@
-program msk144sd
-!
-! A simple decoder for slow msk144.
-! Can be used as a (slow) brute-force multi-decoder by looping
-! over a set of carrier frequencies.
-!
- use options
- use timer_module, only: timer
- use timer_impl, only: init_timer
- use readwav
-
- parameter (NRECENT=10)
- parameter (NSPM=864)
- parameter (NPATTERNS=4)
-
- character ch
- character*80 line
- character*500 infile
- character*12 mycall,hiscall
- character*6 mygrid
- character(len=500) optarg
- character*22 msgreceived
- character*12 recent_calls(NRECENT)
-
- complex cdat(30*375)
- complex c(NSPM)
- complex ct(NSPM)
-
- real softbits(144)
- real xmc(NPATTERNS)
-
- logical :: display_help=.false.
-
- type(wav_header) :: wav
-
- integer iavmask(8)
- integer iavpatterns(8,NPATTERNS)
- integer npkloc(10)
-
- integer*2 id2(30*12000)
- integer*2 ichunk(7*1024)
-
- data iavpatterns/ &
- 1,1,1,1,0,0,0,0, &
- 0,1,1,1,1,0,0,0, &
- 0,0,1,1,1,1,0,0, &
- 1,1,1,1,1,1,0,0/
- data xmc/2.0,4.5,2.5,3.0/
-
- type (option) :: long_options(2) = [ &
- option ('frequency',.true.,'f','rxfreq',''), &
- option ('help',.false.,'h','Display this help message','') &
- ]
- t0=0.0
- ntol=100
- nrxfreq=1500
-
- do
- call getopt('f:h',long_options,ch,optarg,narglen,nstat,noffset,nremain,.true.)
- if( nstat .ne. 0 ) then
- exit
- end if
- select case (ch)
- case ('f')
- read (optarg(:narglen), *) nrxfreq
- case ('h')
- display_help = .true.
- end select
- end do
-
- if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then
- print *, ''
- print *, 'Usage: msk144sd [OPTIONS] file1 [file2 ...]'
- print *, ''
- print *, ' decode pre-recorded .WAV file(s)'
- print *, ''
- print *, 'OPTIONS:'
- do i = 1, size (long_options)
- call long_options(i) % print (6)
- end do
- go to 999
- endif
-
- call init_timer ('timer.out')
- call timer('msk144 ',0)
- ndecoded=0
- do ifile=noffset+1,noffset+nremain
- call get_command_argument(ifile,optarg,narglen)
- infile=optarg(:narglen)
- call timer('read ',0)
- call wav%read (infile)
- i1=index(infile,'.wav')
- if( i1 .eq. 0 ) i1=index(infile,'.WAV')
- read(infile(i1-6:i1-1),*,err=998) nutc
- inquire(FILE=infile,SIZE=isize)
- npts=min((isize-216)/2,360000)
- read(unit=wav%lun) id2(1:npts)
- close(unit=wav%lun)
- call timer('read ',1)
-
-! do if=1,89 ! brute force multi-decoder
- fo=nrxfreq
-! fo=(if-1)*25.0+300.0
- call msksddc(id2,npts,fo,cdat)
- np=npts/32
- ntol=200 ! actual ntol is ntol/32=6.25 Hz. Detection window is 12.5 Hz wide
- fc=1500.0
- call msk144spd(cdat,np,ntol,ndecodesuccess,msgreceived,fc,fest,tdec,navg,ct, &
- softbits,recent_calls,nrecent)
- nsnr=0 ! need an snr estimate
- if( ndecodesuccess .eq. 1 ) then
- fest=fo+fest-fc ! fudging because spd thinks input signal is at 1500 Hz
- goto 900
- endif
-! If short ping decoder doesn't find a decode
- npat=NPATTERNS
- do iavg=1,npat
- iavmask=iavpatterns(1:8,iavg)
- navg=sum(iavmask)
- deltaf=4.0/real(navg) ! search increment for frequency sync
- npeaks=4
- ntol=200
- fc=1500.0
- call msk144sync(cdat(1:6*NSPM),6,ntol,deltaf,iavmask,npeaks,fc, &
- fest,npkloc,nsyncsuccess,xmax,c)
- if( nsyncsuccess .eq. 0 ) cycle
-
- do ipk=1,npeaks
- do is=1,3
- ic0=npkloc(ipk)
- if(is.eq.2) ic0=max(1,ic0-1)
- if(is.eq.3) ic0=min(NSPM,ic0+1)
- ct=cshift(c,ic0-1)
- call msk144decodeframe(ct,softbits,msgreceived,ndecodesuccess, &
- recent_calls,nrecent)
- if(ndecodesuccess .gt. 0) then
- tdec=tsec+xmc(iavg)*tframe
- fest=fo+(fest-fc)/32.0
- goto 900
- endif
- enddo !Slicer dither
- enddo !Peak loop
- enddo
-
-! enddo
-900 continue
- if( ndecodesuccess .gt. 0 ) then
- write(*,1020) nutc,nsnr,tdec,nint(fest),' % ',msgreceived,navg
-1020 format(i6.6,i4,f5.1,i5,a3,a22,i4)
- endif
- enddo
-
- call timer('msk144 ',1)
- call timer('msk144 ',101)
- go to 999
-
-998 print*,'Cannot read from file:'
- print*,infile
-
-999 continue
-end program msk144sd
-
-subroutine msksddc(id2,npts,fc,cdat)
-
-! The msk144 detector/demodulator/decoder will decode signals
-! with carrier frequency, fc, in the range fN/4 +/- 0.03333*fN.
-!
-! For slow MSK144 with nslow=32:
-! fs=12000/32=375 Hz, fN=187.5 Hz
-!
-! This routine accepts input samples with fs=12000 Hz. It
-! downconverts and decimates by 32 to center a signal with input carrier
-! frequency fc at new carrier frequency 1500/32=46.875 Hz.
-! The analytic signal is returned.
-
- parameter (NFFT1=30*12000,NFFT2=30*375)
- integer*2 id2(npts)
- complex cx(0:NFFT1)
- complex cdat(30*375)
-
- dt=1.0/12000.0
- df=1.0/(NFFT1*dt)
- icenter=int(fc/df+0.5)
- i46p875=int(46.875/df+0.5)
- ishift=icenter-i46p875
- cx=cmplx(0.0,0.0)
- cx(1:npts)=id2
- call four2a(cx,NFFT1,1,-1,1)
- cx=cshift(cx,ishift)
- cx(1)=0.5*cx(1)
- cx(2*i46p875+1:)=cmplx(0.0,0.0)
- call four2a(cx,NFFT2,1,1,1)
- cdat(1:npts/32)=cx(0:npts/32-1)/NFFT1
- return
-
-end subroutine msksddc
-
diff --git a/lib/msk144sim.f90 b/lib/msk144sim.f90
index 75c6a1e64..7b2a8a00b 100644
--- a/lib/msk144sim.f90
+++ b/lib/msk144sim.f90
@@ -13,10 +13,10 @@ program msk144sim
integer itone(144) !Message bits
nargs=iargc()
- if(nargs.ne.6) then
- print*,'Usage: msk144sim message freq width nslow snr nfiles'
- print*,'Example: msk144sim "K1ABC W9XYZ EN37" 1500 0.12 1 2 1'
- print*,' msk144sim "K1ABC W9XYZ EN37" 1500 2.5 32 15 1'
+ if(nargs.ne.5) then
+ print*,'Usage: msk144sim message freq width snr nfiles'
+ print*,'Example: msk144sim "K1ABC W9XYZ EN37" 1500 0.12 2 1'
+ print*,' msk144sim "K1ABC W9XYZ EN37" 1500 2.5 15 1'
go to 999
endif
call getarg(1,msg)
@@ -25,10 +25,8 @@ program msk144sim
call getarg(3,arg)
read(arg,*) width
call getarg(4,arg)
- read(arg,*) nslow
- call getarg(5,arg)
read(arg,*) snrdb
- call getarg(6,arg)
+ call getarg(5,arg)
read(arg,*) nfiles
!sig is the peak amplitude of the ping.
@@ -50,9 +48,9 @@ program msk144sim
twopi=8.d0*atan(1.d0)
nsym=144
- nsps=6*nslow
+ nsps=6
if( itone(41) .lt. 0 ) nsym=40
- baud=2000.d0/nslow
+ baud=2000.d0
dphi0=twopi*(freq-0.25d0*baud)/12000.d0
dphi1=twopi*(freq+0.25d0*baud)/12000.d0
phi=0.0
@@ -79,7 +77,7 @@ program msk144sim
go to 999
endif
- if(nslow.eq.1) call makepings(pings,NMAX,width,sig)
+ call makepings(pings,NMAX,width,sig)
! call sgran()
do ifile=1,nfiles !Loop over requested number of files
@@ -92,8 +90,7 @@ program msk144sim
fac=sqrt(6000.0/2500.0)
do i=0,NMAX-1
xx=gran()
- if(nslow.eq.1) wave(i)=pings(i)*waveform(i) + fac*xx
- if(nslow.gt.1) wave(i)=sig*waveform(i) + fac*xx
+ wave(i)=pings(i)*waveform(i) + fac*xx
iwave(i)=30.0*wave(i)
enddo
diff --git a/lib/platanh.f90 b/lib/platanh.f90
new file mode 100644
index 000000000..e610366d7
--- /dev/null
+++ b/lib/platanh.f90
@@ -0,0 +1,24 @@
+subroutine platanh(x,y)
+ isign=+1
+ z=x
+ if( x.lt.0 ) then
+ isign=-1
+ z=abs(x)
+ endif
+ if( z.le. 0.664 ) then
+ y=x/0.83
+ return
+ elseif( z.le. 0.9217 ) then
+ y=isign*(z-0.4064)/0.322
+ return
+ elseif( z.le. 0.9951 ) then
+ y=isign*(z-0.8378)/0.0524
+ return
+ elseif( z.le. 0.9998 ) then
+ y=isign*(z-0.9914)/0.0012
+ return
+ else
+ y=isign*7.0
+ return
+ endif
+end subroutine platanh
diff --git a/lib/pltanh.f90 b/lib/pltanh.f90
new file mode 100644
index 000000000..4c6c2b6d6
--- /dev/null
+++ b/lib/pltanh.f90
@@ -0,0 +1,24 @@
+subroutine pltanh(x,y)
+ isign=+1
+ z=x
+ if( x.lt.0 ) then
+ isign=-1
+ z=abs(x)
+ endif
+ if( z.le. 0.8 ) then
+ y=0.83*x
+ return
+ elseif( z.le. 1.6 ) then
+ y=isign*(0.322*z+0.4064)
+ return
+ elseif( z.le. 3.0 ) then
+ y=isign*(0.0524*z+0.8378)
+ return
+ elseif( z.lt. 7.0 ) then
+ y=isign*(0.0012*z+0.9914)
+ return
+ else
+ y=isign*0.9998
+ return
+ endif
+end subroutine pltanh
diff --git a/lib/sync65.f90 b/lib/sync65.f90
index e0bc924a0..4a681a0a7 100644
--- a/lib/sync65.f90
+++ b/lib/sync65.f90
@@ -57,8 +57,9 @@ subroutine sync65(nfa,nfb,naggressive,ntol,nqsym,ca,ncand,nrobust, &
freq=i*df
itry=0
! if(naggressive.gt.0 .and. ntol.lt.1000 .and. ccfmax.ge.thresh0) then
- if(naggressive.gt.0 .and. ccfmax.ge.thresh0) then
- if(i.ne.ipk) cycle
+! if(naggressive.gt.0 .and. ccfmax.ge.thresh0) then
+ if(bVHF) then
+ if(i.ne.ipk .or. ccfmax.lt.thresh0) cycle
itry=1
ncand=ncand+1
else
diff --git a/lib/unpackmsg144.f90 b/lib/unpackmsg144.f90
deleted file mode 100644
index 96423ff69..000000000
--- a/lib/unpackmsg144.f90
+++ /dev/null
@@ -1,117 +0,0 @@
- subroutine unpackmsg144(dat,msg,c1,c2)
-! special unpackmsg for MSK144 - returns call1 and call2 to enable
-! maintenance of a recent-calls-heard list
-
- use packjt
- parameter (NBASE=37*36*10*27*27*27)
- parameter (NGBASE=180*180)
- integer dat(12)
- character c1*12,c2*12,grid*4,msg*22,grid6*6,psfx*4,junk2*4
- logical cqnnn
-
- cqnnn=.false.
- nc1=ishft(dat(1),22) + ishft(dat(2),16) + ishft(dat(3),10)+ &
- ishft(dat(4),4) + iand(ishft(dat(5),-2),15)
-
- nc2=ishft(iand(dat(5),3),26) + ishft(dat(6),20) + &
- ishft(dat(7),14) + ishft(dat(8),8) + ishft(dat(9),2) + &
- iand(ishft(dat(10),-4),3)
-
- ng=ishft(iand(dat(10),15),12) + ishft(dat(11),6) + dat(12)
-
- if(ng.ge.32768) then
- call unpacktext(nc1,nc2,ng,msg)
- c1(1:12)=' '
- c2(1:12)=' '
- go to 100
- endif
-
- call unpackcall(nc1,c1,iv2,psfx)
- if(iv2.eq.0) then
- ! This is an "original JT65" message
- if(nc1.eq.NBASE+1) c1='CQ '
- if(nc1.eq.NBASE+2) c1='QRZ '
- nfreq=nc1-NBASE-3
- if(nfreq.ge.0 .and. nfreq.le.999) then
- write(c1,1002) nfreq
- 1002 format('CQ ',i3.3)
- cqnnn=.true.
- endif
- endif
-
- call unpackcall(nc2,c2,junk1,junk2)
- call unpackgrid(ng,grid)
-
- if(iv2.gt.0) then
- ! This is a JT65v2 message
- do i=1,4
- if(ichar(psfx(i:i)).eq.0) psfx(i:i)=' '
- enddo
-
- n1=len_trim(psfx)
- n2=len_trim(c2)
- if(iv2.eq.1) msg='CQ '//psfx(:n1)//'/'//c2(:n2)//' '//grid
- if(iv2.eq.2) msg='QRZ '//psfx(:n1)//'/'//c2(:n2)//' '//grid
- if(iv2.eq.3) msg='DE '//psfx(:n1)//'/'//c2(:n2)//' '//grid
- if(iv2.eq.4) msg='CQ '//c2(:n2)//'/'//psfx(:n1)//' '//grid
- if(iv2.eq.5) msg='QRZ '//c2(:n2)//'/'//psfx(:n1)//' '//grid
- if(iv2.eq.6) msg='DE '//c2(:n2)//'/'//psfx(:n1)//' '//grid
- if(iv2.eq.7) msg='DE '//c2(:n2)//' '//grid
- if(iv2.eq.8) msg=' '
- go to 100
- else
-
- endif
-
- grid6=grid//'ma'
- call grid2k(grid6,k)
- if(k.ge.1 .and. k.le.450) call getpfx2(k,c1)
- if(k.ge.451 .and. k.le.900) call getpfx2(k,c2)
-
- i=index(c1,char(0))
- if(i.ge.3) c1=c1(1:i-1)//' '
- i=index(c2,char(0))
- if(i.ge.3) c2=c2(1:i-1)//' '
-
- msg=' '
- j=0
- if(cqnnn) then
- msg=c1//' '
- j=7 !### ??? ###
- go to 10
- endif
-
- do i=1,12
- j=j+1
- msg(j:j)=c1(i:i)
- if(c1(i:i).eq.' ') go to 10
- enddo
- j=j+1
- msg(j:j)=' '
-
- 10 do i=1,12
- if(j.le.21) j=j+1
- msg(j:j)=c2(i:i)
- if(c2(i:i).eq.' ') go to 20
- enddo
- if(j.le.21) j=j+1
- msg(j:j)=' '
-
- 20 if(k.eq.0) then
- do i=1,4
- if(j.le.21) j=j+1
- msg(j:j)=grid(i:i)
- enddo
- if(j.le.21) j=j+1
- msg(j:j)=' '
- endif
-
- 100 continue
- if(msg(1:6).eq.'CQ9DX ') msg(3:3)=' '
- if(msg(1:2).eq.'E9' .and. &
- msg(3:3).ge.'A' .and. msg(3:3).le.'Z' .and. &
- msg(4:4).ge.'A' .and. msg(4:4).le.'Z' .and. &
- msg(5:5).eq.' ') msg='CQ '//msg(3:)
-
- return
- end subroutine unpackmsg144
diff --git a/logbook/WorkedBefore.cpp b/logbook/WorkedBefore.cpp
index b6cd9eca8..41723e003 100644
--- a/logbook/WorkedBefore.cpp
+++ b/logbook/WorkedBefore.cpp
@@ -1,18 +1,34 @@
#include "WorkedBefore.hpp"
+#include
+#include
#include
+#include
#include
#include
+#include
+#include
#include
#include
#include
#include
#include
+#include
+#include "qt_helpers.hpp"
#include "pimpl_impl.hpp"
using namespace boost::multi_index;
+// hash function for QString members in hashed indexes
+inline
+std::size_t hash_value (QString const& s)
+{
+ return std::hash {} (s);
+}
+
+//
// worked before set element
+//
struct worked_entry
{
explicit worked_entry (QString const& call, QString const& grid, QString const& band
@@ -39,7 +55,52 @@ struct worked_entry
int ITU_zone_;
};
-// less then predidate for the Continent enum class
+bool operator == (worked_entry const& lhs, worked_entry const& rhs)
+{
+ return
+ lhs.continent_ == rhs.continent_ // check 1st as it is fast
+ && lhs.CQ_zone_ == rhs.CQ_zone_ // ditto
+ && lhs.ITU_zone_ == rhs.ITU_zone_ // ditto
+ && lhs.call_ == rhs.call_ // check the rest in decreasing
+ && lhs.grid_ == rhs.grid_ // domain size order to shortcut
+ && lhs.country_ == rhs.country_ // differences as quickly as possible
+ && lhs.band_ == rhs.band_
+ && lhs.mode_ == rhs.mode_;
+}
+
+std::size_t hash_value (worked_entry const& we)
+{
+ std::size_t seed {0};
+ boost::hash_combine (seed, we.call_);
+ boost::hash_combine (seed, we.grid_);
+ boost::hash_combine (seed, we.band_);
+ boost::hash_combine (seed, we.mode_);
+ boost::hash_combine (seed, we.country_);
+ boost::hash_combine (seed, we.continent_);
+ boost::hash_combine (seed, we.CQ_zone_);
+ boost::hash_combine (seed, we.ITU_zone_);
+ return seed;
+}
+
+#if !defined (QT_NO_DEBUG_STREAM)
+QDebug operator << (QDebug dbg, worked_entry const& e)
+{
+ QDebugStateSaver saver {dbg};
+ dbg.nospace () << "worked_entry("
+ << e.call_ << ", "
+ << e.grid_ << ", "
+ << e.band_ << ", "
+ << e.mode_ << ", "
+ << e.country_ << ", "
+ << e.continent_ << ", "
+ << e.CQ_zone_ << ", "
+ << e.ITU_zone_ << ')';
+ return dbg;
+}
+#endif
+
+// less then predidate for the Continent enum class, needed for
+// ordered indexes
struct Continent_less
{
bool operator () (AD1CCty::Continent lhs, AD1CCty::Continent rhs) const
@@ -48,7 +109,7 @@ struct Continent_less
}
};
-// tags
+// index tags
struct call_mode_band {};
struct call_band {};
struct grid_mode_band {};
@@ -62,85 +123,92 @@ struct CQ_zone_band {};
struct ITU_zone_mode_band {};
struct ITU_zone_band {};
-// set with multiple ordered unique indexes that allow for efficient
-// determination of various categories of worked before status
+// set with multiple ordered unique indexes that allow for optimally
+// efficient determination of various categories of worked before
+// status
typedef multi_index_container<
worked_entry,
indexed_by<
+ // basic unordered set constraint - we don't need duplicate worked entries
+ hashed_unique>,
+
+ //
+ // The following indexes are used to discover worked before stuff.
+ //
+ // They are ordered so as to support partial lookups and
+ // non-unique because container inserts must be valid for all
+ // indexes.
+ //
+
// call+mode+band
- ordered_unique,
- composite_key,
- member,
- member > >,
+ ordered_non_unique,
+ composite_key,
+ member,
+ member > >,
// call+band
- ordered_unique,
- composite_key,
- member > >,
+ ordered_non_unique,
+ composite_key,
+ member > >,
// grid+mode+band
- ordered_unique,
- composite_key,
- member,
- member > >,
+ ordered_non_unique,
+ composite_key,
+ member,
+ member > >,
// grid+band
- ordered_unique,
- composite_key,
- member > >,
+ ordered_non_unique,
+ composite_key,
+ member > >,
// country+mode+band
- ordered_unique,
- composite_key,
- member,
- member > >,
+ ordered_non_unique,
+ composite_key,
+ member,
+ member > >,
// country+band
- ordered_unique,
- composite_key,
- member > >,
+ ordered_non_unique,
+ composite_key,
+ member > >,
// continent+mode+band
- ordered_unique,
- composite_key,
- member,
- member >,
- composite_key_compare<
- Continent_less,
- std::less,
- std::less > >,
+ ordered_non_unique,
+ composite_key,
+ member,
+ member >,
+ composite_key_compare, std::less > >,
// continent+band
- ordered_unique,
- composite_key,
- member >,
- composite_key_compare<
- Continent_less,
- std::less > >,
+ ordered_non_unique,
+ composite_key,
+ member >,
+ composite_key_compare > >,
// CQ-zone+mode+band
- ordered_unique,
- composite_key,
- member,
- member > >,
+ ordered_non_unique,
+ composite_key,
+ member,
+ member > >,
// CQ-zone+band
- ordered_unique,
- composite_key,
- member > >,
+ ordered_non_unique,
+ composite_key,
+ member > >,
// ITU-zone+mode+band
- ordered_unique,
- composite_key,
- member,
- member > >,
+ ordered_non_unique,
+ composite_key,
+ member,
+ member > >,
// ITU-zone+band
- ordered_unique,
- composite_key,
- member > > >
- > worked_type;
+ ordered_non_unique,
+ composite_key,
+ member > > >
+ > worked_before_database_type;
namespace
{
@@ -188,7 +256,7 @@ public:
QString path_;
AD1CCty prefixes_;
- worked_type worked_;
+ worked_before_database_type worked_;
};
WorkedBefore::WorkedBefore ()
@@ -196,7 +264,7 @@ WorkedBefore::WorkedBefore ()
QFile inputFile {m_->path_};
if (inputFile.open (QFile::ReadOnly))
{
- QTextStream in(&inputFile);
+ QTextStream in {&inputFile};
QString buffer;
bool pre_read {false};
int end_position {-1};
diff --git a/main.cpp b/main.cpp
index 784b709cd..601ae6a7e 100644
--- a/main.cpp
+++ b/main.cpp
@@ -52,6 +52,38 @@ namespace
qsrand (seed); // this is good for rand() as well
}
} seeding;
+
+ // We can't use the GUI after QApplication::exit() is called so
+ // uncaught exceptions can get lost on Windows systems where there
+ // is no console terminal, so here we override
+ // QApplication::notify() and wrap the base class call with a try
+ // block to catch and display exceptions in a message box.
+ class ExceptionCatchingApplication final
+ : public QApplication
+ {
+ public:
+ explicit ExceptionCatchingApplication (int& argc, char * * argv)
+ : QApplication {argc, argv}
+ {
+ }
+ bool notify (QObject * receiver, QEvent * e) override
+ {
+ try
+ {
+ return QApplication::notify (receiver, e);
+ }
+ catch (std::exception const& e)
+ {
+ MessageBox::critical_message (nullptr, translate ("main", "Fatal error"), e.what ());
+ throw;
+ }
+ catch (...)
+ {
+ MessageBox::critical_message (nullptr, translate ("main", "Unexpected fatal error"));
+ throw;
+ }
+ }
+ };
}
int main(int argc, char *argv[])
@@ -68,7 +100,7 @@ int main(int argc, char *argv[])
// Multiple instances communicate with jt9 via this
QSharedMemory mem_jt9;
- QApplication a(argc, argv);
+ ExceptionCatchingApplication a(argc, argv);
try
{
setlocale (LC_NUMERIC, "C"); // ensure number forms are in
@@ -339,12 +371,10 @@ int main(int argc, char *argv[])
}
catch (std::exception const& e)
{
- MessageBox::critical_message (nullptr, a.translate ("main", "Fatal error"), e.what ());
std::cerr << "Error: " << e.what () << '\n';
}
catch (...)
{
- MessageBox::critical_message (nullptr, a.translate ("main", "Unexpected fatal error"));
std::cerr << "Unexpected fatal error\n";
throw; // hoping the runtime might tell us more about the exception
}
diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp
index 3e218d643..965d6f957 100644
--- a/models/CabrilloLog.cpp
+++ b/models/CabrilloLog.cpp
@@ -52,7 +52,7 @@ CabrilloLog::impl::impl (Configuration const * configuration)
SQL_error_check (export_query_, &QSqlQuery::prepare,
"SELECT frequency, \"when\", exchange_sent, call, exchange_rcvd FROM cabrillo_log ORDER BY \"when\"");
- setEditStrategy (QSqlTableModel::OnManualSubmit);
+ setEditStrategy (QSqlTableModel::OnRowChange);
setTable ("cabrillo_log");
setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(kHz)"));
setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)"));
@@ -73,24 +73,49 @@ CabrilloLog::~CabrilloLog ()
{
}
-QAbstractItemModel * CabrilloLog::model ()
+QSqlTableModel * CabrilloLog::model ()
{
return &*m_;
}
-void CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call
+namespace
+{
+ void set_value_maybe_null (QSqlRecord& record, QString const& name, QString const& value)
+ {
+ if (value.size ())
+ {
+ record.setValue (name, value);
+ }
+ else
+ {
+ record.setNull (name);
+ }
+ }
+}
+
+bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call
, QString const& exchange_sent, QString const& exchange_received)
{
- ConditionalTransaction transaction {*m_};
auto record = m_->record ();
record.setValue ("frequency", frequency / 1000ull); // kHz
- record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull);
- record.setValue ("call", call);
- record.setValue ("exchange_sent", exchange_sent);
- record.setValue ("exchange_rcvd", exchange_received);
- record.setValue ("band", m_->configuration_->bands ()->find (frequency));
- SQL_error_check (*m_, &QSqlTableModel::insertRecord, -1, record);
- transaction.submit ();
+ if (!when.isNull ())
+ {
+ record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull);
+ }
+ else
+ {
+ record.setNull ("when");
+ }
+ set_value_maybe_null (record, "call", call);
+ set_value_maybe_null (record, "exchange_sent", exchange_sent);
+ set_value_maybe_null (record, "exchange_rcvd", exchange_received);
+ set_value_maybe_null (record, "band", m_->configuration_->bands ()->find (frequency));
+ auto ok = m_->insertRecord (-1, record);
+ if (ok)
+ {
+ m_->select (); // to refresh views
+ }
+ return ok;
}
bool CabrilloLog::dupe (Frequency frequency, QString const& call) const
@@ -106,9 +131,12 @@ void CabrilloLog::reset ()
{
if (m_->rowCount ())
{
+ m_->setEditStrategy (QSqlTableModel::OnManualSubmit);
ConditionalTransaction transaction {*m_};
SQL_error_check (*m_, &QSqlTableModel::removeRows, 0, m_->rowCount (), QModelIndex {});
transaction.submit ();
+ m_->select (); // to refresh views
+ m_->setEditStrategy (QSqlTableModel::OnRowChange);
}
}
@@ -128,7 +156,7 @@ void CabrilloLog::export_qsos (QTextStream& stream) const
frequency = frequency > 50000000ull ? frequency / 1000ull : frequency;
stream << QString {"QSO: %1 DG %2 %3 %4 %5 %6\n"}
.arg (frequency, 5)
- .arg (QDateTime::fromMSecsSinceEpoch (m_->export_query_.value (when_index).toULongLong () * 1000ull).toString ("yyyy-MM-dd hhmm"))
+ .arg (QDateTime::fromMSecsSinceEpoch (m_->export_query_.value (when_index).toULongLong () * 1000ull, Qt::UTC).toString ("yyyy-MM-dd hhmm"))
.arg (my_call, -12)
.arg (m_->export_query_.value (sent_index).toString (), -13)
.arg (m_->export_query_.value (call_index).toString (), -12)
diff --git a/models/CabrilloLog.hpp b/models/CabrilloLog.hpp
index 9571adeeb..43b9e8f94 100644
--- a/models/CabrilloLog.hpp
+++ b/models/CabrilloLog.hpp
@@ -8,7 +8,7 @@
class Configuration;
class QDateTime;
class QString;
-class QAbstractItemModel;
+class QSqlTableModel;
class QTextStream;
class CabrilloLog final
@@ -21,11 +21,11 @@ public:
~CabrilloLog ();
// returns false if insert fails
- void add_QSO (Frequency, QDateTime const&, QString const& call
+ bool add_QSO (Frequency, QDateTime const&, QString const& call
, QString const& report_sent, QString const& report_received);
bool dupe (Frequency, QString const& call) const;
- QAbstractItemModel * model ();
+ QSqlTableModel * model ();
void reset ();
void export_qsos (QTextStream&) const;
diff --git a/models/FoxLog.cpp b/models/FoxLog.cpp
index 81763d9be..1503e5662 100644
--- a/models/FoxLog.cpp
+++ b/models/FoxLog.cpp
@@ -43,7 +43,7 @@ FoxLog::impl::impl ()
SQL_error_check (dupe_query_, &QSqlQuery::prepare,
"SELECT COUNT(*) FROM fox_log WHERE call = :call AND band = :band");
- setEditStrategy (QSqlTableModel::OnManualSubmit);
+ setEditStrategy (QSqlTableModel::OnRowChange);
setTable ("fox_log");
setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)"));
setHeaderData (fieldIndex ("call"), Qt::Horizontal, tr ("Call"));
@@ -62,7 +62,7 @@ FoxLog::~FoxLog ()
{
}
-QAbstractItemModel * FoxLog::model ()
+QSqlTableModel * FoxLog::model ()
{
return &*m_;
}
@@ -86,21 +86,26 @@ bool FoxLog::add_QSO (QDateTime const& when, QString const& call, QString const&
, QString const& report_sent, QString const& report_received
, QString const& band)
{
- ConditionalTransaction transaction {*m_};
auto record = m_->record ();
- record.setValue ("when", when.toMSecsSinceEpoch () / 1000);
- record.setValue ("call", call);
+ if (!when.isNull ())
+ {
+ record.setValue ("when", when.toMSecsSinceEpoch () / 1000);
+ }
+ else
+ {
+ record.setNull ("when");
+ }
+ set_value_maybe_null (record, "call", call);
set_value_maybe_null (record, "grid", grid);
set_value_maybe_null (record, "report_sent", report_sent);
set_value_maybe_null (record, "report_rcvd", report_received);
- record.setValue ("band", band);
- SQL_error_check (*m_, &QSqlTableModel::insertRecord, -1, record);
- if (!transaction.submit (false))
+ set_value_maybe_null (record, "band", band);
+ auto ok = m_->insertRecord (-1, record);
+ if (ok)
{
- transaction.revert ();
- return false;
+ m_->select (); // to refresh views
}
- return true;
+ return ok;
}
bool FoxLog::dupe (QString const& call, QString const& band) const
@@ -116,8 +121,11 @@ void FoxLog::reset ()
{
if (m_->rowCount ())
{
+ m_->setEditStrategy (QSqlTableModel::OnManualSubmit);
ConditionalTransaction transaction {*m_};
SQL_error_check (*m_, &QSqlTableModel::removeRows, 0, m_->rowCount (), QModelIndex {});
transaction.submit ();
+ m_->select (); // to refresh views
+ m_->setEditStrategy (QSqlTableModel::OnRowChange);
}
}
diff --git a/models/FoxLog.hpp b/models/FoxLog.hpp
index 028f8205c..caa8e358f 100644
--- a/models/FoxLog.hpp
+++ b/models/FoxLog.hpp
@@ -6,7 +6,7 @@
class QDateTime;
class QString;
-class QAbstractItemModel;
+class QSqlTableModel;
class FoxLog final
: private boost::noncopyable
@@ -21,7 +21,7 @@ public:
, QString const& band);
bool dupe (QString const& call, QString const& band) const;
- QAbstractItemModel * model ();
+ QSqlTableModel * model ();
void reset ();
private:
diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp
index e50afe2a4..55844bdfa 100644
--- a/models/FrequencyList.cpp
+++ b/models/FrequencyList.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
@@ -350,14 +351,6 @@ bool FrequencyList_v2::remove (Item f)
return m_->removeRow (row);
}
-namespace
-{
- bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs)
- {
- return lhs.row () > rhs.row ();
- }
-}
-
bool FrequencyList_v2::removeDisjointRows (QModelIndexList rows)
{
bool result {true};
@@ -371,7 +364,10 @@ bool FrequencyList_v2::removeDisjointRows (QModelIndexList rows)
}
// reverse sort by row
- qSort (rows.begin (), rows.end (), row_is_higher);
+ std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs)
+ {
+ return rhs.row () < lhs.row (); // reverse row ordering
+ });
Q_FOREACH (auto index, rows)
{
if (result && !m_->removeRow (index.row ()))
diff --git a/models/StationList.cpp b/models/StationList.cpp
index cfd629ede..eeeb4d607 100644
--- a/models/StationList.cpp
+++ b/models/StationList.cpp
@@ -139,14 +139,6 @@ bool StationList::remove (Station s)
return removeRow (row);
}
-namespace
-{
- bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs)
- {
- return lhs.row () > rhs.row ();
- }
-}
-
bool StationList::removeDisjointRows (QModelIndexList rows)
{
bool result {true};
@@ -160,7 +152,10 @@ bool StationList::removeDisjointRows (QModelIndexList rows)
}
// reverse sort by row
- qSort (rows.begin (), rows.end (), row_is_higher);
+ std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs)
+ {
+ return rhs.row () < lhs.row (); // reverse row ordering
+ });
Q_FOREACH (auto index, rows)
{
if (result && !m_->removeRow (index.row ()))
diff --git a/qt_db_helpers.hpp b/qt_db_helpers.hpp
index 3f159a889..49a082f72 100644
--- a/qt_db_helpers.hpp
+++ b/qt_db_helpers.hpp
@@ -25,37 +25,56 @@ class ConditionalTransaction final
{
public:
explicit ConditionalTransaction (QSqlTableModel& model)
- : model_ {model}
+ : model_ (model)
, submitted_ {false}
{
model_.database ().transaction ();
}
+
bool submit (bool throw_on_error = true)
{
- Q_ASSERT (model_.isDirty ());
bool ok {true};
if (throw_on_error)
{
- SQL_error_check (model_, &QSqlTableModel::submitAll);
+ SQL_error_check (model_
+ , QSqlTableModel::OnManualSubmit == model_.editStrategy ()
+ ? &QSqlTableModel::submitAll
+ : &QSqlTableModel::submit);
}
else
{
- ok = model_.submitAll ();
+ ok = QSqlTableModel::OnManualSubmit == model_.editStrategy ()
+ ? model_.submitAll () : model_.submit ();
}
submitted_ = submitted_ || ok;
return ok;
}
+
void revert ()
{
- Q_ASSERT (model_.isDirty ());
- model_.revertAll ();
+ if (QSqlTableModel::OnManualSubmit == model_.editStrategy ())
+ {
+ model_.revertAll ();
+ }
+ else
+ {
+ model_.revert ();
+ }
}
+
~ConditionalTransaction ()
{
if (model_.isDirty ())
{
// abandon un-submitted changes to the model
- model_.revertAll ();
+ if (QSqlTableModel::OnManualSubmit == model_.editStrategy ())
+ {
+ model_.revertAll ();
+ }
+ else
+ {
+ model_.revert ();
+ }
}
auto database = model_.database ();
if (submitted_)
@@ -67,6 +86,7 @@ public:
database.rollback ();
}
}
+
private:
QSqlTableModel& model_;
bool submitted_;
diff --git a/qt_helpers.hpp b/qt_helpers.hpp
index 0e9439a8a..b2ec7a49f 100644
--- a/qt_helpers.hpp
+++ b/qt_helpers.hpp
@@ -4,6 +4,7 @@
#include
#include
+#include
#include
#include
#include
@@ -77,6 +78,26 @@ public:
}
};
+namespace std
+{
+ // std::hash<> specialization for QString based on the dbj2
+ // algorithm http://www.cse.yorku.ca/~oz/hash.html because qHash()
+ // is poor on 64-bit platforms due to being a 32-bit hash value
+ template<>
+ struct hash
+ {
+ std::size_t operator () (QString const& s) const noexcept
+ {
+ std::size_t hash {5381};
+ for (int i = 0; i < s.size (); ++i)
+ {
+ hash = ((hash << 5) + hash) + ((s.at (i).row () << 8) | s.at (i).cell ());
+ }
+ return hash;
+ }
+ };
+}
+
// Register some useful Qt types with QMetaType
Q_DECLARE_METATYPE (QHostAddress);
diff --git a/widgets/AbstractLogWindow.cpp b/widgets/AbstractLogWindow.cpp
new file mode 100644
index 000000000..e796cdc3e
--- /dev/null
+++ b/widgets/AbstractLogWindow.cpp
@@ -0,0 +1,133 @@
+#include "AbstractLogWindow.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "Configuration.hpp"
+#include "SettingsGroup.hpp"
+#include "MessageBox.hpp"
+#include "models/FontOverrideModel.hpp"
+#include "pimpl_impl.hpp"
+
+class AbstractLogWindow::impl final
+{
+public:
+ impl (AbstractLogWindow * self, QString const& settings_key, QSettings * settings
+ , Configuration const * configuration)
+ : self_ {self}
+ , settings_key_ {settings_key}
+ , settings_ {settings}
+ , configuration_ {configuration}
+ , log_view_ {nullptr}
+ {
+ }
+
+ void delete_QSOs ();
+
+ AbstractLogWindow * self_;
+ QString settings_key_;
+ QSettings * settings_;
+ Configuration const * configuration_;
+ QTableView * log_view_;
+ FontOverrideModel model_;
+};
+
+namespace
+{
+ bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs)
+ {
+ return lhs.row () > rhs.row ();
+ }
+}
+
+void AbstractLogWindow::impl::delete_QSOs ()
+{
+ auto selection_model = log_view_->selectionModel ();
+ selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+ auto row_indexes = selection_model->selectedRows ();
+
+ if (row_indexes.size ()
+ && MessageBox::Yes == MessageBox::query_message (self_
+ , tr ("Confirm Delete")
+ , tr ("Are you sure you want to delete the %n "
+ "selected QSO(s) from the log", ""
+ , row_indexes.size ())))
+ {
+ // We must work with source model indexes because we don't want row
+ // removes to invalidate model indexes we haven't yet processed. We
+ // achieve that by processing them in decending row order.
+ for (auto& row_index : row_indexes)
+ {
+ row_index = model_.mapToSource (row_index);
+ }
+
+ // reverse sort by row
+ std::sort (row_indexes.begin (), row_indexes.end (), row_is_higher);
+ for (auto index : row_indexes)
+ {
+ auto row = model_.mapFromSource (index).row ();
+ model_.removeRow (row);
+ self_->log_model_changed ();
+ }
+ }
+}
+
+AbstractLogWindow::AbstractLogWindow (QString const& settings_key, QSettings * settings
+ , Configuration const * configuration
+ , QWidget * parent)
+ : QWidget {parent}
+ , m_ {this, settings_key, settings, configuration}
+{
+ // ensure view scrolls to latest new row
+ connect (&m_->model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) {
+ if (m_->log_view_) m_->log_view_->scrollToBottom ();
+ });
+}
+
+AbstractLogWindow::~AbstractLogWindow ()
+{
+ SettingsGroup g {m_->settings_, m_->settings_key_};
+ m_->settings_->setValue ("window/geometry", saveGeometry ());
+}
+
+void AbstractLogWindow::set_log_view (QTableView * log_view)
+{
+ // do this here because we know the UI must be setup before this
+ SettingsGroup g {m_->settings_, m_->settings_key_};
+ restoreGeometry (m_->settings_->value ("window/geometry").toByteArray ());
+ m_->log_view_ = log_view;
+ m_->log_view_->setContextMenuPolicy (Qt::ActionsContextMenu);
+ m_->log_view_->setAlternatingRowColors (true);
+ m_->log_view_->setSelectionBehavior (QAbstractItemView::SelectRows);
+ m_->log_view_->setSelectionMode (QAbstractItemView::ExtendedSelection);
+ m_->model_.setSourceModel (m_->log_view_->model ());
+ m_->log_view_->setModel (&m_->model_);
+ m_->log_view_->setColumnHidden (0, true);
+ auto horizontal_header = log_view->horizontalHeader ();
+ horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents);
+ horizontal_header->setSectionsMovable (true);
+ m_->log_view_->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
+ set_log_view_font (m_->configuration_->decoded_text_font ());
+ m_->log_view_->scrollToBottom ();
+
+ // actions
+ auto delete_action = new QAction {tr ("&Delete ..."), m_->log_view_};
+ m_->log_view_->insertAction (nullptr, delete_action);
+ connect (delete_action, &QAction::triggered, [this] (bool /*checked*/) {
+ m_->delete_QSOs ();
+ });
+}
+
+void AbstractLogWindow::set_log_view_font (QFont const& font)
+{
+ // m_->log_view_->setFont (font);
+ // m_->log_view_->horizontalHeader ()->setFont (font);
+ // m_->log_view_->verticalHeader ()->setFont (font);
+ m_->model_.set_font (font);
+}
diff --git a/widgets/AbstractLogWindow.hpp b/widgets/AbstractLogWindow.hpp
new file mode 100644
index 000000000..581212d82
--- /dev/null
+++ b/widgets/AbstractLogWindow.hpp
@@ -0,0 +1,41 @@
+#ifndef ABSTRACT_LOG_WINDOW_HPP_
+#define ABSTRACT_LOG_WINDOW_HPP_
+
+#include
+#include "pimpl_h.hpp"
+
+class QString;
+class QSettings;
+class Configuration;
+class QTableView;
+class QFont;
+
+//
+// AbstractLogWindow - Base class for log view windows
+//
+// QWidget that manages the common functionality shared by windows
+// that include a QSO log view.
+//
+class AbstractLogWindow
+ : public QWidget
+{
+public:
+ AbstractLogWindow (QString const& settings_key, QSettings * settings
+ , Configuration const * configuration
+ , QWidget * parent = nullptr);
+ virtual ~AbstractLogWindow () = 0;
+
+ // set the QTableView that shows the log records, must have its
+ // model set before calling this
+ void set_log_view (QTableView *);
+
+ void set_log_view_font (QFont const&);
+
+private:
+ virtual void log_model_changed (int row = -1) = 0;
+
+ class impl;
+ pimpl m_;
+};
+
+#endif
diff --git a/widgets/CabrilloLogWindow.cpp b/widgets/CabrilloLogWindow.cpp
index 4a86b4509..20f39e4e6 100644
--- a/widgets/CabrilloLogWindow.cpp
+++ b/widgets/CabrilloLogWindow.cpp
@@ -1,77 +1,87 @@
#include "CabrilloLogWindow.hpp"
-#include
#include
-#include
-#include
-#include
-#include
-#include
-
-#include "SettingsGroup.hpp"
+#include
+#include
#include "Configuration.hpp"
#include "models/Bands.hpp"
#include "item_delegates/ForeignKeyDelegate.hpp"
#include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp"
#include "item_delegates/CallsignDelegate.hpp"
-#include "item_delegates/MaidenheadLocatorDelegate.hpp"
-#include "widgets/MessageBox.hpp"
-#include "qt_helpers.hpp"
+#include "pimpl_impl.hpp"
#include "ui_CabrilloLogWindow.h"
-CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const * configuration
- , QAbstractItemModel * cabrillo_log_model, QWidget * parent)
- : QWidget {parent}
- , settings_ {settings}
- , configuration_ {configuration}
- , ui_ {new Ui::CabrilloLogWindow}
+namespace
{
- cabrillo_log_model_.setSourceModel (cabrillo_log_model);
- setWindowTitle (QApplication::applicationName () + " - Cabrillo Log");
- ui_->setupUi (this);
- read_settings ();
- change_font (configuration_->decoded_text_font ());
- ui_->log_table_view->setModel (&cabrillo_log_model_);
- ui_->log_table_view->setColumnHidden (0, true);
- ui_->log_table_view->setItemDelegateForColumn (2, new DateTimeAsSecsSinceEpochDelegate {this});
- ui_->log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this});
- ui_->log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration_->bands (), &cabrillo_log_model_, 0, 6, this});
- ui_->log_table_view->setSelectionMode (QTableView::SingleSelection);
- auto horizontal_header = ui_->log_table_view->horizontalHeader ();
- horizontal_header->setStretchLastSection (true);
- horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents);
- horizontal_header->setSectionsMovable (true);
- horizontal_header->moveSection (6, 1); // band to first column
- ui_->log_table_view->scrollToBottom ();
+ class FormatProxyModel final
+ : public QIdentityProxyModel
+ {
+ public:
+ explicit FormatProxyModel (QObject * parent = nullptr)
+ : QIdentityProxyModel {parent}
+ {
+ }
- // ensure view scrolls to latest new row
- connect (&cabrillo_log_model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) {
- ui_->log_table_view->scrollToBottom ();
- });
+ QVariant data (QModelIndex const& index, int role) const override
+ {
+ if (Qt::TextAlignmentRole == role && index.isValid ())
+ {
+ switch (index.column ())
+ {
+ case 1:
+ case 6:
+ return Qt::AlignRight + Qt::AlignVCenter;
+ default:
+ break;
+ }
+ }
+ return QIdentityProxyModel::data (index, role);
+ }
+ };
+}
+
+class CabrilloLogWindow::impl final
+{
+public:
+ explicit impl (QSqlTableModel * log_model)
+ : log_model_ {log_model}
+ {
+ }
+
+ QSqlTableModel * log_model_;
+ FormatProxyModel format_model_;
+ Ui::CabrilloLogWindow ui_;
+};
+
+CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const * configuration
+ , QSqlTableModel * cabrillo_log_model, QWidget * parent)
+ : AbstractLogWindow {"Cabrillo Log Window", settings, configuration, parent}
+ , m_{cabrillo_log_model}
+{
+ setWindowTitle (QApplication::applicationName () + " - Cabrillo Log");
+ m_->ui_.setupUi (this);
+ m_->format_model_.setSourceModel (m_->log_model_);
+ m_->ui_.log_table_view->setModel (&m_->format_model_);
+ set_log_view (m_->ui_.log_table_view);
+ m_->ui_.log_table_view->setItemDelegateForColumn (2, new DateTimeAsSecsSinceEpochDelegate {this});
+ m_->ui_.log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this});
+ m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), m_->log_model_, 0, 6, this});
+ m_->ui_.log_table_view->horizontalHeader ()->moveSection (6, 1); // band to first column
}
CabrilloLogWindow::~CabrilloLogWindow ()
{
- write_settings ();
}
-void CabrilloLogWindow::read_settings ()
+void CabrilloLogWindow::log_model_changed (int row)
{
- SettingsGroup g {settings_, "Cabrillo Log Window"};
- restoreGeometry (settings_->value ("window/geometery").toByteArray ());
-}
-
-void CabrilloLogWindow::write_settings () const
-{
- SettingsGroup g {settings_, "Cabrillo Log Window"};
- settings_->setValue ("window/geometery", saveGeometry ());
-}
-
-void CabrilloLogWindow::change_font (QFont const& font)
-{
- // ui_->log_table_view->setFont (font);
- // ui_->log_table_view->horizontalHeader ()->setFont (font);
- // ui_->log_table_view->verticalHeader ()->setFont (font);
- cabrillo_log_model_.set_font (font);
+ if (row >= 0)
+ {
+ m_->log_model_->selectRow (row);
+ }
+ else
+ {
+ m_->log_model_->select ();
+ }
}
diff --git a/widgets/CabrilloLogWindow.hpp b/widgets/CabrilloLogWindow.hpp
index 9a352ce9d..e2aa1627a 100644
--- a/widgets/CabrilloLogWindow.hpp
+++ b/widgets/CabrilloLogWindow.hpp
@@ -1,39 +1,27 @@
#ifndef CABRILLO_LOG_WINDOW_HPP_
#define CABRILLO_LOG_WINDOW_HPP_
-#include
-#include
-#include
-#include "models/FontOverrideModel.hpp"
+#include "AbstractLogWindow.hpp"
+#include "pimpl_h.hpp"
class QSettings;
class Configuration;
class QFont;
-class QDateTime;
-class QAbstractItemModel;
-namespace Ui
-{
- class CabrilloLogWindow;
-}
+class QSqlTableModel;
class CabrilloLogWindow final
- : public QWidget
+ : public AbstractLogWindow
{
public:
- explicit CabrilloLogWindow (QSettings *, Configuration const *, QAbstractItemModel * cabrillo_log_model
- , QWidget * parent = nullptr);
+ explicit CabrilloLogWindow (QSettings *, Configuration const *, QSqlTableModel * cabrillo_log_model
+ , QWidget * parent = nullptr);
~CabrilloLogWindow ();
- void change_font (QFont const&);
-
private:
- void read_settings ();
- void write_settings () const;
+ void log_model_changed (int row) override;
- QSettings * settings_;
- Configuration const * configuration_;
- FontOverrideModel cabrillo_log_model_;
- QScopedPointer ui_;
+ class impl;
+ pimpl m_;
};
#endif
diff --git a/widgets/CabrilloLogWindow.ui b/widgets/CabrilloLogWindow.ui
index eb25d1a6b..efefe5d3c 100644
--- a/widgets/CabrilloLogWindow.ui
+++ b/widgets/CabrilloLogWindow.ui
@@ -2,12 +2,27 @@
CabrilloLogWindow
+
+
+ 0
+ 0
+ 493
+ 210
+
+
Contest Log
-
-
+
+
+ <html><head/><body><p>Right-click here for available actions.</p></body></html>
+
+
+ true
+
+
diff --git a/widgets/ExportCabrillo.cpp b/widgets/ExportCabrillo.cpp
index 928a60dc9..0e61f0f08 100644
--- a/widgets/ExportCabrillo.cpp
+++ b/widgets/ExportCabrillo.cpp
@@ -76,7 +76,7 @@ void ExportCabrillo::save_log ()
auto fname = QFileDialog::getSaveFileName (this
, tr ("Save Log File")
, configuration_->writeable_data_dir ().absolutePath ()
- , tr ("Cabrillo Log (*.log)"));
+ , tr ("Cabrillo Log (*.cbr)"));
if (fname.size ())
{
QFile f {fname};
diff --git a/widgets/FoxLogWindow.cpp b/widgets/FoxLogWindow.cpp
index 252045359..0f96529aa 100644
--- a/widgets/FoxLogWindow.cpp
+++ b/widgets/FoxLogWindow.cpp
@@ -1,96 +1,97 @@
#include "FoxLogWindow.hpp"
-#include
#include
-#include
+#include
+#include
+#include
#include
-#include
-#include
-#include
#include "SettingsGroup.hpp"
#include "Configuration.hpp"
+#include "MessageBox.hpp"
#include "models/Bands.hpp"
#include "item_delegates/ForeignKeyDelegate.hpp"
#include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp"
#include "item_delegates/CallsignDelegate.hpp"
#include "item_delegates/MaidenheadLocatorDelegate.hpp"
-#include "widgets/MessageBox.hpp"
-#include "qt_helpers.hpp"
+#include "pimpl_impl.hpp"
#include "ui_FoxLogWindow.h"
+#include "moc_FoxLogWindow.cpp"
+
+class FoxLogWindow::impl final
+{
+public:
+ explicit impl (QSqlTableModel * log_model)
+ : log_model_ {log_model}
+ {
+ }
+
+ QSqlTableModel * log_model_;
+ Ui::FoxLogWindow ui_;
+};
FoxLogWindow::FoxLogWindow (QSettings * settings, Configuration const * configuration
- , QAbstractItemModel * fox_log_model, QWidget * parent)
- : QWidget {parent}
- , settings_ {settings}
- , configuration_ {configuration}
- , ui_ {new Ui::FoxLogWindow}
+ , QSqlTableModel * fox_log_model, QWidget * parent)
+ : AbstractLogWindow {"Fox Log Window", settings, configuration, parent}
+ , m_ {fox_log_model}
{
- fox_log_model_.setSourceModel (fox_log_model);
setWindowTitle (QApplication::applicationName () + " - Fox Log");
- ui_->setupUi (this);
- read_settings ();
- change_font (configuration_->decoded_text_font ());
- ui_->log_table_view->setModel (&fox_log_model_);
- ui_->log_table_view->setColumnHidden (0, true);
- ui_->log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this});
- ui_->log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this});
- ui_->log_table_view->setItemDelegateForColumn (3, new MaidenheadLocatorDelegate {this});
- ui_->log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration_->bands (), &fox_log_model_, 0, 6, this});
- ui_->log_table_view->setSelectionMode (QTableView::SingleSelection);
- auto horizontal_header = ui_->log_table_view->horizontalHeader ();
- horizontal_header->setStretchLastSection (true);
- horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents);
- horizontal_header->setSectionsMovable (true);
- horizontal_header->moveSection (6, 1); // move band to first column
- ui_->rate_label->setNum (0);
- ui_->queued_label->setNum (0);
- ui_->callers_label->setNum (0);
- ui_->log_table_view->scrollToBottom ();
+ m_->ui_.setupUi (this);
+ m_->ui_.log_table_view->setModel (m_->log_model_);
+ set_log_view (m_->ui_.log_table_view);
+ m_->ui_.log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this});
+ m_->ui_.log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this});
+ m_->ui_.log_table_view->setItemDelegateForColumn (3, new MaidenheadLocatorDelegate {this});
+ m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), m_->log_model_, 0, 6, this});
+ m_->ui_.log_table_view->horizontalHeader ()->moveSection (6, 1); // move band to first column
+ m_->ui_.rate_label->setNum (0);
+ m_->ui_.queued_label->setNum (0);
+ m_->ui_.callers_label->setNum (0);
- // ensure view scrolls to latest new row
- connect (&fox_log_model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) {
- ui_->log_table_view->scrollToBottom ();
+ // actions
+ auto reset_action = new QAction {tr ("&Reset ..."), m_->ui_.log_table_view};
+ m_->ui_.log_table_view->insertAction (nullptr, reset_action);
+ connect (reset_action, &QAction::triggered, [this, configuration] (bool /*checked*/) {
+ if (MessageBox::Yes == MessageBox::query_message( this
+ , tr ("Confirm Reset")
+ , tr ("Are you sure you want to erase file FoxQSO.txt "
+ "and start a new Fox log?")))
+ {
+ QFile f{configuration->writeable_data_dir ().absoluteFilePath ("FoxQSO.txt")};
+ f.remove ();
+ Q_EMIT reset_log_model ();
+ }
});
}
FoxLogWindow::~FoxLogWindow ()
{
- write_settings ();
-}
-
-void FoxLogWindow::read_settings ()
-{
- SettingsGroup g {settings_, "Fox Log Window"};
- restoreGeometry (settings_->value ("window/geometery").toByteArray ());
-}
-
-void FoxLogWindow::write_settings () const
-{
- SettingsGroup g {settings_, "Fox Log Window"};
- settings_->setValue ("window/geometery", saveGeometry ());
-}
-
-void FoxLogWindow::change_font (QFont const& font)
-{
- // ui_->log_table_view->setFont (font);
- // ui_->log_table_view->horizontalHeader ()->setFont (font);
- // ui_->log_table_view->verticalHeader ()->setFont (font);
- fox_log_model_.set_font (font);
}
void FoxLogWindow::callers (int n)
{
- ui_->callers_label->setNum (n);
+ m_->ui_.callers_label->setNum (n);
}
void FoxLogWindow::queued (int n)
{
- ui_->queued_label->setNum (n);
+ m_->ui_.queued_label->setNum (n);
}
void FoxLogWindow::rate (int n)
{
- ui_->rate_label->setNum (n);
+ m_->ui_.rate_label->setNum (n);
+}
+
+void FoxLogWindow::log_model_changed (int row)
+{
+ if (row >= 0)
+ {
+ m_->log_model_->selectRow (row);
+ }
+ else
+ {
+ m_->log_model_->select ();
+ }
}
diff --git a/widgets/FoxLogWindow.hpp b/widgets/FoxLogWindow.hpp
index 62895a763..65bcb0bd0 100644
--- a/widgets/FoxLogWindow.hpp
+++ b/widgets/FoxLogWindow.hpp
@@ -1,42 +1,35 @@
#ifndef FOX_LOG_WINDOW_HPP_
#define FOX_LOG_WINDOW_HPP_
-#include
-#include
-#include
-#include "models/FontOverrideModel.hpp"
+#include "AbstractLogWindow.hpp"
+#include "pimpl_h.hpp"
class QSettings;
class Configuration;
class QFont;
-class QDateTime;
-class QAbstractItemModel;
-namespace Ui
-{
- class FoxLogWindow;
-}
+class QSqlTableModel;
class FoxLogWindow final
- : public QWidget
+ : public AbstractLogWindow
{
+ Q_OBJECT
+
public:
- explicit FoxLogWindow (QSettings *, Configuration const *, QAbstractItemModel * fox_log_model
+ explicit FoxLogWindow (QSettings *, Configuration const *, QSqlTableModel * fox_log_model
, QWidget * parent = nullptr);
~FoxLogWindow ();
- void change_font (QFont const&);
void callers (int);
void queued (int);
void rate (int);
-private:
- void read_settings ();
- void write_settings () const;
+ Q_SIGNAL void reset_log_model () const;
- QSettings * settings_;
- Configuration const * configuration_;
- FontOverrideModel fox_log_model_;
- QScopedPointer ui_;
+private:
+ void log_model_changed (int row) override;
+
+ class impl;
+ pimpl m_;
};
#endif
diff --git a/widgets/FoxLogWindow.ui b/widgets/FoxLogWindow.ui
index 2a3e84aba..cd224ed33 100644
--- a/widgets/FoxLogWindow.ui
+++ b/widgets/FoxLogWindow.ui
@@ -2,12 +2,33 @@
FoxLogWindow
+
+
+ 0
+ 0
+ 453
+ 238
+
+
+
+ Qt::DefaultContextMenu
+
Fox Log
-
-
+
+
+ Qt::ActionsContextMenu
+
+
+ <html><head/><body><p>Right-click here for available actions.</p></body></html>
+
+
+ true
+
+
-
diff --git a/widgets/astro.cpp b/widgets/astro.cpp
index c0e2b1fe3..4ee55da4a 100644
--- a/widgets/astro.cpp
+++ b/widgets/astro.cpp
@@ -213,7 +213,7 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const
// we do the next period if we calculate just before it starts
auto sec_since_epoch = t.toMSecsSinceEpoch () / 1000 + 2;
auto target_sec = sec_since_epoch - sec_since_epoch % TR_period + TR_period / 2;
- auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000, QTimeZone::utc ());
+ auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000, Qt::UTC);
QString date {target_date_time.date().toString("yyyy MMM dd").trimmed ()};
QString utc {target_date_time.time().toString().trimmed ()};
int nyear {target_date_time.date().year()};
diff --git a/widgets/logqso.cpp b/widgets/logqso.cpp
index 77324e52b..b6412cb59 100644
--- a/widgets/logqso.cpp
+++ b/widgets/logqso.cpp
@@ -10,6 +10,7 @@
#include "MessageBox.hpp"
#include "Configuration.hpp"
#include "models/Bands.hpp"
+#include "models/CabrilloLog.hpp"
#include "validators/MaidenheadLocatorValidator.hpp"
#include "ui_logqso.h"
@@ -57,11 +58,10 @@ void LogQSO::storeSettings () const
void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode,
QString const& rptSent, QString const& rptRcvd,
QDateTime const& dateTimeOn, QDateTime const& dateTimeOff,
- Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd)
+ Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd,
+ CabrilloLog * cabrillo_log)
{
if(!isHidden()) return;
- m_xSent=xSent;
- m_xRcvd=xRcvd;
ui->call->setText(hisCall);
ui->grid->setText(hisGrid);
ui->name->setText("");
@@ -87,17 +87,23 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString
m_myGrid=m_config->my_grid();
ui->band->setText (m_config->bands ()->find (dialFreq));
ui->loggedOperator->setText(m_config->opCall());
- ui->exchSent->setText(m_xSent);
- ui->exchRcvd->setText(m_xRcvd);
+ ui->exchSent->setText (xSent);
+ ui->exchRcvd->setText (xRcvd);
+ m_cabrilloLog = cabrillo_log;
using SpOp = Configuration::SpecialOperatingActivity;
- if( SpOp::FOX == m_config->special_op_id() or
- (m_config->autoLog() and SpOp::NONE < m_config->special_op_id() and
- m_xSent!="" and m_xRcvd!="")) {
- accept();
- } else {
- show();
- }
+ auto special_op = m_config->special_op_id ();
+ if (SpOp::FOX == special_op
+ || (m_config->autoLog ()
+ && SpOp::NONE < special_op && special_op < SpOp::FOX))
+ {
+ // allow auto logging in Fox mode and contests
+ accept();
+ }
+ else
+ {
+ show();
+ }
}
void LogQSO::accept()
@@ -120,6 +126,29 @@ void LogQSO::accept()
QString strDialFreq(QString::number(m_dialFreq / 1.e6,'f',6));
operator_call = ui->loggedOperator->text();
+ // validate
+ using SpOp = Configuration::SpecialOperatingActivity;
+ auto special_op = m_config->special_op_id ();
+ if (SpOp::NONE < special_op && special_op < SpOp::FOX)
+ {
+ if (ui->exchSent->text ().isEmpty () || ui->exchRcvd->text ().isEmpty ())
+ {
+ show ();
+ MessageBox::warning_message (this, tr ("Invalid QSO Data"),
+ tr ("Check exchange sent and received"));
+ return; // without accepting
+ }
+
+ if (!m_cabrilloLog->add_QSO (m_dialFreq, QDateTime::currentDateTimeUtc (), hisCall,
+ ui->exchSent->text (), ui->exchRcvd->text ()))
+ {
+ show ();
+ MessageBox::warning_message (this, tr ("Invalid QSO Data"),
+ tr ("Check all fields"));
+ return; // without accepting
+ }
+ }
+
//Log this QSO to file "wsjtx.log"
static QFile f {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx.log")};
if(!f.open(QIODevice::Text | QIODevice::Append)) {
@@ -169,8 +198,8 @@ void LogQSO::accept()
, m_myGrid
, m_txPower
, operator_call
- , m_xSent
- , m_xRcvd));
+ , ui->exchSent->text ()
+ , ui->exchRcvd->text ()));
QDialog::accept();
}
diff --git a/widgets/logqso.h b/widgets/logqso.h
index 2f2e4c29e..b0e703a93 100644
--- a/widgets/logqso.h
+++ b/widgets/logqso.h
@@ -17,6 +17,7 @@ namespace Ui {
class QSettings;
class Configuration;
class QByteArray;
+class CabrilloLog;
class LogQSO : public QDialog
{
@@ -28,7 +29,7 @@ public:
void initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode,
QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
QDateTime const& dateTimeOff, Radio::Frequency dialFreq,
- bool noSuffix, QString xSent, QString xRcvd);
+ bool noSuffix, QString xSent, QString xRcvd, CabrilloLog *);
public slots:
void accept();
@@ -56,10 +57,9 @@ private:
Radio::Frequency m_dialFreq;
QString m_myCall;
QString m_myGrid;
- QString m_xSent;
- QString m_xRcvd;
QDateTime m_dateTimeOn;
QDateTime m_dateTimeOff;
+ CabrilloLog * m_cabrilloLog;
};
#endif // LogQSO_H
diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp
index 19243df09..175dff49d 100644
--- a/widgets/mainwindow.cpp
+++ b/widgets/mainwindow.cpp
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -735,6 +736,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
ui->labDXped->setStyleSheet("QLabel {background-color: red; color: white;}");
ui->labNextCall->setText("");
ui->labNextCall->setVisible(false);
+ ui->labNextCall->setToolTip(""); //### Possibly temporary ? ###
for(int i=0; i<28; i++) { //Initialize dBm values
float dbm=(10.0*i)/3.0 - 30.0;
@@ -931,13 +933,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
ui->cbMenus->setChecked(true);
ui->cbMenus->setChecked(false);
}
-
- mouseLastPos=QCursor::pos();
- m_mouseIdleSeconds=0;
- connect(&mouseTimer, &QTimer::timeout, this, &MainWindow::mouseTimerTick);
- mouseTimer.start(1000);
-
- // this must be the last statement of constructor
+// this must be the last statement of constructor
if (!m_valid) throw std::runtime_error {"Fatal initialization exception"};
}
@@ -948,10 +944,16 @@ void MainWindow::not_GA_warning_message ()
MessageBox::critical_message (this,
"This version of WSJT-X is a beta-level Release Candidate.\n\n"
+ "In FT8 and MSK144 modes it uses ONLY the new 77-bit\n"
+ "message formats. It will not decode 75-bit or 72-bit\n"
+ "messages.\n\n"
+ "On December 10, 2018, 77-bit messages will become the\n"
+ "standard. Everyone should upgrade to WSJT-X 2.0 by\n"
+ "January 1, 2019.\n\n"
"On-the-air use carries an obligation to report problems\n"
"to the WSJT Development group and to upgrade to a GA\n"
"(General Availability) release when it becomes available.\n\n"
- "This version cannot be used after December 31, 2018\n\n");
+ "This version cannot be used after December 31, 2018.\n\n");
if(now.daysTo(timeout) < 0) Q_EMIT finished();
}
@@ -962,22 +964,6 @@ void MainWindow::initialize_fonts ()
setDecodedTextFont (m_config.decoded_text_font ());
}
-void MainWindow::mouseTimerTick()
-{
- QPoint point = QCursor::pos();
- if(point != mouseLastPos)
- m_mouseIdleSeconds = 0;
- else
- m_mouseIdleSeconds++;
- mouseLastPos = point;
-//Here we should do what's necessary when mouseIdleSeconds gets too big.
-// qDebug() << m_mouseIdleSeconds;
- if(ui->cbAutoSeq->isChecked() and m_mouseIdleSeconds>300) {
- auto_tx_mode (false);
- }
-}
-
-
void MainWindow::splash_done ()
{
m_splash && m_splash->close ();
@@ -1077,6 +1063,7 @@ void MainWindow::writeSettings()
m_settings->setValue("RR73",m_send_RR73);
m_settings->setValue ("WSPRPreferType1", ui->WSPR_prefer_type_1_check_box->isChecked ());
m_settings->setValue("UploadSpots",m_uploadSpots);
+ m_settings->setValue("NoOwnCall",ui->cbNoOwnCall->isChecked());
m_settings->setValue ("BandHopping", ui->band_hopping_group_box->isChecked ());
m_settings->setValue ("TRPeriod", ui->sbTR->value ());
m_settings->setValue("FastMode",m_bFastMode);
@@ -1168,6 +1155,7 @@ void MainWindow::readSettings()
ui->WSPR_prefer_type_1_check_box->setChecked (m_settings->value ("WSPRPreferType1", true).toBool ());
m_uploadSpots=m_settings->value("UploadSpots",false).toBool();
if(!m_uploadSpots) ui->cbUploadWSPR_Spots->setStyleSheet("QCheckBox{background-color: yellow}");
+ ui->cbNoOwnCall->setChecked(m_settings->value("NoOwnCall",false).toBool());
ui->band_hopping_group_box->setChecked (m_settings->value ("BandHopping", false).toBool());
// setup initial value of tx attenuator
m_block_pwr_tooltip = true;
@@ -1248,10 +1236,10 @@ void MainWindow::setDecodedTextFont (QFont const& font)
m_msgAvgWidget->changeFont (font);
}
if (m_foxLogWindow) {
- m_foxLogWindow->change_font (font);
+ m_foxLogWindow->set_log_view_font (font);
}
if (m_contestLogWindow) {
- m_contestLogWindow->change_font (font);
+ m_contestLogWindow->set_log_view_font (font);
}
updateGeometry ();
}
@@ -1880,7 +1868,6 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) {
m_bandEdited = true;
band_changed(m_freqNominal-2000);
-// qDebug() << "Down" << m_freqNominal;
} else {
n=11;
if(e->modifiers() & Qt::ControlModifier) n+=100;
@@ -1895,7 +1882,6 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) {
m_bandEdited = true;
band_changed(m_freqNominal+2000);
-// qDebug() << "Up " << m_freqNominal;
} else {
n=12;
if(e->modifiers() & Qt::ControlModifier) n+=100;
@@ -2440,6 +2426,10 @@ void MainWindow::on_fox_log_action_triggered()
// Connect signals from fox log window
connect (this, &MainWindow::finished, m_foxLogWindow.data (), &FoxLogWindow::close);
+ connect (m_foxLogWindow.data (), &FoxLogWindow::reset_log_model, [this] () {
+ if (!m_foxLog) m_foxLog.reset (new FoxLog);
+ m_foxLog->reset ();
+ });
}
m_foxLogWindow->showNormal ();
m_foxLogWindow->raise ();
@@ -5353,9 +5343,15 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button
default: break;
}
+ auto special_op = m_config.special_op_id ();
+ if (SpecOp::NONE < special_op && special_op < SpecOp::FOX)
+ {
+ if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config});
+ }
m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd,
m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal +
- ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd);
+ ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd,
+ m_cabrilloLog.data ());
}
void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, QString const& grid
@@ -5372,15 +5368,6 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call,
tr ("Cannot open \"%1\"").arg (m_logBook.path ()));
}
-
- if (SpecOp::NONE < m_config.special_op_id() && SpecOp::FOX > m_config.special_op_id()) {
- if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config});
- m_cabrilloLog->add_QSO (m_freqNominal, QDateTime::currentDateTimeUtc (), m_hisCall, m_xSent, m_xRcvd);
- m_xSent="";
- m_xRcvd="";
- ui->sbSerialNumber->setValue (ui->sbSerialNumber->value () + 1);
- }
-
m_messageClient->qso_logged (QSO_date_off, call, grid, dial_freq, mode, rpt_sent, rpt_received
, tx_power, comments, name, QSO_date_on, operator_call, my_call, my_grid);
m_messageClient->logged_ADIF (ADIF);
@@ -5400,6 +5387,14 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call,
if (m_config.clear_DX () and SpecOp::HOUND != m_config.special_op_id()) clearDX ();
m_dateTimeQSOOn = QDateTime {};
+ auto special_op = m_config.special_op_id ();
+ if (SpecOp::NONE < special_op && special_op < SpecOp::FOX)
+ {
+ ui->sbSerialNumber->setValue (ui->sbSerialNumber->value () + 1);
+ }
+
+ m_xSent.clear ();
+ m_xRcvd.clear ();
}
qint64 MainWindow::nWidgets(QString t)
@@ -5464,7 +5459,6 @@ void MainWindow::displayWidgets(qint64 n)
if(i==32) ui->cbCQonly->setVisible(b);
j=j>>1;
}
- if(!ui->cbAutoSeq->isVisible()) ui->cbAutoSeq->setChecked(false);
b=SpecOp::EU_VHF==m_config.special_op_id() or (SpecOp::RTTY==m_config.special_op_id() and
(m_config.RTTY_Exchange()=="#" or m_config.RTTY_Exchange()=="DX"));
ui->sbSerialNumber->setVisible(b);
@@ -6134,25 +6128,14 @@ void MainWindow::on_actionErase_ALL_TXT_triggered() //Erase ALL.TXT
}
}
-void MainWindow::on_reset_fox_log_action_triggered ()
-{
- int ret = MessageBox::query_message(this, tr("Confirm Reset"),
- tr("Are you sure you want to erase file FoxQSO.txt and start a new Fox log?"));
- if(ret==MessageBox::Yes) {
- QFile f{m_config.writeable_data_dir().absoluteFilePath("FoxQSO.txt")};
- f.remove();
- if (!m_foxLog) m_foxLog.reset (new FoxLog);
- m_foxLog->reset ();
- }
-}
-
void MainWindow::on_reset_cabrillo_log_action_triggered ()
{
- if (MessageBox::Yes == MessageBox::query_message(this, tr("Confirm Erase"),
- tr("Are you sure you want to erase file cabrillo.log"
- " and start a new Cabrillo log?")))
+ if (MessageBox::Yes == MessageBox::query_message (this, tr ("Confirm Reset"),
+ tr ("Are you sure you want to erase your contest log?"),
+ tr ("Doing this will remove all QSO records for the current contest. "
+ "They will be kept in the ADIF log file but will not be available "
+ "for export in your Cabrillo log.")))
{
- QFile {m_config.writeable_data_dir ().absoluteFilePath ("cabrillo.log")}.remove ();
ui->sbSerialNumber->setValue (1);
if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config});
m_cabrilloLog->reset ();
@@ -6505,15 +6488,17 @@ void MainWindow::on_readFreq_clicked()
void MainWindow::on_pbTxMode_clicked()
{
- if(m_modeTx=="JT9") {
- m_modeTx="JT65";
- ui->pbTxMode->setText("Tx JT65 #");
- } else {
- m_modeTx="JT9";
- ui->pbTxMode->setText("Tx JT9 @");
+ if(m_mode=="JT9+JT65") {
+ if(m_modeTx=="JT9") {
+ m_modeTx="JT65";
+ ui->pbTxMode->setText("Tx JT65 #");
+ } else {
+ m_modeTx="JT9";
+ ui->pbTxMode->setText("Tx JT9 @");
+ }
+ m_wideGraph->setModeTx(m_modeTx);
+ statusChanged();
}
- m_wideGraph->setModeTx(m_modeTx);
- statusChanged();
}
void MainWindow::setXIT(int n, Frequency base)
@@ -7266,6 +7251,10 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout
QString t1;
while(p1.canReadLine()) {
QString t(p1.readLine());
+ if(ui->cbNoOwnCall->isChecked()) {
+ if(t.contains(" " + m_config.my_callsign() + " ")) continue;
+ if(t.contains(" <" + m_config.my_callsign() + "> ")) continue;
+ }
if(t.indexOf("") >= 0) {
m_bDecoded = m_nWSPRdecodes > 0;
if(!m_diskData) {
@@ -7391,7 +7380,6 @@ void MainWindow::WSPR_history(Frequency dialFreq, int ndecodes)
}
}
-
void MainWindow::uploadSpots()
{
// do not spot replays or if rig control not working
@@ -7933,9 +7921,9 @@ QString MainWindow::sortHoundCalls(QString t, int isort, int max_dB)
if(isort>1) {
if(bReverse) {
- qSort(list.begin(),list.end(),qGreater());
+ std::sort (list.begin (), list.end (), std::greater ());
} else {
- qSort(list.begin(),list.end());
+ std::sort (list.begin (), list.end ());
}
}
diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h
index 2ef380e74..4cab787b5 100644
--- a/widgets/mainwindow.h
+++ b/widgets/mainwindow.h
@@ -204,7 +204,6 @@ private slots:
void on_actionDeepestDecode_toggled (bool);
void bumpFqso(int n);
void on_actionErase_ALL_TXT_triggered();
- void on_reset_fox_log_action_triggered ();
void on_reset_cabrillo_log_action_triggered ();
void on_actionErase_wsjtx_log_adi_triggered();
void on_actionExport_Cabrillo_log_triggered();
@@ -446,7 +445,6 @@ private:
qint32 m_Nslots=5;
qint32 m_nFoxMsgTimes[5]={0,0,0,0,0};
qint32 m_tAutoOn;
- qint32 m_mouseIdleSeconds;
qint32 m_tFoxTx=0;
qint32 m_tFoxTx0=0;
qint32 m_maxStrikes=3; //Max # of repeats: 3 strikes and you're out
@@ -570,9 +568,6 @@ private:
QTimer minuteTimer;
QTimer splashTimer;
QTimer p1Timer;
- QTimer mouseTimer;
-
- QPoint mouseLastPos;
QString m_path;
QString m_baseCall;
@@ -701,7 +696,6 @@ private:
void CQTxFreq();
void useNextCall();
void abortQSO();
- void mouseTimerTick();
bool isWorked(int itype, QString key, float fMHz=0, QString="");
QString save_wave_file (QString const& name
diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui
index fe9aa30bc..21799434e 100644
--- a/widgets/mainwindow.ui
+++ b/widgets/mainwindow.ui
@@ -573,6 +573,430 @@ QLabel[oob="true"] {
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 16777215
+
+
+
+ <html><head/><body><p>30dB recommended when only noise present<br/>Green when good<br/>Red when clipping may occur<br/>Yellow when too low</p></body></html>
+
+
+ QFrame::Panel
+
+
+ QFrame::Sunken
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 252
+ 252
+ 252
+
+
+
+
+
+
+ 159
+ 175
+ 213
+
+
+
+
+
+
+
+
+ 252
+ 252
+ 252
+
+
+
+
+
+
+ 159
+ 175
+ 213
+
+
+
+
+
+
+
+
+ 159
+ 175
+ 213
+
+
+
+
+
+
+ 159
+ 175
+ 213
+
+
+
+
+
+
+
+ true
+
+
+ DX Call
+
+
+ Qt::AlignCenter
+
+
+ 5
+
+
+ 2
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 252
+ 252
+ 252
+
+
+
+
+
+
+ 159
+ 175
+ 213
+
+
+
+
+
+
+
+
+ 252
+ 252
+ 252
+
+
+
+
+
+
+ 159
+ 175
+ 213
+
+
+
+
+
+
+
+
+ 159
+ 175
+ 213
+
+
+
+
+
+
+ 159
+ 175
+ 213
+
+
+
+
+
+
+
+ true
+
+
+ DX Grid
+
+
+ Qt::AlignCenter
+
+
+ 5
+
+
+ 2
+
+
+
+ -
+
+
+ Callsign of station to be worked
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Search for callsign in database
+
+
+ &Lookup
+
+
+
+ -
+
+
+ Locator of station to be worked
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ true
+
+
+ Az: 251 16553 km
+
+
+ Qt::AlignCenter
+
+
+ 4
+
+
+
+ -
+
+
+ Add callsign and locator to database
+
+
+ Add
+
+
+
+
+
+
+ -
+
+
+ Pwr
+
+
+
+ -
+
+
+ false
+
+
+ <html><head/><body><p>If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode.</p></body></html>
+
+
+ QPushButton {
+ font-family: helvetica;
+ font-size: 9pt;
+ font-weight: bold;
+ background-color: white;
+ color: black;
+ border-style: solid;
+ border-width:1px;
+ border-radius:10px;
+ border-color: gray;
+ max-width:20px;
+ max-height:20px;
+ min-width:20px;
+ min-height:20px;
+}
+QPushButton[state="error"] {
+ background-color: red;
+}
+QPushButton[state="warning"] {
+ background-color: orange;
+}
+QPushButton[state="ok"] {
+ background-color: #00ff00;
+}
+
+
+ ?
+
+
+
+ -
+
+
+ Adjust Tx audio level
+
+
+ 450
+
+
+ 0
+
+
+ Qt::Vertical
+
+
+ true
+
+
+ true
+
+
+ QSlider::TicksBelow
+
+
+ 50
+
+
+
+ -
+
+
+ <html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html>
+
+
+ true
+
+
+ QComboBox::NoInsert
+
+
+ QComboBox::AdjustToMinimumContentsLength
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QLabel {
+ font-family: MS Shell Dlg 2;
+ font-size: 16pt;
+ background-color : black;
+ color : yellow;
+}
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Sunken
+
+
+ 2
+
+
+ 0
+
+
+ <html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html>
+
+
+ Qt::AlignCenter
+
+
+ 5
+
+
+
-
@@ -845,7 +1269,7 @@ QLabel[oob="true"] {
false
- <html><head/><body><p>Check this to call CQ on the "Tx CQ" frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to type 2 compound callsign holders.</p></body></html>
+ <html><head/><body><p>Check this to call CQ on the "Tx CQ" frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to nonstandard callsign holders.</p></body></html>
@@ -2105,6 +2529,13 @@ list. The list can be maintained in Settings (F2).
+ -
+
+
+ No own call decodes
+
+
+
-
-
@@ -2199,430 +2630,6 @@ list. The list can be maintained in Settings (F2).
- -
-
-
-
- 0
- 0
-
-
-
-
- 100
- 16777215
-
-
-
- <html><head/><body><p>30dB recommended when only noise present<br/>Green when good<br/>Red when clipping may occur<br/>Yellow when too low</p></body></html>
-
-
- QFrame::Panel
-
-
- QFrame::Sunken
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
- 252
- 252
- 252
-
-
-
-
-
-
- 159
- 175
- 213
-
-
-
-
-
-
-
-
- 252
- 252
- 252
-
-
-
-
-
-
- 159
- 175
- 213
-
-
-
-
-
-
-
-
- 159
- 175
- 213
-
-
-
-
-
-
- 159
- 175
- 213
-
-
-
-
-
-
-
- true
-
-
- DX Call
-
-
- Qt::AlignCenter
-
-
- 5
-
-
- 2
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
- 252
- 252
- 252
-
-
-
-
-
-
- 159
- 175
- 213
-
-
-
-
-
-
-
-
- 252
- 252
- 252
-
-
-
-
-
-
- 159
- 175
- 213
-
-
-
-
-
-
-
-
- 159
- 175
- 213
-
-
-
-
-
-
- 159
- 175
- 213
-
-
-
-
-
-
-
- true
-
-
- DX Grid
-
-
- Qt::AlignCenter
-
-
- 5
-
-
- 2
-
-
-
- -
-
-
- Callsign of station to be worked
-
-
-
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- Locator of station to be worked
-
-
-
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- Search for callsign in database
-
-
- &Lookup
-
-
-
- -
-
-
- Add callsign and locator to database
-
-
- Add
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- true
-
-
- Az: 251 16553 km
-
-
- Qt::AlignCenter
-
-
- 4
-
-
-
-
-
-
- -
-
-
- Pwr
-
-
-
- -
-
-
- false
-
-
- <html><head/><body><p>If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode.</p></body></html>
-
-
- QPushButton {
- font-family: helvetica;
- font-size: 9pt;
- font-weight: bold;
- background-color: white;
- color: black;
- border-style: solid;
- border-width:1px;
- border-radius:10px;
- border-color: gray;
- max-width:20px;
- max-height:20px;
- min-width:20px;
- min-height:20px;
-}
-QPushButton[state="error"] {
- background-color: red;
-}
-QPushButton[state="warning"] {
- background-color: orange;
-}
-QPushButton[state="ok"] {
- background-color: #00ff00;
-}
-
-
- ?
-
-
-
- -
-
-
- Adjust Tx audio level
-
-
- 450
-
-
- 0
-
-
- Qt::Vertical
-
-
- true
-
-
- true
-
-
- QSlider::TicksBelow
-
-
- 50
-
-
-
- -
-
-
- <html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html>
-
-
- true
-
-
- QComboBox::NoInsert
-
-
- QComboBox::AdjustToMinimumContentsLength
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QLabel {
- font-family: MS Shell Dlg 2;
- font-size: 16pt;
- background-color : black;
- color : yellow;
-}
-
-
- QFrame::StyledPanel
-
-
- QFrame::Sunken
-
-
- 2
-
-
- 0
-
-
- <html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html>
-
-
- Qt::AlignCenter
-
-
- 5
-
-
-
@@ -2646,7 +2653,6 @@ QPushButton[state="ok"] {
-
diff --git a/widgets/widgets.pri b/widgets/widgets.pri
index 019fdcd17..e70c5cb9e 100644
--- a/widgets/widgets.pri
+++ b/widgets/widgets.pri
@@ -7,7 +7,8 @@ SOURCES += \
widgets/echoplot.cpp widgets/echograph.cpp widgets/fastgraph.cpp \
widgets/fastplot.cpp widgets/MessageBox.cpp \
widgets/colorhighlighting.cpp widgets/ExportCabrillo.cpp \
- widgets/CabrilloLogWindow.cpp
+ widgets/AbstractLogWindow.cpp \
+ widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp
HEADERS += \
widgets/mainwindow.h widgets/plotter.h \
@@ -17,8 +18,8 @@ HEADERS += \
widgets/meterwidget.h widgets/messageaveraging.h \
widgets/echoplot.h widgets/echograph.h widgets/fastgraph.h \
widgets/fastplot.h widgets/MessageBox.hpp widgets/colorhighlighting.h \
- widgets/ExportCabrillo.h \
- widgets/CabrilloLogWindow.cpp
+ widgets/ExportCabrillo.h widgets/AbstractLogWindow.hpp \
+ widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp
FORMS += \
widgets/mainwindow.ui widgets/about.ui \
@@ -26,5 +27,4 @@ FORMS += \
widgets/logqso.ui widgets/messageaveraging.ui \
widgets/echograph.ui widgets/fastgraph.ui \
widgets/colorhighlighting.ui widgets/ExportCabrillo.ui \
- widgets/FoxLogWindow.ui \
- widgets/CabrilloLogWindow.ui
+ widgets/FoxLogWindow.ui widgets/CabrilloLogWindow.ui