diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39411f8a2..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
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/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/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/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/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 055f8ae07..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);
}
}
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 da823b0cb..49a082f72 100644
--- a/qt_db_helpers.hpp
+++ b/qt_db_helpers.hpp
@@ -30,32 +30,51 @@ public:
{
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/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/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 baf85ccad..175dff49d 100644
--- a/widgets/mainwindow.cpp
+++ b/widgets/mainwindow.cpp
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1235,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 ();
}
@@ -2425,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 ();
@@ -5338,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
@@ -5357,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);
@@ -5385,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)
@@ -6118,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 ();
@@ -6489,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)
@@ -7920,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 e5b9de9a8..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();
diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui
index 8256eb606..21799434e 100644
--- a/widgets/mainwindow.ui
+++ b/widgets/mainwindow.ui
@@ -2653,7 +2653,6 @@ list. The list can be maintained in Settings (F2).
-
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